UNPKG

myst-cli

Version:
115 lines (114 loc) 5.67 kB
import fs from 'node:fs'; import path from 'node:path'; import { createDocFromState, DocxSerializer, writeDocx } from 'myst-to-docx'; import { tic, writeFileToFolder } from 'myst-cli-utils'; import { FRONTMATTER_ALIASES, PAGE_FRONTMATTER_KEYS, PROJECT_FRONTMATTER_KEYS, validateProjectFrontmatter, } from 'myst-frontmatter'; import MystTemplate from 'myst-templates'; import { htmlTransform } from 'myst-transforms'; import { fileError, fileWarn, RuleId, TemplateKind } from 'myst-common'; import { selectAll } from 'unist-util-select'; import { filterKeys } from 'simple-validators'; import { VFile } from 'vfile'; import { frontmatterValidationOpts } from '../../frontmatter.js'; import { finalizeMdast } from '../../process/mdast.js'; import { createTempFolder } from '../../utils/createTempFolder.js'; import { logMessagesFromVFile } from '../../utils/logging.js'; import { ImageExtensions } from '../../utils/resolveExtension.js'; import { cleanOutput } from '../utils/cleanOutput.js'; import { getFileContent } from '../utils/getFileContent.js'; import { createFooter } from './footers.js'; import { createArticleTitle, createReferenceTitle } from './titles.js'; const DOCX_IMAGE_EXTENSIONS = [ImageExtensions.png, ImageExtensions.jpg, ImageExtensions.jpeg]; function defaultWordRenderer(session, data, doc, opts, staticPath, vfile) { var _a, _b; const { mdast, frontmatter, references } = data; const frontmatterNodes = createArticleTitle(frontmatter.title, frontmatter.authors); const serializer = new DocxSerializer(vfile, { getImageBuffer(image) { // This extra read somehow prevents an error when buffer-image-size tries to get image dimensions... fs.readFileSync(image); return Buffer.from(fs.readFileSync(image).buffer); }, useFieldsForCrossReferences: false, }, frontmatter); frontmatterNodes.forEach((node) => { serializer.render(node); }); serializer.renderChildren(mdast); const referencesDocStates = Object.values((_b = (_a = references.cite) === null || _a === void 0 ? void 0 : _a.data) !== null && _b !== void 0 ? _b : {}) .map(({ html }) => html) .sort((a, b) => a.localeCompare(b)) .map((html) => { return { type: 'html', value: html }; }); if (referencesDocStates.length > 0) { serializer.render(createReferenceTitle()); const referencesRoot = htmlTransform({ type: 'root', children: referencesDocStates }); serializer.renderChildren(referencesRoot); serializer.closeBlock(); } selectAll('footnoteDefinition', mdast).forEach((footnote) => { serializer.render(footnote); }); const logo = path.join(staticPath, 'logo.png'); const docfooter = fs.existsSync(logo) && !opts.hideFooter ? createFooter(logo) : undefined; const styles = path.join(staticPath, 'styles.xml'); const docstyles = fs.existsSync(styles) ? fs.readFileSync(styles).toString() : undefined; return createDocFromState(serializer, docfooter, docstyles); } export async function runWordExport(session, file, exportOptions, opts) { var _a; const { output, articles } = exportOptions; const { clean, projectPath, extraLinkTransformers, execute } = opts !== null && opts !== void 0 ? opts : {}; // At this point, export options are resolved to contain one-and-only-one article const article = articles[0]; if (!(article === null || article === void 0 ? void 0 : article.file)) return { tempFolders: [] }; if (clean) cleanOutput(session, output); const vfile = new VFile(); vfile.path = output; const imageWriteFolder = createTempFolder(session); const [data] = await getFileContent(session, [article.file], { projectPath, imageExtensions: DOCX_IMAGE_EXTENSIONS, extraLinkTransformers, preFrontmatters: [ filterKeys(article, [...PAGE_FRONTMATTER_KEYS, ...Object.keys(FRONTMATTER_ALIASES)]), ], execute, }); const mystTemplate = new MystTemplate(session, { kind: TemplateKind.docx, template: exportOptions.template || undefined, buildDir: session.buildPath(), errorLogFn: (message) => { fileError(vfile, message, { ruleId: RuleId.docxRenders }); }, warningLogFn: (message) => { fileWarn(vfile, message, { ruleId: RuleId.docxRenders }); }, }); await mystTemplate.ensureTemplateExistsOnPath(); const toc = tic(); const exportFrontmatter = validateProjectFrontmatter(filterKeys(exportOptions, [...PROJECT_FRONTMATTER_KEYS, ...Object.keys(FRONTMATTER_ALIASES)]), frontmatterValidationOpts(vfile)); logMessagesFromVFile(session, vfile); data.frontmatter = { ...data.frontmatter, ...exportFrontmatter }; const { options, doc } = mystTemplate.prepare({ frontmatter: data.frontmatter, parts: {}, options: { ...data.frontmatter.options, ...exportOptions }, sourceFile: file, }); const renderer = (_a = exportOptions.renderer) !== null && _a !== void 0 ? _a : defaultWordRenderer; await finalizeMdast(session, data.mdast, data.frontmatter, article.file, { imageWriteFolder, imageExtensions: DOCX_IMAGE_EXTENSIONS, simplifyFigures: true, }); const docx = renderer(session, data, doc, options, mystTemplate.templatePath, vfile); logMessagesFromVFile(session, vfile); await writeDocx(docx, (buffer) => writeFileToFolder(output, buffer)); session.log.info(toc(`📄 Exported DOCX in %s, copying to ${output}`)); return { tempFolders: [imageWriteFolder] }; }