Skip to content

Commit

Permalink
add lib modules for refactored siteTree
Browse files Browse the repository at this point in the history
  • Loading branch information
sarahs committed Mar 29, 2021
1 parent c1e3348 commit 4ffcff3
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 2 deletions.
60 changes: 60 additions & 0 deletions lib/create-tree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const fs = require('fs')
const path = require('path')
const Page = require('./page')
const { sortBy } = require('lodash')

let basePath

module.exports = async function createTree (originalPath, langObj) {
// Do not reset this value on recursive runs
if (!basePath) basePath = originalPath

// On recursive runs, this is processing page.children items in `/<link>` format.
// If the path exists as is, assume this is a directory with a child index.md.
// Otherwise, assume it's a child .md file and add `.md` to the path.
let filepath
try {
await fs.promises.access(originalPath)
filepath = `${originalPath}/index.md`
} catch {
filepath = `${originalPath}.md`
}

const relativePath = filepath.replace(`${basePath}/`, '')
const localizedBasePath = path.join(__dirname, '..', langObj.dir, 'content')

// Initialize the Page! This is where the magic happens (sorry).
const page = await Page.init({
basePath: localizedBasePath,
relativePath,
languageCode: langObj.code
})

if (!page) {
// Do not throw an error if early access is not available
if (relativePath.startsWith('early-access')) return

throw Error(`Cannot initialize page for ${filepath}`)
}

// Create the root tree object on the first run, and create children recursively
const item = {
relativePath,
title: page.shortTitle || page.title,
// parentPath: parentPath || null,
page
}

// Process frontmatter children recursively
if (item.page.children) {
item.childPages = sortBy(
(await Promise.all(item.page.children
.map(async (child) => await createTree(path.join(originalPath, child), langObj))))
.filter(Boolean),
// Sort by the ordered array of children in the frontmatter
item.page.children
)
}

return item
}
3 changes: 3 additions & 0 deletions lib/frontmatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ const schema = {
minimum: 2,
maximum: 4
},
children: {
type: 'array'
},
mapTopic: {
type: 'boolean'
},
Expand Down
17 changes: 17 additions & 0 deletions lib/get-document-type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = function getDocumentType (relativePath) {
if (!relativePath.endsWith('index.md')) {
return 'article'
}

// Derive the document type from the path segment length
switch (relativePath.split('/').length) {
case 1:
return 'homepage'
case 2:
return 'product'
case 3:
return 'category'
case 4:
return 'mapTopic'
}
}
9 changes: 8 additions & 1 deletion lib/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const statsd = require('./statsd')
const readFileContents = require('./read-file-contents')
const getLinkData = require('./get-link-data')
const union = require('lodash/union')
// const getDocumentType = require('./get-document-type')

class Page {
static async init (opts) {
Expand Down Expand Up @@ -69,8 +70,14 @@ class Page {
this.rawLearningTracks = this.learningTracks
this.rawIncludeGuides = this.includeGuides

// Is this a Product, Category, Topic, or Article?
// this.documentType = getDocumentType(this.relativePath)

// Get array of versions that the page is available in for fast lookup
this.applicableVersions = getApplicableVersions(this.versions, this.fullPath)

// a page should only be available in versions that its parent product is available in
const versionsParentProductIsNotAvailableIn = getApplicableVersions(this.versions, this.fullPath)
const versionsParentProductIsNotAvailableIn = this.applicableVersions
// only the homepage will not have this.parentProduct
.filter(availableVersion => this.parentProduct && !this.parentProduct.versions.includes(availableVersion))

Expand Down
79 changes: 78 additions & 1 deletion lib/pages.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,82 @@
const path = require('path')
const languages = require('./languages')
const versions = Object.keys(require('./all-versions'))
const createTree = require('./create-tree')
const nonEnterpriseDefaultVersion = require('./non-enterprise-default-version')
const englishPath = path.join(__dirname, '..', 'content')
const walk = require('walk-sync').entries
const Page = require('./page')
const languages = require('./languages')

// This function creates a nested object that can be accessed like this:
// siteTree[languageCode][version].childPages[<array of pages>].childPages[<array of pages>] (etc...)
async function loadTree () {
// We only need to initialize pages once per language (since pages don't change per version), so we do that
// first since it's the most expensive work. This gets us a nested object with pages attached that we can use
// as the basis for the siteTree after we do some versioning.
const rawTree = {}
await Promise.all(Object.values(languages)
.map(async (langObj) => {
rawTree[langObj.code] = await createTree(englishPath, langObj)
}))

// Now that we have the paged tree, we can walk it for every version and do two operations:
// 1. Add a versioned href to every node (we can get this easily from the permalinks array).
// 2. Recurisvely drop any child pages that are not available in the current version.
// Note that order of languages and versions doesn't matter, but order of child page arrays DOES matter (for nav).
const siteTree = {}
await Promise.all(Object.keys(languages).map(async (langCode) => {
const treePerVersion = {}

await Promise.all(versions.map(async (version) => {
// Yes, we are mutating the rawTree object here.
versionPages(rawTree[langCode])

// This step can't be asynchronous because the order of child pages matters.
function versionPages (item) {
// Add a versioned href as a convenience for use in layouts.
item.href = item.page.permalinks
.find(pl => pl.pageVersion === version || (pl.pageVersion === 'homepage' && version === nonEnterpriseDefaultVersion))

if (!item.childPages) return item

// Drop child pages that do not apply to the current version
item.childPages = item.childPages.filter(childPage => childPage.page.applicableVersions.includes(version))
item.childPages.forEach(childPage => versionPages(childPage))
}

treePerVersion[version] = rawTree[langCode]
}))

siteTree[langCode] = treePerVersion
}))

console.log(siteTree.en[nonEnterpriseDefaultVersion])

return siteTree
}

async function loadPageListFromTree (tree) {
const siteTree = tree || await loadTree()

// Traverse the tree of pages and create a simple array of pages.
// (We don't care about the language code or version here, so we can start two levels in.)
const collection = Object.values(siteTree).map(v => Object.values(v)).flat()
const result = []
collectPages(collection, result)

function collectPages (arr, result) {
arr.forEach(item => {
if (item.page) {
result.push(item.page)
}
if (item.childPages) {
collectPages(item.childPages, result)
}
})
}

return result
}

async function loadPageList () {
// load english pages
Expand Down Expand Up @@ -66,6 +141,8 @@ async function loadPageMap (pageList) {
}

module.exports = {
loadTree,
// loadPages: loadPageListFromTree,
loadPages: loadPageList,
loadPageMap
}

0 comments on commit 4ffcff3

Please sign in to comment.