Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/src/core/handlers/embed.ts
3583 views
1
/*
2
* embed.ts
3
*
4
* Copyright (C) 2022-2025 by Posit, PBC
5
*/
6
7
import { LanguageCellHandlerContext, LanguageHandler } from "./types.ts";
8
import { baseHandler, install } from "./base.ts";
9
import {
10
EitherString,
11
mappedConcat,
12
MappedString,
13
} from "../lib/mapped-text.ts";
14
15
import { DirectiveCell } from "../lib/break-quarto-md-types.ts";
16
import {
17
notebookMarkdownPlaceholder,
18
parseNotebookAddress,
19
} from "../jupyter/jupyter-embed.ts";
20
21
interface EmbedHandler {
22
name: string;
23
handle(
24
filename: string,
25
params: Record<string, unknown>,
26
handlerContext: LanguageCellHandlerContext,
27
): Promise<{
28
handled: boolean;
29
markdownFragments: EitherString[];
30
resources?: string[];
31
}>;
32
}
33
34
const kHandlers: EmbedHandler[] = [
35
{
36
name: "Jupyter Notebook Embed",
37
handle(
38
filename: string,
39
params: Record<string, unknown>,
40
handlerContext: LanguageCellHandlerContext,
41
) {
42
const markdownFragments: EitherString[] = [];
43
44
// Resolve the filename into a path
45
const notebookAddress = parseNotebookAddress(filename);
46
if (notebookAddress) {
47
const outputs = params.outputs as string | undefined;
48
const placeHolder = notebookMarkdownPlaceholder(
49
handlerContext.options.context.target.input,
50
filename,
51
{
52
echo: params.echo !== undefined ? params.echo as boolean : false,
53
warning: false,
54
asis: true,
55
eval: false,
56
},
57
outputs,
58
);
59
60
markdownFragments.push(placeHolder);
61
return Promise.resolve({
62
handled: true,
63
markdownFragments,
64
resources: [
65
notebookAddress.path,
66
],
67
});
68
} else {
69
return Promise.resolve({
70
handled: false,
71
markdownFragments: [],
72
});
73
}
74
},
75
},
76
];
77
78
const embedHandler: LanguageHandler = {
79
...baseHandler,
80
81
languageName: "embed",
82
83
type: "directive",
84
stage: "post-engine",
85
86
async directive(
87
handlerContext: LanguageCellHandlerContext,
88
directive: DirectiveCell,
89
): Promise<MappedString> {
90
const textFragments: EitherString[] = [];
91
92
// The first parameter is a path to a file
93
const filename = directive.shortcode.params[0];
94
if (!filename) {
95
throw new Error("Embed directive requires a filename as a parameter");
96
}
97
98
// Go through handlers until one handles the embed by returning markdown
99
for (const handler of kHandlers) {
100
const result = await handler.handle(
101
filename,
102
directive.shortcode.namedParams,
103
handlerContext,
104
);
105
if (result.handled) {
106
textFragments.push(...result.markdownFragments);
107
if (result.resources) {
108
result.resources.forEach((res) => {
109
handlerContext.addResource(res);
110
});
111
}
112
113
break;
114
}
115
}
116
117
// Return the markdown
118
return mappedConcat(textFragments);
119
},
120
};
121
122
install(embedHandler);
123
124