mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-11-30 09:47:56 +01:00
fix(components): prevent infinite recursion from circular transcludes (#2187)
* fix(components): prevent infinite recursion from circular transcludes * chore(components): modify warning message Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com> --------- Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import { visit } from "unist-util-visit"
|
|||||||
import { Root, Element, ElementContent } from "hast"
|
import { Root, Element, ElementContent } from "hast"
|
||||||
import { GlobalConfiguration } from "../cfg"
|
import { GlobalConfiguration } from "../cfg"
|
||||||
import { i18n } from "../i18n"
|
import { i18n } from "../i18n"
|
||||||
|
import { styleText } from "util"
|
||||||
|
|
||||||
interface RenderComponents {
|
interface RenderComponents {
|
||||||
head: QuartzComponent
|
head: QuartzComponent
|
||||||
@@ -68,6 +69,7 @@ function renderTranscludes(
|
|||||||
cfg: GlobalConfiguration,
|
cfg: GlobalConfiguration,
|
||||||
slug: FullSlug,
|
slug: FullSlug,
|
||||||
componentData: QuartzComponentProps,
|
componentData: QuartzComponentProps,
|
||||||
|
visited: Set<FullSlug>,
|
||||||
) {
|
) {
|
||||||
// process transcludes in componentData
|
// process transcludes in componentData
|
||||||
visit(root, "element", (node, _index, _parent) => {
|
visit(root, "element", (node, _index, _parent) => {
|
||||||
@@ -76,6 +78,30 @@ function renderTranscludes(
|
|||||||
if (classNames.includes("transclude")) {
|
if (classNames.includes("transclude")) {
|
||||||
const inner = node.children[0] as Element
|
const inner = node.children[0] as Element
|
||||||
const transcludeTarget = (inner.properties["data-slug"] ?? slug) as FullSlug
|
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)
|
const page = componentData.allFiles.find((f) => f.slug === transcludeTarget)
|
||||||
if (!page) {
|
if (!page) {
|
||||||
return
|
return
|
||||||
@@ -196,7 +222,8 @@ export function renderPage(
|
|||||||
// make a deep copy of the tree so we don't remove the transclusion references
|
// make a deep copy of the tree so we don't remove the transclusion references
|
||||||
// for the file cached in contentMap in build.ts
|
// for the file cached in contentMap in build.ts
|
||||||
const root = clone(componentData.tree) as Root
|
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
|
// set componentData.tree to the edited html that has transclusions rendered
|
||||||
componentData.tree = root
|
componentData.tree = root
|
||||||
|
|||||||
Reference in New Issue
Block a user