Files
upgrading-ethereum-book/plugins/my-search-index/gatsby-node.js
Ben Edgington f65b39aee9 More idiomatic
2023-06-08 11:41:47 +01:00

155 lines
3.5 KiB
JavaScript

const cheerio = require('cheerio')
/*
* Creates GraphQL nodes containing data for the local search
*/
// Concatenate all text in child nodes while respecting exclusions
const getText = ($, node, exclude) => {
return [...$(node).contents().not(exclude.ignore)]
.map(e => (e.type === 'text') ? e.data : getText($, e, exclude))
.join('')
}
// Recurse until we find an element we want to treat as a chunk, then get all its text content.
const getChunks = ($, node, chunkTypes, exclude, counts) => {
if (counts === undefined) {
counts = Array(chunkTypes.length).fill(0)
}
for (let idx = 0; idx < chunkTypes.length; idx++) {
const type = chunkTypes[idx]
if ($(node).is(type.query)) {
const text = getText($, node, exclude)
if (text !== '') {
const tagName = $(node).prop('tagName').toLowerCase()
let id = $(node).attr('id')
if ( id === undefined) {
id = tagName + '_' + counts[idx]
$(node).attr('id', id)
++counts[idx]
}
return [{
type: tagName,
label: type.label,
id: id,
text: text,
weight: type.weight === undefined ? 1 : type.weight,
}]
}
}
}
return [...$(node).children().not(exclude.ignore)]
.map(e => getChunks($, e, chunkTypes, exclude, counts))
.flat()
}
const isExcludedFrontmatter = (frontmatter, exclude) => {
for (let i = 0; i < exclude.frontmatter.length; i++) {
const test = exclude.frontmatter[i]
const [key, ...rest] = Object.keys(test)
if (Object.prototype.hasOwnProperty.call(frontmatter, key)
&& frontmatter[key] == test[key]) {
return true
}
}
return false
}
exports.createPages = async (
{
actions: { createNode },
graphql,
createNodeId,
createContentDigest,
}, pluginOptions,
) => {
const {
enabled = true,
chunkTypes = [],
exclude = {frontmatter: [], pages: [], ignore: ''},
} = pluginOptions
const result = await graphql(`
{
allMarkdownRemark {
edges {
node {
html
frontmatter {
path
index
sequence
titles
hide
}
}
}
}
}
`)
const pages = result.data.allMarkdownRemark.edges
await Promise.all(pages.map(async (page) => {
const $ = cheerio.load(page.node.html, null, false)
const frontmatter = page.node.frontmatter
let chunks = []
if (enabled
&& frontmatter !== undefined
&& isExcludedFrontmatter(frontmatter, exclude) === false
&& exclude.pages.indexOf(frontmatter.path) === -1) {
chunks = getChunks($, $.root(), chunkTypes, exclude)
}
// It seems to be hard to modify the underlying MarkdownRemark node's HTML, so we add
// the modified HTML to a new node and deal with it in the page template.
const nodeData = {
frontmatter: {
path: frontmatter.path,
titles: frontmatter.titles,
},
chunks: chunks,
html: $.html(),
}
createNode({
...nodeData,
id: createNodeId(nodeData.frontmatter.path),
internal: {
type: 'mySearchData',
contentDigest: createContentDigest(nodeData)
}
})
}))
}
exports.createSchemaCustomization = ({ actions: { createTypes } }) => {
createTypes(`
type Frontmatter {
path: String!
titles: [String]
}
type mySearchData implements Node {
frontmatter: Frontmatter!
chunks: JSON
html: String
}
`)
}