models/model.js

import { matcher } from "../tag_utils.js";

/**
 * Base Model for all entities.
 */
class Model {
  /**
   * @param {Object} params
   *   @param [params.tags] {String[]} an array of tags to add to this model instance.
   */
  constructor({ tags = [] } = {}) {
    /**
     * An array of string tags that characterize this item.
     * @property {Set} tags
     */
    this.tags = new Set(tags);
  }
  /**
   * Given a prefix like `ammo` or `media`, will return the specific tag for this
   * item, such as `ammo:22` or `media:35mm`.
   *
   * @param prefix {String} the prefix to match
   * @return {String} the first tag found that matches this prefix
   */
  typeOf(prefix) {
    if (typeof prefix !== "string") {
      throw Error("typeOf argument must be a string");
    }
    let p = prefix + ":";
    let r = Array.from(this.tags).find((tag) => tag.startsWith(p));
    return r ? r : null;
  }
  /**
   * Does this model have the given tag?
   * @param {String} tag
   * @returns {boolean} true if it does, false otherwise
   */
  is(tag) {
    return matcher(tag, this.tags);
  }
  /**
   * Does this model have the given tag?
   * @param {String} tag
   * @returns {boolean} true if it does, false otherwise
   */
  has(tag) {
    return matcher(tag, this.tags);
  }
  /**
   * Does this model not have the given tag?
   * @param {String} tag
   * @returns {boolean} true if it does not have the tag, false otherwise
   */
  not(tag) {
    return !matcher(tag, this.tags);
  }
  /**
   * Converts the model to JSON, converting sets to arrays.
   *
   * @returns {String} JSON
   */
  asJSON() {
    return JSON.stringify(this, (_key, value) =>
      value instanceof Set ? [...value].sort() : value
    );
  }
  equals(model) {
    if (!model || !model.asJSON) {
      return false;
    }
    console.log(this.asJSON(), model.asJSON());
    return this.asJSON() === model.asJSON();
  }
}

export default Model;