Skip to content

Commit a28ac25

Browse files
committed
create ProjectContext in single-file mode to guarantee engine and target caching
1 parent e41b4c9 commit a28ac25

26 files changed

+273
-96
lines changed

src/command/preview/cmd.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import { previewShiny } from "./preview-shiny.ts";
5252
import { serve } from "../serve/serve.ts";
5353
import { fileExecutionEngine } from "../../execute/engine.ts";
5454
import { notebookContext } from "../../render/notebook/notebook-context.ts";
55+
import { singleFileProjectContext } from "../../project/types/single-file/single-file.ts";
5556

5657
export const previewCommand = new Command()
5758
.name("preview")
@@ -275,7 +276,8 @@ export const previewCommand = new Command()
275276
if (Deno.statSync(file).isFile) {
276277
// get project and preview format
277278
const nbContext = notebookContext();
278-
const project = await projectContext(dirname(file), nbContext);
279+
const project = (await projectContext(dirname(file), nbContext)) ||
280+
singleFileProjectContext(file, nbContext);
279281
const formats = await (async () => {
280282
const services = renderServices(nbContext);
281283
try {

src/command/preview/preview.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ import {
100100
rswURL,
101101
} from "../../core/previewurl.ts";
102102
import { notebookContext } from "../../render/notebook/notebook-context.ts";
103+
import { singleFileProjectContext } from "../../project/types/single-file/single-file.ts";
103104

104105
export async function resolvePreviewOptions(
105106
options: ProjectPreview,
@@ -365,11 +366,13 @@ export async function previewFormat(
365366
if (format) {
366367
return format;
367368
}
369+
const nbContext = notebookContext();
370+
project = project || singleFileProjectContext(file, nbContext);
368371
formats = formats ||
369372
await withRenderServices(
370-
notebookContext(),
373+
nbContext,
371374
(services: RenderServices) =>
372-
renderFormats(file, services, "all", project),
375+
renderFormats(file, services, "all", project!),
373376
);
374377
format = Object.keys(formats)[0] || "html";
375378
return format;

src/command/render/render-contexts.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ export async function renderContexts(
210210
options: RenderOptions,
211211
forExecute: boolean,
212212
notebookContext: NotebookContext,
213-
project?: ProjectContext,
213+
project: ProjectContext,
214214
cloneOptions: boolean = true,
215215
enforceProjectFormats: boolean = true,
216216
): Promise<Record<string, RenderContext>> {
@@ -304,11 +304,10 @@ export async function renderContexts(
304304
if (engineClaimReason === "markdown") {
305305
// since the content decided the engine, and the content now changed,
306306
// we need to re-evaluate the engine and target based on new content.
307-
const { engine, target } = await fileExecutionEngineAndTarget(
307+
const { engine, target } = await project.fileExecutionEngineAndTarget(
308308
file.path,
309-
options.flags,
310309
markdown,
311-
project,
310+
true,
312311
);
313312
context.engine = engine;
314313
context.target = target;
@@ -327,7 +326,7 @@ export async function renderFormats(
327326
file: string,
328327
services: RenderServices,
329328
to = "all",
330-
project?: ProjectContext,
329+
project: ProjectContext,
331330
): Promise<Record<string, Format>> {
332331
const contexts = await renderContexts(
333332
{ path: file },

src/command/render/render-files.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,9 @@ export async function renderFiles(
288288
files: RenderFile[],
289289
options: RenderOptions,
290290
notebookContext: NotebookContext,
291-
alwaysExecuteFiles?: string[],
292-
pandocRenderer?: PandocRenderer,
293-
project?: ProjectContext,
291+
alwaysExecuteFiles: string[] | undefined,
292+
pandocRenderer: PandocRenderer | undefined,
293+
project: ProjectContext,
294294
): Promise<RenderFilesResult> {
295295
// provide default renderer
296296
pandocRenderer = pandocRenderer || defaultPandocRenderer(options, project);
@@ -368,7 +368,7 @@ export async function renderFile(
368368
file: RenderFile,
369369
options: RenderOptions,
370370
services: RenderServices,
371-
project?: ProjectContext,
371+
project: ProjectContext,
372372
enforceProjectFormats: boolean = true,
373373
): Promise<RenderFilesResult> {
374374
// provide default renderer
@@ -420,7 +420,7 @@ async function renderFileInternal(
420420
lifetime: Lifetime,
421421
file: RenderFile,
422422
options: RenderOptions,
423-
project: ProjectContext | undefined,
423+
project: ProjectContext,
424424
pandocRenderer: PandocRenderer,
425425
files: RenderFile[],
426426
tempContext: TempContext,
@@ -456,6 +456,8 @@ async function renderFileInternal(
456456
const { engine, target } = await fileExecutionEngineAndTarget(
457457
file.path,
458458
options.flags,
459+
undefined,
460+
project,
459461
);
460462
const validationResult = await validateDocumentFromSource(
461463
target.markdown,
@@ -695,7 +697,7 @@ async function renderFileInternal(
695697
// default pandoc renderer immediately renders each execute result
696698
function defaultPandocRenderer(
697699
_options: RenderOptions,
698-
_project?: ProjectContext,
700+
_project: ProjectContext,
699701
): PandocRenderer {
700702
const renderCompletions: PandocRenderCompletion[] = [];
701703
const renderedFiles: RenderedFile[] = [];

src/command/render/render-shared.ts

+21-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ import { renderProject } from "./project.ts";
1818
import { renderFiles } from "./render-files.ts";
1919
import { resourceFilesFromRenderedFile } from "./resources.ts";
2020
import { RenderFlags, RenderOptions, RenderResult } from "./types.ts";
21-
import { fileExecutionEngine } from "../../execute/engine.ts";
21+
import {
22+
fileExecutionEngine,
23+
fileExecutionEngineAndTarget,
24+
} from "../../execute/engine.ts";
2225

2326
import {
2427
isProjectInputFile,
@@ -33,6 +36,7 @@ import { initYamlIntelligenceResourcesFromFilesystem } from "../../core/schema/u
3336
import { kTextPlain } from "../../core/mime.ts";
3437
import { normalizePath } from "../../core/path.ts";
3538
import { notebookContext } from "../../render/notebook/notebook-context.ts";
39+
import { singleFileProjectContext } from "../../project/types/single-file/single-file.ts";
3640

3741
export async function render(
3842
path: string,
@@ -95,11 +99,24 @@ export async function render(
9599
// validate that we didn't get any project-only options
96100
validateDocumentRenderFlags(options.flags);
97101

102+
// NB: singleFileProjectContext is currently not fully-featured
103+
context = singleFileProjectContext(path, nbContext, options.flags);
104+
98105
// otherwise it's just a file render
99-
const result = await renderFiles([{ path }], options, nbContext);
106+
const result = await renderFiles(
107+
[{ path }],
108+
options,
109+
nbContext,
110+
undefined,
111+
undefined,
112+
context,
113+
);
100114

101115
// get partitioned markdown if we had result files
102-
const engine = fileExecutionEngine(path);
116+
const { engine } = await context.fileExecutionEngineAndTarget(
117+
path,
118+
undefined,
119+
);
103120
const partitioned = (engine && result.files.length > 0)
104121
? await engine.partitionedMarkdown(path)
105122
: undefined;
@@ -126,6 +143,7 @@ export async function render(
126143
};
127144
})),
128145
error: result.error,
146+
baseDir: normalizePath(dirname(path)),
129147
};
130148

131149
if (!renderResult.error && engine?.postRender) {

src/command/render/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export interface RenderContext {
5959
engine: ExecutionEngine;
6060
format: Format;
6161
libDir: string;
62-
project?: ProjectContext;
62+
project: ProjectContext;
6363
active: boolean;
6464
}
6565

src/command/serve/cmd.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { previewFormat } from "../preview/preview.ts";
1818
import { withRenderServices } from "../render/render-services.ts";
1919
import { notebookContext } from "../../render/notebook/notebook-context.ts";
2020
import { RenderServices } from "../render/types.ts";
21+
import { singleFileProjectContext } from "../../project/types/single-file/single-file.ts";
2122

2223
export const serveCommand = new Command()
2324
.name("serve")
@@ -65,7 +66,8 @@ export const serveCommand = new Command()
6566
const { host, port } = await resolveHostAndPort(options);
6667

6768
const nbContext = notebookContext();
68-
const context = await projectContext(input, nbContext);
69+
const context = (await projectContext(input, nbContext)) ||
70+
singleFileProjectContext(input, nbContext);
6971
const formats = await withRenderServices(
7072
nbContext,
7173
(services: RenderServices) =>

src/core/jupyter/jupyter-embed.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ function unsupportedEmbed(path: string) {
157157
export async function ensureNotebookContext(
158158
markdown: string,
159159
services: RenderServices,
160-
context?: ProjectContext,
160+
context: ProjectContext,
161161
) {
162162
const regex = placeholderRegex();
163163
let match = regex.exec(markdown);
@@ -353,9 +353,9 @@ export async function replaceNotebookPlaceholders(
353353
};
354354
}
355355

356-
function resolveNbPath(input: string, path: string, context?: ProjectContext) {
356+
function resolveNbPath(input: string, path: string, context: ProjectContext) {
357357
// If this is a project, absolute means project relative
358-
if (context) {
358+
if (!context.isSingleFile) {
359359
const projectMatch = path.match(/^[\\/](.*)/);
360360
if (projectMatch) {
361361
return join(context.dir, projectMatch[1]);
@@ -368,8 +368,9 @@ function resolveNbPath(input: string, path: string, context?: ProjectContext) {
368368
if (isAbsolute(input)) {
369369
return join(dirname(input), path);
370370
} else {
371-
const baseDir = context ? context.dir : Deno.cwd();
372-
return join(baseDir, dirname(input), path);
371+
const baseDir = context.isSingleFile ? Deno.cwd() : context.dir;
372+
const result = join(baseDir, dirname(input), path);
373+
return result;
373374
}
374375
}
375376
}
@@ -803,7 +804,7 @@ function resolveRange(rangeRaw?: string) {
803804
function jupyterFromNotebookOrQmd(
804805
nbAbsPath: string,
805806
services: RenderServices,
806-
project?: ProjectContext,
807+
project: ProjectContext,
807808
) {
808809
// See if we can resolve non-notebooks. Note that this
809810
// requires that we have pre-rendered any notebooks that we discover

0 commit comments

Comments
 (0)