-
Notifications
You must be signed in to change notification settings - Fork 69
/
build.js
143 lines (127 loc) · 4.14 KB
/
build.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
'use strict'
const collections = require('metalsmith-collections')
const drafts = require('metalsmith-drafts')
const layouts = require('metalsmith-layouts')
const markdown = require('metalsmith-markdown')
const Metalsmith = require('metalsmith')
const permalinks = require('metalsmith-permalinks')
const { convertToKatex } = require('./katex-plugin')
const { addLanguageMarkers } = require('./language-switching-plugin')
const { addConcealmentMarkers } = require('./concealed-portions-plugin')
const { incorporateLiterateCode } = require('./literate-code-plugin')
const { highlightCode } = require('./prism-plugin')
const { wrapFigures } = require('./captions-plugin')
process.env.SITE_ROOT = process.env.SITE_ROOT || '/'
const BUILD_DESTINATION = process.env.BUILD_DESTINATION || '/tmp/algos-book-dev-build'
const chapters = [
['analysis', 'Analysis'],
['stacks', 'Stacks'],
['queues', 'Queues'],
['deques', 'Deques'],
['lists', 'Lists'],
['recursion', 'Recursion'],
['searching', 'Searching'],
['trees', 'Trees'],
['graphs', 'Graphs'],
]
const collectionConfig = {}
const nextSection = {}
const previousSection = {}
chapters.forEach(([label, name], i) => {
collectionConfig[label] = {
sortBy: 'position',
metadata: { name: name },
}
nextSection[label] = chapters[i + 1] ? chapters[i + 1][0] : null
previousSection[label] = chapters[i - 1] ? chapters[i - 1][0] : null
})
const INDEX_PATH = 'index.html'
// UGH! fix this ugly hack around the fact that the collections plugin
// does not link previous/next between chapters
const bridgeLinksBetweenCollections =
(files, metalsmith) => {
for (let path in files) {
// ignore non-html files
if (path.search('\.html$') === -1) continue
const file = files[path]
// special case: link introduction to first section
if (path === INDEX_PATH) {
file.next = metalsmith._metadata.collections[chapters[0][0]][0]
continue
}
if (file.collection.length === 1) {
const collection = file.collection[0]
if (file.next === undefined) {
const nextCollection = nextSection[collection]
if (nextCollection) {
file.next = metalsmith._metadata.collections[nextCollection][0]
}
}
if (file.previous === undefined) {
const previousCollection = previousSection[collection]
if (previousCollection) {
const collection = metalsmith._metadata.collections[previousCollection]
file.previous = collection[collection.length - 1]
} else {
// special case: link first section of first chapter back to intro
file.previous = files[INDEX_PATH]
}
}
}
}
}
const byPosition = (a, b) => a.position - b.position
const generateTableOfContents =
(files, metalsmith) => {
const metadata = metalsmith.metadata()
metadata['tableOfContents'] = chapters.map(([label, name]) => {
return {
name: name,
collection: (metadata[label] || []).sort(byPosition),
}
})
}
console.log(`Building to ${BUILD_DESTINATION} ..`)
const EXCLUSION_FILE_PATTERNS = [
'\.pyc$',
'\.py$',
'\.DS_STORE',
]
const removeNonPublicFiles =
files => {
for (let path in files) {
for (let i in EXCLUSION_FILE_PATTERNS) {
if (path.search(EXCLUSION_FILE_PATTERNS[i]) !== -1) {
delete files[path]
continue
}
}
}
}
// const log = (filePath) =>
// (files) =>
// console.log(files[filePath].contents.toString('utf8'))
if (!process.env.TEST) {
Metalsmith(__dirname)
.source('book')
.destination(BUILD_DESTINATION)
.use(drafts())
.use(incorporateLiterateCode)
.use(convertToKatex)
.use(highlightCode)
.use(markdown({ tables: true, pedantic: true }))
.use(addLanguageMarkers)
.use(addConcealmentMarkers)
// .use(log('analysis/an-anagram-detection-example.html'))
.use(collections(collectionConfig))
.use(bridgeLinksBetweenCollections)
.use(wrapFigures)
.use(removeNonPublicFiles)
.use(permalinks())
.use(generateTableOfContents)
.use(layouts({ engine: 'ejs' }))
.build(err => {
console.log('Built')
if (err) { throw err }
})
}