Skip to content

Commit 3fbc18c

Browse files
committed
[CM2] Introduce deep categorization
This is a combination of 3 commits. Brace yourself. For now the taxonomy depth is max 3. Because why not. This required looking up to parent context for content modelling information, instead of reaching out to the collection. So, throughout the depth of the taxonomy, content modelling can manipulate the cascade. To achieve that, the context object is converted into a stack. An ImmutableStack class is used to pop() it without worrying. It has a throwUntil() to dig the stack until reaching a point of interest (for example digging the context to find a collection). That was needed to avoid passing post and category contexts to tags, as tags don't carry a hierarchial-relationship in respect to them. Now, each subCategory can define content-modelling attributes in its index file. Therefore, each subCategory can have a custom indexFileName and custom names for its subCategories and posts. For example: Demos (collection contentType: DemoPortfolio) - CSS (category contentType: Technology) + CSS-Only (category contentType: Technique) + Sliding Doors (category contentType: Technique) - Three.js - Whatever The easiest way to deal with rendering subCategories was to merge the rendering counterpart of models into the models themselves. So, now, in addition to match() and create(), there's a render(). The render() is pretty scrappy for now and probably needs more thinking. One of the main ideas in this implementation is to nest the rendering of the model's child entities (e.g. for a category, rendering of subCategories, posts, attachments) into the models' render(). When root render()s, render flows downstream from there. So, CM2's rendering counterpart is now only the renderer itself, there's no more views. Invent something called 'levelPosts' in Category. It contains only the posts belonging to the category's specific depth. The regular 'posts' field contains all posts downstream. This was particularly necessary to avoid duplicate rendering of sub-categorized posts. So, each category renders only its levelPosts. For now, inject the global settings and debug as dependencies into models. That's for keeping templates' access to those. Maybe a classier way is needed. Also, don't pass keys like collection and category into the templates any more. Should the pagination helper be kept in renderer though? Feels much like it's a content-model thing. But the code implies otherwise.
1 parent 150bdce commit 3fbc18c

File tree

21 files changed

+616
-463
lines changed

21 files changed

+616
-463
lines changed

src/compiler/contentModel2/index.js

