Skip to content

Commit

Permalink
lint(contentIndex): move helpers into single file
Browse files Browse the repository at this point in the history
  • Loading branch information
bfahrenfort committed Nov 21, 2024
1 parent bda8569 commit 8a0e78b
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 153 deletions.
125 changes: 114 additions & 11 deletions quartz/plugins/emitters/contentIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,6 @@ import { toHtml } from "hast-util-to-html"
import { write } from "./helpers"
import { i18n } from "../../i18n"
import { BuildCtx } from "../../util/ctx"
import {
Tree,
TreeNode,
Feed,
Visitor,
isFeed,
Entry,
defaultFeed,
compareTreeNodes,
isContentDetails,
} from "./contentIndex/indexTree"
import DepGraph from "../../depgraph"
import chalk from "chalk"
import { ProcessedContent } from "../vfile"
Expand Down Expand Up @@ -288,6 +277,120 @@ export const ContentIndex: QuartzEmitterPlugin<Partial<Options>> = (opts) => {
}
}

class Tree<T> {
children: Set<Tree<T>>
data: T
childComparator: (a: T, b: T) => boolean

constructor(data: T, childComparator: (a: T, b: T) => boolean, children?: Set<Tree<T>>) {
this.data = data
this.children = children ?? new Set<Tree<T>>()
this.childComparator = childComparator
}

// BFS insertion-order traversal
accept(visitor: Visitor<T>, parent?: Tree<T>) {
visitor.visit(parent ?? this, this) // Root has no parent

for (var child of this.children) {
var childVisitor = visitor.descend(child)
child.accept(childVisitor, this)
}
}

// Visit children before parent
acceptPostorder(visitor: Visitor<T>, parent?: Tree<T>) {
let branchesFirst = [...this.children].toSorted((_, c2) => (c2.children.size > 0 ? 1 : -1))

for (var child of branchesFirst) {
var childVisitor = visitor.descend(child)
child.acceptPostorder(childVisitor, this)
}

visitor.visit(parent ?? this, this)
}

child(data: T): Tree<T> {
for (var child of this.children) {
if (this.childComparator(child.data, data)) {
return child
}
}

return this.childFromTree(new Tree<T>(data, this.childComparator))
}

childFromTree(child: Tree<T>): Tree<T> {
this.children.add(child)
return child
}

// Convert entire tree to array of only its leaves
// ex. Tree<TreeNode> -> ContentDetails[]
spread(): T[] {
var flattened: T[] = []

const flatten = (tree: Tree<T>) => {
for (let child of tree.children) {
if (child.children.size == 0) flattened.push(child.data)
else flatten(child)
}
}

flatten(this)
return flattened
}
}

interface Visitor<T> {
// Prefix action at each tree level
descend: (tree: Tree<T>) => Visitor<T>

// Action at each child of parent
visit: (parent: Tree<T>, tree: Tree<T>) => void
}

// Hierarchy of directories with metadata children
// To be turned into a hierarchy of RSS text arrays generated from metadata children
type TreeNode = ContentDetails | Feed

// All of the files in one folder, as RSS entries
// Entry[] is the vehicle for composition while keeping content metadata intact
type Feed = {
dir: FullSlug
raw: Entry[]
dirIndex?: ContentDetails
}
function defaultFeed(): Feed {
return {
dir: "index" as FullSlug,
raw: new Array<Entry>(),
}
}

type Entry = {
item: string
// Must be maintained for sorting purposes
date: Date
title: string
}

// Type guards
function isFeed(feed: TreeNode): boolean {
return Object.hasOwn(feed, "dir")
}

function isContentDetails(details: TreeNode): boolean {
return Object.hasOwn(details, "slug")
}

function compareTreeNodes(a: TreeNode, b: TreeNode) {
let feedComp = isFeed(a) && isFeed(b) && (a as Feed).dir == (b as Feed).dir
let contentComp =
isContentDetails(a) && isContentDetails(b) && (a as ContentDetails) == (b as ContentDetails)
return feedComp || contentComp
}

type IndexVisitor = Visitor<TreeNode> // ContentIndex in interface form

// Note: only use with acceptPostorder
Expand Down
142 changes: 0 additions & 142 deletions quartz/plugins/emitters/contentIndex/indexTree.ts

This file was deleted.

0 comments on commit 8a0e78b

Please sign in to comment.