{"version":3,"sources":["../../src/linked_list.ts","../../src/list_dictionary.ts","../../src/lru_cache.ts"],"sourcesContent":["/*!\n * This module defines the LinkedList class, which represents a doubly-linked list data structure.\n *\n * Author: Jan Curn (jan@apify.com)\n * Copyright(c) 2014 Apify. All rights reserved.\n *\n */\n\n/**\n * A helper function to determine whether two data objects are equal.\n * The function attempts to do so using data1's function 'equal(data)' if there is one,\n * otherwise it uses '==' operator.\n */\nconst dataEqual = <T>(data1: T, data2: T): boolean => {\n    if (data1 === null) return data2 === null;\n    if ((data1 as any).equals) return (data1 as any).equals(data2);\n\n    return data1 === data2;\n};\n\nexport class LinkedListNode<T> {\n    prev?: LinkedListNode<T> | null = null;\n\n    next?: LinkedListNode<T> | null = null;\n\n    dictKey?: string;\n\n    constructor(readonly data: T) {}\n}\n\n/**\n * A class representing a doubly-linked list.\n */\nexport class LinkedList<T = any> {\n    head?: LinkedListNode<T> | null = null;\n\n    tail?: LinkedListNode<T> | null = null;\n\n    length = 0;\n\n    /**\n     * Appends a new node with specific data to the end of the linked list.\n     */\n    add(data: T, toFirstPosition?: boolean): LinkedListNode<T> {\n        const node = new LinkedListNode(data);\n        this.addNode(node, toFirstPosition);\n\n        return node;\n    }\n\n    /**\n     * Appends a new node to the end of the linked list or the beginning if firstPosition is true-ish.\n     */\n    addNode(node: LinkedListNode<T>, toFirstPosition?: boolean) {\n        if (typeof node !== 'object' || node === null) throw new Error('Parameter \"node\" must be an object');\n        if (node.prev || node.next) throw new Error('New node is still included in some linked list');\n\n        // ensure they are null and not undefined!\n        node.prev = null;\n        node.next = null;\n\n        if (this.length === 0) {\n            this.tail = node;\n            this.head = node;\n        } else if (toFirstPosition) {\n            node.next = this.head;\n            this.head!.prev = node;\n            this.head = node;\n        } else {\n            // last position\n            node.prev = this.tail;\n            this.tail!.next = node;\n            this.tail = node;\n        }\n        this.length++;\n    }\n\n    /**\n     * Finds a first node that holds a specific data object. See 'dataEqual' function for a description\n     * how the object equality is tested. Function returns null if the data cannot be found.\n     */\n    find(data: T) {\n        for (let node = this.head; node != null; node = node.next) {\n            if (dataEqual(node.data, data)) {\n                return node;\n            }\n        }\n\n        return null;\n    }\n\n    removeNode(node: LinkedListNode<T>) {\n        if (typeof node !== 'object' || node == null) throw new Error('Parameter \"node\" must be an object');\n\n        if (node.prev != null) {\n            // some predecessor\n            if (node.next != null) {\n                // some successor\n                node.prev.next = node.next;\n                node.next.prev = node.prev;\n                node.prev = null;\n                node.next = null;\n            } else {\n                // no successor\n                this.tail = node.prev;\n                node.prev.next = null;\n                node.prev = null;\n            }\n        } else if (node.next != null) {\n            // some successor\n            this.head = node.next;\n            node.next.prev = null;\n            node.next = null;\n        } else {\n            // no successor\n            this.head = null;\n            this.tail = null;\n            node.next = null; // TODO: not needed???\n            node.prev = null;\n        }\n\n        this.length--;\n    }\n\n    /**\n     * Removes the first item from the list. The function\n     * returns the item object or null if the list is empty.\n     */\n    removeFirst() {\n        const { head } = this;\n        if (!head) return null;\n\n        this.removeNode(head);\n\n        return head.data;\n    }\n}\n","/*!\n * This module defines the ListDictionary class, a data structure\n * that combines a linked list and a dictionary.\n *\n * Author: Jan Curn (jan@apify.com)\n * Copyright(c) 2015 Apify. All rights reserved.\n *\n */\n\nimport type { LinkedListNode } from './linked_list';\nimport { LinkedList } from './linked_list';\n\n/**\n * The main ListDictionary class.\n */\nexport class ListDictionary<T = unknown> {\n    private linkedList = new LinkedList<T>();\n\n    dictionary: Record<string, LinkedListNode<T>> = {};\n\n    /**\n     * Gets the number of item in the list.\n     */\n    length() {\n        return this.linkedList.length;\n    }\n\n    /**\n     * Adds an item to the list. If there is already an item with same key, the function\n     * returns false and doesn't make any changes. Otherwise, it returns true.\n     */\n    add(key: string, item: T, toFirstPosition?: boolean) {\n        if (typeof key !== 'string') throw new Error('Parameter \"key\" must be a string.');\n        if (key in this.dictionary) return false;\n\n        const linkedListNode = this.linkedList.add(item, toFirstPosition);\n        linkedListNode.dictKey = key;\n        this.dictionary[key] = linkedListNode;\n\n        return true;\n    }\n\n    /**\n     * Gets the first item in the list. The function returns null if the list is empty.\n     */\n    getFirst() {\n        const { head } = this.linkedList;\n        if (head) return head.data;\n\n        return null;\n    }\n\n    /**\n     * Gets the last item in the list. The function returns null if the list is empty.\n     */\n    getLast() {\n        const { tail } = this.linkedList;\n        if (tail) return tail.data;\n\n        return null;\n    }\n\n    /**\n     * Gets the first item from the list and moves it to the end of the list.\n     * The function returns null if the queue is empty.\n     */\n    moveFirstToEnd() {\n        const node = this.linkedList.head;\n\n        if (!node) return null;\n\n        this.linkedList.removeNode(node);\n        this.linkedList.addNode(node);\n\n        return node.data;\n    }\n\n    /**\n     * Removes the first item from the list.\n     * The function returns the item or null if the list is empty.\n     */\n    removeFirst() {\n        const { head } = this.linkedList;\n\n        if (!head) return null;\n\n        this.linkedList.removeNode(head);\n        delete this.dictionary[head.dictKey!];\n\n        return head.data;\n    }\n\n    /**\n     * Removes the last item from the list.\n     * The function returns the item or null if the list is empty.\n     */\n    removeLast() {\n        const { tail } = this.linkedList;\n\n        if (!tail) return null;\n\n        this.linkedList.removeNode(tail);\n        delete this.dictionary[tail.dictKey!];\n\n        return tail.data;\n    }\n\n    /**\n     * Removes an item identified by a key. The function returns the\n     * object if it was found or null if it wasn't.\n     */\n    remove(key: string) {\n        if (typeof key !== 'string') throw new Error('Parameter \"key\" must be a string.');\n\n        const node = this.dictionary[key];\n\n        if (!node) return null;\n\n        delete this.dictionary[key];\n        this.linkedList.removeNode(node);\n\n        return node.data;\n    }\n\n    /**\n     * Finds a request based on the URL.\n     */\n    get(key: string) {\n        if (typeof key !== 'string') throw new Error('Parameter \"key\" must be a string.');\n        const node = this.dictionary[key];\n\n        if (!node) return null;\n\n        return node.data;\n    }\n\n    /**\n     * Removes all items from the list.\n     */\n    clear() {\n        if (this.linkedList.length > 0) {\n            this.linkedList = new LinkedList<T>();\n            this.dictionary = {};\n        }\n    }\n}\n","import { ListDictionary } from './list_dictionary';\n\nexport interface LruCacheOptions {\n    maxLength: number;\n}\n\n/**\n * Least recently used cache.\n */\nexport class LruCache<T = any> {\n    listDictionary = new ListDictionary<T>();\n\n    maxLength: number;\n\n    constructor(private options: LruCacheOptions) {\n        if (typeof options.maxLength !== 'number') {\n            throw new Error('Parameter \"maxLength\" must be a number.');\n        }\n\n        this.maxLength = options.maxLength;\n    }\n\n    /**\n     * Gets the number of item in the list.\n     */\n    length() {\n        return this.listDictionary.length();\n    }\n\n    /**\n     * Get item from Cache and move to last position\n     */\n    get(key: string) {\n        if (typeof key !== 'string') throw new Error('Parameter \"key\" must be a string.');\n        const node = this.listDictionary.dictionary[key];\n        if (!node) return null;\n        // remove item and move it to the end of the list\n        this.listDictionary.remove(key);\n        this.listDictionary.add(key, node.data);\n        return node.data;\n    }\n\n    /**\n     * Add new item to cache, remove least used item if length exceeds maxLength\n     */\n    add(key: string, value: T) {\n        const added = this.listDictionary.add(key, value);\n        if (!added) return false;\n        if (this.length() > this.maxLength) {\n            this.listDictionary.removeFirst();\n        }\n        return true;\n    }\n\n    /**\n     * Remove item with key\n     */\n    remove(key: string) {\n        return this.listDictionary.remove(key);\n    }\n\n    /**\n     * Clear cache\n     */\n    clear() {\n        return this.listDictionary.clear();\n    }\n}\n"],"mappings":"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","names":[]}