Skip to content

Instantly share code, notes, and snippets.

@danodic
Created June 1, 2024 03:39
Show Gist options
  • Save danodic/530021d72f9335d3f2391900ec43aad7 to your computer and use it in GitHub Desktop.
Save danodic/530021d72f9335d3f2391900ec43aad7 to your computer and use it in GitHub Desktop.
Transform a list of html headings and return a TOC tree
;; I had to create a Table of Contents component for my personal site, and in
;; order to do that I had to scan all headings in the document (using .querySelectorAll)
;; and transform them into a list of maps that I could use to nest them properly.
;; The idea is to get a plain vector of nodes created using `make-node` and return
;; a tree in which nodes are nested according to their level.
(defn make-node
"Creates the representation of an HTML heading. You can search for all headings
in your document and convert them to this structure."
[tag-name tag-level value]
{:tag (keyword tag-name)
:level tag-level
:value value})
(defn parse-nodes
"Given a vector of nodes created with `make-node`, transforms the vector into a
tree composed of nested vectors."
[elements current-level]
(loop [elements-left elements
parsed-elements []]
(if-not (empty? elements-left)
(let [next-element (first elements-left)
element-level (:level next-element)]
(cond
(> element-level current-level) (let [[r-parsed r-left] (parse-nodes elements-left (inc current-level))]
(recur r-left (conj parsed-elements r-parsed)))
(< element-level current-level) [parsed-elements elements-left]
:else (recur (drop 1 elements-left) (conj parsed-elements next-element))))
[parsed-elements elements-left])))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment