@@ -27,13 +27,10 @@ import {
2727} from "../../config/format.ts" ;
2828import { resolveParams } from "../../command/render/flags.ts" ;
2929import { RenderContext , RenderFlags } from "../../command/render/types.ts" ;
30- import {
31- JupyterAssets ,
32- JupyterCell ,
33- JupyterCellOutput ,
34- } from "../jupyter/types.ts" ;
30+ import { JupyterAssets , JupyterCellOutput } from "../jupyter/types.ts" ;
3531
3632import { dirname , extname } from "path/mod.ts" ;
33+ import { getNamedLifetime } from "../lifetimes.ts" ;
3734
3835export interface NotebookAddress {
3936 path : string ;
@@ -94,60 +91,133 @@ export function parseNotebookPath(path: string): NotebookAddress | undefined {
9491 }
9592}
9693
97- export async function notebookMarkdown (
94+ type JupyterNotebookOutputCache = Record <
95+ string ,
96+ { outputs : JupyterCellOutput [ ] }
97+ > ;
98+
99+ async function getCellOutputs (
98100 nbAddress : NotebookAddress ,
99101 assets : JupyterAssets ,
100102 context : RenderContext ,
101103 flags : RenderFlags ,
102- filter ?: ( cell : JupyterCell ) => JupyterCell ,
104+ options ?: JupyterMarkdownOptions ,
103105) {
104- // Read and filter notebook
105- const notebook = jupyterFromFile ( nbAddress . path ) ;
106- if ( filter ) {
107- notebook . cells = notebook . cells . map ( filter ) ;
106+ const boolkey = ( key : string , value : boolean ) => {
107+ return `${ key } :${ String ( value ) } ` ;
108+ } ;
109+ const optionsKey = options
110+ ? Object . keys ( options ) . reduce ( ( key , current ) => {
111+ return current + boolkey ( key , options [ key ] ) ;
112+ } , "" )
113+ : "" ;
114+ const notebookKey = `${ nbAddress . path } -${ optionsKey } ` ;
115+
116+ // TODO: Ensure that we're properly dealing with formats for includes
117+ // (e.g. docx / pdf
118+
119+ const lifetime = getNamedLifetime ( "render-file" ) ;
120+ /*
121+ if (lifetime === undefined) {
122+ throw new Error("Internal Error: named lifetime render-file not found");
123+ }*/
124+ const nbCache = lifetime
125+ ? lifetime . get ( "notebook-cache" ) as unknown as JupyterNotebookOutputCache
126+ : undefined ||
127+ { } ;
128+
129+ if ( ! nbCache [ notebookKey ] ) {
130+ // Render the notebook and place it in the cache
131+ // Read and filter notebook
132+ const notebook = jupyterFromFile ( nbAddress . path ) ;
133+ if ( options ) {
134+ notebook . cells = notebook . cells . map ( ( cell ) => {
135+ if ( options . echo !== undefined ) {
136+ cell . metadata [ kEcho ] = options . echo ;
137+ }
138+
139+ if ( options . warning !== undefined ) {
140+ cell . metadata [ kWarning ] = options . warning ;
141+ }
142+
143+ if ( options . asis !== undefined ) {
144+ cell . metadata [ kOutput ] = options . asis ? true : false ;
145+ }
146+ return cell ;
147+ } ) ;
148+ }
149+
150+ const format = context . format ;
151+ const executeOptions = {
152+ target : context . target ,
153+ resourceDir : resourcePath ( ) ,
154+ tempDir : context . options . services . temp . createDir ( ) ,
155+ dependencies : true ,
156+ libDir : context . libDir ,
157+ format : context . format ,
158+ projectDir : context . project ?. dir ,
159+ cwd : flags . executeDir ||
160+ dirname ( Deno . realPathSync ( context . target . source ) ) ,
161+ params : resolveParams ( flags . params , flags . paramsFile ) ,
162+ quiet : flags . quiet ,
163+ previewServer : context . options . previewServer ,
164+ handledLanguages : languages ( ) ,
165+ } ;
166+ const result = await jupyterToMarkdown (
167+ notebook ,
168+ {
169+ executeOptions,
170+ language : notebook . metadata . kernelspec . language . toLowerCase ( ) ,
171+ assets,
172+ execute : format . execute ,
173+ keepHidden : format . render [ kKeepHidden ] ,
174+ toHtml : isHtmlCompatible ( format ) ,
175+ toLatex : isLatexOutput ( format . pandoc ) ,
176+ toMarkdown : isMarkdownOutput ( format . pandoc ) ,
177+ toIpynb : isIpynbOutput ( format . pandoc ) ,
178+ toPresentation : isPresentationOutput ( format . pandoc ) ,
179+ figFormat : format . execute [ kFigFormat ] ,
180+ figDpi : format . execute [ kFigDpi ] ,
181+ figPos : format . render [ kFigPos ] ,
182+ } ,
183+ ) ;
184+ nbCache [ notebookKey ] = { outputs : result . cellOutputs } ;
185+
186+ // TODO: set this back into the lifetime
108187 }
188+ return nbCache [ notebookKey ] . outputs ;
189+ }
109190
110- const format = context . format ;
111- const executeOptions = {
112- target : context . target ,
113- resourceDir : resourcePath ( ) ,
114- tempDir : context . options . services . temp . createDir ( ) ,
115- dependencies : true ,
116- libDir : context . libDir ,
117- format : context . format ,
118- projectDir : context . project ?. dir ,
119- cwd : flags . executeDir ||
120- dirname ( Deno . realPathSync ( context . target . source ) ) ,
121- params : resolveParams ( flags . params , flags . paramsFile ) ,
122- quiet : flags . quiet ,
123- previewServer : context . options . previewServer ,
124- handledLanguages : languages ( ) ,
125- } ;
126- const result = await jupyterToMarkdown (
127- notebook ,
128- {
129- executeOptions,
130- language : notebook . metadata . kernelspec . language . toLowerCase ( ) ,
131- assets,
132- execute : format . execute ,
133- keepHidden : format . render [ kKeepHidden ] ,
134- toHtml : isHtmlCompatible ( format ) ,
135- toLatex : isLatexOutput ( format . pandoc ) ,
136- toMarkdown : isMarkdownOutput ( format . pandoc ) ,
137- toIpynb : isIpynbOutput ( format . pandoc ) ,
138- toPresentation : isPresentationOutput ( format . pandoc ) ,
139- figFormat : format . execute [ kFigFormat ] ,
140- figDpi : format . execute [ kFigDpi ] ,
141- figPos : format . render [ kFigPos ] ,
142- } ,
191+ export interface JupyterMarkdownOptions extends Record < string , boolean > {
192+ echo : boolean ;
193+ warning : boolean ;
194+ asis : boolean ;
195+ }
196+ const kEcho = "echo" ;
197+ const kWarning = "warning" ;
198+ const kOutput = "output" ;
199+
200+ export async function notebookMarkdown (
201+ nbAddress : NotebookAddress ,
202+ assets : JupyterAssets ,
203+ context : RenderContext ,
204+ flags : RenderFlags ,
205+ options ?: JupyterMarkdownOptions ,
206+ ) {
207+ const cellOutputs = await getCellOutputs (
208+ nbAddress ,
209+ assets ,
210+ context ,
211+ flags ,
212+ options ,
143213 ) ;
144214
145215 if ( nbAddress . ids ) {
146216 // If cellIds are present, filter the notebook to only include
147217 // those cells (cellIds can eiher be an explicitly set cellId, a label in the
148218 // cell metadata, or a tag on a cell that matches an id)
149219 const theCells = nbAddress . ids . map ( ( id ) => {
150- const cell = cellForId ( id , result . cellOutputs ) ;
220+ const cell = cellForId ( id , cellOutputs ) ;
151221 if ( cell === undefined ) {
152222 throw new Error (
153223 `The cell ${ id } does not exist in notebook` ,
@@ -160,16 +230,16 @@ export async function notebookMarkdown(
160230 } else if ( nbAddress . indexes ) {
161231 // Filter and sort based upon cell index
162232 const theCells = nbAddress . indexes . map ( ( idx ) => {
163- if ( idx < 0 || idx >= result . cellOutputs . length ) {
233+ if ( idx < 0 || idx >= cellOutputs . length ) {
164234 throw new Error (
165235 `The cell index ${ idx } isn't within the range of cells` ,
166236 ) ;
167237 }
168- return result . cellOutputs [ idx ] ;
238+ return cellOutputs [ idx ] ;
169239 } ) ;
170240 return theCells . map ( ( cell ) => cell . markdown ) . join ( "" ) ;
171241 } else {
172- return result . cellOutputs . map ( ( cell ) => cell . markdown ) . join ( "" ) ;
242+ return cellOutputs . map ( ( cell ) => cell . markdown ) . join ( "" ) ;
173243 }
174244}
175245
0 commit comments