зеркало из https://github.com/github/docs.git
200 строки
6.3 KiB
JavaScript
200 строки
6.3 KiB
JavaScript
const path = require('path')
|
|
const findPage = require('./find-page')
|
|
const getApplicableVersions = require('./get-applicable-versions')
|
|
const products = Object.values(require('../lib/all-products'))
|
|
const { getVersionedPathWithoutLanguage } = require('./path-utils')
|
|
const languageCodes = Object.keys(require('./languages'))
|
|
const addTitlesToTree = require('./site-tree-titles')
|
|
const allVersions = Object.keys(require('./all-versions'))
|
|
|
|
// 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 (pages, site, redirects) {
|
|
const siteTree = {}
|
|
|
|
languageCodes.forEach(languageCode => {
|
|
siteTree[languageCode] = {}
|
|
|
|
allVersions.forEach(version => {
|
|
siteTree[languageCode][version] = {}
|
|
const productTree = {}
|
|
|
|
products.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
|
|
}
|
|
|
|
product.href = item.href
|
|
|
|
// find the product TOC page and get TOC items
|
|
const page = findPage(item.href, pages, redirects, languageCode)
|
|
|
|
product.categories = buildCategoriesTree(page.tocItems, item.href, pages, redirects, version, languageCode)
|
|
|
|
productTree[item.id] = product
|
|
return null
|
|
})
|
|
|
|
siteTree[languageCode][version].products = productTree
|
|
})
|
|
})
|
|
|
|
await addTitlesToTree(siteTree, site)
|
|
|
|
return siteTree
|
|
}
|
|
|
|
function buildCategoriesTree (tocItems, productHref, pages, redirects, version, languageCode) {
|
|
const categoryTree = {}
|
|
|
|
// for every category in a product TOC...
|
|
tocItems.forEach(item => {
|
|
const category = {}
|
|
|
|
const categoryHref = path.join(productHref, item.href)
|
|
|
|
const versionedCategoryHref = getVersionedPathWithoutLanguage(categoryHref, version)
|
|
category.href = versionedCategoryHref
|
|
|
|
// find the category TOC page and get its TOC items
|
|
const page = findPage(categoryHref, pages, redirects, languageCode)
|
|
|
|
// skip if translated page can't be found
|
|
if (!page && languageCode !== 'en') return
|
|
|
|
category.title = page.shortTitle || page.title
|
|
|
|
if (!getApplicableVersions(page.versions, page.fullPath).includes(version)) {
|
|
return
|
|
}
|
|
|
|
// 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, categoryHref, pages, redirects, version, languageCode)
|
|
} else {
|
|
category.articles = buildArticlesTree(page.tocItems, categoryHref, pages, redirects, version, languageCode)
|
|
}
|
|
}
|
|
|
|
categoryTree[versionedCategoryHref] = category
|
|
})
|
|
|
|
return categoryTree
|
|
}
|
|
|
|
function buildMaptopicsTree (tocItems, categoryHref, pages, redirects, version, languageCode) {
|
|
const maptopicTree = {}
|
|
|
|
// for every maptopic in a category TOC...
|
|
tocItems
|
|
.filter(item => item.type === 'maptopic')
|
|
.forEach(item => {
|
|
const maptopic = {}
|
|
|
|
const maptopicHref = path.join(categoryHref, item.href)
|
|
|
|
const versionedMaptopicHref = getVersionedPathWithoutLanguage(maptopicHref, version)
|
|
maptopic.href = versionedMaptopicHref
|
|
|
|
// we already have access to the child articles via the category TOC items
|
|
// but we still need the page to get the available versions
|
|
const page = findPage(maptopicHref, pages, redirects, languageCode)
|
|
|
|
// skip if translated page can't be found
|
|
if (!page && languageCode !== 'en') return
|
|
|
|
// if this is not a maptopic, return early
|
|
if (!page.mapTopic) return
|
|
|
|
if (!getApplicableVersions(page.versions, page.fullPath).includes(version)) {
|
|
return
|
|
}
|
|
|
|
const childArticles = getChildArticles(tocItems, item.href)
|
|
|
|
maptopic.title = page.title
|
|
maptopic.shortTitle = page.shortTitle
|
|
maptopic.hidden = page.hidden
|
|
|
|
// make the child articles accessible to the page object for maptopic rendering
|
|
if (!page.childArticles) page.childArticles = childArticles
|
|
|
|
maptopic.articles = buildArticlesTree(childArticles, categoryHref, pages, redirects, version, languageCode)
|
|
maptopicTree[versionedMaptopicHref] = maptopic
|
|
})
|
|
|
|
return maptopicTree
|
|
}
|
|
|
|
function buildArticlesTree (tocItems, categoryHref, pages, redirects, version, languageCode) {
|
|
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 = {}
|
|
|
|
const articleHref = path.join(categoryHref, item.href)
|
|
|
|
const versionedArticleHref = getVersionedPathWithoutLanguage(articleHref, version)
|
|
article.href = versionedArticleHref
|
|
|
|
const page = findPage(articleHref, pages, redirects, languageCode)
|
|
|
|
// skip if translated page can't be found
|
|
if (!page && languageCode !== 'en') return
|
|
|
|
article.title = page.shortTitle || page.title
|
|
|
|
if (!getApplicableVersions(page.versions, page.fullPath).includes(version)) {
|
|
return
|
|
}
|
|
|
|
articleTree[versionedArticleHref] = 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
|
|
})
|
|
}
|