Skip to content

Commit

Permalink
refactor utils od sidebar and document into services
Browse files Browse the repository at this point in the history
  • Loading branch information
sharpchen committed Apr 9, 2024
1 parent d095576 commit 6fdb4f6
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 90 deletions.
4 changes: 2 additions & 2 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineConfig } from 'vitepress';
import { transformerTwoslash } from 'vitepress-plugin-twoslash';
import { getRegisteredMarkdownTheme } from '../shared/utils';
import { builder } from '../shared/multipleSidebarBuilder';
import { sidebarService } from '../services/SidebarService';

// https://vitepress.dev/reference/site-config
export default defineConfig({
Expand Down Expand Up @@ -33,7 +33,7 @@ export default defineConfig({
{ text: 'Contact', link: '../contact.md' },
],
logo: '/favicon.ico',
sidebar: builder.emitSidebar(),
sidebar: sidebarService.getMultipleSidebar(),
outline: {
level: 'deep',
},
Expand Down
16 changes: 0 additions & 16 deletions docs/data/global.data.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,5 @@
import { version } from '../../node_modules/vitepress/package.json';

export const documentMap = {
'Csharp Design Patterns': '👾',
'Modern CSharp': '🐱‍👤',
Articles: '📰',
Avalonia: '😱',
Docker: '🐋',
Git: '🐱',
JavaScript: '😅',
SQL: '📝',
TypeScript: '⌨',
VBA: '💩',
Vue3: '⚡',
} as const;
export type DocumentName = keyof typeof documentMap;
export type DocumentIcon = (typeof documentMap)[keyof typeof documentMap];

const globalData = {
vitepressVersion: version,
} as const;
Expand Down
45 changes: 45 additions & 0 deletions docs/services/DocumentService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { DocumentName, documentMap } from '../data/global.data';
import * as File from '../shared/FileSystem';
import { IDocumentService } from './IDocumentService';

class DocumentService implements IDocumentService {
getDocumentEntryFolder(name: DocumentName): File.DirectoryInfo {
const ret = this.registeredDocumentFolders().find(x => x.name === name);
if (!ret) throw new Error(`Document entry of ${name} not found.`);
return ret;
}
registeredDocumentFolders(): File.DirectoryInfo[] {
return this.documentSrc.getDirectories().filter(x => Object.keys(documentMap).includes(x.name));
}
physicalDocumentFolders(): File.DirectoryInfo[] {
return this.documentSrc.getDirectories();
}
getMarkdownEntryFolder(name: DocumentName): File.DirectoryInfo {
const ret = this.getDocumentEntryFolder(name)
.getDirectories()
.find(x => x.name === 'docs');
if (!ret) throw new Error(`Markdown entry of ${name} not found.`);
return ret;
}
registeredCount(): number {
return Object.keys(documentMap).length;
}
physicalCount(): number {
return this.documentSrc.getDirectories().length;
}
physicalCountBy(f: (x: File.DirectoryInfo) => boolean): number {
return this.documentSrc.getDirectories().filter(x => f(x)).length;
}
getIndexLinkOfDocument(name: DocumentName): string {
throw new Error('Method not implemented.');
}
get documentSrc(): File.DirectoryInfo {
const ret = File.projectRoot()
.getDirectories()
.find(x => x.name === 'document');
if (!ret) throw new Error('Document source not found.');
return ret;
}
}

export const documentService: IDocumentService = new DocumentService();
28 changes: 28 additions & 0 deletions docs/services/IDocumentService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as File from '../shared/FileSystem';

export interface IDocumentService {
physicalCount(): number;
registeredCount(): number;
physicalCountBy(f: (x: File.DirectoryInfo) => boolean): number;
getIndexLinkOfDocument(name: DocumentName): string;
get documentSrc(): File.DirectoryInfo;
getMarkdownEntryFolder(name: DocumentName): File.DirectoryInfo;
getDocumentEntryFolder(name: DocumentName): File.DirectoryInfo;
registeredDocumentFolders(): File.DirectoryInfo[];
physicalDocumentFolders(): File.DirectoryInfo[];
}
export const documentMap = {
'Csharp Design Patterns': '👾',
'Modern CSharp': '🐱‍👤',
Articles: '📰',
Avalonia: '😱',
Docker: '🐋',
Git: '🐱',
JavaScript: '😅',
SQL: '📝',
TypeScript: '⌨',
VBA: '💩',
Vue3: '⚡',
} as const;
export type DocumentName = keyof typeof documentMap;
export type DocumentIcon = (typeof documentMap)[keyof typeof documentMap];
13 changes: 13 additions & 0 deletions docs/services/ISidebarService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { DefaultTheme } from 'vitepress';
import { DocumentName } from './IDocumentService';
import * as File from '../shared/FileSystem';
import { IDocumentService } from './IDocumentService';
export interface ISidebarService {
readonly documentService: IDocumentService;
getMultipleSidebar(): DefaultTheme.SidebarMulti;
getSidebarOfDocument(name: DocumentName): DefaultTheme.SidebarItem[];
transformFolderToSidebarItem(
folder: File.DirectoryInfo,
baseLink: string
): DefaultTheme.SidebarItem[];
}
7 changes: 7 additions & 0 deletions docs/services/IThemeService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { themes } from '../../.github/workflows/beforeBuild/sync-themes.mjs';
export type ThemeName = keyof typeof themes;
export interface IThemeService {
register(): void;
getTheme(name: ThemeName): any;
themes(): any[];
}
72 changes: 72 additions & 0 deletions docs/services/SidebarService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Enumerable from 'linq';
import { DefaultTheme } from 'vitepress';
import { DocumentName, documentMap } from './IDocumentService';
import { DirectoryInfo, FileInfo, Path, documentRoot } from '../shared/FileSystem';
import { documentService } from './DocumentService';
import { IDocumentService } from './IDocumentService';
import { ISidebarService } from './ISidebarService';

class SidebarService implements ISidebarService {
private readonly base: string = `/${documentRoot().name}`;
readonly documentService: IDocumentService = documentService;
getMultipleSidebar(): DefaultTheme.SidebarMulti {
let sidebar: DefaultTheme.SidebarMulti = {};
for (const name of Object.keys(documentMap)) {
sidebar[`${this.base}/${name}/docs/`] = this.getSidebarOfDocument(name as DocumentName);
}
return sidebar;
}
getSidebarOfDocument(name: DocumentName): DefaultTheme.SidebarItem[] {
const markdownEntry = this.documentService.getMarkdownEntryFolder(name as DocumentName);
return [
{
text: name,
items: this.transformFolderToSidebarItem(markdownEntry, `${this.base}/${name}`),
},
];
}
transformFolderToSidebarItem(folder: DirectoryInfo, base: string): DefaultTheme.SidebarItem[] {
const subs = folder.getDirectories();
// load files in this folder
let items: DefaultTheme.SidebarItem[] = folder.getFiles().length
? filesToSidebarItems(folder.getFiles(), `${base}/${folder.name}`)
: [];
for (const index in subs) {
if (Object.prototype.hasOwnProperty.call(subs, index)) {
const sub = subs[index];
const currentSidebarItem: DefaultTheme.SidebarItem = {
collapsed: false,
text: sub.name.replace(/^\d+\.\s*/, ''), // remove leading index
items: this.transformFolderToSidebarItem(sub, `${base}/${folder.name}`),
};
items.push(currentSidebarItem);
}
}
return items;
function filesToSidebarItems(files: FileInfo[], base: string): DefaultTheme.SidebarItem[] {
return files
.map(file => {
const link = `${base}/${file.name}`;
return {
text: Path.GetFileNameWithoutExtension(file.name),
link: link.substring(0, link.lastIndexOf('.')),
};
})
.sort((x, y) => {
// if (!/^\d+\.\s*/.test(x.text) || !/^\d+\.\s*/.test(y.text))
// throw new Error(
// `Files:\n${Enumerable.from(files)
// .select(f => f.fullName)
// .aggregate(
// (prev, current) => `${prev},\n${current}\n`
// )} don't have consistent leading indices.`
// );
return (
parseInt(x.text.match(/^\d+\.\s*/)?.[0]!) - parseInt(y.text.match(/^\d+\.\s*/)?.[0]!)
);
});
}
}
}

export const sidebarService: ISidebarService = new SidebarService();
File renamed without changes.
32 changes: 0 additions & 32 deletions docs/shared/multipleSidebarBuilder.ts

This file was deleted.

54 changes: 14 additions & 40 deletions docs/shared/utils.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,20 @@
import * as fs from 'fs';
import path from 'path';
import * as shikiji from 'shikiji';
import { DefaultTheme } from 'vitepress';
import { themes } from '../../.github/workflows/beforeBuild/sync-themes.mjs';
import { FileInfo, Path, DirectoryInfo, projectRoot } from './FileSystem';
import { projectRoot } from './FileSystem';

export async function getRegisteredMarkdownTheme(theme: keyof typeof themes): Promise<shikiji.ThemeRegistration> {
let isThemeRegistered = (await shikiji.getSingletonHighlighter()).getLoadedThemes().find(x => x === theme);
if (!isThemeRegistered) {
const myTheme = JSON.parse(fs.readFileSync(path.join(projectRoot().fullName, `public/${theme}.json`), 'utf8'));
(await shikiji.getSingletonHighlighter()).loadTheme(myTheme);
}
return (await shikiji.getSingletonHighlighter()).getTheme(theme);
}

export function filesToSidebarItems(files: FileInfo[], base: string): DefaultTheme.SidebarItem[] {
return files.map(file => {
const link = `${base}/${file.name}`;
return {
text: Path.GetFileNameWithoutExtension(file.name),
link: link.substring(0, link.lastIndexOf('.')),
};
});
}

export function folderToSidebarItems(folder: DirectoryInfo, base: string): DefaultTheme.SidebarItem[] {
if (!folder.exists) throw new Error(`folder: ${folder.name} not found`);
const subs = folder.getDirectories();
// load files in this folder
let items: DefaultTheme.SidebarItem[] = folder.getFiles().length
? filesToSidebarItems(folder.getFiles(), `${base}/${folder.name}`)
: [];
for (const index in subs) {
if (Object.prototype.hasOwnProperty.call(subs, index)) {
const sub = subs[index];
const currentSidebarItem: DefaultTheme.SidebarItem = {
collapsed: false,
text: sub.name.replace(/^\d+\.\s*/, ''), // remove leading index
items: folderToSidebarItems(sub, `${base}/${folder.name}`),
};
items.push(currentSidebarItem);
}
}
return items;
export async function getRegisteredMarkdownTheme(
theme: keyof typeof themes
): Promise<shikiji.ThemeRegistration> {
let isThemeRegistered = (await shikiji.getSingletonHighlighter())
.getLoadedThemes()
.find(x => x === theme);
if (!isThemeRegistered) {
const myTheme = JSON.parse(
fs.readFileSync(path.join(projectRoot().fullName, `public/${theme}.json`), 'utf8')
);
(await shikiji.getSingletonHighlighter()).loadTheme(myTheme);
}
return (await shikiji.getSingletonHighlighter()).getTheme(theme);
}

0 comments on commit 6fdb4f6

Please sign in to comment.