summaryrefslogtreecommitdiff
path: root/gui/src/logic/trill/helpers.ts
diff options
context:
space:
mode:
Diffstat (limited to 'gui/src/logic/trill/helpers.ts')
-rw-r--r--gui/src/logic/trill/helpers.ts186
1 files changed, 185 insertions, 1 deletions
diff --git a/gui/src/logic/trill/helpers.ts b/gui/src/logic/trill/helpers.ts
index 8bd1b0c..6936cf0 100644
--- a/gui/src/logic/trill/helpers.ts
+++ b/gui/src/logic/trill/helpers.ts
@@ -1,4 +1,6 @@
-import type { FullNode, Poast } from "@/types/trill";
+import type { NostrEvent } from "@/types/nostr";
+import type { FlatFeed, FullFeed, FullNode, Poast } from "@/types/trill";
+import { eventToPoast } from "../nostrill";
export function toFlat(n: FullNode): Poast {
return {
@@ -32,3 +34,185 @@ export function extractThread(node: FullNode): res {
}, bunt);
return r;
}
+
+export function findReplies(n: Poast, f: FlatFeed): Poast[] {
+ const posts = Object.values(f);
+ const kids: Poast[] = [];
+ for (const p of posts) {
+ if (p.parent === n.id) kids.push(p);
+ }
+ return kids;
+}
+
+export function eventToFn(ev: NostrEvent) {
+ const p = eventToPoast(ev)!;
+ const fn: FullNode = { ...p, children: {} };
+ return fn;
+}
+export function eventsToFF(nodes: FullNode[]): FullFeed {
+ // Step 1: Create a map with all nodes having empty children
+ const nodeMap: Record<string, FullNode> = {};
+ nodes.forEach((node) => {
+ nodeMap[node.hash] = node;
+ });
+
+ // Step 2: Build relationships by adding each node to its parent's children
+ const rootNodes: FullFeed = {};
+ nodes.forEach((node) => {
+ const currentNode = nodeMap[node.hash];
+
+ if (!node.parent) {
+ rootNodes[node.hash] = currentNode; // It's a root
+ } else if (nodeMap[node.parent]) {
+ nodeMap[node.parent].children[node.hash] = currentNode; // Add to parent
+ } else {
+ rootNodes[node.hash] = currentNode; // Parent missing, treat as root
+ }
+ });
+
+ return rootNodes;
+}
+
+export function getDescendants(node: FullNode): FullNode[] {
+ const descendants: FullNode[] = [];
+
+ function traverse(currentNode: FullNode) {
+ Object.values(currentNode.children).forEach((child) => {
+ descendants.push(child);
+ traverse(child);
+ });
+ }
+
+ traverse(node);
+ return descendants;
+}
+
+/**
+ * Alternative implementation that handles orphaned nodes differently
+ * Orphaned nodes (whose parents aren't in the array) are collected separately
+ */
+export function buildTreeWithOrphans(nodes: FullNode[]): {
+ tree: FullFeed;
+ orphans: FullFeed;
+} {
+ const nodeMap: Record<string, FullNode> = {};
+
+ // Initialize all nodes
+ nodes.forEach((node) => {
+ nodeMap[node.hash] = node;
+ });
+
+ const rootNodes: FullFeed = {};
+ const orphanNodes: FullFeed = {};
+
+ nodes.forEach((node) => {
+ const currentNode = nodeMap[node.id];
+
+ if (!node.parent) {
+ // Root node
+ rootNodes[node.id] = currentNode;
+ } else if (nodeMap[node.parent]) {
+ // Parent exists, add to parent's children
+ nodeMap[node.parent].children[node.id] = currentNode;
+ } else {
+ // Parent doesn't exist, it's an orphan
+ orphanNodes[node.id] = currentNode;
+ }
+ });
+
+ return { tree: rootNodes, orphans: orphanNodes };
+}
+
+export function findNodeById(
+ tree: FullFeed,
+ targetId: string,
+): FullNode | null {
+ function search(nodes: FullFeed): FullNode | null {
+ for (const node of Object.values(nodes)) {
+ if (node.id === targetId) {
+ return node;
+ }
+
+ const found = search(node.children);
+ if (found) {
+ return found;
+ }
+ }
+ return null;
+ }
+
+ return search(tree);
+}
+
+export function getPathToNode(
+ tree: FullFeed,
+ targetId: string,
+): FullNode[] | null {
+ function search(nodes: FullFeed, path: FullNode[]): FullNode[] | null {
+ for (const node of Object.values(nodes)) {
+ const currentPath = [...path, node];
+
+ if (node.id === targetId) {
+ return currentPath;
+ }
+
+ const found = search(node.children, currentPath);
+ if (found) {
+ return found;
+ }
+ }
+ return null;
+ }
+
+ return search(tree, []);
+}
+
+export function flattenTree(tree: FullFeed): FullNode[] {
+ const result: FullNode[] = [];
+
+ function traverse(nodes: FullFeed) {
+ Object.values(nodes).forEach((node) => {
+ result.push(node);
+ traverse(node.children);
+ });
+ }
+
+ traverse(tree);
+ return result;
+}
+
+export function getTreeDepth(tree: FullFeed): number {
+ function getDepth(nodes: FullFeed, currentDepth: number): number {
+ if (Object.keys(nodes).length === 0) {
+ return currentDepth;
+ }
+
+ let maxDepth = currentDepth;
+ Object.values(nodes).forEach((node) => {
+ const childDepth = getDepth(node.children, currentDepth + 1);
+ maxDepth = Math.max(maxDepth, childDepth);
+ });
+
+ return maxDepth;
+ }
+
+ return getDepth(tree, 0);
+}
+
+/**
+ * Count total nodes in the tree
+ */
+export function countNodes(tree: FullFeed): number {
+ let count = 0;
+
+ function traverse(nodes: FullFeed) {
+ count += Object.keys(nodes).length;
+ Object.values(nodes).forEach((node) => {
+ traverse(node.children);
+ });
+ }
+
+ traverse(tree);
+ return count;
+}
+// http://localhost:5173/apps/nostrill/t/nevent1qqsp3faj5jy9fpc6779rcs9kdccc0mxwlv2pnhymwqtjmletn72u5echttguv