index.jsjavascript
/**
 * A small, fully-documented sample module that exists purely to demonstrate
 * what an **API reference page** looks like when generated by
 * `clean-jsdoc-theme`. It is not a real library — it is a showcase of the
 * common JSDoc constructs (classes, methods, params, returns, examples,
 * typedefs, and cross-references) and how the theme renders them.
 *
 * @module sample-api
 */

/**
 * Options accepted by the {@link Cache} constructor.
 *
 * @typedef {Object} CacheOptions
 * @property {number} [maxSize=100] - Maximum number of entries to keep before
 *   the least-recently-used entry is evicted.
 * @property {number} [ttl=0] - Time-to-live for an entry in milliseconds. `0`
 *   disables expiry.
 */

/**
 * A tiny in-memory, least-recently-used (LRU) cache.
 *
 * This class is a demo of how `clean-jsdoc-theme` renders a documented class:
 * the signature, the constructor, properties, and each method get their own
 * section with parameters, return types, and examples.
 *
 * @example <caption>Basic usage</caption>
 * const cache = new Cache({ maxSize: 2 });
 * cache.set('a', 1);
 * cache.set('b', 2);
 * cache.get('a'); // => 1
 *
 * @see {@link CacheOptions}
 */
export class Cache {
  /**
   * Create a new cache.
   *
   * @param {CacheOptions} [options={}] - Configuration for the cache.
   */
  constructor(options = {}) {
    /**
     * The maximum number of entries this cache will hold.
     *
     * @type {number}
     */
    this.maxSize = options.maxSize ?? 100;

    /**
     * Time-to-live per entry, in milliseconds. `0` means entries never expire.
     *
     * @type {number}
     */
    this.ttl = options.ttl ?? 0;

    /** @private */
    this._store = new Map();
  }

  /**
   * The number of entries currently stored.
   *
   * @type {number}
   * @readonly
   */
  get size() {
    return this._store.size;
  }

  /**
   * Store a value under a key. If the cache is full, the least-recently-used
   * entry is evicted first.
   *
   * @param {string} key - The key to store the value under.
   * @param {*} value - The value to cache.
   * @returns {Cache} The cache instance, for chaining.
   *
   * @example
   * cache.set('user:1', { name: 'Ada' }).set('user:2', { name: 'Linus' });
   */
  set(key, value) {
    if (this._store.size >= this.maxSize && !this._store.has(key)) {
      const oldest = this._store.keys().next().value;
      this._store.delete(oldest);
    }
    this._store.set(key, value);
    return this;
  }

  /**
   * Look up a value by key, marking it as recently used.
   *
   * @param {string} key - The key to look up.
   * @returns {*} The cached value, or `undefined` if the key is not present.
   */
  get(key) {
    if (!this._store.has(key)) return undefined;
    const value = this._store.get(key);
    this._store.delete(key);
    this._store.set(key, value);
    return value;
  }

  /**
   * Check whether a key is present without affecting its recency.
   *
   * @param {string} key - The key to test.
   * @returns {boolean} `true` if the key is cached.
   */
  has(key) {
    return this._store.has(key);
  }

  /**
   * Remove every entry from the cache.
   *
   * @returns {void}
   */
  clear() {
    this._store.clear();
  }
}

/**
 * Create a {@link Cache} pre-populated from an object of key/value pairs.
 *
 * @param {Object<string, *>} entries - Initial entries to seed the cache with.
 * @param {CacheOptions} [options] - Options forwarded to the {@link Cache}
 *   constructor.
 * @returns {Cache} A new, seeded cache.
 *
 * @example
 * const cache = createCache({ a: 1, b: 2 }, { maxSize: 10 });
 * cache.get('b'); // => 2
 */
export function createCache(entries, options) {
  const cache = new Cache(options);
  for (const [key, value] of Object.entries(entries)) {
    cache.set(key, value);
  }
  return cache;
}