forked from github/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
site-tree.js
187 lines (142 loc) · 6.03 KB
/
site-tree.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
const path = require('path')
const { productMap } = require('./all-products')
const languageCodes = Object.keys(require('./languages'))
const addTitlesToTree = require('./site-tree-titles')
const allVersions = Object.keys(require('./all-versions'))
const { getPathWithoutVersion } = require('./path-utils')
const getApplicableVersions = require('./get-applicable-versions')
const findPage = require('./find-page')
const removeFPTFromPath = require('./remove-fpt-from-path')
// This module builds a localized tree of every page on the site
// It includes single-source pages that have different variants
// for different product versions, e.g. dotcom vs GHES
//
// siteTree[languageCode][version].products[productHref].categories[categoryHref].maptopics[maptopicHref].articles
// or if a category has direct child articles:
// siteTree[languageCode][version].products[productHref].categories[categoryHref].articles
module.exports = async function buildSiteTree (pageMap, site, redirects) {
const siteTree = {}
languageCodes.forEach(languageCode => {
siteTree[languageCode] = {}
allVersions.forEach(version => {
siteTree[languageCode][version] = {}
const productTree = {}
Object.values(productMap).forEach(item => {
const product = { title: item.name }
// return early if the product has external docs, like Atom
if (item.external) {
product.href = item.href
product.external = true
productTree[item.id] = product
return
}
// find the product TOC page so we have access to the TOC items
const page = findPage(item.href, pageMap, redirects)
// skip if page can't be found in this version
if (!page) return
if (!getApplicableVersions(page.versions).includes(version)) return
// item.hrefs have a default version via lib/all-products, so update to the current version
product.href = removeFPTFromPath(path.join('/', languageCode, version, getPathWithoutVersion(item.href)))
product.categories = buildCategoriesTree(page.tocItems, product.href, pageMap, redirects, version)
productTree[item.id] = product
return null
})
siteTree[languageCode][version].products = productTree
})
})
await addTitlesToTree(siteTree, site)
return siteTree
}
function buildCategoriesTree (tocItems, versionedProductHref, pageMap, redirects, version) {
const categoryTree = {}
// for every category in a product TOC...
tocItems.forEach(item => {
const category = {}
category.href = path.posix.join(versionedProductHref, item.href)
// find the category TOC page and get its TOC items
const page = findPage(category.href, pageMap, redirects)
// skip if page can't be found in this version
if (!page) return
if (!getApplicableVersions(page.versions).includes(version)) return
category.title = page.title
category.shortTitle = page.shortTitle
// support standalone pages at the category level, like actions/quickstart.md
if (!page.tocItems) {
category.standalone = true
}
// TOC items can be maptopics and/or articles
if (page.tocItems) {
const hasMaptopics = page.tocItems.some(item => item.type === 'maptopic')
// if TOC contains maptopics, build a maptopics tree
// otherwise build an articles tree
if (hasMaptopics) {
category.maptopics = buildMaptopicsTree(page.tocItems, category.href, pageMap, redirects, version)
} else {
category.articles = buildArticlesTree(page.tocItems, category.href, pageMap, redirects, version)
}
}
categoryTree[category.href] = category
})
return categoryTree
}
function buildMaptopicsTree (tocItems, versionedCategoryHref, pageMap, redirects, version) {
const maptopicTree = {}
// for every maptopic in a category TOC...
tocItems
.filter(item => item.type === 'maptopic')
.forEach(item => {
const maptopic = {}
maptopic.href = path.posix.join(versionedCategoryHref, item.href)
// find the category TOC page and get its TOC items
const page = findPage(maptopic.href, pageMap, redirects)
// skip if page can't be found in this version
if (!page) return
if (!getApplicableVersions(page.versions).includes(version)) return
// if this is not a maptopic, return early
if (!page.mapTopic) return
maptopic.title = page.title
maptopic.shortTitle = page.shortTitle
maptopic.hidden = page.hidden
// make the child articles accessible to the page object for maptopic rendering
maptopic.childArticles = getChildArticles(tocItems, item.href)
maptopic.articles = buildArticlesTree(maptopic.childArticles, versionedCategoryHref, pageMap, redirects, version)
maptopicTree[maptopic.href] = maptopic
})
return maptopicTree
}
function buildArticlesTree (tocItems, versionedCategoryHref, pageMap, redirects, version) {
const articleTree = {}
// REST categories may not have TOC items
if (!tocItems) return articleTree
// for every article in a maptopic (or category) TOC...
tocItems.forEach(item => {
const article = {}
article.href = path.posix.join(versionedCategoryHref, item.href)
// find the category TOC page and get its TOC items
const page = findPage(article.href, pageMap, redirects)
// skip if page can't be found in this version
if (!page) return
if (!getApplicableVersions(page.versions).includes(version)) return
article.title = page.title
article.shortTitle = page.shortTitle
article.hidden = page.hidden
articleTree[article.href] = article
})
return articleTree
}
// in a category TOC, get the {% link_in_list %} items under the current {% topic_link_in_list %}
function getChildArticles (tocItems, maptopicPath) {
let withinMaptopic = false
return tocItems.filter(item => {
if (item.type === 'maptopic') {
if (item.href === maptopicPath) {
withinMaptopic = true
} else {
withinMaptopic = false
}
} else {
if (withinMaptopic) return item.href
}
return false
})
}