diff --git a/website/scripts/index_search_content.js b/website/scripts/index_search_content.js index f853b4ddf..b3f2f7cab 100644 --- a/website/scripts/index_search_content.js +++ b/website/scripts/index_search_content.js @@ -1,3 +1,95 @@ -const { indexDocsContent } = require('@hashicorp/react-search/tools') +require('dotenv').config() +const fs = require('fs') +const path = require('path') +const { + indexContent, + getDocsSearchObject, +} = require('@hashicorp/react-search/tools') +const resolveNavData = require('../components/remote-plugin-docs/utils/resolve-nav-data') -indexDocsContent() +// Run indexing +indexContent({ getSearchObjects }) + +async function getSearchObjects() { + // Resolve /docs, /guides, and /intro nav data, which + // corresponds to all the content we will actually render + // This avoids indexing non-rendered content, and partials. + // Fetch objects for `docs` content + async function fetchDocsObjects() { + const navFile = 'data/docs-nav-data.json' + const contentDir = 'content/docs' + const opts = { remotePluginsFile: 'data/docs-remote-plugins.json' } + const navData = await resolveNavData(navFile, contentDir, opts) + return await searchObjectsFromNavData(navData, 'docs') + } + // Fetch objects for `guides` content + async function fetchGuidesObjects() { + const navFile = 'data/guides-nav-data.json' + const contentDir = 'content/guides' + const navData = await resolveNavData(navFile, contentDir) + return await searchObjectsFromNavData(navData, 'guides') + } + // Fetch objects for `intro` content + async function fetchIntroObjects() { + const navFile = 'data/intro-nav-data.json' + const contentDir = 'content/intro' + const navData = await resolveNavData(navFile, contentDir) + return await searchObjectsFromNavData(navData, 'intro') + } + // Collect, flatten and return the collected search objects + const searchObjects = ( + await Promise.all([ + fetchDocsObjects(), + fetchGuidesObjects(), + fetchIntroObjects(), + ]) + ).reduce((acc, array) => acc.concat(array), []) + return searchObjects +} + +/** + * Given navData, return a flat array of search objects + * for each content file referenced in the navData nodes + * @param {Object[]} navData - an array of nav-data nodes, as detailed in [mktg-032](https://docs.google.com/document/d/1kYvbyd6njHFSscoE1dtDNHQ3U8IzaMdcjOS0jg87rHg) + * @param {string} baseRoute - the base route where the navData will be rendered. For example, "docs". + * @returns {Object[]} - an array of searchObjects to pass to Algolia. Must include an objectID property. See https://www.algolia.com/doc/api-reference/api-methods/add-objects/?client=javascript#examples. + */ +async function searchObjectsFromNavData(navData, baseRoute = '') { + const searchObjectsFromNodes = await Promise.all( + navData.map((n) => searchObjectsFromNavNode(n, baseRoute)) + ) + const flattenedSearchObjects = searchObjectsFromNodes.reduce( + (acc, searchObjects) => acc.concat(searchObjects), + [] + ) + return flattenedSearchObjects +} + +/** + * Given a single navData node, return a flat array of search objects. + * For "leaf" nodes, this will yield an array with a single object. + * For "branch" nodes, this may yield an array with zero or more search objects. + * For all other nodes, this will yield an empty array. + * @param {object} node - a nav-data nodes, as detailed in [mktg-032](https://docs.google.com/document/d/1kYvbyd6njHFSscoE1dtDNHQ3U8IzaMdcjOS0jg87rHg) + * @param {string} baseRoute - the base route where the navData will be rendered. For example, "docs". + * @returns {Object[]} - an array of searchObjects to pass to Algolia. Must include an objectID property. See https://www.algolia.com/doc/api-reference/api-methods/add-objects/?client=javascript#examples. + */ +async function searchObjectsFromNavNode(node, baseRoute) { + // If this is a node, build a search object + if (node.path) { + // Fetch the MDX file content + const fileString = node.filePath + ? fs.readFileSync(path.join(process.cwd(), node.filePath), 'utf8') + : node.remoteFile.fileString + const searchObject = await getDocsSearchObject( + path.join(baseRoute, node.path), + fileString + ) + return searchObject + } + // If this is a branch, recurse + if (node.routes) return await searchObjectsFromNavData(node.routes, baseRoute) + // Otherwise, return an empty array + // (for direct link nodes, divider nodes) + return [] +}