diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 22672493..6c79c09d 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -3,6 +3,7 @@ import { transformerTwoslash } from 'vitepress-plugin-twoslash'; import { getRegisteredMarkdownTheme } from '../shared/utils'; import { builder } from '../shared/multipleSidebarBuilder'; +console.log(JSON.stringify(builder.emitSidebar()['/document/Avalonia/docs/'], null, 2)); // https://vitepress.dev/reference/site-config export default defineConfig({ markdown: { diff --git a/docs/data/Features.data.ts b/docs/data/Features.data.ts index 6055f638..713c95dd 100644 --- a/docs/data/Features.data.ts +++ b/docs/data/Features.data.ts @@ -1,7 +1,7 @@ import matter from 'gray-matter'; import Enumerable from 'linq'; import { type Feature } from 'vitepress/dist/client/theme-default/components/VPFeatures.vue'; -import { Path, documentRoot } from '../shared/FileSystem'; +import { DirectoryInfo, Path, documentRoot } from '../shared/FileSystem'; // const matter = require('gray-matter'); const featuresLiteral = `--- @@ -82,14 +82,13 @@ const getIndexLink = (title: string): string | undefined => { if (!docs) return; // has multiple chapters if (docs.getDirectories().length > 0) { - const folder = Enumerable.from(docs.getDirectories()) - .where(x => x.getFiles().length > 0) - .orderBy(x => x.name) - .firstOrDefault(); + const { first: folder, level } = findFirstFolder(docs); const file = folder?.getFiles()[0]; - return `${documentRoot().name}/${title}/docs/${folder?.name}/${Path.GetFileNameWithoutExtension( - file?.name! - )}`; + let name = `${documentRoot().name}/${title}/docs/`; + for (let i = level - 1; i > 0; i--) { + name += file?.directory.up(i)?.name + '/'; + } + return `${name}${folder?.name}/${Path.GetFileNameWithoutExtension(file?.name!)}`; } // no chapter if (docs.getFiles().length > 0) { @@ -134,6 +133,25 @@ function addLinkToFeatures(features: Feature[]): Feature[] { return features; } +function findFirstFolder( + current: DirectoryInfo, + level: number = 1 +): { first?: DirectoryInfo; level: number } { + // has direct file in sub folder + const first = Enumerable.from(current.getDirectories()) + .where(x => x.getFiles().length > 0) + .orderBy(x => x.name) + .firstOrDefault(); + if (!first) { + const next = Enumerable.from(current.getDirectories()) + .orderBy(x => x.name) + .firstOrDefault(); + if (!next) return { first: undefined, level: level + 1 }; + return findFirstFolder(next, level + 1); + } + return { first, level }; +} + const featuresItems: Feature[] = addLinkToFeatures(matter(featuresLiteral).data.features); const articleFeature: Feature[] = addLinkToFeatures(matter(articleLiteral).data.features); const loader = { diff --git a/docs/shared/FileSystem.ts b/docs/shared/FileSystem.ts index a7726863..1b86f68e 100644 --- a/docs/shared/FileSystem.ts +++ b/docs/shared/FileSystem.ts @@ -2,120 +2,127 @@ import * as fs from 'fs'; import * as path from 'path'; abstract class FileSystemInfo { - protected path: string; - abstract get name(): string; - abstract get fullName(): string; - abstract get exists(): boolean; - constructor(path: string) { - this.path = path; - } + protected path: string; + abstract get name(): string; + abstract get fullName(): string; + abstract get exists(): boolean; + constructor(path: string) { + this.path = path; + } } export class DirectoryInfo extends FileSystemInfo { - constructor(directoryPath: string) { - super(directoryPath); - this.path = directoryPath; - } - get name(): string { - return path.basename(this.path); - } + constructor(directoryPath: string) { + super(directoryPath); + this.path = directoryPath; + } + get name(): string { + return path.basename(this.path); + } - get fullName(): string { - return this.path; - } + get fullName(): string { + return this.path; + } - get exists(): boolean { - return fs.existsSync(this.path) && fs.statSync(this.path).isDirectory(); - } - get parent(): DirectoryInfo | null { - const parentPath = path.dirname(this.path); - return parentPath !== this.path ? new DirectoryInfo(parentPath) : null; - } + get exists(): boolean { + return fs.existsSync(this.path) && fs.statSync(this.path).isDirectory(); + } + get parent(): DirectoryInfo | null { + const parentPath = path.dirname(this.path); + return parentPath !== this.path ? new DirectoryInfo(parentPath) : null; + } - getFiles(): FileInfo[] { - if (!this.exists) { - return []; - } - const fileInfos = fs - .readdirSync(this.path) - .map(fileName => { - const filePath = path.join(this.path, fileName); - const stat = fs.statSync(filePath); - - if (stat.isFile()) { - return new FileInfo(filePath); - } - }) - .filter(Boolean) as FileInfo[]; - return fileInfos; - } + getFiles(): FileInfo[] { + if (!this.exists) { + return []; + } + const fileInfos = fs + .readdirSync(this.path) + .map(fileName => { + const filePath = path.join(this.path, fileName); + const stat = fs.statSync(filePath); - getDirectories(): DirectoryInfo[] { - try { - const directoryNames = fs - .readdirSync(this.path) - .filter(item => fs.statSync(path.join(this.path, item)).isDirectory()); - return directoryNames.map( - directory => new DirectoryInfo(path.join(this.path, directory)) - ); - } catch (error) { - console.error(`Error reading directories in ${this.path}: ${error.message}`); - return []; + if (stat.isFile()) { + return new FileInfo(filePath); } - } + }) + .filter(Boolean) as FileInfo[]; + return fileInfos; + } + + getDirectories(): DirectoryInfo[] { + try { + const directoryNames = fs + .readdirSync(this.path) + .filter(item => fs.statSync(path.join(this.path, item)).isDirectory()); + return directoryNames.map(directory => new DirectoryInfo(path.join(this.path, directory))); + } catch (error) { + console.error(`Error reading directories in ${this.path}: ${error.message}`); + return []; + } + } + up(count: number): DirectoryInfo | undefined { + if (count < 0) throw new Error('count must be greater than or equal to 0'); + let current: DirectoryInfo | null | undefined = this; + for (let i = 0; i < count; i++) { + current = current?.parent; + } + return current || undefined; + } } export class FileInfo extends FileSystemInfo { - constructor(filePath: string) { - super(filePath); - this.path = filePath; - } + constructor(filePath: string) { + super(filePath); + this.path = filePath; + } - get name(): string { - return path.basename(this.path); - } + get name(): string { + return path.basename(this.path); + } - get fullName(): string { - return this.path; - } + get fullName(): string { + return this.path; + } - get exists(): boolean { - return fs.existsSync(this.path) && fs.statSync(this.path).isFile(); - } + get exists(): boolean { + return fs.existsSync(this.path) && fs.statSync(this.path).isFile(); + } - get length(): number { - if (!this.exists) { - return 0; - } - return fs.statSync(this.path).size; - } - get directory(): DirectoryInfo { - const directoryPath = path.dirname(this.path); - return new DirectoryInfo(directoryPath); - } + get length(): number { + if (!this.exists) { + return 0; + } + return fs.statSync(this.path).size; + } + get directory(): DirectoryInfo { + const directoryPath = path.dirname(this.path); + return new DirectoryInfo(directoryPath); + } } export abstract class Path { - static GetRelativePath(relativeTo: string, to: string): string { - return path.relative(relativeTo, to); - } - static GetBaseName(fullName: string) { - return path.basename(fullName); - } - static GetFileNameWithoutExtension(path: string): string { - const fileName: string = new FileInfo(path).name; - const lastPeriod: number = fileName.lastIndexOf('.'); - return lastPeriod < 0 - ? fileName // No extension was found - : fileName.slice(0, lastPeriod); - } + private constructor() {} + static GetRelativePath(relativeTo: string, to: string): string { + return path.relative(relativeTo, to); + } + static GetBaseName(fullName: string) { + return path.basename(fullName); + } + static GetFileNameWithoutExtension(path: string): string { + const fileName: string = new FileInfo(path).name; + const lastPeriod: number = fileName.lastIndexOf('.'); + return lastPeriod < 0 + ? fileName // No extension was found + : fileName.slice(0, lastPeriod); + } } export function projectRoot(): DirectoryInfo { - return new DirectoryInfo(__dirname).parent!; + return new DirectoryInfo(__dirname).parent!; } export function documentRoot(): DirectoryInfo { - return projectRoot() - .getDirectories() - .filter(x => x.name === 'document')[0]; + return projectRoot() + .getDirectories() + .filter(x => x.name === 'document')[0]; }