Files
netease-modsdk-wiki/scripts/sidebar-wiki.ts
2025-03-20 11:52:46 +08:00

266 lines
8.2 KiB
TypeScript

import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import fetch from 'node-fetch'
const baseUrl = '/'
// define whether big pages should be built.
// fastBuild should only be used when testing, since it will not compile some of the wikis content.
const excludeFiles = [
'entities/vanilla-usage-components.md',
'entities/vanilla-usage-spawn-rules.md',
'entities/vuc-full.md',
'entities/vusr-full.md',
]
const fastBuild = process.env.fastBuild === 'true ' // SPACE has to be there, since the SET var=val command adds a space at the end!
if (fastBuild && process.env.NODE_ENV == 'production') {
console.log(
`\nINFO: fastBuild selected. the files:\n${JSON.stringify(
excludeFiles,
null,
4
)}\nwill not be compiled!\n`
)
}
function formatLink(path: string) {
return path.split(/\\|\//g).join('/').replace('.md', '')
}
/*
Gets the categories from within the frontmatter of an index.md file, and returns them as list.
*/
function getCategoryOrder(frontMatter: matter.GrayMatterFile<string>) {
const data: { [Key: string]: number } = {}
if (!frontMatter.data.categories) {
return data
}
frontMatter.data.categories.forEach(function (
category: { title: string | number },
index: number
) {
data[category.title] = index + 1
})
return data
}
function getCategories(frontMatter: matter.GrayMatterFile<string>) {
const data: {
text: any
data: any
tags: any
prefix: any
section: boolean
color: any
link: string
activeMatch: string
}[] = []
if (!frontMatter.data.categories) {
return data
}
frontMatter.data.categories.forEach(function (
category: {
nav_order: number
category: any
title: any
tags: any
prefix: any
color: any
},
index: any
) {
category.nav_order = -1
category.category = category.title
data.push({
text: category.title,
data: category,
tags: category.tags,
prefix: category.prefix,
section: true,
color: category.color,
link: '',
activeMatch: ' ',
})
})
return data
}
let order: { [Key: string]: number }
/*
Recursively generate the navigation links for the sidebar.
*/
export function generateWikiSidebar(base: string, dir: string) {
const data: {
text: any
data: { [key: string]: any }
children?: any
tags?: any
prefix?: any
section?: any
color?: any
link?: string
activeMatch?: string
}[] = []
const files = fs.readdirSync(dir)
files.forEach(function (file) {
let joinedPath = path.join(dir, file)
const stats = fs.statSync(joinedPath)
// Handle top level directories
if (
stats.isDirectory() &&
fs.existsSync(path.join(joinedPath, 'index.md'))
) {
const str = fs.readFileSync(
path.join(joinedPath, 'index.md'),
'utf8'
)
let frontMatter
try {
frontMatter = matter(str)
} catch (e) {
joinedPath = path.relative(
process.cwd(),
path.join(joinedPath, 'index.md')
)
console.log(
// @ts-ignore
`::error file=${joinedPath},line=1,col=1::File ${joinedPath} has invalid frontmatter! ${e.message}`
)
throw new Error(
// @ts-ignore
`File ${joinedPath} has invalid frontmatter! ${e.message}`
)
}
order = getCategoryOrder(frontMatter)
const children = generateWikiSidebar(base, joinedPath).concat(
getCategories(frontMatter)
)
children.sort(
(
{ data: dataA, text: textA },
{ data: dataB, text: textB }
) => {
// Default to max int, so without nav order you will show second
// Multiply by category value if it exists
const navA =
(dataA.nav_order || 50) +
(order[dataA.category] || 0) * 100 ||
Number.MAX_SAFE_INTEGER
const navB =
(dataB.nav_order || 50) +
(order[dataB.category] || 0) * 100 ||
Number.MAX_SAFE_INTEGER
// Tie goes to the text compare! (Will also apply for elements without nav order)
if (navA == navB) {
return textA.localeCompare(textB)
}
// Return nav order
return navA - navB
}
)
data.push({
text: frontMatter.data.title,
data: frontMatter.data,
children: children,
})
if (frontMatter.data.title === void 0) {
throw new Error(
'File ' +
path.join(joinedPath, 'index.md') +
' has invalid frontmatter!'
)
}
}
// Handle the normal files
else if (stats.isFile()) {
// Don't include non-markdown files, or the index page itself
if (!file.endsWith('.md') || file.endsWith('index.md')) return
const str = fs.readFileSync(joinedPath, 'utf8')
let frontMatter
try {
frontMatter = matter(str)
} catch (e) {
joinedPath = path.relative(process.cwd(), joinedPath)
console.log(
// @ts-ignore
`::error file=${joinedPath},line=1,col=1::File ${joinedPath} has invalid frontmatter! ${e.message}`
)
throw new Error(
// @ts-ignore
`File ${joinedPath} has invalid frontmatter! ${e.message}`
)
}
const link = formatLink(joinedPath.toString().replace(base, ''))
// Don't include hidden pages (ignores children)
if (frontMatter.data.hidden === true) return
let prefix = null
if (frontMatter.data.prefix != null) {
prefix = frontMatter.data.prefix
}
let tags = null
if (frontMatter.data.tags != null) {
tags = frontMatter.data.tags
}
data.push({
text: frontMatter.data.title,
data: frontMatter.data,
tags: tags,
prefix: prefix,
section: frontMatter.data.section || false,
color: frontMatter.data.color || 'none',
link,
activeMatch: `^${link}`,
})
if (frontMatter.data.title === void 0) {
joinedPath = path.relative(process.cwd(), joinedPath)
console.log(
`::error file=${joinedPath},line=1,col=1::File ${joinedPath} has invalid frontmatter!`
)
throw new Error(`File ${joinedPath} has invalid frontmatter!`)
}
}
})
return data.sort(
({ data: dataA, text: textA }, { data: dataB, text: textB }) => {
// Default to max int, so without nav order you will show second
// Multiply by category value if it exists
const navA =
(dataA.nav_order || 50) + (order[dataA.category] || 0) * 100 ||
Number.MAX_SAFE_INTEGER
const navB =
(dataB.nav_order || 50) + (order[dataB.category] || 0) * 100 ||
Number.MAX_SAFE_INTEGER
// Tie goes to the text compare! (Will also apply for elements without nav order)
if (navA == navB) {
return textA.localeCompare(textB)
}
// Return nav order
return navA - navB
}
)
}