You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/website/components/temporary_docs-page/server.js

140 lines
4.3 KiB

// -----------------------------------------------------
// This code is LOCKED
//
// If any changes are needed to this code, or if this code
// is needed in any other projects, instead of changing or
// using it, instead we must complete this task as a prerequisite
//
// https://app.asana.com/0/1100423001970639/1195001770724993
//
// ------------------------------------------------------
import fs from 'fs'
import path from 'path'
import existsSync from 'fs-exists-sync'
import readdirp from 'readdirp'
import lineReader from 'line-reader'
import matter from 'gray-matter'
import { safeLoad } from 'js-yaml'
import renderToString from 'next-mdx-remote/render-to-string'
import markdownDefaults from '@hashicorp/nextjs-scripts/markdown'
import generateComponents from './components'
export async function generateStaticPaths(subpath) {
const paths = await getStaticMdxPaths(
path.join(process.cwd(), 'content', subpath)
)
return { paths, fallback: false }
}
export async function generateStaticProps(subpath, productName, params) {
const docsPath = path.join(process.cwd(), 'content', subpath)
const pagePath = params.page ? params.page.join('/') : '/'
// get frontmatter from all other pages in the category, for the sidebar
const allFrontMatter = await fastReadFrontMatter(docsPath)
// render the current page path markdown
const { mdxSource, frontMatter } = await renderPageMdx(
docsPath,
pagePath,
generateComponents(productName)
)
return {
props: {
data: allFrontMatter.map((p) => {
p.__resourcePath = `docs/${p.__resourcePath}`
return p
}),
mdxSource,
frontMatter,
pagePath: `/docs/${pagePath}`,
},
}
}
export async function getStaticMdxPaths(root) {
const files = await readdirp.promise(root, { fileFilter: ['*.mdx'] })
return files.map(({ path: p }) => {
return {
params: {
page: p
.replace(/\.mdx$/, '')
.split('/')
.filter((p) => p !== 'index'),
},
}
})
}
export async function renderPageMdx(root, pagePath, components) {
// get the page being requested - figure out if its index page or leaf
// prefer leaf if both are present
const leafPath = path.join(root, `${pagePath}.mdx`)
const indexPath = path.join(root, `${pagePath}/index.mdx`)
let page
if (existsSync(leafPath)) {
page = fs.readFileSync(leafPath, 'utf8')
} else if (existsSync(indexPath)) {
page = fs.readFileSync(indexPath, 'utf8')
} else {
// NOTE: if we decide to let docs pages render dynamically, we should replace this
// error with a straight 404, at least in production.
throw new Error(
`We went looking for "${leafPath}" and "${indexPath}" but neither one was found.`
)
}
const { data: frontMatter, content } = matter(page)
const mdxSource = await renderToString(content, {
mdxOptions: markdownDefaults({
resolveIncludes: path.join(process.cwd(), 'content/partials'),
}),
components,
})
return { mdxSource, frontMatter }
}
export function fastReadFrontMatter(p) {
return new Promise((resolve) => {
const fm = []
readdirp(p, { fileFilter: '*.mdx' })
.on('data', (entry) => {
let lineNum = 0
const content = []
fm.push(
new Promise((resolve2, reject2) => {
lineReader.eachLine(
entry.fullPath,
(line) => {
// if it has any content other than `---`, the file doesn't have front matter, so we close
if (lineNum === 0 && !line.match(/^---$/)) return false
// if it's not the first line and we have a bottom delimiter, exit
if (lineNum !== 0 && line.match(/^---$/)) return false
// now we read lines until we match the bottom delimiters
content.push(line)
// increment line number
lineNum++
},
(err) => {
if (err) return reject2(err)
content.push(`__resourcePath: "${entry.path}"`)
resolve2(safeLoad(content.slice(1).join('\n')), {
filename: entry.fullPath,
})
}
)
})
)
})
.on('end', () => {
Promise.all(fm).then((res) => resolve(res))
})
})
}