import fs, {promises as fsp} from 'fs'; import {join} from 'path'; import cpy from 'cpy'; // @ts-expect-error import htmlclean from 'htmlclean'; import marked from 'marked'; import nunjucks from 'nunjucks'; import refractor from 'refractor'; import rehype from 'rehype'; import sass from 'sass'; import {generateLove, LoveVariant} from './love'; import {getVersions, Versions} from './version'; export async function main(): Promise { // Create all required directories for the website. await fsp.mkdir(join(__dirname, '../../public/css/'), {recursive: true}); await fsp.copyFile( join(__dirname, '../../node_modules/modern-normalize/modern-normalize.css'), join(__dirname, '../../public/css/modern-normalize.css') ); await fsp.mkdir(join(__dirname, '../../public/images/'), {recursive: true}); // Configure Nunjucks to use the templates for `source/pages/`. nunjucks.configure(join(__dirname, '../pages/'), { lstripBlocks: true, trimBlocks: true, throwOnUndefined: true }); const love: LoveVariant[] = generateLove(); const versions: Versions = await getVersions(); // Write the colors to file. await writeJSON(join(__dirname, '../../public/love.json'), love); // Render the Sass to CSS. let css: string = sass .renderSync({ file: join(__dirname, '../pages/scss/style.scss'), sourceMap: false }) .css.toString(); // Generate the CSS custom properties. const cssProperties = `:root { --foreground-1: ${love[0].colors.foreground1}; --foreground-2: ${love[0].colors.foreground2}; --background-1: ${love[0].colors.background1}; --background-2: ${love[0].colors.background2}; ${love[0].colors.accents .map((value, index) => ` --dark-accent-${index + 1}: ${value};`) .join('\n')} ${love[0].colors.grays .map((value, index) => ` --dark-gray-${index + 1}: ${value};`) .join('\n')} ${love[1].colors.accents .map((value, index) => ` --light-accent-${index + 1}: ${value};`) .join('\n')} ${love[1].colors.grays .map((value, index) => ` --light-gray-${index + 1}: ${value};`) .join('\n')} }\n`; // Replace the predefined `:root` location with our properties. css = css.replace(/\/\* :root-insert \*\//, cssProperties); // Write the CSS to file. await fsp.writeFile(join(__dirname, '../../public/css/style.css'), css); // Render and write the `index.html` file. await fsp.writeFile( join(__dirname, '../../public/index.html'), htmlclean(nunjucks.render('index.html', {love})) ); const renderer: marked.Renderer = new marked.Renderer(); renderer.code = (code: string, language: string | undefined): string => { if (language === undefined) { throw new Error('Markdown code block with no language detected'); } const codeHTML: string = rehype() .stringify({type: 'root', children: refractor.highlight(code, language)}) .toString(); return `
${codeHTML}
`; }; await fsp.mkdir(join(__dirname, '../../public/get/'), {recursive: true}); const pagesToCreate: string[] = ( await fsp.readdir(join(__dirname, '../')) ).filter((value) => !['pages', 'scripts'].includes(value)); for (const page of pagesToCreate) { const markdown: string = marked( nunjucks.renderString( await fsp.readFile( join(__dirname, `../${page}/SITE README.md`), 'utf8' ), {versions} ), {renderer} ); await fsp.mkdir(join(__dirname, `../../public/images/${page}/`), { recursive: true }); if (fs.existsSync(join(__dirname, `../${page}/images/`))) { await cpy( join(__dirname, `../${page}/images/*`), join(__dirname, `../../public/images/${page}/`) ); } let title = `Love for ${page .replace(/-/g, ' ') .split(' ') .map((value) => capitalize(value)) .join(' ')}`; switch (page) { case 'vscode': title = 'Love for VS Code'; break; default: break; } const directory = join(__dirname, `../../public/get/${page}/`); await fsp.mkdir(directory, {recursive: true}); await fsp.writeFile( join(directory, 'index.html'), htmlclean(nunjucks.render('get.html', {love, markdown, title})) ); } } export function capitalize(word: string): string { return `${word.slice(0, 1).toUpperCase()}${word.slice(1)}`; } // Utility helper function to write some data to file as JSON. export async function writeJSON(path: string, data: unknown): Promise { await fsp.writeFile(path, JSON.stringify(data, null, 2)); } if (require.main === module) { void main(); }