Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix docussarus plugin when there are no docs #719

Merged
merged 3 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 129 additions & 93 deletions packages/plugin-docusaurus-v3/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,67 +1,70 @@
import { readFileSync, writeFileSync } from "node:fs"
import type { Plugin } from "@docusaurus/types"
import { cp } from "node:fs/promises"
import { gzip } from "pako"
import { resolve } from "node:path"
import { readFileSync, writeFileSync } from 'node:fs'
import type { Plugin } from '@docusaurus/types'
import { cp } from 'node:fs/promises'
import { gzip } from 'pako'
import { resolve } from 'node:path'
// @ts-ignore
import { presets } from "@orama/searchbox"
import { create, insertMultiple, save } from "@orama/orama"
import { JSDOM } from "jsdom"
import MarkdownIt from "markdown-it"
import matter from "gray-matter"
import { createSnapshot, deployIndex, fetchEndpointConfig } from "./utils"
import { presets } from '@orama/searchbox'
import { create, insertMultiple, save } from '@orama/orama'
import { JSDOM } from 'jsdom'
import MarkdownIt from 'markdown-it'
import matter from 'gray-matter'
import { createSnapshot, deployIndex, fetchEndpointConfig } from './utils'

type CloudConfig = {
deploy: boolean,
deploy: boolean
endpoint: string
indexId: string,
indexId: string
oramaCloudAPIKey?: string
public_api_key: string,
public_api_key: string
}

type PluginOptions = {
analytics?: {
enabled: boolean
apiKey: string
indexId: string
},
}
cloud?: CloudConfig
}

