diff options
| author | LMBishop <13875753+LMBishop@users.noreply.github.com> | 2021-12-20 14:48:04 +0000 |
|---|---|---|
| committer | LMBishop <13875753+LMBishop@users.noreply.github.com> | 2021-12-20 14:48:04 +0000 |
| commit | 3f91a121b33151cd466de930d0e68bdf87f4d19e (patch) | |
| tree | 62e9555661340d85537d8441da8cb92384d21180 /app/directory.ts | |
| parent | 1a1f5a10fb60426dae868d2a73ed2cac46100f2b (diff) | |
Convert to typescript
Diffstat (limited to 'app/directory.ts')
| -rw-r--r-- | app/directory.ts | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/app/directory.ts b/app/directory.ts new file mode 100644 index 0000000..6449e8e --- /dev/null +++ b/app/directory.ts @@ -0,0 +1,210 @@ +'use strict'; + +import { parse } from './wikiparser.mjs'; +import { readFileSync, readdirSync, statSync } from 'fs'; +import glob from 'glob'; + +export class PageDirectory { + + pages: Record<string, Page>; + primaryPages: Page[]; + pagePath: string; + lastBuild: number; + + constructor(root: string) { + this.lastBuild = 0; + this.pages = {}; + this.pagePath = root; + + this.rebuild(); + } + + /** + * Build this page directory. + * + * @returns whether the directory was built + */ + rebuild(): boolean { + if (this.lastBuild + parseInt(process.env.REBUILD_COOLDOWN_MIN, 10) * 60 * 1000 > Date.now()) { + return false; + } + for (var page in this.pages) { + delete this.pages[page]; + } + + let pages = glob.sync(`**/*.wiki`, { cwd: this.pagePath }) + + pages.forEach(page => { + page = page.replace('.wiki', '').replace('/', ':').replace(/[^a-z0-9:]/gi, '_').toLowerCase(); + this.pages[page] = this.buildPage(page); + }); + + let primaryPages = []; + Object.entries(this.pages).forEach(([name, page]) => { + if (page.metadata.includeInNavbar) { + primaryPages.push(page); + } + }); + + primaryPages.sort((a, b) => { + return a.metadata.sortOrder - b.metadata.sortOrder; + }); + this.primaryPages = primaryPages; + this.lastBuild = Date.now(); + return true; + } + + /** + * Get whether a page exists with this name. + * + * @param name standard name for page + * @returns whether the page exists + */ + exists(name: string): boolean { + return !!this.pages[this.convertNameToStandard(name)]; + } + + /** + * Get a page. + * + * @param name standard name for page + * @returns page + */ + get(name: string): Page { + name = this.convertNameToStandard(name); + let page = this.pages[name]; + if (!page) { + return undefined; + } + + if (!page.html) { + return this.buildPage(name) + } + + return page; + } + + /** + * Get the raw wikitext for a page. + * + * @param name standard name for page + * @returns raw wikitext + */ + getRaw(name: string): string { + name = this.convertNameToStandard(name); + return this.pages[name]?.raw; + } + + /** + * Purge (rebuild) a page. + * + * @param name standard name for page + * @returns whether the page was rebuilt + */ + purge(name: string): boolean { + name = this.convertNameToStandard(name); + let page = this.pages[name]; + if (page) { + if (page.buildTime + parseInt(process.env.PURGE_COOLDOWN_MIN, 10) * 60 * 1000 > Date.now()) { + return false; + } else { + delete this.pages[name]; + if (this.buildPage(name)) { + return true; + } + } + } + return false; + } + + /** + * Get all pages. + * + * @returns all pages + */ + getPages(): Record<string, Page> { + return this.pages; + } + + /** + * Get primary pages. + * + * @param current + * @returns + */ + getPrimaryPages(): Page[] { + return this.primaryPages; + } + + /** + * Build a page. + * + * @param path standard name for page + * @returns newly built page, or undefined + */ + private buildPage(name: string): Page { + name = this.convertNameToStandard(name); + let data: string; + try { + data = readFileSync(`${this.pagePath}/${this.convertStandardToFilePath(name)}`, 'utf-8'); + } catch { + return undefined; + } + let result = parse(data); + let title = result.metadata.displayTitle ?? name; + let content = `${result.metadata.notitle ? '' : `<h1>${title}</h1>`}${result.html}`; + + let page: Page = { + html: content, + raw: data, + standardName: name, + buildTime: Date.now(), + metadata: { + includeInNavbar: result.metadata.primary ?? false, + sortOrder: result.metadata.sortOrder ?? -1, + showTitle: !result.metadata.notitle ?? true, + displayTitle: title + } + }; + this.pages[name] = page; + return page; + } + + /** + * Convert a page name to a standard name. + * A standard name is the key used by the page directory. + * + * @param name non-standard name for a page + */ + private convertNameToStandard(name: string): string { + return name.replace(/[^a-z0-9:]/gi, '_').toLowerCase(); + } + + /** + * Convert a standard name to a file path. + * + * @param name standard name for a page + */ + private convertStandardToFilePath(name: string): string { + let [first, second] = name.split(':'); + let [title, subpage] = ((second) ? second : first).split('.') + let namespace = (second) ? first : undefined + + return `${namespace ? `${namespace}/` : ''}${title}${subpage ? `.${subpage}` : ''}.wiki` + } +}; + +export type Page = { + html: string; + raw: string; + standardName: string, + buildTime: number; + metadata: PageMetadata; +}; + +export type PageMetadata = { + displayTitle?: string; + sortOrder?: number; + showTitle?: boolean; + includeInNavbar?: boolean; +}; |
