完整版BedrockWiki镜像!

This commit is contained in:
boybook
2025-03-20 11:52:46 +08:00
parent 1994c41f01
commit bf9aa4b056
214 changed files with 9042 additions and 8867 deletions

View File

@@ -58,11 +58,17 @@ async function findMarkdownFiles(dir) {
if (entry.isDirectory()) {
await traverse(fullPath);
} else if (entry.isFile() && entry.name.endsWith('.md')) {
} else if (entry.isFile() && entry.name.endsWith('.md') && entry.name !== 'index.md') {
try {
// 读取文件内容
const content = await fs.readFile(fullPath, 'utf-8');
// 如果超过600行跳过
const lines = content.split('\n').length;
if (lines > 600) {
console.log(`⏭️ 跳过超过600行的文件: ${path.relative(targetDir, fullPath)}`);
continue;
}
// 如果文件不包含中文,则添加到待翻译列表
if (!containsChinese(content)) {
files.push(fullPath);

266
scripts/sidebar-wiki.ts Normal file
View File

@@ -0,0 +1,266 @@
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
}
)
}

View File

@@ -1,7 +1,8 @@
import fs from 'fs/promises';
import path from 'path';
import fg from 'fast-glob';
import matter from 'gray-matter'
import matter from 'gray-matter';
import { generateWikiSidebar } from './sidebar-wiki';
// 定义侧边栏项目接口
interface SidebarItem {
@@ -54,8 +55,10 @@ async function generateSidebar(): Promise<Record<string, SidebarItem[]>> {
const sidebar: Record<string, SidebarItem[]> = {};
const files = await fg([`${DOCS_DIR}/**/*.md`]);
// 处理所有非 index.md 文件
// 处理所有非 wiki 文件
for (const filePath of files) {
// 跳过wiki
if (filePath.includes('wiki')) continue;
const relativePath = path.relative(DOCS_DIR, filePath);
if (IGNORE_PATHS.some(ignore => relativePath.toLowerCase().includes(ignore.toLowerCase()))) continue;
@@ -149,6 +152,69 @@ async function generateSidebar(): Promise<Record<string, SidebarItem[]>> {
});
}
// 处理wiki
const wiki = generateWikiSidebar(path.join(process.cwd(), 'docs'), path.join(process.cwd(), 'docs/wiki'));
const wikiSidebar: SidebarItem[] = [];
wiki.forEach(item => {
if (item.data.categories) {
// 一级大分类
// 二级分类
const secondUrls: string[] = [];
const second = item.data.categories.map((category: any) => {;
return {
text: category.title,
collapsed: false,
items: item.children
.filter(child => child.data.category === category.title)
.filter(child => child.link)
.map(child => {
secondUrls.push(child.link);
return {
text: child.text,
link: child.link,
activeMatch: child.activeMatch
}
})
}
});
// 匹配到一级但是未匹配到二级
const notMatched = item.children
.filter(child => !secondUrls.includes(child.link))
.filter(child => child.link)
.map(child => {
return {
text: child.text,
link: child.link,
activeMatch: child.activeMatch
}
});
wikiSidebar.push({
text: item.data.title,
collapsed: true,
items: [...second, ...notMatched]
});
} else {
// 一级大分类
wikiSidebar.push({
text: item.text,
collapsed: true,
items: item.children
.filter(child => child.link)
.map(child => {
return {
text: child.text,
link: child.link,
activeMatch: child.activeMatch
}
})
});
}
});
// 添加 wiki
sidebarFlat['wiki'] = wikiSidebar;
return sidebarFlat;
}