diff --git a/src/core/lib/break-quarto-md-types.ts b/src/core/lib/break-quarto-md-types.ts index 8d03252288..436b18e4e3 100644 --- a/src/core/lib/break-quarto-md-types.ts +++ b/src/core/lib/break-quarto-md-types.ts @@ -10,7 +10,7 @@ import { Shortcode } from "./parse-shortcode-types.ts"; import { MappedString } from "./text-types.ts"; export interface CodeCellType { - language: string; + language: string; // I'd like to say "string but not '_directive'" but I don't know how } export interface DirectiveCell { diff --git a/src/project/project-shared.ts b/src/project/project-shared.ts index 36a908a1e5..e45739f779 100644 --- a/src/project/project-shared.ts +++ b/src/project/project-shared.ts @@ -39,11 +39,12 @@ import { RenderContext, RenderFlags } from "../command/render/types.ts"; import { LanguageCellHandlerOptions } from "../core/handlers/types.ts"; import { ExecutionEngine } from "../execute/types.ts"; import { InspectedMdCell } from "../quarto-core/inspect-types.ts"; -import { breakQuartoMd } from "../core/lib/break-quarto-md.ts"; +import { breakQuartoMd, QuartoMdCell } from "../core/lib/break-quarto-md.ts"; import { partitionCellOptionsText } from "../core/lib/partition-cell-options.ts"; import { parse } from "yaml/mod.ts"; import { mappedIndexToLineCol } from "../core/lib/mapped-text.ts"; import { normalizeNewlines } from "../core/lib/text.ts"; +import { DirectiveCell } from "../core/lib/break-quarto-md-types.ts"; export function projectExcludeDirs(context: ProjectContext): string[] { const outputDir = projectOutputDir(context); @@ -368,30 +369,57 @@ export async function projectResolveCodeCellsForFile( markdown = await mdForFile(project, engine, file); } - const chunks = await breakQuartoMd(markdown); const result: InspectedMdCell[] = []; - for (const cell of chunks.cells) { - if ( - typeof cell.cell_type !== "string" && - cell.cell_type.language !== "_directive" - ) { - const cellOptions = partitionCellOptionsText( - cell.cell_type.language, - cell.sourceWithYaml ?? cell.source, + const fileStack: string[] = []; + + const inner = async (file: string, cells: QuartoMdCell[]) => { + if (fileStack.includes(file)) { + throw new Error( + "Circular include detected:\n " + fileStack.join(" ->\n "), ); - const metadata = cellOptions.yaml - ? parse(cellOptions.yaml.value) as Record - : {}; - const lineLocator = mappedIndexToLineCol(cell.sourceVerbatim); - result.push({ - start: lineLocator(0).line, - end: lineLocator(cell.sourceVerbatim.value.length - 1).line, - source: normalizeNewlines(cell.source.value), - language: cell.cell_type.language, - metadata, - }); } - } + fileStack.push(file); + for (const cell of cells) { + if (typeof cell.cell_type === "string") { + continue; + } + if (cell.cell_type.language === "_directive") { + const directiveCell = cell.cell_type as DirectiveCell; + if (directiveCell.name !== "include") { + continue; + } + const innerFile = join(project.dir, directiveCell.shortcode.params[0]); + await inner( + innerFile, + (await breakQuartoMd( + await mdForFile(project, engine, innerFile), + )).cells, + ); + } + if ( + cell.cell_type.language !== "_directive" + ) { + const cellOptions = partitionCellOptionsText( + cell.cell_type.language, + cell.sourceWithYaml ?? cell.source, + ); + const metadata = cellOptions.yaml + ? parse(cellOptions.yaml.value) as Record + : {}; + const lineLocator = mappedIndexToLineCol(cell.sourceVerbatim); + result.push({ + start: lineLocator(0).line, + end: lineLocator(cell.sourceVerbatim.value.length - 1).line, + file: file, + source: normalizeNewlines(cell.source.value), + language: cell.cell_type.language, + metadata, + }); + } + } + fileStack.pop(); + }; + await inner(file, (await breakQuartoMd(markdown)).cells); cache.codeCells = result; return result; } diff --git a/src/quarto-core/inspect-types.ts b/src/quarto-core/inspect-types.ts index 66a9f9c7a1..ec4465ec4d 100644 --- a/src/quarto-core/inspect-types.ts +++ b/src/quarto-core/inspect-types.ts @@ -14,6 +14,7 @@ import { export type InspectedMdCell = { start: number; end: number; + file: string; source: string; language: string; metadata: Record; diff --git a/tests/docs/websites/issue-9253/index.qmd b/tests/docs/websites/issue-9253/index.qmd index 94fdba42ac..6198cd6872 100644 --- a/tests/docs/websites/issue-9253/index.qmd +++ b/tests/docs/websites/issue-9253/index.qmd @@ -6,4 +6,6 @@ This is a Quarto website. To learn more about Quarto websites visit . +{{< include _include.qmd >}} + {{< include _include.qmd >}} \ No newline at end of file