UNPKG

rich-domain

Version:

This package provide utils file and interfaces to assistant build a complex application with domain driving design

244 lines 8.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Iterator = void 0; /** * @description The Iterator class provides a way to traverse through a collection of items sequentially, * without exposing the underlying data structure. It supports both forward and backward traversal, * optional looping behavior, and methods to manipulate the underlying collection. */ class Iterator { currentIndex; items; lastCommand; returnCurrentOnReversion; restartOnFinish; constructor(config) { this.currentIndex = -1; this.items = config?.initialData ?? []; this.lastCommand = 'none'; this.returnCurrentOnReversion = !!config?.returnCurrentOnReversion; this.restartOnFinish = !!config?.restartOnFinish; } /** * @description Creates a new Iterator instance from the provided configuration. * @param config Optional configuration object. * @param config.initialData An initial array of items to iterate over. * @param config.returnCurrentOnReversion If `true`, when switching iteration direction (from `next` to `prev` or vice versa), * the current item will be returned again before moving on. * @param config.restartOnFinish If `true`, when reaching the end of the items (`next` beyond last item or `prev` before first item), * iteration continues from the opposite end, effectively looping the iteration indefinitely. * * @returns A new Iterator instance. */ static create(config) { return new Iterator(config); } /** * @description Removes a specific item from the iterator's collection. * If the item is found and removed, the current index is adjusted accordingly. * @param item The item to be removed. */ removeItem(item) { const index = this.items.findIndex((value) => JSON.stringify(item) === JSON.stringify(value)); if (index !== -1) { this.items.splice(index, 1); if (index >= this.currentIndex) this.prev(); } } /** * @description Checks if there is another item after the current position. * @returns `true` if another item is available after the current index, otherwise `false`. */ hasNext() { if (this.isEmpty()) return false; return (this.currentIndex + 1) < this.items.length; } /** * @description Checks if there is another item before the current position. * @returns `true` if another item is available before the current index, otherwise `false`. */ hasPrev() { if (this.isEmpty()) return false; return (this.currentIndex - 1) >= 0; } /** * @description Checks if the iterator has no items. * @returns `true` if there are no items, otherwise `false`. */ isEmpty() { return this.total() === 0; } /** * @description Moves the iterator forward and returns the next item. * If `restartOnFinish` is `true` and the end is reached, iteration restarts from the beginning. * If `restartOnFinish` is `false` and the end is reached, returns `null`. * * @returns The next item, or `null` if no next item exists and looping is disabled. */ next() { if (this.hasNext()) { // If we were going backward and now go forward from the start, return current item before moving on. if (this.lastCommand === 'prev' && this.currentIndex === 0) { this.lastCommand = 'next'; return this.items[this.currentIndex]; } const nextIndex = this.currentIndex + 1; this.currentIndex = nextIndex; this.lastCommand = this.returnCurrentOnReversion ? 'next' : 'none'; return this.items[nextIndex]; } if (!this.restartOnFinish) return null; this.toFirst(); return this.first(); } /** * @description Moves the iterator backward and returns the previous item. * If `restartOnFinish` is `true` and the beginning is reached, iteration continues from the end. * If `restartOnFinish` is `false` and the beginning is reached, returns `null`. * * @returns The previous item, or `null` if no previous item exists and looping is disabled. */ prev() { if (this.hasPrev()) { // If we were going forward and now go backward from the end, return current item before moving on. if (this.lastCommand === 'next' && this.currentIndex === this.total() - 1) { this.lastCommand = 'prev'; return this.items[this.currentIndex]; } const prevIndex = this.currentIndex - 1; this.currentIndex = prevIndex; this.lastCommand = this.returnCurrentOnReversion ? 'prev' : 'none'; return this.items[prevIndex]; } if (!this.restartOnFinish) return null; this.toLast(); return this.last(); } /** * @description Returns the first item in the collection without changing the current index. * @returns The first item, or `undefined` if empty. */ first() { return this.items.at(0); } /** * @description Returns the last item in the collection without changing the current index. * @returns The last item, or `undefined` if empty. */ last() { return this.items.at(-1); } /** * @description Moves the internal cursor to the start of the collection. * @returns The current Iterator instance. */ toFirst() { if (this.currentIndex === 0 || this.currentIndex === -1) { this.currentIndex = -1; return this; } this.currentIndex = 0; return this; } /** * @description Moves the internal cursor to the end of the collection. * @returns The current Iterator instance. */ toLast() { if (this.currentIndex === this.total() - 1 || this.currentIndex === -1) { this.currentIndex = this.total(); return this; } this.currentIndex = this.total() - 1; return this; } /** * @description Removes all items from the collection. * @returns The current Iterator instance. */ clear() { this.items.splice(0, this.total()); this.currentIndex = -1; return this; } /** * @description Adds a new item to the end of the collection. * @param data The item to add. * @returns The current Iterator instance. */ addToEnd(data) { this.items.push(data); return this; } /** * @description Alias for `addToEnd` - adds a new item to the end of the collection. * @param data The item to add. * @returns The current Iterator instance. */ add(data) { return this.addToEnd(data); } /** * @description Adds a new item to the start of the collection and resets the cursor to before the first element. * @param data The item to add. * @returns The current Iterator instance. */ addToStart(data) { this.currentIndex = -1; this.items.unshift(data); return this; } /** * @description Removes the last item from the collection. * @returns The current Iterator instance. */ removeLast() { if (this.currentIndex >= this.total()) this.currentIndex -= 1; this.items.pop(); return this; } /** * @description Removes the first item from the collection. * @returns The current Iterator instance. */ removeFirst() { if (this.currentIndex > 0) this.currentIndex -= 1; this.items.shift(); return this; } /** * @description Creates a new Iterator instance with the same configuration and current state as the existing one. * @returns A cloned Iterator instance. */ clone() { return Iterator.create({ initialData: this.toArray(), restartOnFinish: this.restartOnFinish, returnCurrentOnReversion: this.returnCurrentOnReversion }); } /** * @description Returns all items in the iterator as an array. * @returns A copy of the internal array of items. */ toArray() { return [...this.items]; } /** * @description Returns the total number of items in the iterator. * @returns The count of items in the underlying collection. */ total() { return this.items.length; } } exports.Iterator = Iterator; exports.default = Iterator; //# sourceMappingURL=iterator.js.map