Skip to content

Commit af454e8

Browse files
authored
Merge pull request #12223 from quarto-dev/bugfix/issue-12042
convert - preserve markdown after yaml in raw cells
2 parents 4ca63a7 + d6ca49c commit af454e8

File tree

4 files changed

+91
-6
lines changed

4 files changed

+91
-6
lines changed

news/changelog-1.7.md

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ All changes included in 1.7:
3737

3838
- ([#11608](https://github.com/quarto-dev/quarto-cli/pull/11608)): Do not issue error message when calling `quarto check info`.
3939

40+
## `quarto convert`
41+
42+
- ([#12042](https://github.com/quarto-dev/quarto-cli/issues/12042)): Preserve Markdown content that follows YAML metadata in a `raw` .ipynb cell.
43+
4044
## `html` format
4145

4246
- ([#11860](https://github.com/quarto-dev/quarto-cli/issues/11860)): ES6 modules that import other local JS modules in documents with `embed-resources: true` are now correctly embedded.

src/command/convert/jupyter.ts

+19-6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
jupyterCellSrcAsLines,
3131
jupyterCellSrcAsStr,
3232
} from "../../core/jupyter/jupyter-shared.ts";
33+
import { assert } from "testing/asserts";
3334

3435
export async function markdownToJupyterNotebook(
3536
file: string,
@@ -71,11 +72,15 @@ export async function jupyterNotebookToMarkdown(
7172
case "raw":
7273
// see if this is the front matter
7374
if (frontMatter === undefined) {
74-
frontMatter = partitionYamlFrontMatter(
75-
jupyterCellSrcAsStr(cell),
76-
)?.yaml;
77-
if (!frontMatter) {
78-
md.push(...mdFromRawCell(cellWithOptions));
75+
const { yaml: cellYaml, markdown: cellMarkdown } =
76+
partitionYamlFrontMatter(
77+
jupyterCellSrcAsStr(cell),
78+
) || {};
79+
if (cellYaml) {
80+
frontMatter = cellYaml;
81+
}
82+
if (cellMarkdown) {
83+
md.push(cellMarkdown);
7984
}
8085
} else {
8186
md.push(...mdFromRawCell(cellWithOptions));
@@ -130,14 +135,22 @@ export async function jupyterNotebookToMarkdown(
130135
}
131136
}
132137

138+
// if we found front matter, then the markdown source will start with enough
139+
// newlines for the front matter to have been detected in the first place.
140+
// So we only need to add newlines if there was no front matter.
141+
//
142+
// If this invariant breaks, we have a bug of some kind, so let's just assert it
143+
assert(frontMatter || !mdSource.match(/^\n\n/));
144+
const maybeYamlMdBreak = frontMatter ? "" : "\n\n";
145+
133146
// return yaml + markdown
134147
const yamlText = stringify(yaml, {
135148
indent: 2,
136149
lineWidth: -1,
137150
sortKeys: false,
138151
skipInvalid: true,
139152
});
140-
return `---\n${yamlText}---\n\n${mdSource}`;
153+
return `---\n${yamlText}---${maybeYamlMdBreak}${mdSource}`;
141154
}
142155

143156
async function mdFromCodeCell(

tests/docs/convert/issue-12042.ipynb

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"---\n",
8+
"title: My Document\n",
9+
"format: html\n",
10+
"jupyter: python3\n",
11+
"keep-ipynb: true\n",
12+
"---\n",
13+
"\n",
14+
"\n",
15+
"\n",
16+
"## Introduction\n",
17+
"\n",
18+
"Here I place some text."
19+
]
20+
}
21+
],
22+
"metadata": {
23+
"kernelspec": {
24+
"name": "python3",
25+
"language": "python",
26+
"display_name": "Python 3 (ipykernel)",
27+
"path": "/Users/cscheid/virtualenvs/homebrew-python3/share/jupyter/kernels/python3"
28+
}
29+
},
30+
"nbformat": 4,
31+
"nbformat_minor": 4
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* convert-backticks.test.ts
3+
*
4+
* Copyright (C) 2020-2024 Posit Software, PBC
5+
*
6+
*/
7+
import { existsSync } from "../../../src/deno_ral/fs.ts";
8+
import {
9+
ExecuteOutput,
10+
testQuartoCmd,
11+
} from "../../test.ts";
12+
import { assert } from "testing/asserts";
13+
14+
(() => {
15+
const input = "docs/convert/backticks.ipynb";
16+
testQuartoCmd(
17+
"convert",
18+
["docs/convert/issue-12042.ipynb"],
19+
[
20+
{
21+
name: "convert-markdown-after-yaml",
22+
verify: async (outputs: ExecuteOutput[]) => {
23+
const txt = Deno.readTextFileSync("docs/convert/issue-12042.qmd");
24+
assert(txt.includes("Here I place some text."), "Markdown text not found in output");
25+
}
26+
}
27+
],
28+
{
29+
teardown: async () => {
30+
if (existsSync("docs/convert/issue-12042.qmd")) {
31+
Deno.removeSync("docs/convert/issue-12042.qmd");
32+
}
33+
}
34+
},
35+
);
36+
})();

0 commit comments

Comments
 (0)