Lines changed: 80 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const { resolve } = require('path')
22
const _ = require('lodash')
33
const frontMatter = require('front-matter')
4+
const ImmutableStack = require('../../lib/ImmutableStack')
45
const { isTemplateFile } = require('./helpers')
56
const models = {
67
homepage: require('./models/homepage'),
@@ -57,7 +58,12 @@ const defaultContentModelSettings = {
5758
defaultCategoryName: 'Unclassified',
5859
assetsDirectory: 'assets',
5960
pagesDirectory: 'pages',
60-
homepageDirectory: 'homepage'
61+
homepageDirectory: 'homepage',
62+
debug: false,
63+
site: {
64+
title: '',
65+
description: ''
66+
}
6167
}
6268
class ContentModel {
6369
constructor(contentModelSettings = defaultContentModelSettings, contentTypes = []) {
@@ -80,10 +86,11 @@ class ContentModel {
8086
const indexFile = fileSystemTree.find(isRootIndexFile)
8187
const indexProps = indexFile ? frontMatter(indexFile.content) : {}
8288

83-
const context = {
89+
const context = new ImmutableStack([{
90+
key: 'root',
8491
outputPath: this.settings.out,
8592
permalink: this.settings.permalinkPrefix
86-
}
93+
}])
8794

8895
this.models = {
8996
collection: models.collection({
@@ -109,66 +116,119 @@ class ContentModel {
109116
})
110117
}
111118

112-
const contentModel = {
119+
this.contentModel = {
113120
homepage: this.models.homepage.create({
114121
name: 'index',
115122
extension: 'md',
116123
content: ''
117-
}, { root: context }),
124+
}, context),
118125
subpages: [],
119126
collections: [],
120127
assets: []
121128
}
122129

123130
fileSystemTree.forEach(node => {
124131
if (this.models.homepage.match(node)) {
125-
contentModel.homepage = this.models.homepage.create(node, { root: context })
132+
this.contentModel.homepage = this.models.homepage.create(node, context)
126133
return
127134
}
128135

129136
if (this.models.subpage.match(node)) {
130-
return contentModel.subpages.push(
131-
this.models.subpage.create(node, { root: context })
137+
return this.contentModel.subpages.push(
138+
this.models.subpage.create(node, context)
132139
)
133140
}
134141

135142
if (this.models.subpage.matchPagesDirectory(node)) {
136143
return node.children.forEach(childNode => {
137144
if (this.models.subpage.match(childNode)) {
138-
contentModel.subpages.push(
139-
this.models.subpage.create(childNode, { root: context })
145+
this.contentModel.subpages.push(
146+
this.models.subpage.create(childNode, context)
140147
)
141148
} else if (this.models.asset.match(childNode)) {
142-
contentModel.assets.push(
143-
this.models.asset.create(childNode, { root: context })
149+
this.contentModel.assets.push(
150+
this.models.asset.create(childNode, context)
144151
)
145152
}
146153
})
147154
}
148155

149156
if (this.models.collection.match(node)) {
150-
return contentModel.collections.push(
151-
this.models.collection.create(node, { root: context })
157+
return this.contentModel.collections.push(
158+
this.models.collection.create(node, context)
152159
)
153160
}
154161

155162
if (this.models.asset.matchAssetsDirectory(node)) {
156-
return contentModel.assets.push(
163+
return this.contentModel.assets.push(
157164
...node.children.map(childNode => {
158-
return this.models.asset.create(childNode, { root: context })
165+
return this.models.asset.create(childNode, context)
159166
})
160167
)
161168
}
162169

163170
if (this.models.asset.match(node)) {
164-
return contentModel.assets.push(
165-
this.models.asset.create(node, { root: context })
171+
return this.contentModel.assets.push(
172+
this.models.asset.create(node, context)
166173
)
167174
}
168175
})
169176

170-
linkEntries(contentModel)
171-
return contentModel
177+
linkEntries(this.contentModel)
178+
return this.contentModel
179+
}
180+
181+
render(renderer) {
182+
const renderHomepage = () => {
183+
return this.models.homepage.render(renderer, this.contentModel.homepage, {
184+
contentModel: this.contentModel,
185+
settings: this.settings,
186+
debug: this.settings.debug
187+
})
188+
}
189+
190+
const renderCollections = () => {
191+
return Promise.all(
192+
this.contentModel.collections.map(collection => {
193+
return this.models.collection.render( renderer, collection, {
194+
contentModel: this.contentModel,
195+
settings: this.settings,
196+
debug: this.settings.debug
197+
})
198+
})
199+
)
200+
}
201+
202+
const renderSubpages = () => {
203+
return Promise.all(
204+
this.contentModel.subpages.map(subpage => {
205+
return this.models.subpage.render(renderer, subpage, {
206+
contentModel: this.contentModel,
207+
settings: this.settings,
208+
debug: this.settings.debug
209+
})
210+
})
211+
)
212+
}
213+
214+
const renderAssets = () => {
215+
return Promise.all(
216+
this.contentModel.assets.map(asset => {
217+
return this.models.asset.render(renderer, asset, {
218+
contentModel: this.contentModel,
219+
settings: this.settings,
220+
debug: this.settings.debug
221+
})
222+
})
223+
)
224+
}
225+
226+
return Promise.all([
227+
renderHomepage(),
228+
renderCollections(),
229+
renderSubpages(),
230+
renderAssets()
231+
])
172232
}
173233
}
174234

src/compiler/contentModel2/models/asset.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const { join, resolve } = require('path')
33
const defaultSettings = {
44
assetsDirectory: 'assets'
55
}
6-
module.exports = function asset(settings = defaultSettings) {
6+
module.exports = function Asset(settings = defaultSettings) {
77
const assetsDirectoryNameOptions = [settings.assetsDirectory, 'assets']
88

99
const isAssetsDirectory = (node) => {
@@ -18,14 +18,15 @@ module.exports = function asset(settings = defaultSettings) {
1818
return {
1919
match: node => true,
2020
matchAssetsDirectory: isAssetsDirectory,
21+
2122
create: (node, context) => {
2223
const permalink = (
23-
context.root.permalink +
24+
context.peek().permalink +
2425
[settings.assetsDirectory, node.name].join('/')
2526
)
2627

2728
const outputPath = join(
28-
context.root.outputPath,
29+
context.peek().outputPath,
2930
settings.assetsDirectory,
3031
node.name
3132
)
@@ -37,6 +38,14 @@ module.exports = function asset(settings = defaultSettings) {
3738
outputPath,
3839
date: new Date(node.stats.birthtime || Date.now())
3940
}
41+
},
42+
43+
render: (renderer, asset) => {
44+
return renderer.copy({
45+
src: asset.absolutePath,
46+
dest: asset.outputPath,
47+
recursive: !!asset.children
48+
})
4049
}
4150
}
4251
}
Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
11
const { join } = require('path')
2+
const _ = require('lodash')
23

3-
module.exports = function attachment() {
4+
module.exports = function Attachment() {
45
return {
56
match: node => true,
7+
68
create(node, context) {
7-
const permalink = [
8-
context.page?.permalink ||
9-
context.post?.permalink ||
10-
context.category?.permalink ||
11-
context.collection?.permalink,
9+
const permalink = _.compact([
10+
context.peek()?.permalink,
1211
node.name
13-
].filter(Boolean).join('/')
12+
]).join('/')
1413

15-
const outputPath = join(...[
16-
context.page?.outputPath ||
17-
context.post?.outputPath ||
18-
context.category?.outputPath ||
19-
context.collection?.outputPath,
20-
node.name
21-
].filter(Boolean))
14+
const outputPath = join(
15+
..._.compact([
16+
context.peek()?.outputPath,
17+
node.name
18+
])
19+
)
2220

2321
return {
2422
...node,
@@ -27,6 +25,14 @@ module.exports = function attachment() {
2725
outputPath,
2826
date: new Date(node.stats.birthtime || Date.now())
2927
}
28+
},
29+
30+
render: (renderer, attachment) => {
31+
return renderer.copy({
32+
src: attachment.absolutePath,
33+
dest: attachment.outputPath,
34+
recursive: !!attachment.children
35+
})
3036
}
3137
}
3238
}

0 commit comments

Comments
 (0)