From 493bd6e96ed2dbe0c2c0a1e72721ba873ce8b383 Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Thu, 6 Mar 2025 13:17:34 -0500 Subject: [PATCH 1/3] convert - preserve markdown content that follows yaml configuration in raw cells --- news/changelog-1.7.md | 4 ++++ src/command/convert/jupyter.ts | 25 +++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/news/changelog-1.7.md b/news/changelog-1.7.md index d6aba673a3..5150e648ee 100644 --- a/news/changelog-1.7.md +++ b/news/changelog-1.7.md @@ -37,6 +37,10 @@ All changes included in 1.7: - ([#11608](https://github.com/quarto-dev/quarto-cli/pull/11608)): Do not issue error message when calling `quarto check info`. +## `quarto convert` + +- ([#12042](https://github.com/quarto-dev/quarto-cli/issues/12042)): Preserve Markdown content that follows YAML metadata in a `raw` .ipynb cell. + ## `html` format - ([#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. diff --git a/src/command/convert/jupyter.ts b/src/command/convert/jupyter.ts index 4b6b9b73d2..d3156b21c0 100644 --- a/src/command/convert/jupyter.ts +++ b/src/command/convert/jupyter.ts @@ -30,6 +30,7 @@ import { jupyterCellSrcAsLines, jupyterCellSrcAsStr, } from "../../core/jupyter/jupyter-shared.ts"; +import { assert } from "testing/asserts"; export async function markdownToJupyterNotebook( file: string, @@ -71,11 +72,15 @@ export async function jupyterNotebookToMarkdown( case "raw": // see if this is the front matter if (frontMatter === undefined) { - frontMatter = partitionYamlFrontMatter( - jupyterCellSrcAsStr(cell), - )?.yaml; - if (!frontMatter) { - md.push(...mdFromRawCell(cellWithOptions)); + const { yaml: cellYaml, markdown: cellMarkdown } = + partitionYamlFrontMatter( + jupyterCellSrcAsStr(cell), + ) || {}; + if (cellYaml) { + frontMatter = cellYaml; + } + if (cellMarkdown) { + md.push(cellMarkdown); } } else { md.push(...mdFromRawCell(cellWithOptions)); @@ -130,6 +135,14 @@ export async function jupyterNotebookToMarkdown( } } + // if we found front matter, then the markdown source will start with enough + // newlines for the front matter to have been detected in the first place. + // So we only need to add newlines if there was no front matter. + // + // If this invariant breaks, we have a bug of some kind, so let's just assert it + assert(frontMatter || !mdSource.match(/^\n\n/)); + const maybeYamlMdBreak = frontMatter ? "" : "\n\n"; + // return yaml + markdown const yamlText = stringify(yaml, { indent: 2, @@ -137,7 +150,7 @@ export async function jupyterNotebookToMarkdown( sortKeys: false, skipInvalid: true, }); - return `---\n${yamlText}---\n\n${mdSource}`; + return `---\n${yamlText}---${maybeYamlMdBreak}${mdSource}`; } async function mdFromCodeCell( From 9f8f0e916348c6b0ba034cc2dc8930becc60af2c Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Thu, 6 Mar 2025 13:18:46 -0500 Subject: [PATCH 2/3] test - add test for #12042 --- tests/docs/convert/issue-12042.ipynb | 32 +++++++++++++++++ .../smoke/convert/convert-issue-12042.test.ts | 36 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/docs/convert/issue-12042.ipynb create mode 100644 tests/smoke/convert/convert-issue-12042.test.ts diff --git a/tests/docs/convert/issue-12042.ipynb b/tests/docs/convert/issue-12042.ipynb new file mode 100644 index 0000000000..9766e73723 --- /dev/null +++ b/tests/docs/convert/issue-12042.ipynb @@ -0,0 +1,32 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "title: My Document\n", + "format: html\n", + "jupyter: python3\n", + "keep-ipynb: true\n", + "---\n", + "\n", + "\n", + "\n", + "## Introduction\n", + "\n", + "Here I place some text." + ] + } + ], + "metadata": { + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3 (ipykernel)", + "path": "/Users/cscheid/virtualenvs/homebrew-python3/share/jupyter/kernels/python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/tests/smoke/convert/convert-issue-12042.test.ts b/tests/smoke/convert/convert-issue-12042.test.ts new file mode 100644 index 0000000000..56e0a610d0 --- /dev/null +++ b/tests/smoke/convert/convert-issue-12042.test.ts @@ -0,0 +1,36 @@ +/* +* convert-backticks.test.ts +* +* Copyright (C) 2020-2024 Posit Software, PBC +* +*/ +import { existsSync } from "../../../src/deno_ral/fs.ts"; +import { + ExecuteOutput, + testQuartoCmd, +} from "../../test.ts"; +import { assert } from "testing/asserts"; + +(() => { + const input = "docs/convert/backticks.ipynb"; + testQuartoCmd( + "convert", + ["docs/convert/issue-12042.ipynb"], + [ + { + name: "convert-markdown-after-yaml", + verify: async (outputs: ExecuteOutput[]) => { + const txt = Deno.readTextFileSync("docs/convert/issue-12042.qmd"); + assert(txt.includes("Here I place some text."), "Markdown text not found in output"); + } + } + ], + { + teardown: async () => { + if (existsSync("docs/convert/backticks.qmd")) { + Deno.removeSync("docs/convert/backticks.qmd"); + } + } + }, + ); +})(); From d6ca49cb2db18409954e80d11a5abd2a671cf87d Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger <285675+cscheid@users.noreply.github.com> Date: Thu, 6 Mar 2025 14:56:04 -0500 Subject: [PATCH 3/3] Update tests/smoke/convert/convert-issue-12042.test.ts Co-authored-by: Christophe Dervieux --- tests/smoke/convert/convert-issue-12042.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/smoke/convert/convert-issue-12042.test.ts b/tests/smoke/convert/convert-issue-12042.test.ts index 56e0a610d0..fb1af4ed97 100644 --- a/tests/smoke/convert/convert-issue-12042.test.ts +++ b/tests/smoke/convert/convert-issue-12042.test.ts @@ -27,8 +27,8 @@ import { assert } from "testing/asserts"; ], { teardown: async () => { - if (existsSync("docs/convert/backticks.qmd")) { - Deno.removeSync("docs/convert/backticks.qmd"); + if (existsSync("docs/convert/issue-12042.qmd")) { + Deno.removeSync("docs/convert/issue-12042.qmd"); } } },