<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
"use strict";

//TODO ability to dynamically add required columns from plugins

const Column = require("./column");
const Issues = require("./issues");
const TweetCard = require("./tweet-card");
const EventEmitter = require("events");

const defaultColumnNames = {
    ideas: "Ideas",
    reactions: "Needs Reaction",
    events: "Events",
    toTweet: "To Tweet",
    tweeted: "Tweeted"
};

/**
 * Used in arrangeColumns. Internal column names get converted to
 * after:columnName, except that after is currently broken.
 *
 * @type {Object.<string, string>}
 * @readonly
 */
const columnOrder = {
    toTweet: "last",
    tweeted: "last",
    events: "first",
    reactions: "first",
    ideas: "first",
};

class ProjectNotFoundError extends Error {
    /**
     * @param {string} projectName - Name of the project that was not found.
     */
    constructor(projectName) {
        super(`Could not find project ${projectName}`);
    }
}

/**
 * Abstraction over the GitHub project.
 */
class Board extends EventEmitter {
    /**
     * @param {PromisifiedGitHub} githubClient - GitHub Client.
     * @param {Object} config - Config for the project board.
     * @constructs
     */
    constructor(githubClient, config) {
        super();

        this.githubClient = githubClient;
        this.config = config;
        this.columnNames = Object.assign(Object.assign({}, defaultColumnNames), config.columns);
        this.columns = {};
        this.columnIds = {};
        for(const column in this.columnNames) {
            this.columnIds[column] = 0;
        }

        let firstRun = true;

        this.updateInterval = setInterval(() => {
            firstRun = false;
            this.update().then(() => this.syncCardsToColumns()).then(() => {
                this.emit("updated");
                //TODO ensure the issue events are all done?
            }).catch(console.error);
        }, 60000);

        this.setup().then(() => {
            this.issues = new Issues(githubClient, config);

            // Boards will be filled via this event handler, as that's how the
            // initial issue load works.
            this.issues.on("opened", async (issue) => {
                for(const column of Object.values(this.columns)) {
                    if(column && (await column.hasIssue(issue.number))) {
                        return column.addCard(new TweetCard(issue, config), firstRun);
                    }
                }
                this.emit("opened", issue);
            });

            this.issues.on("updated", (issue) => {
                for(const column of Object.values(this.columns)) {
                    if(column && column.hasCard(issue.id) && column.id != this.columnIds.tweeted) {
                        column.getCard(issue.id).checkValidity();
                        break;
                    }
                }
            });

            this.issues.on("closed", (issue) => {
                for(const column of Object.values(this.columns)) {
                    if(column && column.hasCard(issue.id) && column.id != this.columnIds.tweeted) {
                        column.removeCard(this.columnInstances.getCard(issue.id));
                        break;
                    }<commit_msg>Some todos<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
"use strict";

//TODO get rid of built in columns and use sources instead. Main problem to solve here is how to sort those columns.

const Column = require("./column");
const Issues = require("./issues");
const TweetCard = require("./tweet-card");
const EventEmitter = require("events");

const defaultColumnNames = {
    ideas: "Ideas",
    reactions: "Needs Reaction",
    events: "Events",
    toTweet: "To Tweet",
    tweeted: "Tweeted"
};

/**
 * Used in arrangeColumns. Internal column names get converted to
 * after:columnName, except that after is currently broken.
 *
 * @type {Object.<string, string>}
 * @readonly
 */
const columnOrder = {
    toTweet: "last",
    tweeted: "last",
    events: "first",
    reactions: "first",
    ideas: "first",
};

class ProjectNotFoundError extends Error {
    /**
     * @param {string} projectName - Name of the project that was not found.
     */
    constructor(projectName) {
        super(`Could not find project ${projectName}`);
    }
}

/**
 * Abstraction over the GitHub project.
 */
class Board extends EventEmitter {
    /**
     * @param {PromisifiedGitHub} githubClient - GitHub Client.
     * @param {Object} config - Config for the project board.
     * @constructs
     */
    constructor(githubClient, config) {
        super();

        this.githubClient = githubClient;
        this.config = config;
        this.columnNames = Object.assign(Object.assign({}, defaultColumnNames), config.columns);
        this.columns = {};
        this.columnIds = {};
        for(const column in this.columnNames) {
            this.columnIds[column] = 0;
        }

        let firstRun = true;

        this.updateInterval = setInterval(() => {
            firstRun = false;
            this.update().then(() => this.syncCardsToColumns()).then(() => {
                this.emit("updated");
                //TODO ensure the issue events are all done?
            }).catch(console.error);
        }, 60000);

        this.setup().then(() => {
            this.issues = new Issues(githubClient, config);

            // Boards will be filled via this event handler, as that's how the
            // initial issue load works.
            this.issues.on("opened", async (issue) => {
                for(const column of Object.values(this.columns)) {
                    if(column && (await column.hasIssue(issue.number))) {
                        return column.addCard(new TweetCard(issue, config), firstRun);
                    }
                }
                this.emit("opened", issue);
            });

            this.issues.on("updated", (issue) => {
                for(const column of Object.values(this.columns)) {
                    //TODO generalize this into columns that are not to be worked on provided by sources
                    if(column && column.hasCard(issue.id) && column.id != this.columnIds.tweeted) {
                        column.getCard(issue.id).checkValidity();
                        break;
                    }
                }
            });

            this.issues.on("closed", (issue) => {
                for(const column of Object.values(this.columns)) {
                    //TODO generalize this into columns that are not to be worked on provided by sources
                    if(column && column.hasCard(issue.id) && column.id != this.columnIds.tweeted) {
                        column.removeCard(this.columnInstances.getCard(issue.id));
                        break;
                    }
{'fraction_non_alphanumeric': 0.12440988614273812, 'fraction_numerical': 0.0027770063871146904, 'mean_word_length': 1.9605425400739827, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1488111', 'n_tokens_mistral': 1974, 'n_tokens_neox': 1889, 'n_words': 542}