UNPKG

myst-cli

Version:
169 lines (168 loc) โ€ข 5.47 kB
import fs from 'node:fs'; import path from 'node:path'; import chalk from 'chalk'; import inquirer from 'inquirer'; import { ExportFormats } from 'myst-frontmatter'; import { collectAllBuildExportOptions, getProjectPaths } from './build.js'; import { getLogOutputFolder, getTexOutputFolder } from './pdf/create.js'; function promptContinue() { return { name: 'cont', message: 'Would you like to continue?', type: 'confirm', default: true, }; } const ALL_OPTS = { docx: true, pdf: true, tex: true, xml: true, md: true, meca: true, site: true, html: true, temp: true, logs: true, cache: true, exports: true, execute: true, templates: true, }; const DEFAULT_OPTS = { docx: true, pdf: true, tex: true, xml: true, md: true, meca: true, site: true, html: true, temp: true, logs: true, exports: true, execute: true, }; function coerceOpts(opts) { const { docx, pdf, tex, xml, md, meca, site, html, temp, logs, cache, exports, execute, templates, all, } = opts; if (all) return { ...opts, ...ALL_OPTS }; if (!docx && !pdf && !tex && !xml && !md && !meca && !site && !html && !temp && !logs && !cache && !exports && !execute && !templates) { return { ...opts, ...DEFAULT_OPTS }; } return { ...opts }; } /** * Returns true if 'item' is a subpath under folder * * e.g. isSubpath('_build/exports/out.pdf', '_build/exports') => true * isSubpath('_build/exports', '_build/exports/out.pdf') => false * isSubpath('_build/exports', '_build/exports') => false */ function isSubpath(item, folder) { if (item === folder) return false; const itemParts = item.split(path.sep); const folderParts = folder.split(path.sep); let subpath = true; folderParts.forEach((part, index) => { if (itemParts[index] !== part) subpath = false; }); return subpath; } function isSubpathOfAny(item, folders) { let subpath = false; folders.forEach((folder) => { if (isSubpath(item, folder)) subpath = true; }); return subpath; } function deduplicatePaths(paths) { const uniquePaths = [...new Set(paths)]; return uniquePaths.filter((item) => !isSubpathOfAny(item, [...uniquePaths])); } export async function clean(session, files, opts) { opts = coerceOpts(opts); const { site, html, temp, logs, cache, exports, execute, templates, yes } = opts; let pathsToDelete = []; const exportOptionsList = await collectAllBuildExportOptions(session, files, opts); if (exports) { exportOptionsList.forEach((exportOptions) => { pathsToDelete.push(exportOptions.output); if (exportOptions.format === ExportFormats.pdftex) { pathsToDelete.push(getLogOutputFolder(exportOptions.output)); pathsToDelete.push(getTexOutputFolder(exportOptions.output)); } }); } let buildFolders = []; if (temp || logs || cache || exports || execute || templates || html) { const projectPaths = [ ...getProjectPaths(session), ...exportOptionsList.map((exp) => exp.$project), ]; projectPaths .filter((projPath) => Boolean(projPath)) .forEach((projPath) => { buildFolders.push(path.join(projPath, '_build')); }); buildFolders.push(session.buildPath()); } buildFolders = [...new Set(buildFolders)].sort(); if (temp || logs || cache || exports || templates || execute || html) { buildFolders.forEach((folder) => { if (temp) pathsToDelete.push(path.join(folder, 'temp')); if (logs) pathsToDelete.push(path.join(folder, 'logs')); if (cache) pathsToDelete.push(path.join(folder, 'cache')); if (exports) pathsToDelete.push(path.join(folder, 'exports')); if (templates) pathsToDelete.push(path.join(folder, 'templates')); if (html) pathsToDelete.push(path.join(folder, 'html')); if (execute) pathsToDelete.push(path.join(folder, 'execute')); }); } if (site) { pathsToDelete.push(session.sitePath()); } pathsToDelete = deduplicatePaths(pathsToDelete.filter((p) => fs.existsSync(p))).sort(); if (pathsToDelete.length === 0) { session.log.info(chalk.yellow(`๐Ÿงน Your folders are already so clean! โœจ`)); return; } session.log.info(`Deleting all the following paths:\n\n - ${pathsToDelete.join('\n - ')}\n`); const cont = yes || (await inquirer.prompt([promptContinue()])).cont; if (cont) { pathsToDelete.forEach((pathToDelete) => { session.log.info(`๐Ÿ—‘ Deleting: ${pathToDelete}`); fs.rmSync(pathToDelete, { recursive: true, force: true }); }); // Delete any empty build folders buildFolders.forEach((buildFolder) => { if (fs.existsSync(buildFolder) && fs.readdirSync(buildFolder).length === 0) { session.log.debug(`Deleting empty build folder: ${buildFolder}`); fs.rmSync(buildFolder, { recursive: true, force: true }); } }); } }