filter.js

const obsceneWords = require('../data/amharic.json').words;

class Filter {
  /** Filter object constructor
   * @param {boolean} useDefaultWords - Use the default set of obscene words
   * @param {array} excludeWords - Words to exclude from obscenity set
   * @param {string} replaceBy - Character used to replace obscene words
  */
  constructor(useDefaultWords, excludeWords, replaceBy) {
    this.obscenitySet = {};
    if (useDefaultWords === undefined || useDefaultWords === true) {
      this.obscenitySet = obsceneWords;
    }

    this.replaceBy = replaceBy || '*';
    this.removeWords(excludeWords || []);
  }

  /** Add new words to obscenity set
   * @param {array} words  New words to add to obscenity set
   * @param {array} labels An array of arrays with all the labels for each new word
   */
  addWords(words, labels) {
    if (!words || !labels) {
      throw new Error('Empty argument exception: addWords requires two positional parameters');
    }
    for (let i = 0; i < words.length; i += 1) {
      this.addWord(words[i], labels[i] || null);
    }
  }

  /** Add single word to the set of obscenity words
   * @param {string} word
   * @param {array} labels Labels of the new word: Existing labels are [PN, RT, IN, NO]
   */

  addWord(word, labels) {
    if (!labels || labels.length === 0) {
      this.obscenitySet[word] = ['NO'];
    } else {
      this.obscenitySet[word] = labels;
    }
  }

  /**
   * Checks if a word is obscene.
   * Returns true if the word is not obscene
   *
   * @param {string} word
   * @returns {boolean}
   */
  isPure(word) {
    return !(word in this.obscenitySet);
  }

  /** Remove words from the set of obscenity words
   * @param {list} words A list of strings
   *
  */
  removeWords(words) {
    for (let i = 0; i < words.length; i += 1) {
      this.removeWord(words[i]);
    }
  }

  /** Remove single word from the set of obscenity words
   * @param {string} word
   */
  removeWord(word) {
    delete this.obscenitySet[word];
  }

  /**
   * Returns the categorizing labels for a given obscene word.
   * Returns an empty array if isPure(word) == true.
   *
   * @param {string} word
   * @returns {array}
   */
  getLabels(word) {
    let labels = [];

    if (word in this.obscenitySet) {
      labels = this.obscenitySet[word];
    }
    return labels;
  }

  /**
   * Checks if a phrase/sentence contains any obscene word.
   * Splits the string by whitespace before checking each word for obscenity.
   *
   * @param {string} phrase
   * @return {boolean}
  */
  containsObscenity(phrase) {
    const words = phrase.trim().split(/\s+/);

    for (let i = 0; i < words.length; i += 1) {
      if (!this.isPure(words[i])) {
        return true;
      }
    }

    return false;
  }

  /**
   * Scrubs all obscene words and replaces them with asterisk characters.
   *
   * @param {string} phrase
   * @return {string}
   */

  scrub(phrase) {
    const words = phrase.trim().split(/\s+/);

    const filtered = [];
    for (let i = 0; i < words.length; i += 1) {
      if (this.isPure(words[i])) {
        filtered.push(words[i]);
      } else {
        filtered.push(this.replaceBy.repeat(words[i].length));
      }
    }

    return filtered.join(' ');
  }
}

module.exports = Filter;