poops 1.0.20 → 1.2.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/README.md +674 -138
- package/lib/copy.js +14 -18
- package/lib/markup/collections.js +247 -0
- package/lib/markup/engines/liquid.js +240 -0
- package/lib/markup/engines/nunjucks.js +261 -0
- package/lib/markup/helpers.js +170 -0
- package/lib/markup/highlight.js +77 -0
- package/lib/markup/indexer.js +154 -0
- package/lib/markup/stop-words-en.json +25 -0
- package/lib/markups.js +233 -456
- package/lib/postcss.js +127 -0
- package/lib/reactor.js +169 -0
- package/lib/scripts.js +20 -23
- package/lib/styles.js +28 -117
- package/lib/utils/helpers.js +41 -181
- package/lib/utils/log.js +64 -0
- package/package.json +38 -12
- package/poops.js +153 -158
- package/lib/utils/print-style.js +0 -72
package/lib/markups.js
CHANGED
|
@@ -1,126 +1,80 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
this.includePaths = includePaths || []
|
|
16
|
-
this.includePaths.push('_*') // XXX: It is better to define templates and layouts directories in the config file? then all together include paths?
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
getSource(name) {
|
|
20
|
-
let fullPath = name
|
|
21
|
-
if (!fs.existsSync(name)) {
|
|
22
|
-
let pattern = `**/${name}`
|
|
23
|
-
if (this.includePaths) {
|
|
24
|
-
pattern = `{${this.includePaths.join(',')}}/${pattern}`
|
|
25
|
-
}
|
|
26
|
-
fullPath = glob.sync(path.join(this.templatesDir, pattern))[0]
|
|
27
|
-
}
|
|
28
|
-
if (!fs.existsSync(fullPath)) {
|
|
29
|
-
console.log(`${pstyle.cyanBright + pstyle.bold}[markup]${pstyle.reset} ${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Template not found:${pstyle.reset} ${pstyle.italic + pstyle.underline}${name}${pstyle.reset}`)
|
|
30
|
-
// throw new Error(`Template not found: ${name}`)
|
|
31
|
-
return { src: '', path: fullPath, noCache: true }
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let source = ''
|
|
35
|
-
let frontMatter = {}
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
const frontMatterResult = parseFrontMatter(fullPath)
|
|
39
|
-
frontMatter = frontMatterResult.frontMatter
|
|
40
|
-
source = frontMatterResult.content
|
|
41
|
-
} catch (err) {
|
|
42
|
-
console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Failed parsing front matter:${pstyle.reset} ${pstyle.italic + pstyle.underline}${fullPath}${pstyle.reset}`)
|
|
43
|
-
console.log(err)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (path.extname(fullPath) === '.md') {
|
|
47
|
-
source = require('marked').parse(source)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (frontMatter.layout) {
|
|
51
|
-
source = `{% extends '${frontMatter.layout}.html' %}\n{% block content %}\n${source}\n{% endblock %}`
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return { src: source, path: fullPath, noCache: true }
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
resolve(from, to) {
|
|
58
|
-
return path.resolve(path.dirname(from), to)
|
|
59
|
-
}
|
|
1
|
+
import { pathExists, pathIsDirectory, readDataFile, mkDir, buildTime } from './utils/helpers.js'
|
|
2
|
+
import { replaceOutExtensions, getRelativePathPrefix, getPageUrl, getPageUrlRelativeToOutput, parseFrontMatter, clearFrontMatterCache } from './markup/helpers.js'
|
|
3
|
+
import { collectionAutoDiscovery, getCollectionDataBasedOnConfig, buildCollectionPaginationData, generateCollectionPaginationPages } from './markup/collections.js'
|
|
4
|
+
import { generateIndexFiles } from './markup/indexer.js'
|
|
5
|
+
import NunjucksEngine from './markup/engines/nunjucks.js'
|
|
6
|
+
import LiquidEngine from './markup/engines/liquid.js'
|
|
7
|
+
import fs from 'node:fs'
|
|
8
|
+
import { globSync } from 'glob'
|
|
9
|
+
import path from 'node:path'
|
|
10
|
+
import log from './utils/log.js'
|
|
11
|
+
|
|
12
|
+
const ENGINES = {
|
|
13
|
+
nunjucks: NunjucksEngine,
|
|
14
|
+
liquid: LiquidEngine
|
|
60
15
|
}
|
|
61
16
|
|
|
62
|
-
|
|
17
|
+
export default class Markups {
|
|
63
18
|
constructor(config) {
|
|
64
19
|
this.config = config
|
|
65
|
-
|
|
20
|
+
const moduleConfig = this.config.markup
|
|
21
|
+
|
|
22
|
+
if (!moduleConfig || !moduleConfig.in) return
|
|
23
|
+
if (!moduleConfig.options) moduleConfig.options = {}
|
|
24
|
+
|
|
25
|
+
// Determine engine
|
|
26
|
+
const engineName = moduleConfig.engine || moduleConfig.options.engine || 'nunjucks'
|
|
27
|
+
this.logTag = 'markup'
|
|
28
|
+
|
|
29
|
+
// Normalize config
|
|
30
|
+
this.markupIn = moduleConfig.in
|
|
31
|
+
this.markupOut = moduleConfig.out || process.cwd()
|
|
32
|
+
this.siteData = moduleConfig.site || moduleConfig.options.site || {}
|
|
33
|
+
this.timeDateFormat = moduleConfig.options.timeDateFormat || moduleConfig.timeDateFormat
|
|
34
|
+
this.collectionsConfig = moduleConfig.options.collections || moduleConfig.collections
|
|
35
|
+
this.includePaths = moduleConfig.includePaths || moduleConfig.options.includePaths || []
|
|
36
|
+
this.searchIndexConfig = moduleConfig.options.searchIndex || moduleConfig.searchIndex
|
|
37
|
+
this.sitemapConfig = moduleConfig.options.sitemap || moduleConfig.sitemap
|
|
66
38
|
this.dataFiles = []
|
|
67
|
-
this.includePaths = this.config.markup.includePaths || this.config.markup.options.includePaths || []
|
|
68
39
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
noCache: true
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (this.config.markup.autoescape) {
|
|
78
|
-
options.autoescape = this.config.markup.autoescape || this.config.markup.options.autoescape
|
|
40
|
+
// Instantiate engine
|
|
41
|
+
const EngineClass = ENGINES[engineName]
|
|
42
|
+
if (!EngineClass) {
|
|
43
|
+
log({ tag: 'error', text: `Unknown markup engine: ${engineName}` })
|
|
44
|
+
return
|
|
79
45
|
}
|
|
80
46
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
this.nunjucksEnv.addFilter('slugify', str => {
|
|
85
|
-
return str.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-')
|
|
47
|
+
const templatesDir = path.join(process.cwd(), this.markupIn)
|
|
48
|
+
this.engine = new EngineClass(templatesDir, this.includePaths, {
|
|
49
|
+
autoescape: moduleConfig.autoescape || moduleConfig.options.autoescape || false
|
|
86
50
|
})
|
|
87
51
|
|
|
88
|
-
this.
|
|
89
|
-
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
this.nunjucksEnv.addFilter('markdown', str => {
|
|
93
|
-
return require('marked').parse(str)
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
this.nunjucksEnv.addFilter('date', (str, template) => {
|
|
97
|
-
if (!template) template = this.config.markup.options.timeDateFormat || this.config.markup.timeDateFormat
|
|
98
|
-
if (!template) return str
|
|
99
|
-
const date = !str || str.trim() === '' ? new Date() : new Date(str)
|
|
100
|
-
return require('moment')(date).format(template)
|
|
101
|
-
})
|
|
52
|
+
this.engine.registerFilters({ timeDateFormat: this.timeDateFormat, markupOut: this.markupOut })
|
|
53
|
+
this.engine.registerTags(() => path.join(process.cwd(), this.markupOut))
|
|
102
54
|
|
|
103
55
|
// Load global variables
|
|
104
|
-
|
|
105
56
|
const pkgPath = path.join(process.cwd(), 'package.json')
|
|
106
|
-
|
|
107
57
|
if (fs.existsSync(pkgPath)) {
|
|
108
|
-
|
|
109
|
-
this.nunjucksEnv.addGlobal('package', pkg)
|
|
58
|
+
this.engine.setGlobal('package', JSON.parse(fs.readFileSync(pkgPath, 'utf-8')))
|
|
110
59
|
}
|
|
111
60
|
|
|
112
|
-
|
|
113
|
-
this.nunjucksEnv.addGlobal('site', siteData)
|
|
61
|
+
this.engine.setGlobal('site', this.siteData)
|
|
114
62
|
|
|
115
63
|
if (this.config.livereload_port) {
|
|
116
|
-
this.
|
|
64
|
+
this.engine.setGlobal('livereload_port', this.config.livereload_port)
|
|
117
65
|
}
|
|
118
66
|
|
|
119
|
-
|
|
67
|
+
if (this.config.reactorData) {
|
|
68
|
+
for (const [name, html] of Object.entries(this.config.reactorData)) {
|
|
69
|
+
this.engine.setGlobal(name, html)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const data = moduleConfig.data || moduleConfig.options.data
|
|
120
74
|
this.loadDataFiles(data)
|
|
121
75
|
|
|
122
|
-
if (!
|
|
123
|
-
|
|
76
|
+
if (!moduleConfig.out) {
|
|
77
|
+
moduleConfig.out = this.markupOut
|
|
124
78
|
}
|
|
125
79
|
}
|
|
126
80
|
|
|
@@ -132,30 +86,37 @@ module.exports = class Markups {
|
|
|
132
86
|
files = [files]
|
|
133
87
|
}
|
|
134
88
|
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
89
|
+
const dataDir = pathIsDirectory(this.markupIn) ? this.markupIn : path.dirname(this.markupIn)
|
|
90
|
+
const resolved = []
|
|
91
|
+
for (const file of files) {
|
|
92
|
+
const fullPath = path.join(process.cwd(), dataDir, file)
|
|
93
|
+
if (pathIsDirectory(fullPath)) {
|
|
94
|
+
const dirFiles = globSync(path.join(fullPath, '**/*.+(json|yml|yaml)'))
|
|
95
|
+
for (const f of dirFiles) {
|
|
96
|
+
resolved.push(path.relative(path.join(process.cwd(), dataDir), f))
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
resolved.push(file)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
138
102
|
|
|
139
|
-
if (!this.dataFiles.length) this.dataFiles =
|
|
103
|
+
if (!this.dataFiles.length) this.dataFiles = resolved
|
|
140
104
|
|
|
141
|
-
for (const dataFile of
|
|
105
|
+
for (const dataFile of resolved) {
|
|
142
106
|
try {
|
|
143
|
-
const dataDir = pathIsDirectory(this.config.markup.in) ? this.config.markup.in : path.dirname(this.config.markup.in)
|
|
144
107
|
const data = readDataFile(path.join(process.cwd(), dataDir, dataFile))
|
|
145
108
|
const globalKeyName = path.basename(dataFile, path.extname(dataFile)).replace(/[.\-\s]/g, '_')
|
|
146
|
-
|
|
147
|
-
promises.push(this.nunjucksEnv.addGlobal(globalKeyName, data))
|
|
109
|
+
this.engine.setGlobal(globalKeyName, data)
|
|
148
110
|
} catch (err) {
|
|
149
|
-
|
|
111
|
+
log({ tag: 'error', text: 'Data file not found:', link: dataFile })
|
|
150
112
|
continue
|
|
151
113
|
}
|
|
152
114
|
}
|
|
153
|
-
|
|
154
|
-
return Promise.all(promises)
|
|
155
115
|
}
|
|
156
116
|
|
|
157
117
|
reloadDataFiles() {
|
|
158
|
-
|
|
118
|
+
this.loadDataFiles(this.dataFiles)
|
|
119
|
+
return Promise.resolve()
|
|
159
120
|
}
|
|
160
121
|
|
|
161
122
|
generateMarkupGlobPattern(excludes) {
|
|
@@ -169,411 +130,227 @@ module.exports = class Markups {
|
|
|
169
130
|
markupDefaultExcludes.push(...this.config.includePaths)
|
|
170
131
|
}
|
|
171
132
|
|
|
172
|
-
markupDefaultExcludes.push('_*')
|
|
173
|
-
|
|
174
|
-
markupDefaultExcludes = [...new Set(markupDefaultExcludes)] // Remove duplicates
|
|
133
|
+
markupDefaultExcludes.push('_*')
|
|
134
|
+
markupDefaultExcludes = [...new Set(markupDefaultExcludes)]
|
|
175
135
|
|
|
176
|
-
return `!(${markupDefaultExcludes.join('|')})/**/*.+(
|
|
136
|
+
return `!(${markupDefaultExcludes.join('|')})/**/*.+(${this.engine.markupExtensions})`
|
|
177
137
|
}
|
|
178
138
|
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const match = source.match(/^\s*---\s*([\s\S]*?)---\s*/) // Front matter match
|
|
184
|
-
let frontMatter = {}
|
|
139
|
+
async compileEntry(templateName, additionalContext) {
|
|
140
|
+
const context = { page: {} }
|
|
141
|
+
let pageUrl
|
|
185
142
|
|
|
186
|
-
if (
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Failed parsing front matter:${pstyle.reset} ${pstyle.italic + pstyle.underline}${fileName}${pstyle.reset}`)
|
|
191
|
-
console.log(err)
|
|
143
|
+
if (additionalContext) {
|
|
144
|
+
if (additionalContext._url) {
|
|
145
|
+
pageUrl = additionalContext._url
|
|
146
|
+
delete additionalContext._url
|
|
192
147
|
}
|
|
148
|
+
Object.assign(context, additionalContext)
|
|
193
149
|
}
|
|
194
150
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
let frontMatter = {}
|
|
202
|
-
|
|
203
|
-
try {
|
|
204
|
-
const frontMatterResult = parseFrontMatter(file)
|
|
205
|
-
frontMatter = frontMatterResult.frontMatter
|
|
206
|
-
} catch (err) {
|
|
207
|
-
console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Failed parsing front matter:${pstyle.reset} ${pstyle.italic + pstyle.underline}${file}${pstyle.reset}`)
|
|
208
|
-
console.log(err)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (frontMatter.published === false) return // Skip unpublished items
|
|
212
|
-
|
|
213
|
-
if (!frontMatter.date) {
|
|
214
|
-
frontMatter.date = fs.statSync(file).ctime.toISOString().slice(0, 16)
|
|
215
|
-
}
|
|
216
|
-
frontMatter.fileName = path.basename(file)
|
|
217
|
-
frontMatter.filePath = path.relative(process.cwd(), file)
|
|
218
|
-
frontMatter.collection = collectionName
|
|
219
|
-
frontMatter.url = path.join(collectionName, path.basename(frontMatter.filePath))
|
|
220
|
-
|
|
221
|
-
frontMatter.url = this.replaceOutExtensions(frontMatter.url)
|
|
222
|
-
|
|
223
|
-
if (!frontMatter.title) {
|
|
224
|
-
frontMatter.title = path.basename(frontMatter.filePath, path.extname(frontMatter.filePath))
|
|
225
|
-
}
|
|
226
|
-
collectionData.push(frontMatter)
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
return collectionData
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
collectionAutoDiscovery() {
|
|
233
|
-
const indexFiles = glob.sync(path.join(process.cwd(), this.config.markup.in, '/**/index.+(html|njk|md)'))
|
|
234
|
-
|
|
235
|
-
const collectionData = {}
|
|
236
|
-
|
|
237
|
-
for (const indexFile of indexFiles) {
|
|
238
|
-
let frontMatter = {}
|
|
239
|
-
|
|
240
|
-
try {
|
|
241
|
-
const frontMatterResult = parseFrontMatter(indexFile)
|
|
242
|
-
frontMatter = frontMatterResult.frontMatter
|
|
243
|
-
} catch (err) {
|
|
244
|
-
console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Failed parsing front matter:${pstyle.reset} ${pstyle.italic + pstyle.underline}${indexFile}${pstyle.reset}`)
|
|
245
|
-
console.log(err)
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if (!frontMatter.collection) continue
|
|
249
|
-
|
|
250
|
-
if (frontMatter.collection === true) {
|
|
251
|
-
frontMatter.collection = path.basename(path.dirname(indexFile))
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const collectionName = frontMatter.collection.trim()
|
|
255
|
-
|
|
256
|
-
if (collectionName === '') continue
|
|
257
|
-
|
|
258
|
-
frontMatter.name = collectionName
|
|
259
|
-
const collection = this.buildCollectionObject(frontMatter)
|
|
260
|
-
if (!collection) continue
|
|
261
|
-
collectionData[collection.name] = collection
|
|
151
|
+
try {
|
|
152
|
+
const frontMatterResult = parseFrontMatter(templateName)
|
|
153
|
+
context.page = frontMatterResult.frontMatter
|
|
154
|
+
} catch (err) {
|
|
155
|
+
log({ tag: 'error', text: 'Failed parsing front matter:', link: templateName })
|
|
156
|
+
console.error(err)
|
|
262
157
|
}
|
|
263
158
|
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
getCollectionDataBasedOnConfig(collectionConfig) {
|
|
268
|
-
if (!collectionConfig) return {}
|
|
269
|
-
|
|
270
|
-
const items = Array.isArray(collectionConfig)
|
|
271
|
-
? collectionConfig
|
|
272
|
-
: [collectionConfig]
|
|
159
|
+
if (pageUrl) context.page.url = pageUrl
|
|
273
160
|
|
|
274
|
-
const
|
|
161
|
+
const frontMatter = context.page
|
|
275
162
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if (!item || !item.name) continue
|
|
279
|
-
const collection = this.buildCollectionObject(item)
|
|
280
|
-
if (collection) collectionData[item.name] = collection
|
|
163
|
+
if (frontMatter && frontMatter.published === false) {
|
|
164
|
+
return { result: '', frontMatter, skipped: true }
|
|
281
165
|
}
|
|
282
166
|
|
|
283
|
-
|
|
167
|
+
const result = await this.engine.render(templateName, context)
|
|
168
|
+
return { result, frontMatter }
|
|
284
169
|
}
|
|
285
170
|
|
|
286
|
-
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (collectionProtoObject.paginate && !isNaN(parseInt(collectionProtoObject.paginate))) {
|
|
295
|
-
collection.paginate = parseInt(collectionProtoObject.paginate)
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (collectionProtoObject.sort) {
|
|
299
|
-
collection.sort = collectionProtoObject.sort
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
if (typeof collection.sort === 'string') {
|
|
303
|
-
collection.sort = { by: collection.sort }
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (!collection.sort) {
|
|
307
|
-
collection.sort = { by: 'date' }
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
if (!collection.sort.by) {
|
|
311
|
-
collection.sort.by = 'date'
|
|
312
|
-
}
|
|
171
|
+
async compileDirectory(markupIn, collectionData, pageEntries) {
|
|
172
|
+
const markupStart = performance.now()
|
|
173
|
+
const markupFiles = [
|
|
174
|
+
...globSync(path.join(markupIn, this.generateMarkupGlobPattern(this.includePaths))),
|
|
175
|
+
...globSync(path.join(markupIn, `*.+(${this.engine.markupExtensions})`))
|
|
176
|
+
]
|
|
177
|
+
const compilePromises = []
|
|
178
|
+
const indexableExtensions = this.engine.indexableExtensions
|
|
313
179
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
collection.sort.type = 'alphabetical'
|
|
318
|
-
}
|
|
180
|
+
for (const file of markupFiles) {
|
|
181
|
+
const relativePath = path.relative(markupIn, file)
|
|
182
|
+
const relativePathParts = relativePath.split(path.sep)
|
|
319
183
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
184
|
+
if (relativePathParts.length > 1 &&
|
|
185
|
+
collectionData[relativePathParts[0]] &&
|
|
186
|
+
relativePathParts[1].startsWith('index.') && indexableExtensions.has(path.extname(relativePathParts[1])) &&
|
|
187
|
+
collectionData[relativePathParts[0]].items.length > 0) {
|
|
188
|
+
continue
|
|
189
|
+
}
|
|
323
190
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
return new Date(a[collection.sort.by]) - new Date(b[collection.sort.by])
|
|
328
|
-
}
|
|
191
|
+
let markupOut = path.join(process.cwd(), this.markupOut, relativePath)
|
|
192
|
+
const fromPath = path.join(process.cwd(), this.markupOut)
|
|
193
|
+
const markupOutDir = path.dirname(markupOut)
|
|
329
194
|
|
|
330
|
-
|
|
331
|
-
} else {
|
|
332
|
-
if (collection.sort.order === 'asc') {
|
|
333
|
-
return a[collection.sort.by] > b[collection.sort.by] ? 1 : -1
|
|
334
|
-
}
|
|
195
|
+
mkDir(markupOutDir)
|
|
335
196
|
|
|
336
|
-
|
|
197
|
+
const fileContext = {
|
|
198
|
+
...collectionData,
|
|
199
|
+
relativePathPrefix: getRelativePathPrefix(markupOutDir, fromPath),
|
|
200
|
+
_url: getPageUrl(markupOut)
|
|
337
201
|
}
|
|
338
|
-
})
|
|
339
202
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
203
|
+
const shouldIndex = pageEntries && indexableExtensions.has(path.extname(file))
|
|
204
|
+
const fileCollection = relativePathParts.length > 1 && collectionData[relativePathParts[0]]
|
|
205
|
+
? relativePathParts[0]
|
|
206
|
+
: null
|
|
207
|
+
|
|
208
|
+
const compilePromise = this.compileEntry(file, fileContext).then(({ result, frontMatter, skipped }) => {
|
|
209
|
+
if (skipped) {
|
|
210
|
+
const outFile = replaceOutExtensions(markupOut)
|
|
211
|
+
if (fs.existsSync(outFile)) {
|
|
212
|
+
fs.unlinkSync(outFile)
|
|
213
|
+
log({ tag: this.logTag, text: 'Removed unpublished:', link: path.relative(process.cwd(), outFile) })
|
|
214
|
+
}
|
|
215
|
+
return
|
|
216
|
+
}
|
|
217
|
+
markupOut = replaceOutExtensions(markupOut)
|
|
218
|
+
fs.writeFileSync(markupOut, result)
|
|
347
219
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
220
|
+
if (shouldIndex && frontMatter.published !== false) {
|
|
221
|
+
if (!frontMatter.title) frontMatter.title = path.basename(file, path.extname(file))
|
|
222
|
+
if (fileCollection && !frontMatter.collection) frontMatter.collection = fileCollection
|
|
351
223
|
|
|
352
|
-
|
|
353
|
-
|
|
224
|
+
pageEntries.push({
|
|
225
|
+
...frontMatter,
|
|
226
|
+
url: getPageUrlRelativeToOutput(markupOut, this.markupOut),
|
|
227
|
+
content: result,
|
|
228
|
+
isIndex: false
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
compilePromises.push(compilePromise)
|
|
354
233
|
}
|
|
355
234
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
upDir += `..${path.sep}`
|
|
235
|
+
try {
|
|
236
|
+
await Promise.all(compilePromises)
|
|
237
|
+
const markupEnd = performance.now()
|
|
238
|
+
log({ tag: this.logTag, text: `Compiled: ${markupFiles.length} file${markupFiles.length > 1 ? 's' : ''} into`, link: this.markupOut, time: buildTime(markupStart, markupEnd) })
|
|
239
|
+
} catch (err) {
|
|
240
|
+
log({ tag: this.logTag, error: true, text: 'Failed compiling' })
|
|
241
|
+
console.error(err)
|
|
242
|
+
throw err
|
|
243
|
+
} finally {
|
|
244
|
+
clearFrontMatterCache()
|
|
367
245
|
}
|
|
368
|
-
return upDir
|
|
369
246
|
}
|
|
370
247
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
248
|
+
async compileSingleFile(markupIn, collectionData, pageEntries) {
|
|
249
|
+
const markupStart = performance.now()
|
|
250
|
+
let markupOut = path.join(process.cwd(), this.markupOut)
|
|
251
|
+
const markupOutDir = path.dirname(markupOut)
|
|
252
|
+
const indexableExtensions = this.engine.indexableExtensions
|
|
253
|
+
mkDir(markupOutDir)
|
|
375
254
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
break
|
|
381
|
-
case '.njk':
|
|
382
|
-
outputPath = outputPath.replace(/\.njk$/, '.html')
|
|
383
|
-
break
|
|
255
|
+
const fileContext = {
|
|
256
|
+
...collectionData,
|
|
257
|
+
relativePathPrefix: getRelativePathPrefix(markupOutDir),
|
|
258
|
+
_url: getPageUrl(markupOut)
|
|
384
259
|
}
|
|
385
260
|
|
|
386
|
-
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
compileEntry(templateName, additionalContext) {
|
|
390
|
-
const context = { page: {} }
|
|
391
|
-
let pageUrl
|
|
392
|
-
|
|
393
|
-
if (additionalContext) {
|
|
394
|
-
if (additionalContext._url) {
|
|
395
|
-
pageUrl = additionalContext._url
|
|
396
|
-
delete additionalContext._url
|
|
397
|
-
}
|
|
398
|
-
Object.assign(context, additionalContext)
|
|
399
|
-
}
|
|
261
|
+
const shouldIndex = pageEntries && indexableExtensions.has(path.extname(markupIn))
|
|
400
262
|
|
|
401
263
|
try {
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
} catch (err) {
|
|
405
|
-
console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Failed parsing front matter:${pstyle.reset} ${pstyle.italic + pstyle.underline}${templateName}${pstyle.reset}`)
|
|
406
|
-
console.log(err)
|
|
407
|
-
}
|
|
264
|
+
const { result, frontMatter, skipped } = await this.compileEntry(markupIn, fileContext)
|
|
265
|
+
markupOut = replaceOutExtensions(markupOut)
|
|
408
266
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
env.getTemplate(templateName).render(context, (error, result) => {
|
|
414
|
-
if (!error) {
|
|
415
|
-
resolve(result)
|
|
416
|
-
} else {
|
|
417
|
-
reject(error)
|
|
267
|
+
if (skipped) {
|
|
268
|
+
if (fs.existsSync(markupOut)) {
|
|
269
|
+
fs.unlinkSync(markupOut)
|
|
270
|
+
log({ tag: this.logTag, text: 'Removed unpublished:', link: path.relative(process.cwd(), markupOut) })
|
|
418
271
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
getCollectionIndexFile(collectionName) {
|
|
424
|
-
const indexFiles = glob.sync(path.join(process.cwd(), this.config.markup.in, collectionName, 'index.+(html|njk|md)'))
|
|
425
|
-
if (indexFiles.length === 0) return null
|
|
426
|
-
return indexFiles[0]
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
buildCollectionPaginationData(collectionData) {
|
|
430
|
-
if (!collectionData) return
|
|
431
|
-
|
|
432
|
-
for (const collectionName of Object.keys(collectionData)) {
|
|
433
|
-
const collection = collectionData[collectionName]
|
|
272
|
+
return
|
|
273
|
+
}
|
|
434
274
|
|
|
435
|
-
|
|
275
|
+
fs.writeFileSync(markupOut, result)
|
|
436
276
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
277
|
+
if (shouldIndex && frontMatter.published !== false) {
|
|
278
|
+
if (!frontMatter.title) frontMatter.title = path.basename(markupIn, path.extname(markupIn))
|
|
279
|
+
pageEntries.push({
|
|
280
|
+
...frontMatter,
|
|
281
|
+
url: getPageUrlRelativeToOutput(markupOut, this.markupOut),
|
|
282
|
+
content: result,
|
|
283
|
+
isIndex: false
|
|
284
|
+
})
|
|
445
285
|
}
|
|
446
|
-
collection.pages.push(pageItems)
|
|
447
286
|
|
|
448
|
-
|
|
287
|
+
const markupEnd = performance.now()
|
|
288
|
+
log({ tag: this.logTag, text: 'Compiled:', link: path.relative(process.cwd(), path.join(process.cwd(), this.markupOut, path.basename(markupIn))), time: buildTime(markupStart, markupEnd) })
|
|
289
|
+
} catch (err) {
|
|
290
|
+
log({ tag: this.logTag, error: true, text: 'Failed compiling:', link: path.relative(process.cwd(), path.join(process.cwd(), this.markupOut, path.basename(markupIn))) })
|
|
291
|
+
console.error(err)
|
|
292
|
+
throw err
|
|
293
|
+
} finally {
|
|
294
|
+
clearFrontMatterCache()
|
|
449
295
|
}
|
|
450
296
|
}
|
|
451
297
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
for (const collectionName of Object.keys(collectionData)) {
|
|
456
|
-
const collection = collectionData[collectionName]
|
|
457
|
-
const file = this.getCollectionIndexFile(collectionName)
|
|
458
|
-
|
|
459
|
-
if (!collection.totalPages || collection.totalPages === 0) {
|
|
460
|
-
collection.totalPages = 1
|
|
461
|
-
collection.pages = [collection.items]
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
for (let i = 0; i < collection.totalPages; i++) {
|
|
465
|
-
collection.pageItems = collection.pages[i]
|
|
466
|
-
collection.pageNumber = i + 1
|
|
467
|
-
collection.pageUrl = collection.pageNumber === 1 ? collection.name : `${collection.name}/${collection.pageNumber}`
|
|
468
|
-
collection.nextPage = collection.pageNumber === collection.totalPages ? null : collection.pageNumber + 1
|
|
469
|
-
collection.nextPageUrl = collection.pageNumber === collection.totalPages ? null : `${collection.name}/${collection.pageNumber + 1}`
|
|
470
|
-
collection.prevPage = collection.pageNumber === 1 ? null : collection.pageNumber - 1
|
|
471
|
-
collection.prevPageUrl = collection.pageNumber === 1 ? null : `${collection.name}/${collection.pageNumber - 1}`
|
|
472
|
-
if (collection.prevPage === 1) {
|
|
473
|
-
collection.prevPageUrl = collection.name
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
const markupOut = path.join(process.cwd(), this.config.markup.out, collection.pageUrl, 'index.html')
|
|
477
|
-
const fromPath = path.join(process.cwd(), this.config.markup.out)
|
|
478
|
-
const markupOutDir = path.dirname(markupOut)
|
|
479
|
-
|
|
480
|
-
mkDir(markupOutDir)
|
|
481
|
-
|
|
482
|
-
collectionData.relativePathPrefix = this.getRelativePathPrefix(markupOutDir, fromPath)
|
|
483
|
-
collectionData._url = this.getPageUrl(markupOut)
|
|
484
|
-
|
|
485
|
-
if (!file) {
|
|
486
|
-
continue
|
|
487
|
-
}
|
|
298
|
+
async compile() {
|
|
299
|
+
const moduleConfig = this.config.markup
|
|
300
|
+
if (!moduleConfig || !moduleConfig.in) return
|
|
488
301
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
compilePromises.push(compilePromise)
|
|
302
|
+
if (this.config.reactorData) {
|
|
303
|
+
for (const [name, html] of Object.entries(this.config.reactorData)) {
|
|
304
|
+
this.engine.setGlobal(name, html)
|
|
493
305
|
}
|
|
494
306
|
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
compile() {
|
|
498
|
-
if (!this.config.markup || !this.config.markup.in) return
|
|
499
307
|
|
|
500
|
-
const markupIn = path.join(process.cwd(), this.
|
|
501
|
-
const compilePromises = []
|
|
308
|
+
const markupIn = path.join(process.cwd(), this.markupIn)
|
|
502
309
|
|
|
503
310
|
if (!pathExists(markupIn)) {
|
|
504
|
-
|
|
311
|
+
log({ tag: 'error', text: 'Markup path does not exist:', link: markupIn })
|
|
505
312
|
return
|
|
506
313
|
}
|
|
507
314
|
|
|
508
315
|
const collectionData = {
|
|
509
|
-
...this.
|
|
510
|
-
...
|
|
316
|
+
...collectionAutoDiscovery(this.markupIn),
|
|
317
|
+
...getCollectionDataBasedOnConfig(this.markupIn, this.collectionsConfig)
|
|
511
318
|
}
|
|
512
319
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
this.generateCollectionPaginationPages(collectionData, compilePromises)
|
|
516
|
-
|
|
517
|
-
if (pathIsDirectory(markupIn)) {
|
|
518
|
-
const markupFiles = [...glob.sync(path.join(markupIn, this.generateMarkupGlobPattern(this.includePaths))), ...glob.sync(path.join(markupIn, '*.+(html|xml|rss|atom|json|njk|md)'))]
|
|
519
|
-
|
|
520
|
-
markupFiles.forEach((file) => {
|
|
521
|
-
const relativePath = path.relative(markupIn, file)
|
|
522
|
-
const relativePathParts = relativePath.split(path.sep)
|
|
523
|
-
|
|
524
|
-
// Collection pages already generated, skip them
|
|
525
|
-
if (relativePathParts.length > 1 &&
|
|
526
|
-
collectionData[relativePathParts[0]] &&
|
|
527
|
-
/^index\.(html|njk|md)$/.test(relativePathParts[1]) &&
|
|
528
|
-
collectionData[relativePathParts[0]].items.length > 0) {
|
|
529
|
-
return
|
|
530
|
-
}
|
|
320
|
+
const shouldIndex = this.searchIndexConfig || this.sitemapConfig
|
|
321
|
+
const pageEntries = shouldIndex ? [] : null
|
|
531
322
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
const markupOutDir = path.dirname(markupOut)
|
|
323
|
+
buildCollectionPaginationData(collectionData)
|
|
324
|
+
const collectionPromises = generateCollectionPaginationPages(collectionData, this.markupIn, this.markupOut, this.compileEntry.bind(this))
|
|
535
325
|
|
|
536
|
-
|
|
326
|
+
await Promise.all(collectionPromises)
|
|
537
327
|
|
|
538
|
-
|
|
539
|
-
|
|
328
|
+
if (pageEntries) {
|
|
329
|
+
for (const collectionName of Object.keys(collectionData)) {
|
|
330
|
+
const collection = collectionData[collectionName]
|
|
331
|
+
const totalPages = collection.totalPages || 1
|
|
540
332
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
333
|
+
for (let i = 0; i < totalPages; i++) {
|
|
334
|
+
const pageUrl = i === 0 ? collectionName : `${collectionName}/${i + 1}`
|
|
335
|
+
pageEntries.push({
|
|
336
|
+
url: pageUrl,
|
|
337
|
+
title: collectionName,
|
|
338
|
+
isIndex: true
|
|
339
|
+
})
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
547
343
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
console.log(`${pstyle.cyanBright + pstyle.bold}[markup]${pstyle.reset} ${pstyle.dim}Compiled: ${pstyle.reset}${markupFiles.length} file${markupFiles.length > 1 ? 's' : ''} into ${pstyle.italic + pstyle.underline}${this.config.markup.out}${pstyle.reset}`)
|
|
551
|
-
clearFrontMatterCache()
|
|
552
|
-
resolve()
|
|
553
|
-
}).catch((err) => {
|
|
554
|
-
console.log(`${pstyle.cyanBright + pstyle.bold}[markup]${pstyle.reset} ${pstyle.redBright + pstyle.bold}[error]${pstyle.reset} ${pstyle.dim}Failed compiling${pstyle.reset + pstyle.bell}`)
|
|
555
|
-
console.log(err)
|
|
556
|
-
clearFrontMatterCache()
|
|
557
|
-
reject(err)
|
|
558
|
-
})
|
|
559
|
-
})
|
|
344
|
+
if (pathIsDirectory(markupIn)) {
|
|
345
|
+
await this.compileDirectory(markupIn, collectionData, pageEntries)
|
|
560
346
|
} else {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
mkDir(markupOutDir)
|
|
564
|
-
|
|
565
|
-
collectionData.relativePathPrefix = this.getRelativePathPrefix(markupOutDir)
|
|
566
|
-
collectionData._url = this.getPageUrl(markupOut)
|
|
347
|
+
await this.compileSingleFile(markupIn, collectionData, pageEntries)
|
|
348
|
+
}
|
|
567
349
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
clearFrontMatterCache()
|
|
573
|
-
}).catch((err) => {
|
|
574
|
-
console.log(`${pstyle.cyanBright + pstyle.bold}[markup]${pstyle.reset} ${pstyle.redBright + pstyle.bold}[error]${pstyle.reset} ${pstyle.dim}Failed compiling:${pstyle.reset} ${pstyle.italic + pstyle.underline}${path.relative(process.cwd(), path.join(process.cwd(), this.config.markup.out, path.basename(markupIn)))}${pstyle.reset + pstyle.bell}`)
|
|
575
|
-
console.log(err)
|
|
576
|
-
clearFrontMatterCache()
|
|
350
|
+
if (shouldIndex && pageEntries) {
|
|
351
|
+
generateIndexFiles(pageEntries, this.markupOut, this.siteData.url, {
|
|
352
|
+
searchIndex: this.searchIndexConfig,
|
|
353
|
+
sitemap: this.sitemapConfig
|
|
577
354
|
})
|
|
578
355
|
}
|
|
579
356
|
}
|