From 4c50cf93387347fefeb2d3aca6cdb94f5719a196 Mon Sep 17 00:00:00 2001 From: bfahrenfort Date: Fri, 6 Oct 2023 15:51:39 -0500 Subject: [PATCH 1/4] chore: rebase Add per-folder RSS feeds --- quartz.config.ts | 1 + quartz/plugins/emitters/contentIndex.ts | 61 +++++++++++++++---------- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/quartz.config.ts b/quartz.config.ts index 4e36e9408..04e4e305a 100644 --- a/quartz.config.ts +++ b/quartz.config.ts @@ -70,6 +70,7 @@ const config: QuartzConfig = { Plugin.ContentIndex({ enableSiteMap: true, enableRSS: true, + feedDirectories: ["index"], // For a feed for only pages in content/Folder/, add "Folder" to the array }), Plugin.Assets(), Plugin.Static(), diff --git a/quartz/plugins/emitters/contentIndex.ts b/quartz/plugins/emitters/contentIndex.ts index c0fef86d2..511871e2b 100644 --- a/quartz/plugins/emitters/contentIndex.ts +++ b/quartz/plugins/emitters/contentIndex.ts @@ -26,6 +26,7 @@ interface Options { rssLimit?: number rssFullHtml: boolean includeEmptyFiles: boolean + feedDirectories: string[] } const defaultOptions: Options = { @@ -34,6 +35,7 @@ const defaultOptions: Options = { rssLimit: 10, rssFullHtml: false, includeEmptyFiles: true, + feedDirectories: ["index"], } function generateSiteMap(cfg: GlobalConfiguration, idx: ContentIndex): string { @@ -48,7 +50,10 @@ function generateSiteMap(cfg: GlobalConfiguration, idx: ContentIndex): string { return `${urls}` } -function generateRSSFeed(cfg: GlobalConfiguration, idx: ContentIndex, limit?: number): string { +function generateRSSFeed(cfg: GlobalConfiguration, idx?: ContentIndex, limit?: number): string { + if (idx == undefined) { + return "" + } const base = cfg.baseUrl ?? "" const createURLEntry = (slug: SimpleSlug, content: ContentDetails): string => ` @@ -116,30 +121,35 @@ export const ContentIndex: QuartzEmitterPlugin> = (opts) => { async emit(ctx, content, _resources) { const cfg = ctx.cfg.configuration const emitted: FilePath[] = [] - const linkIndex: ContentIndex = new Map() - for (const [tree, file] of content) { - const slug = file.data.slug! - const date = getDate(ctx.cfg.configuration, file.data) ?? new Date() - if (opts?.includeEmptyFiles || (file.data.text && file.data.text !== "")) { - linkIndex.set(slug, { - title: file.data.frontmatter?.title!, - links: file.data.links ?? [], - tags: file.data.frontmatter?.tags ?? [], - content: file.data.text ?? "", - richContent: opts?.rssFullHtml - ? escapeHTML(toHtml(tree as Root, { allowDangerousHtml: true })) - : undefined, - date: date, - description: file.data.description ?? "", - }) + const feedIndices: Map = new Map() + for (const feed of opts?.feedDirectories) { + const linkIndex: ContentIndex = new Map() + for (const [tree, file] of content) { + const slug = file.data.slug! + + const date = getDate(ctx.cfg.configuration, file.data) ?? new Date() + if ((opts?.includeEmptyFiles || (file.data.text && file.data.text !== "")) && (slug.startsWith(feed) || feed == "index")) { + linkIndex.set(slug, { + title: file.data.frontmatter?.title!, + links: file.data.links ?? [], + tags: file.data.frontmatter?.tags ?? [], + content: file.data.text ?? "", + richContent: opts?.rssFullHtml + ? escapeHTML(toHtml(tree as Root, { allowDangerousHtml: true })) + : undefined, + date: date, + description: file.data.description ?? "", + }) + } } + feedIndices.set(feed, linkIndex) } if (opts?.enableSiteMap) { emitted.push( await write({ ctx, - content: generateSiteMap(cfg, linkIndex), + content: generateSiteMap(cfg, feedIndices.get("index")), slug: "sitemap" as FullSlug, ext: ".xml", }), @@ -147,19 +157,20 @@ export const ContentIndex: QuartzEmitterPlugin> = (opts) => { } if (opts?.enableRSS) { - emitted.push( - await write({ + opts?.feedDirectories?.map(async (feed) => { + const emittedFeed = await write({ ctx, - content: generateRSSFeed(cfg, linkIndex, opts.rssLimit), - slug: "index" as FullSlug, + content: generateRSSFeed(cfg, feedIndices.get(feed), opts?.rssLimit), + slug: feed as FullSlug, ext: ".xml", - }), - ) + }) + emitted.push(emittedFeed) + }) } const fp = joinSegments("static", "contentIndex") as FullSlug const simplifiedIndex = Object.fromEntries( - Array.from(linkIndex).map(([slug, content]) => { + Array.from(feedIndices.get("index") ?? [] ).map(([slug, content]) => { // remove description and from content index as nothing downstream // actually uses it. we only keep it in the index as we need it // for the RSS feed From c1b7ef4f6fbe67c9bbfc97a9b81858dc06f00cd5 Mon Sep 17 00:00:00 2001 From: bfahrenfort Date: Fri, 6 Oct 2023 15:57:37 -0500 Subject: [PATCH 2/4] Formatting --- quartz/plugins/emitters/contentIndex.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/quartz/plugins/emitters/contentIndex.ts b/quartz/plugins/emitters/contentIndex.ts index 511871e2b..15561486b 100644 --- a/quartz/plugins/emitters/contentIndex.ts +++ b/quartz/plugins/emitters/contentIndex.ts @@ -128,7 +128,10 @@ export const ContentIndex: QuartzEmitterPlugin> = (opts) => { const slug = file.data.slug! const date = getDate(ctx.cfg.configuration, file.data) ?? new Date() - if ((opts?.includeEmptyFiles || (file.data.text && file.data.text !== "")) && (slug.startsWith(feed) || feed == "index")) { + if ( + (opts?.includeEmptyFiles || (file.data.text && file.data.text !== "")) && + (slug.startsWith(feed) || feed == "index") + ) { linkIndex.set(slug, { title: file.data.frontmatter?.title!, links: file.data.links ?? [], @@ -170,7 +173,7 @@ export const ContentIndex: QuartzEmitterPlugin> = (opts) => { const fp = joinSegments("static", "contentIndex") as FullSlug const simplifiedIndex = Object.fromEntries( - Array.from(feedIndices.get("index") ?? [] ).map(([slug, content]) => { + Array.from(feedIndices.get("index") ?? []).map(([slug, content]) => { // remove description and from content index as nothing downstream // actually uses it. we only keep it in the index as we need it // for the RSS feed From 35c8351ea9228cc9b00add0a068e8395b00e53ec Mon Sep 17 00:00:00 2001 From: bfahrenfort Date: Tue, 13 Feb 2024 19:36:22 -0600 Subject: [PATCH 3/4] chore: rebase fix type error --- quartz/plugins/emitters/contentIndex.ts | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/quartz/plugins/emitters/contentIndex.ts b/quartz/plugins/emitters/contentIndex.ts index 15561486b..4d4b72f8e 100644 --- a/quartz/plugins/emitters/contentIndex.ts +++ b/quartz/plugins/emitters/contentIndex.ts @@ -50,7 +50,7 @@ function generateSiteMap(cfg: GlobalConfiguration, idx: ContentIndex): string { return `${urls}` } -function generateRSSFeed(cfg: GlobalConfiguration, idx?: ContentIndex, limit?: number): string { +function generateRSSFeed(cfg: GlobalConfiguration, idx: ContentIndex, limit?: number): string { if (idx == undefined) { return "" } @@ -94,7 +94,7 @@ function generateRSSFeed(cfg: GlobalConfiguration, idx?: ContentIndex, limit?: n ` } -export const ContentIndex: QuartzEmitterPlugin> = (opts) => { +export const ContentIndex: QuartzEmitterPlugin = (opts) => { opts = { ...defaultOptions, ...opts } return { name: "ContentIndex", @@ -122,7 +122,12 @@ export const ContentIndex: QuartzEmitterPlugin> = (opts) => { const cfg = ctx.cfg.configuration const emitted: FilePath[] = [] const feedIndices: Map = new Map() - for (const feed of opts?.feedDirectories) { + + // bfahrenfort: ts can't see the expansion of opts above that guarantees a non-null feedDirectories + const directories = + opts?.feedDirectories == null ? defaultOptions.feedDirectories : opts.feedDirectories + + for (const feed of directories) { const linkIndex: ContentIndex = new Map() for (const [tree, file] of content) { const slug = file.data.slug! @@ -152,7 +157,9 @@ export const ContentIndex: QuartzEmitterPlugin> = (opts) => { emitted.push( await write({ ctx, - content: generateSiteMap(cfg, feedIndices.get("index")), + // bfahrenfort: "index" is guaranteed non-null + // see directories instantiation and feedIndices.set iterating over directories + content: generateSiteMap(cfg, feedIndices.get("index")!), slug: "sitemap" as FullSlug, ext: ".xml", }), @@ -160,10 +167,11 @@ export const ContentIndex: QuartzEmitterPlugin> = (opts) => { } if (opts?.enableRSS) { - opts?.feedDirectories?.map(async (feed) => { + directories.map(async (feed) => { const emittedFeed = await write({ ctx, - content: generateRSSFeed(cfg, feedIndices.get(feed), opts?.rssLimit), + // bfahrenfort: we just generated a feedIndices entry for every directories entry, guaranteed non-null + content: generateRSSFeed(cfg, feedIndices.get(feed)!, opts?.rssLimit), slug: feed as FullSlug, ext: ".xml", }) From 8b0dd136e476983150400cb6021af89b6b685d7e Mon Sep 17 00:00:00 2001 From: bfahrenfort Date: Tue, 13 Feb 2024 19:38:32 -0600 Subject: [PATCH 4/4] fix: signature --- quartz/plugins/emitters/contentIndex.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quartz/plugins/emitters/contentIndex.ts b/quartz/plugins/emitters/contentIndex.ts index 4d4b72f8e..81e91542a 100644 --- a/quartz/plugins/emitters/contentIndex.ts +++ b/quartz/plugins/emitters/contentIndex.ts @@ -94,7 +94,7 @@ function generateRSSFeed(cfg: GlobalConfiguration, idx: ContentIndex, limit?: nu ` } -export const ContentIndex: QuartzEmitterPlugin = (opts) => { +export const ContentIndex: QuartzEmitterPlugin> = (opts) => { opts = { ...defaultOptions, ...opts } return { name: "ContentIndex",