From e1a73ac3689568581d84216ddec27f2b4358cd5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dandelion=20Man=C3=A9?= Date: Fri, 11 Oct 2019 13:46:49 -0600 Subject: [PATCH] refactor discourse createGraph (#1409) This is a minor refactor to re-organize the createGraph function in the Discourse plugin to use a class under the hood. Using a hidden class makes sense because there is a fair bit of shared state that's needed while creating the graph. The proximate cause for this refactor is tha adding reference edges will bloat the `addPost` section of the function, which was already a little too complex. Simply shoving in more complexity would make it unweidy. So I opted for this minor refactor. It's internal-only (no public APIs are changed). Test plan: `yarn test` passes. As noted, refactor is internal-only. This is progress towards [Discourse reference and mention detection][1]. [1]: https://discourse.sourcecred.io/t/discourse-reference-mention-detection/270 --- src/plugins/discourse/createGraph.js | 77 +++++++++++++++++++--------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/src/plugins/discourse/createGraph.js b/src/plugins/discourse/createGraph.js index 44e234f..b20979b 100644 --- a/src/plugins/discourse/createGraph.js +++ b/src/plugins/discourse/createGraph.js @@ -128,27 +128,59 @@ export function likesEdge(serverUrl: string, like: LikeAction): Edge { } export function createGraph(serverUrl: string, data: DiscourseData): Graph { - if (serverUrl.endsWith("/")) { - throw new Error(`by convention, serverUrl should not end with /`); - } - const g = new Graph(); - const topicIdToTitle: Map = new Map(); + const gc = new _GraphCreator(serverUrl, data); + return gc.graph; +} - for (const username of data.users()) { - g.addNode(userNode(serverUrl, username)); +class _GraphCreator { + graph: Graph; + serverUrl: string; + data: DiscourseData; + topicIdToTitle: Map; + + constructor(serverUrl: string, data: DiscourseData) { + if (serverUrl.endsWith("/")) { + throw new Error(`by convention, serverUrl should not end with /`); + } + this.serverUrl = serverUrl; + this.data = data; + this.graph = new Graph(); + this.topicIdToTitle = new Map(); + + for (const username of data.users()) { + this.graph.addNode(userNode(serverUrl, username)); + } + + for (const topic of data.topics()) { + this.topicIdToTitle.set(topic.id, topic.title); + this.graph.addNode(topicNode(serverUrl, topic)); + this.graph.addEdge(authorsTopicEdge(serverUrl, topic)); + } + + for (const post of data.posts()) { + this.addPost(post); + } + + for (const like of data.likes()) { + this.graph.addEdge(likesEdge(serverUrl, like)); + } } - for (const topic of data.topics()) { - topicIdToTitle.set(topic.id, topic.title); - g.addNode(topicNode(serverUrl, topic)); - g.addEdge(authorsTopicEdge(serverUrl, topic)); + addPost(post: Post) { + const topicTitle = + this.topicIdToTitle.get(post.topicId) || "[unknown topic]"; + this.graph.addNode(postNode(this.serverUrl, post, topicTitle)); + this.graph.addEdge(authorsPostEdge(this.serverUrl, post)); + this.graph.addEdge(topicContainsPostEdge(this.serverUrl, post)); + this.maybeAddPostRepliesEdge(post); } - for (const post of data.posts()) { - const topicTitle = topicIdToTitle.get(post.topicId) || "[unknown topic]"; - g.addNode(postNode(serverUrl, post, topicTitle)); - g.addEdge(authorsPostEdge(serverUrl, post)); - g.addEdge(topicContainsPostEdge(serverUrl, post)); + /** + * Any post that is not the first post in the thread is a reply to some post. + * This method adds those reply edges. It is a bit hairy to work around unintuitive + * choices in the Discourse API. + */ + maybeAddPostRepliesEdge(post: Post) { let replyToPostIndex = post.replyToPostIndex; if (replyToPostIndex == null && post.indexWithinTopic > 1) { // For posts that are a reply to the first posts (or, depending on how you look at it, @@ -158,16 +190,13 @@ export function createGraph(serverUrl: string, data: DiscourseData): Graph { replyToPostIndex = 1; } if (replyToPostIndex != null) { - const basePostId = data.findPostInTopic(post.topicId, replyToPostIndex); + const basePostId = this.data.findPostInTopic( + post.topicId, + replyToPostIndex + ); if (basePostId != null) { - g.addEdge(postRepliesEdge(serverUrl, post, basePostId)); + this.graph.addEdge(postRepliesEdge(this.serverUrl, post, basePostId)); } } } - - for (const like of data.likes()) { - g.addEdge(likesEdge(serverUrl, like)); - } - - return g; }