This commit is contained in:
Suryaansh Rai 2026-01-29 05:38:34 +01:00 committed by GitHub
commit 8005a9367f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -2,7 +2,15 @@ import { Root } from "hast"
import { GlobalConfiguration } from "../../cfg" import { GlobalConfiguration } from "../../cfg"
import { getDate } from "../../components/Date" import { getDate } from "../../components/Date"
import { escapeHTML } from "../../util/escape" import { escapeHTML } from "../../util/escape"
import { FilePath, FullSlug, SimpleSlug, joinSegments, simplifySlug } from "../../util/path" import {
FilePath,
FullSlug,
SimpleSlug,
getAllSegmentPrefixes,
joinSegments,
simplifySlug,
slugTag,
} from "../../util/path"
import { QuartzEmitterPlugin } from "../types" import { QuartzEmitterPlugin } from "../types"
import { toHtml } from "hast-util-to-html" import { toHtml } from "hast-util-to-html"
import { write } from "./helpers" import { write } from "./helpers"
@ -28,6 +36,9 @@ interface Options {
rssFullHtml: boolean rssFullHtml: boolean
rssSlug: string rssSlug: string
includeEmptyFiles: boolean includeEmptyFiles: boolean
includeTags: boolean
rssTagsLimit: number
rssTags: string[]
} }
const defaultOptions: Options = { const defaultOptions: Options = {
@ -37,6 +48,9 @@ const defaultOptions: Options = {
rssFullHtml: false, rssFullHtml: false,
rssSlug: "index", rssSlug: "index",
includeEmptyFiles: true, includeEmptyFiles: true,
includeTags: false,
rssTagsLimit: 15,
rssTags: [],
} }
function generateSiteMap(cfg: GlobalConfiguration, idx: ContentIndexMap): string { function generateSiteMap(cfg: GlobalConfiguration, idx: ContentIndexMap): string {
@ -135,6 +149,62 @@ export const ContentIndex: QuartzEmitterPlugin<Partial<Options>> = (opts) => {
slug: (opts?.rssSlug ?? "index") as FullSlug, slug: (opts?.rssSlug ?? "index") as FullSlug,
ext: ".xml", ext: ".xml",
}) })
if (opts?.includeTags) {
// Optimization: Build a map of tag -> content list once (reverse index)
const tagsInput: Map<string, ContentDetails[]> = new Map()
// Iterate over the content index once to populate the reverse index
for (const [_, content] of linkIndex) {
const tags = content.tags.flatMap(getAllSegmentPrefixes)
for (const tag of new Set(tags)) {
// Use Set to avoid double counting per file
if (!tagsInput.has(tag)) {
tagsInput.set(tag, [])
}
tagsInput.get(tag)!.push(content)
}
}
let sortedTags: string[] = []
if (opts.rssTags && opts.rssTags.length > 0) {
// Deduplicate and slugify user-provided tags
const userTags = new Set(opts.rssTags.map((tag) => slugTag(tag)))
// Filter user tags to only those that exist in the content
sortedTags = Array.from(userTags).filter((tag) => tagsInput.has(tag))
} else if ((opts.rssTagsLimit ?? 0) > 0) {
// Sort available tags by frequency (number of content items)
sortedTags = Array.from(tagsInput.entries())
.sort((a, b) => b[1].length - a[1].length) // Sort by frequency descending
.slice(0, opts.rssTagsLimit)
.map(([tag]) => tag)
}
if (sortedTags.length === 0) {
console.warn(
"[contentIndex] includeTags is enabled, but no tag-based RSS feeds will be generated. " +
"Either provide non-empty `rssTags` matching content tags or set `rssTagsLimit` to a positive number.",
)
}
for (const tag of sortedTags) {
const tagContent = tagsInput.get(tag)
if (!tagContent) continue // Should not happen given logic above
// Reconstruct a map for generateRSSFeed (it expects a ContentIndexMap)
// We can optimize this by making generateRSSFeed accept an array, but for now we conform to the interface
const tagFilteredIndex = new Map(tagContent.map((content) => [content.slug, content]))
yield write({
ctx,
content: generateRSSFeed(cfg, tagFilteredIndex, opts.rssLimit),
slug: joinSegments("tags", tag, "index") as FullSlug,
ext: ".xml",
})
}
}
} }
const fp = joinSegments("static", "contentIndex") as FullSlug const fp = joinSegments("static", "contentIndex") as FullSlug