Okay, fun is an alternative way to describe it.

To feed Neigh Dev it's pages I export notes from Trilium using a search command and then determining the root note for which to retrieve all the children.  

The note tree for Neigh.dev at the time of writing.

I do this pretty naively by looking through the note list for a note for which the parent is not in the search results. I then recreate the paths to the notes in memory by grabbing each note title and it's parent note title and it's parent note title etc etc. However, I found out that the title of a note is not necessarily the same as its filename. 

So I had to parse the !!!meta.json file that is in the export to gather the names of the notes and folders on disk. The !!!meta.json contains the whole note tree that is exported.

Parsing that file was fun, I took the tree and flattened it into a note id → Note map. Every note has a list containing it's parent notes called the nodePath. (In Trilium everything is a note, even folders). Using the nodePath I could further parse the flattened list by checking the dir- or dataFileName.

meta = json.loads(output.read('!!!meta.json'))

metaNotes: dict[str, dict] = {} # Flattened meta notes 
stack: list[dict] = [meta['files'][0]] # Start at the root node
while(stack): # The stack is used to remember the previous branches we took in the tree
    tos = stack.pop()              # Pop one result of the stack 
    metaNotes[tos['noteId']] = tos # and add it to our flattened list
    if tos.get('children'): 
        for child in tos['children']:
            stack.append(child) # Add the children to our stack to walk through
    # If there are no children the stack will have shrunk in size because of the earlier pop
# The while loop ends when the stack is depleted

It has been a while since I had to traverse trees in code.