From 2fdc8129b675d4e9090ba214a5a36646e630c817 Mon Sep 17 00:00:00 2001
From: Michael Thomason <mthomason@gmail.com>
Date: Sat, 01 Nov 2025 10:22:29 +0000
Subject: [PATCH] fix(components): prevent infinite recursion from circular transcludes (#2187)
---
quartz/components/renderPage.tsx | 29 ++++++++++++++++++++++++++++-
1 files changed, 28 insertions(+), 1 deletions(-)
diff --git a/quartz/components/renderPage.tsx b/quartz/components/renderPage.tsx
index 3ebfe48..2c1bf5e 100644
--- a/quartz/components/renderPage.tsx
+++ b/quartz/components/renderPage.tsx
@@ -9,6 +9,7 @@
import { Root, Element, ElementContent } from "hast"
import { GlobalConfiguration } from "../cfg"
import { i18n } from "../i18n"
+import { styleText } from "util"
interface RenderComponents {
head: QuartzComponent
@@ -68,6 +69,7 @@
cfg: GlobalConfiguration,
slug: FullSlug,
componentData: QuartzComponentProps,
+ visited: Set<FullSlug>,
) {
// process transcludes in componentData
visit(root, "element", (node, _index, _parent) => {
@@ -76,6 +78,30 @@
if (classNames.includes("transclude")) {
const inner = node.children[0] as Element
const transcludeTarget = (inner.properties["data-slug"] ?? slug) as FullSlug
+ if (visited.has(transcludeTarget)) {
+ console.warn(
+ styleText(
+ "yellow",
+ `Warning: Skipping circular transclusion: ${slug} -> ${transcludeTarget}`,
+ ),
+ )
+ node.children = [
+ {
+ type: "element",
+ tagName: "p",
+ properties: { style: "color: var(--secondary);" },
+ children: [
+ {
+ type: "text",
+ value: `Circular transclusion detected: ${transcludeTarget}`,
+ },
+ ],
+ },
+ ]
+ return
+ }
+ visited.add(transcludeTarget)
+
const page = componentData.allFiles.find((f) => f.slug === transcludeTarget)
if (!page) {
return
@@ -196,7 +222,8 @@
// make a deep copy of the tree so we don't remove the transclusion references
// for the file cached in contentMap in build.ts
const root = clone(componentData.tree) as Root
- renderTranscludes(root, cfg, slug, componentData)
+ const visited = new Set<FullSlug>([slug])
+ renderTranscludes(root, cfg, slug, componentData, visited)
// set componentData.tree to the edited html that has transclusions rendered
componentData.tree = root
--
Gitblit v1.10.0