Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/src/format/ipynb/format-ipynb.ts
6451 views
1
/*
2
* format-ipynb.ts
3
*
4
* Copyright (C) 2020-2022 Posit Software, PBC
5
*/
6
7
import { basename, dirname, join } from "../../deno_ral/path.ts";
8
import { readPartials } from "../../command/render/template.ts";
9
import {
10
kCellFormat,
11
kCellRawMimeType,
12
kDefaultImageExtension,
13
kIPynbTitleBlockTemplate,
14
} from "../../config/constants.ts";
15
import { Format, PandocFlags } from "../../config/types.ts";
16
import {
17
jupyterFromFile,
18
kQuartoMimeType,
19
} from "../../core/jupyter/jupyter.ts";
20
import {
21
kApplicationRtf,
22
kRestructuredText,
23
kTextHtml,
24
kTextLatex,
25
} from "../../core/mime.ts";
26
import { formatResourcePath } from "../../core/resources.ts";
27
import { createFormat } from "../formats-shared.ts";
28
29
import { decodeBase64 as base64decode } from "encoding/base64";
30
import {
31
JupyterOutput,
32
JupyterOutputDisplayData,
33
} from "../../core/jupyter/types.ts";
34
35
export function ipynbTitleTemplatePath() {
36
return formatResourcePath(
37
"ipynb",
38
join("templates", "title-block.md"),
39
);
40
}
41
42
export function ipynbFormat(): Format {
43
return createFormat("Jupyter", "ipynb", {
44
pandoc: {
45
standalone: true,
46
[kDefaultImageExtension]: "png",
47
},
48
formatExtras: (
49
input: string,
50
_markdown: string,
51
_flags: PandocFlags,
52
format: Format,
53
) => {
54
// Snag the p
55
56
const resolveTemplate = () => {
57
// iPynbs have a special title-block template partial that they can provide
58
// to permit the customization of the title block
59
const titleTemplate = ipynbTitleTemplatePath();
60
61
const partials = readPartials(format.metadata, dirname(input));
62
if (partials.length > 0) {
63
const userTitleTemplate = partials.find((part) => {
64
return basename(part) === "title-block.md";
65
});
66
if (userTitleTemplate) {
67
return userTitleTemplate;
68
} else {
69
return titleTemplate;
70
}
71
} else {
72
return titleTemplate;
73
}
74
};
75
76
return {
77
metadata: {
78
[kIPynbTitleBlockTemplate]: resolveTemplate(),
79
},
80
postprocessors: [(output: string) => {
81
// read notebook
82
const nb = jupyterFromFile(output);
83
84
// We 'hide' widget metadata from the YAML by encoding it to
85
// prevent the YAML representation from mangling it. Restore
86
// it here if it is so hidden
87
const widgets = nb.metadata.widgets as unknown;
88
if (widgets && typeof widgets === "string") {
89
nb.metadata.widgets = JSON.parse(
90
new TextDecoder().decode(base64decode(widgets)),
91
);
92
}
93
94
// convert raw cell metadata format to raw_mimetype used by jupyter
95
nb.cells = nb.cells.map((cell) => {
96
if (cell.cell_type == "raw") {
97
if (cell.metadata[kCellFormat]) {
98
const format = cell.metadata[kCellFormat];
99
delete cell.metadata[kCellFormat];
100
if (format === kTextHtml) {
101
cell.metadata[kCellRawMimeType] = format;
102
} else if (format === "tex") {
103
cell.metadata[kCellRawMimeType] = kTextLatex;
104
} else if (format === "rst") {
105
cell.metadata[kCellRawMimeType] = kRestructuredText;
106
} else if (format === "rtf") {
107
cell.metadata[kCellRawMimeType] = kApplicationRtf;
108
} else {
109
// restore format b/c we didn't convert it
110
cell.metadata[kCellFormat] = format;
111
}
112
}
113
}
114
115
// Fix up mime types that Quarto has emplaced
116
cell.outputs?.forEach((output) => {
117
const cellOutput = output as JupyterOutput;
118
if (cellOutput.output_type === "display_data") {
119
const cellDisplayOutput =
120
cellOutput as JupyterOutputDisplayData;
121
if (cellDisplayOutput.data["application/json"]) {
122
const jsonData = cellDisplayOutput
123
.data["application/json"] as Record<
124
string,
125
unknown
126
>;
127
if (jsonData[kQuartoMimeType]) {
128
const realMimetype = jsonData[kQuartoMimeType] as string;
129
delete jsonData[kQuartoMimeType];
130
131
cellDisplayOutput.data[realMimetype] = jsonData;
132
delete cellDisplayOutput.data["application/json"];
133
}
134
}
135
}
136
});
137
138
return cell;
139
});
140
Deno.writeTextFileSync(output, JSON.stringify(nb, null, 2));
141
return Promise.resolve();
142
}],
143
};
144
},
145
});
146
}
147
148