Source: AMF3/reference.js

/** @module AMF3/Reference */
export default class Reference {
  /**
   * Initialize the array to hold referenced 'seen' strings
   * @private
   * @type {string[]}
   */
  #strings;
  /**
   * Initialize the array to hold referenced 'seen' objects
   * @private
   * @type {object[]}
   */
  #objects;
  /**
   * Initialize the array to hold referenced 'seen' traits. These values are hashed to improve performance
   * @private
   * @type {string[]}
   */
  #traits;

  /**
   * Creates a new AMF3 Reference holder
   */
  constructor() {
    this.#strings = [];
    this.#objects = [];
    this.#traits = [];
    this.reset = this.reset.bind(this); // Bind so 'serializePacket' and 'deserializePacket' can pass from within AMF entrypoint
  }

  /**
   * Returns the referenced 'seen' strings
   * @returns {string[]}
   */
  get strings() { return this.#strings; }
  /**
   * Returns the referenced 'seen' objects
   * @returns {object[]}
   */
  get objects() { return this.#objects; }
  /**
   * Returns the referenced 'seen' traits
   * @returns {string[]}
   */
  get traits() { return this.#traits; }

  /**
   * Resets the references
   */
  reset() {
    this.#strings = [];
    this.#objects = [];
    this.#traits = [];
  }

  /**
   * Retrieves a referenced value by its index
   * @param {number} index - The index in the referenced type's array table to look up
   * @param {'strings'|'objects'|'traits'} table - The reference table type
   * @returns {object|string} The referenced value
   */
  get(index, table) {
    const value = this[table][index];

    return (table === 'traits') ? JSON.parse(value) : value;
  }

  /**
   * Sets an object to hold as a reference
   * @param {object|string} value - The value to reference and mark as 'seen'
   * @param {'strings'|'objects'|'traits'} table - The reference table type
   */
  set(value, table) {
    this[table][this[table].length] = value;
  }

  /**
   * Checks whether the given object is referenced (or, 'seen'). If not, then it's added. For every call, a 'cache' object is returned
   * @param {object} - The object to check if it's referenced or not
   * @param {'strings'|'objects'|'traits'} table - The reference table type
   * @returns {{index: number, referenced: boolean}} The cache object; its index and if it's referenced or not
   */
  has(value, table) {
    const index = this[table].indexOf(value);
    const cache = { index, referenced: (index !== -1) };

    if (!cache.referenced) this.set(value, table);

    return cache;
  }
}