Path: blob/main/src/render/notebook/notebook-contributor-ipynb.ts
6465 views
/*1* notebook-contributor-ipynb.ts2*3* Copyright (C) 2020-2022 Posit Software, PBC4*/56import { renderFile } from "../../command/render/render-files.ts";7import {8ExecutedFile,9RenderedFile,10RenderServices,11} from "../../command/render/types.ts";12import {13kClearCellOptions,14kClearHiddenClasses,15kIpynbProduceSourceNotebook,16kIPynbTitleBlockTemplate,17kKeepHidden,18kOutputFile,19kRemoveHidden,20kTo,21kUnrollMarkdownCells,22} from "../../config/constants.ts";23import { InternalError } from "../../core/lib/error.ts";24import { dirAndStem } from "../../core/path.ts";25import { ProjectContext } from "../../project/types.ts";26import { NotebookContributor, NotebookMetadata } from "./notebook-types.ts";27import { error } from "../../deno_ral/log.ts";28import { Format } from "../../config/types.ts";29import { ipynbTitleTemplatePath } from "../../format/ipynb/format-ipynb.ts";30import { projectOutputDir } from "../../project/project-shared.ts";31import { existsSync } from "../../deno_ral/fs.ts";32import { dirname, join, relative } from "../../deno_ral/path.ts";33import { safeCloneDeep } from "../../core/safe-clone-deep.ts";3435export const outputNotebookContributor: NotebookContributor = {36resolve: resolveOutputNotebook,37render: renderOutputNotebook,38outputFile,39cachedPath,40};4142export function outputFile(43nbAbsPath: string,44): string {45return ipynbOutputFile(nbAbsPath);46}4748function cachedPath(nbAbsPath: string, project?: ProjectContext) {49if (project) {50const nbRelative = relative(project.dir, dirname(nbAbsPath));51const nbOutputDir = join(projectOutputDir(project), nbRelative);5253const outFile = outputFile(nbAbsPath);54const outPath = join(nbOutputDir, outFile);55if (existsSync(outPath)) {56return outPath;57}58}59}6061function resolveOutputNotebook(62nbAbsPath: string,63_token: string,64executedFile: ExecutedFile,65_notebookMetadata?: NotebookMetadata,66) {67const resolved = safeCloneDeep(executedFile);68resolved.recipe.format.pandoc[kOutputFile] = outputFile(nbAbsPath);69resolved.recipe.output = resolved.recipe.format.pandoc[kOutputFile];7071resolved.recipe.format.pandoc.to = "ipynb";7273// TODO: Move to shared74const template = ipynbTitleTemplatePath();7576// Configure echo for this rendering77resolved.recipe.format.execute.echo = false;78resolved.recipe.format.execute.warning = false;79resolved.recipe.format.render[kKeepHidden] = true;80resolved.recipe.format.metadata[kClearHiddenClasses] = "all";81resolved.recipe.format.metadata[kRemoveHidden] = "none";82resolved.recipe.format.metadata[kIPynbTitleBlockTemplate] = template;8384// If this recipe is using a a source notebook, clear the cell options85// from the output when rendering86if (resolved.recipe.format.render[kIpynbProduceSourceNotebook]) {87resolved.recipe.format.render[kClearCellOptions] = true;88}8990// Configure markdown behavior for this rendering91resolved.recipe.format.metadata[kUnrollMarkdownCells] = false;92return resolved;93}94async function renderOutputNotebook(95nbPath: string,96_format: Format,97_subArticleToken: string,98services: RenderServices,99_notebookMetadata: NotebookMetadata | undefined,100project: ProjectContext,101): Promise<RenderedFile> {102const rendered = await renderFile(103{ path: nbPath, formats: ["ipynb"] },104{105services,106flags: {107metadata: {108[kTo]: "ipynb",109[kOutputFile]: outputFile(nbPath),110},111quiet: false,112},113echo: true,114warning: true,115quietPandoc: true,116},117services,118project,119);120121// An error occurred rendering this subarticle122if (rendered.error) {123error("Rendering of output notebook produced an unexpected result");124throw (rendered.error);125}126127// There should be only one file128if (rendered.files.length !== 1) {129throw new InternalError(130`Rendering an output notebook should only result in a single file. This attempt resulted in ${rendered.files.length} file(s).`,131);132}133134return rendered.files[0];135}136137function ipynbOutputFile(nbAbsPath: string) {138const [_dir, stem] = dirAndStem(nbAbsPath);139return `${stem}.out.ipynb`;140}141142143