UNPKG

c4dslbuilder

Version:

A CLI tool designed to compile a folder structure of markdowns and mermaid files into a site, pdf, single file markdown or a collection of markdowns with links - inspired by c4builder

137 lines (136 loc) 6.14 kB
import path from 'path'; import chalk from 'chalk'; import { OutputType, ProcessorBase } from './processor-base.js'; import { SafeFiles } from './safe-files.js'; import { CliLogger } from './cli-logger.js'; import { MermaidProcessor } from './mermaid-processor.js'; import { docsifyTemplate } from '../assets/docsify.template.js'; import { CacheManager } from './cache-manager.js'; import * as Constants from '../types/constants.js'; export class SiteProcessor extends ProcessorBase { safeFiles; logger; mermaid; cache; constructor(safeFiles = new SafeFiles(), logger = new CliLogger(SiteProcessor.name), mermaid = new MermaidProcessor(), cache = new CacheManager(path.resolve(Constants.CACHE_FILENAME), safeFiles, logger)) { super(safeFiles, logger, mermaid); this.safeFiles = safeFiles; this.logger = logger; this.mermaid = mermaid; this.cache = cache; } async shouldProcessItem(item) { if (Array.isArray(item.mdFiles)) { for (const md of item.mdFiles) { const fullPath = path.join(item.dir, md.name); if (await this.cache.hasChanged(fullPath)) return true; } } if (Array.isArray(item.mmdFiles)) { for (const mmd of item.mmdFiles) { const fullPath = path.join(item.dir, mmd.name); if (await this.cache.hasChanged(fullPath)) return true; } } return false; } async markProcessedItem(item) { if (Array.isArray(item.mdFiles)) { for (const md of item.mdFiles) { const fullPath = path.join(item.dir, md.name); await this.cache.markProcessed(fullPath); } } if (Array.isArray(item.mmdFiles)) { for (const mmd of item.mmdFiles) { const fullPath = path.join(item.dir, mmd.name); await this.cache.markProcessed(fullPath); } } } getOutputFileName(buildConfig, dir, name) { const destFldr = path.resolve(buildConfig.distFolder); const destPath = path.resolve(dir.replace(buildConfig.rootFolder, buildConfig.distFolder)); const destFileName = path.join(destPath, `${name}.md`); return path.relative(destFldr, destFileName); } async writeUnifiedMarkdown(item, buildConfig) { const destFileName = this.getOutputFileName(buildConfig, item.dir, item.name); let MD = `# ${item.name}\n\n`; MD += await this.processMarkdownDocument(item, buildConfig); await this.safeFiles.ensureDir(path.resolve(item.dir.replace(buildConfig.rootFolder, buildConfig.distFolder))); await this.safeFiles.writeFile(path.resolve(path.join(buildConfig.distFolder, destFileName)), MD); } async writeSidebar(tree, buildConfig) { const sidebar = tree .map((item) => { const indent = ' '.repeat(item.level); const mdPath = this.getOutputFileName(buildConfig, item.dir, item.name); return `${indent}* [${item.name}](${encodeURI(mdPath)})`; }) .join('\n'); await this.safeFiles.ensureDir(path.resolve(buildConfig.distFolder)); await this.safeFiles.writeFile(path.resolve(path.join(buildConfig.distFolder, '_sidebar.md')), sidebar); } async generateSiteFromTree(tree, buildConfig) { await this.writeSidebar(tree, buildConfig); for (const item of tree) { const filesChanged = await this.shouldProcessItem(item); if (filesChanged) { await this.writeUnifiedMarkdown(item, buildConfig); await this.markProcessedItem(item); } else { this.logger.info(`Skipping unchanged item: ${item.name}`); } } const docOptions = { name: buildConfig.projectName, repo: buildConfig.repoName, loadSidebar: true, auto2top: true, homepage: `${buildConfig.homepageName}.md`, stylesheet: buildConfig.webTheme, supportSearch: buildConfig.webSearch, mermaidConfig: { querySelector: '.mermaid', }, }; let docTemplate = ''; if (buildConfig.docsifyTemplate === '') { docTemplate = docsifyTemplate(docOptions); } else { try { const templateModulePath = path.resolve(buildConfig.docsifyTemplate); const templateModule = await import(templateModulePath); if (typeof templateModule.docsifyTemplate === 'function') { docTemplate = templateModule.docsifyTemplate(docOptions); } else { this.logger.warn(`Custom docsify template module at ${buildConfig.docsifyTemplate} does not export a valid 'docsifyTemplate' function. Using default.`); docTemplate = docsifyTemplate(docOptions); } } catch (error) { this.logger.error(`Error loading custom docsify template at ${buildConfig.docsifyTemplate}. Using default.`, error); docTemplate = docsifyTemplate(docOptions); } } await this.safeFiles.ensureDir(path.resolve(buildConfig.distFolder)); await this.safeFiles.writeFile(path.join(buildConfig.distFolder, 'index.html'), docTemplate); await this.safeFiles.writeFile(path.join(buildConfig.distFolder, '.nojekyll'), ''); } async prepareSite(buildConfig, cleanBeforeBuild = true) { if (!(await this.prepareOutputFolder(OutputType.site, buildConfig, cleanBeforeBuild))) { this.logger.warn('Output folder preparation failed.'); return; } await this.cache.loadCache(); const tree = await this.generateSourceTree(buildConfig); await this.generateSiteFromTree(tree, buildConfig); this.logger.log(chalk.green(`\nSITE documentation generated successfully!`)); } }