export default function OramaPluginDocusaurus(ctx: {
siteDir: any;
generatedFilesDir: any
}, options: PluginOptions): Plugin {
export default function OramaPluginDocusaurus(
ctx: {
siteDir: any
generatedFilesDir: any
},
options: PluginOptions
): Plugin {
let versions: any[] = []

return {
name: "@orama/plugin-docusaurus-v3",
name: '@orama/plugin-docusaurus-v3',

getThemePath() {
return "../lib/theme"
return '../lib/theme'
},

getTypeScriptThemePath() {
return "../src/theme"
return '../src/theme'
},

getClientModules() {
return ["../lib/theme/SearchBar/index.css"]
return ['../lib/theme/SearchBar/index.css']
},

async allContentLoaded({ actions, allContent }) {
const isDevelopment = process.env.NODE_ENV === "development"
const isDevelopment = process.env.NODE_ENV === 'development'
let docsInstances: string[] = []
const oramaCloudAPIKey = options.cloud?.oramaCloudAPIKey
const searchDataConfig = [
{
docs: allContent["docusaurus-plugin-content-docs"]
docs: allContent['docusaurus-plugin-content-docs']
},
{
blogs: allContent["docusaurus-plugin-content-blog"]
blogs: allContent['docusaurus-plugin-content-blog']
},
{
pages: allContent["docusaurus-plugin-content-pages"]
pages: allContent['docusaurus-plugin-content-pages']
}
]

Expand All @@ -75,71 +78,82 @@ export default function OramaPluginDocusaurus(ctx: {
searchDataConfig.forEach((config) => {
const [key, value] = Object.entries(config)[0]
switch (key) {
case "docs":
case 'docs':
if (!value) break
Object.keys(value).forEach((docsInstance: any) => {
const loadedVersions = value?.[docsInstance]?.loadedVersions
versions = loadedVersions.map((v: any) => v.versionName)
docsInstances.push(docsInstance)
versions.flatMap(async (version) => {
const currentVersion = loadedVersions.find((v: any) => v.versionName === version)
allOramaDocsPromises.push(...currentVersion.docs.map((data: any) => generateDocs({
siteDir:ctx.siteDir,
version,
category: docsInstance,
data
})))
allOramaDocsPromises.push(
...currentVersion.docs.map((data: any) =>
generateDocs({
siteDir: ctx.siteDir,
version,
category: docsInstance,
data
})
)
)
})
})
break
case "blogs":
case 'blogs':
const blogsInstances = Object.keys(value)
blogsInstances.forEach(async (instance) => {
const loadedInstance = value[instance]
allOramaDocsPromises.push(...loadedInstance.blogPosts.map(({ metadata }: any) => generateDocs({
siteDir: ctx.siteDir,
version: "current",
category: "blogs",
data: metadata
})))
allOramaDocsPromises.push(
...loadedInstance.blogPosts.map(({ metadata }: any) => {
return generateDocs({
siteDir: ctx.siteDir,
version: 'current',
category: 'blogs',
data: metadata
})
})
)
})
break
case "pages":
case 'pages':
const pagesInstances = Object.keys(value)
pagesInstances.forEach(async (instance) => {
const loadedInstance = value[instance]
allOramaDocsPromises.push(...loadedInstance.map((data: any) => generateDocs({
siteDir: ctx.siteDir,
version: "current",
category: "pages",
data
})))
allOramaDocsPromises.push(
...loadedInstance.map((data: any) =>
generateDocs({
siteDir: ctx.siteDir,
version: 'current',
category: 'pages',
data
})
)
)
})
break
}
})

const oramaDocs = (await Promise.all(allOramaDocsPromises))
.flat()
.map((data) => ({
title: data.title,
content: data.content,
section: data.originalTitle,
version: data.version,
path: data.path,
category: data.category
}))

const oramaDocs = (await Promise.all(allOramaDocsPromises)).flat().map((data) => ({
title: data.title,
content: data.content,
section: data.originalTitle,
version: data.version,
path: data.path,
category: data.category
}))
const endpointConfig = await deployData({
oramaDocs,
generatedFilesDir: ctx.generatedFilesDir,
version: "current",
version: 'current',
deployConfig
})

actions.setGlobalData({
...(isDevelopment && !options.cloud && {
searchData: Object.fromEntries([['current', readFileSync(indexPath(ctx.generatedFilesDir, 'current'))]])
}),
...(isDevelopment &&
!options.cloud && {
searchData: Object.fromEntries([['current', readFileSync(indexPath(ctx.generatedFilesDir, 'current'))]])
}),
docsInstances,
availableVersions: versions,
analytics: options.analytics,
Expand All @@ -148,12 +162,12 @@ export default function OramaPluginDocusaurus(ctx: {
url: endpointConfig?.endpoint,
key: endpointConfig?.public_api_key
}
}),
})
})
},

async postBuild({ outDir }) {
!options.cloud && await cp(indexPath(ctx.generatedFilesDir, "current"), indexPath(outDir, "current"))
!options.cloud && (await cp(indexPath(ctx.generatedFilesDir, 'current'), indexPath(outDir, 'current')))
}
}
}
Expand All @@ -164,13 +178,13 @@ async function generateDocs({
category,
data
}: {
siteDir: string,
version: string,
category: string,
siteDir: string
version: string
category: string
data: Record<string, string>
}) {
const { title, permalink, source } = data
const fileContent = readFileSync(source.replace("@site", siteDir), "utf-8")
const fileContent = readFileSync(source.replace('@site', siteDir), 'utf-8')
const contentWithoutFrontMatter = matter(fileContent).content

return parseHTMLContent({
Expand All @@ -182,41 +196,57 @@ async function generateDocs({
})
}

function parseHTMLContent({ html, path, originalTitle, version, category }: {
html: any;
path: any;
originalTitle: any,
version: string,
function parseHTMLContent({
html,
path,
originalTitle,
version,
category
}: {
html: any
path: any
originalTitle: any
version: string
category: string
}) {
const dom = new JSDOM(html)
const document = dom.window.document

const sections: {
originalTitle: any;
title: string;
header: string;
content: string;
version: string;
category: string;
originalTitle: any
title: string
header: string
content: string
version: string
category: string
path: any
}[] = []

const headers = document.querySelectorAll("h1, h2, h3, h4, h5, h6")
const headers = document.querySelectorAll('h1, h2, h3, h4, h5, h6')
if (!headers.length) {
sections.push({
originalTitle,
title: originalTitle,
header: 'h1',
content: html,
version,
category,
path
})
}
headers.forEach((header) => {
const sectionTitle = header.textContent?.trim()
const headerTag = header.tagName.toLowerCase()
let sectionContent = ""
let sectionContent = ''

let sibling = header.nextElementSibling
while (sibling && !["H1", "H2", "H3", "H4", "H5", "H6"].includes(sibling.tagName)) {
sectionContent += sibling.textContent?.trim() + "\n"
while (sibling && !['H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(sibling.tagName)) {
sectionContent += sibling.textContent?.trim() + '\n'
sibling = sibling.nextElementSibling
}

sections.push({
originalTitle,
title: sectionTitle ?? "",
title: sectionTitle ?? '',
header: headerTag,
content: sectionContent,
version,
Expand All @@ -229,7 +259,7 @@ function parseHTMLContent({ html, path, originalTitle, version, category }: {
}

function indexPath(outDir: string, version: string) {
return resolve(outDir, "orama-search-index-@VERSION@.json.gz".replace("@VERSION@", version))
return resolve(outDir, 'orama-search-index-@VERSION@.json.gz'.replace('@VERSION@', version))
}

async function deployData({
Expand All @@ -238,13 +268,19 @@ async function deployData({
version,
deployConfig
}: {
oramaDocs: any[],
generatedFilesDir: string,
version: string,
deployConfig: { indexId: string, enabled: boolean, oramaCloudAPIKey: string | undefined } | undefined
oramaDocs: any[]
generatedFilesDir: string
version: string
deployConfig:
| {
indexId: string
enabled: boolean
oramaCloudAPIKey: string | undefined
}
| undefined
}) {
const { ORAMA_CLOUD_BASE_URL } = process.env
const baseUrl = ORAMA_CLOUD_BASE_URL || "https://cloud.oramasearch.com"
const baseUrl = ORAMA_CLOUD_BASE_URL || 'https://cloud.oramasearch.com'

if (deployConfig) {
const endpointConfig = await fetchEndpointConfig(baseUrl, deployConfig.oramaCloudAPIKey!, deployConfig.indexId!)
Expand All @@ -257,7 +293,7 @@ async function deployData({
return endpointConfig
} else {
const db = await create({
schema: { ...presets.docs.schema, version: "enum" }
schema: { ...presets.docs.schema, version: 'enum' }
})

await insertMultiple(db, oramaDocs as any)
Expand Down
Loading
Loading