|
| 1 | +const path = require('path') |
| 2 | +const languages = require('./languages') |
| 3 | +const versions = Object.keys(require('./all-versions')) |
| 4 | +const createTree = require('./create-tree') |
| 5 | +const nonEnterpriseDefaultVersion = require('./non-enterprise-default-version') |
| 6 | +const englishPath = path.posix.join(__dirname, '..', 'content') |
| 7 | + |
| 8 | +/** |
| 9 | + * We only need to initialize pages _once per language_ since pages don't change per version. So we do that |
| 10 | + * first since it's the most expensive work. This gets us a nested object with pages attached that we can use |
| 11 | + * as the basis for the siteTree after we do some versioning. We can also use it to derive the pageList. |
| 12 | +*/ |
| 13 | +async function loadUnversionedTree () { |
| 14 | + const unversionedTree = {} |
| 15 | + |
| 16 | + await Promise.all(Object.values(languages) |
| 17 | + .map(async (langObj) => { |
| 18 | + unversionedTree[langObj.code] = await createTree(englishPath, langObj) |
| 19 | + })) |
| 20 | + |
| 21 | + return unversionedTree |
| 22 | +} |
| 23 | + |
| 24 | +/** |
| 25 | + * The siteTree is a nested object with pages for every language and version, useful for nav because it |
| 26 | + * contains parent, child, and sibling relationships: |
| 27 | + * |
| 28 | + * siteTree[languageCode][version].childPages[<array of pages>].childPages[<array of pages>] (etc...) |
| 29 | +
|
| 30 | +* Given an unversioned tree of all pages per language, we can walk it for each version and do a couple operations: |
| 31 | + * 1. Add a versioned href to every item, where the href is the relevant permalink for the current version. |
| 32 | + * 2. Drop any child pages that are not available in the current version. |
| 33 | + * |
| 34 | + * Order of languages and versions doesn't matter, but order of child page arrays DOES matter (for navigation). |
| 35 | +*/ |
| 36 | +async function loadSiteTree (unversionedTree) { |
| 37 | + const rawTree = Object.assign({}, (unversionedTree || await loadUnversionedTree())) |
| 38 | + const siteTree = {} |
| 39 | + |
| 40 | + // For every language... |
| 41 | + await Promise.all(Object.keys(languages).map(async (langCode) => { |
| 42 | + const treePerVersion = {} |
| 43 | + // in every version... |
| 44 | + await Promise.all(versions.map(async (version) => { |
| 45 | + // "version" the pages. |
| 46 | + treePerVersion[version] = versionPages(Object.assign({}, rawTree[langCode]), version) |
| 47 | + })) |
| 48 | + |
| 49 | + siteTree[langCode] = treePerVersion |
| 50 | + })) |
| 51 | + |
| 52 | + return siteTree |
| 53 | +} |
| 54 | + |
| 55 | +// This step can't be asynchronous because the order of child pages matters. |
| 56 | +function versionPages (obj, version) { |
| 57 | + // Add a versioned href as a convenience for use in layouts. |
| 58 | + obj.href = obj.page.permalinks |
| 59 | + .find(pl => pl.pageVersion === version || (pl.pageVersion === 'homepage' && version === nonEnterpriseDefaultVersion)) |
| 60 | + .href |
| 61 | + |
| 62 | + if (!obj.childPages) return obj |
| 63 | + |
| 64 | + const versionedChildPages = obj.childPages |
| 65 | + // Drop child pages that do not apply to the current version. |
| 66 | + .filter(childPage => childPage.page.applicableVersions.includes(version)) |
| 67 | + // Version the child pages recursively. |
| 68 | + .map(childPage => versionPages(Object.assign({}, childPage), version)) |
| 69 | + |
| 70 | + obj.childPages = [...versionedChildPages] |
| 71 | + |
| 72 | + return obj |
| 73 | +} |
| 74 | + |
| 75 | +// Derive a flat array of Page objects in all languages. |
| 76 | +async function loadPageList (unversionedTree) { |
| 77 | + const rawTree = unversionedTree || await loadUnversionedTree() |
| 78 | + const pageList = [] |
| 79 | + |
| 80 | + await Promise.all(Object.keys(languages).map(async (langCode) => { |
| 81 | + await addToCollection(rawTree[langCode], pageList) |
| 82 | + })) |
| 83 | + |
| 84 | + async function addToCollection (item, collection) { |
| 85 | + if (!item.page) return |
| 86 | + collection.push(item.page) |
| 87 | + |
| 88 | + if (!item.childPages) return |
| 89 | + await Promise.all(item.childPages.map(async (childPage) => await addToCollection(childPage, collection))) |
| 90 | + } |
| 91 | + |
| 92 | + return pageList |
| 93 | +} |
| 94 | + |
| 95 | +// Create an object from the list of all pages with permalinks as keys for fast lookup. |
| 96 | +function createMapFromArray (pageList) { |
| 97 | + const pageMap = |
| 98 | + pageList.reduce( |
| 99 | + (pageMap, page) => { |
| 100 | + for (const permalink of page.permalinks) { |
| 101 | + pageMap[permalink.href] = page |
| 102 | + } |
| 103 | + return pageMap |
| 104 | + }, |
| 105 | + {} |
| 106 | + ) |
| 107 | + |
| 108 | + return pageMap |
| 109 | +} |
| 110 | + |
| 111 | +async function loadPageMap (pageList) { |
| 112 | + const pages = pageList || await loadPageList() |
| 113 | + return createMapFromArray(pages) |
| 114 | +} |
| 115 | + |
| 116 | +module.exports = { |
| 117 | + loadUnversionedTree, |
| 118 | + loadSiteTree, |
| 119 | + loadPages: loadPageList, |
| 120 | + loadPageMap |
| 121 | +} |
0 commit comments