forked from public/fvtt-cthulhu-eternal
		
	Initial import with skill sheet working
This commit is contained in:
		
							
								
								
									
										64
									
								
								node_modules/@seald-io/binary-search-tree/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								node_modules/@seald-io/binary-search-tree/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| # Changelog | ||||
|  | ||||
| All notable changes to this project will be documented in this file. | ||||
|  | ||||
| The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||||
| and this project adheres | ||||
| to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||||
|  | ||||
| ## [1.0.3] - 2023-01-19 | ||||
|  | ||||
| ### Changed | ||||
|  | ||||
| - Correctly log object keys [#1](https://github.com/seald/node-binary-search-tree/pull/1) | ||||
|  | ||||
|  | ||||
| ## [1.0.2] - 2021-05-19 | ||||
|  | ||||
| ### Changed | ||||
|  | ||||
| - Specify files to be included in published version, v1.0.1 contained cache, | ||||
|   which contains, a now revoked, npm authentication token. | ||||
|  | ||||
| ## [1.0.1] - 2021-05-19 | ||||
|  | ||||
| ### Added | ||||
|  | ||||
| - Added a changelog. | ||||
|  | ||||
| ### Changed | ||||
|  | ||||
| - Removed `underscore` dependency which was used only in the tests. | ||||
|  | ||||
| ## [1.0.0] - 2021-05-17 | ||||
|  | ||||
| This version should be a drop-in replacement for `binary-search-tree@0.2.6` | ||||
| provided you use modern browsers / versions of Node.js since ES6 features are | ||||
| now used (such as `class` and `const` / `let`). | ||||
|  | ||||
| ### Changed | ||||
|  | ||||
| - Update `homepage` & `repository` fields in the `package.json` | ||||
| - New maintainer [seald](https://github.com/seald/) and new package | ||||
|   name [@seald-io/binary-search-tree](https://www.npmjs.com/package/@seald-io/binary-search-tree) | ||||
|   ; | ||||
| - Added `lockfileVersion: 2` `package-lock.json`; | ||||
| - Modernized some of the code with ES6 features (`class`, `const` & `let`); | ||||
| - Uses [`standard`](https://standardjs.com/) to lint the code (which removes all | ||||
|   unnecessary semicolons); | ||||
| - Updated dependencies; | ||||
|  | ||||
| ### Removed | ||||
|  | ||||
| - Compatibility with old browsers and old version of Node.js that don't support | ||||
|   ES6 features. | ||||
|  | ||||
| ### Security | ||||
|  | ||||
| - This version no longer | ||||
|   uses [a vulnerable version of `underscore`](https://github.com/advisories/GHSA-cf4h-3jhx-xvhq) | ||||
|   . | ||||
|  | ||||
| ## [0.2.6] - 2016-02-28 | ||||
|  | ||||
| See [original repo](https://github.com/louischatriot/node-binary-search-tree) | ||||
							
								
								
									
										19
									
								
								node_modules/@seald-io/binary-search-tree/LICENSE.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								node_modules/@seald-io/binary-search-tree/LICENSE.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| Copyright (c) 2013 Louis Chatriot <louis.chatriot@gmail.com> | ||||
| Copyright (c) 2021 Seald [contact@seald.io](mailto:contact@seald.io); | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the | ||||
| 'Software'), to deal in the Software without restriction, including without | ||||
| limitation the rights to use, copy, modify, merge, publish, distribute, | ||||
| sublicense, and/or sell copies of the Software, and to permit persons to whom | ||||
| the Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
							
								
								
									
										130
									
								
								node_modules/@seald-io/binary-search-tree/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								node_modules/@seald-io/binary-search-tree/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| # Binary search trees for Node.js | ||||
|  | ||||
| This module is a fork | ||||
| of [node-binary-search-tree](https://github.com/louischatriot/node-binary-search-tree) | ||||
| written by Louis Chatriot for storing indexes | ||||
| in [nedb](https://github.com/louischatriot/nedb). | ||||
|  | ||||
| Since the original maintainer doesn't support these packages anymore, we forked | ||||
| them (here is [nedb](https://github.com/seald/nedb)) and maintain them for the | ||||
| needs of [Seald](https://www.seald.io). | ||||
|  | ||||
| Two implementations of binary search | ||||
| tree: [basic](http://en.wikipedia.org/wiki/Binary_search_tree) | ||||
| and [AVL](http://en.wikipedia.org/wiki/AVL_tree) (a kind of self-balancing | ||||
| binmary search tree). | ||||
|  | ||||
| ## Installation and tests | ||||
|  | ||||
| Package name is `@seald-io/binary-search-tree`. | ||||
|  | ||||
| ```bash | ||||
| npm install @seald-io/binary-search-tree | ||||
| ``` | ||||
|  | ||||
| If you want to run the tests, you'll have to clone the repository: | ||||
|  | ||||
| ```bash | ||||
| git clone https://github.com/seald/node-binary-search-tree | ||||
| npm install | ||||
| npm test | ||||
| ``` | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| The API mainly provides 3 functions: `insert`, `search` and `delete`. If you do | ||||
| not create a unique-type binary search tree, you can store multiple pieces of | ||||
| data for the same key. Doing so with a unique-type BST will result in an error | ||||
| being thrown. Data is always returned as an array, and you can delete all data | ||||
| relating to a given key, or just one piece of data. | ||||
|  | ||||
| Values inserted can be anything except `undefined`. | ||||
|  | ||||
| ```javascript | ||||
| const BinarySearchTree = require('binary-search-tree').BinarySearchTree | ||||
| const AVLTree = require('binary-search-tree').AVLTree   // Same API as BinarySearchTree | ||||
|  | ||||
| // Creating a binary search tree | ||||
| const bst = new BinarySearchTree() | ||||
|  | ||||
| // Inserting some data | ||||
| bst.insert(15, 'some data for key 15') | ||||
| bst.insert(12, 'something else') | ||||
| bst.insert(18, 'hello') | ||||
|  | ||||
| // You can insert multiple pieces of data for the same key | ||||
| // if your tree doesn't enforce a unique constraint | ||||
| bst.insert(18, 'world') | ||||
|  | ||||
| // Retrieving data (always returned as an array of all data stored for this key) | ||||
| bst.search(15)   // Equal to ['some data for key 15'] | ||||
| bst.search(18)   // Equal to ['hello', 'world'] | ||||
| bst.search(1)    // Equal to [] | ||||
|  | ||||
| // Search between bounds with a MongoDB-like query | ||||
| // Data is returned in key order | ||||
| // Note the difference between $lt (less than) and $gte (less than OR EQUAL) | ||||
| bst.betweenBounds({ $lt: 18, $gte: 12 })   // Equal to ['something else', 'some data for key 15'] | ||||
|  | ||||
| // Deleting all the data relating to a key | ||||
| bst.delete(15)   // bst.search(15) will now give [] | ||||
| bst.delete(18, 'world')   // bst.search(18) will now give ['hello'] | ||||
| ``` | ||||
|  | ||||
| There are three optional parameters you can pass the BST constructor, allowing | ||||
| you to enforce a key-uniqueness constraint, use a custom function to compare | ||||
| keys and use a custom function to check whether values are equal. These | ||||
| parameters are all passed in an object. | ||||
|  | ||||
| ### Uniqueness | ||||
|  | ||||
| ```javascript | ||||
| const bst = new BinarySearchTree({ unique: true }); | ||||
| bst.insert(10, 'hello'); | ||||
| bst.insert(10, 'world');   // Will throw an error | ||||
| ``` | ||||
|  | ||||
| ### Custom key comparison | ||||
|  | ||||
| ```javascript | ||||
| // Custom key comparison function | ||||
| // It needs to return a negative number if a is less than b, | ||||
| // a positive number if a is greater than b | ||||
| // and 0 if they are equal | ||||
| // If none is provided, the default one can compare numbers, dates and strings | ||||
| // which are the most common usecases | ||||
| const compareKeys = (a, b) => { | ||||
|   if (a.age < b.age) return -1 | ||||
|   if (a.age > b.age) return 1 | ||||
|  | ||||
|   return 0 | ||||
| } | ||||
|  | ||||
| // Now we can use objects with an 'age' property as keys | ||||
| const bst = new BinarySearchTree({ compareKeys }) | ||||
| bst.insert({ age: 23 }, 'Mark') | ||||
| bst.insert({ age: 47 }, 'Franck') | ||||
| ``` | ||||
|  | ||||
| ### Custom value checking | ||||
|  | ||||
| ```javascript | ||||
| // Custom value equality checking function used when we try to just delete one piece of data | ||||
| // Returns true if a and b are considered the same, false otherwise | ||||
| // The default function is able to compare numbers and strings | ||||
| const checkValueEquality = (a, b) => a.length === b.length | ||||
|  | ||||
| var bst = new BinarySearchTree({ checkValueEquality }) | ||||
| bst.insert(10, 'hello') | ||||
| bst.insert(10, 'world') | ||||
| bst.insert(10, 'howdoyoudo') | ||||
|  | ||||
| bst.delete(10, 'abcde') | ||||
| bst.search(10)   // Returns ['howdoyoudo'] | ||||
| ``` | ||||
|  | ||||
| ## License | ||||
|  | ||||
| The package is released under the MIT License as the original package. | ||||
|  | ||||
| See LICENSE.md. | ||||
							
								
								
									
										2
									
								
								node_modules/@seald-io/binary-search-tree/index.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								node_modules/@seald-io/binary-search-tree/index.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| module.exports.BinarySearchTree = require('./lib/bst') | ||||
| module.exports.AVLTree = require('./lib/avltree') | ||||
							
								
								
									
										412
									
								
								node_modules/@seald-io/binary-search-tree/lib/avltree.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										412
									
								
								node_modules/@seald-io/binary-search-tree/lib/avltree.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,412 @@ | ||||
| /** | ||||
|  * Self-balancing binary search tree using the AVL implementation | ||||
|  */ | ||||
| const BinarySearchTree = require('./bst') | ||||
| const customUtils = require('./customUtils') | ||||
|  | ||||
| class AVLTree { | ||||
|   /** | ||||
|    * Constructor | ||||
|    * We can't use a direct pointer to the root node (as in the simple binary search tree) | ||||
|    * as the root will change during tree rotations | ||||
|    * @param {Boolean}  options.unique Whether to enforce a 'unique' constraint on the key or not | ||||
|    * @param {Function} options.compareKeys Initialize this BST's compareKeys | ||||
|    */ | ||||
|   constructor (options) { | ||||
|     this.tree = new _AVLTree(options) | ||||
|   } | ||||
|  | ||||
|   checkIsAVLT () { this.tree.checkIsAVLT() } | ||||
|  | ||||
|   // Insert in the internal tree, update the pointer to the root if needed | ||||
|   insert (key, value) { | ||||
|     const newTree = this.tree.insert(key, value) | ||||
|  | ||||
|     // If newTree is undefined, that means its structure was not modified | ||||
|     if (newTree) { this.tree = newTree } | ||||
|   } | ||||
|  | ||||
|   // Delete a value | ||||
|   delete (key, value) { | ||||
|     const newTree = this.tree.delete(key, value) | ||||
|  | ||||
|     // If newTree is undefined, that means its structure was not modified | ||||
|     if (newTree) { this.tree = newTree } | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _AVLTree extends BinarySearchTree { | ||||
|   /** | ||||
|    * Constructor of the internal AVLTree | ||||
|    * @param {Object} options Optional | ||||
|    * @param {Boolean}  options.unique Whether to enforce a 'unique' constraint on the key or not | ||||
|    * @param {Key}      options.key Initialize this BST's key with key | ||||
|    * @param {Value}    options.value Initialize this BST's data with [value] | ||||
|    * @param {Function} options.compareKeys Initialize this BST's compareKeys | ||||
|    */ | ||||
|   constructor (options) { | ||||
|     super() | ||||
|     options = options || {} | ||||
|  | ||||
|     this.left = null | ||||
|     this.right = null | ||||
|     this.parent = options.parent !== undefined ? options.parent : null | ||||
|     if (Object.prototype.hasOwnProperty.call(options, 'key')) this.key = options.key | ||||
|     this.data = Object.prototype.hasOwnProperty.call(options, 'value') ? [options.value] : [] | ||||
|     this.unique = options.unique || false | ||||
|  | ||||
|     this.compareKeys = options.compareKeys || customUtils.defaultCompareKeysFunction | ||||
|     this.checkValueEquality = options.checkValueEquality || customUtils.defaultCheckValueEquality | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Check the recorded height is correct for every node | ||||
|    * Throws if one height doesn't match | ||||
|    */ | ||||
|   checkHeightCorrect () { | ||||
|     if (!Object.prototype.hasOwnProperty.call(this, 'key')) { return } // Empty tree | ||||
|  | ||||
|     if (this.left && this.left.height === undefined) { throw new Error('Undefined height for node ' + this.left.key) } | ||||
|     if (this.right && this.right.height === undefined) { throw new Error('Undefined height for node ' + this.right.key) } | ||||
|     if (this.height === undefined) { throw new Error('Undefined height for node ' + this.key) } | ||||
|  | ||||
|     const leftH = this.left ? this.left.height : 0 | ||||
|     const rightH = this.right ? this.right.height : 0 | ||||
|  | ||||
|     if (this.height !== 1 + Math.max(leftH, rightH)) { throw new Error('Height constraint failed for node ' + this.key) } | ||||
|     if (this.left) { this.left.checkHeightCorrect() } | ||||
|     if (this.right) { this.right.checkHeightCorrect() } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Return the balance factor | ||||
|    */ | ||||
|   balanceFactor () { | ||||
|     const leftH = this.left ? this.left.height : 0 | ||||
|     const rightH = this.right ? this.right.height : 0 | ||||
|     return leftH - rightH | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Check that the balance factors are all between -1 and 1 | ||||
|    */ | ||||
|   checkBalanceFactors () { | ||||
|     if (Math.abs(this.balanceFactor()) > 1) { throw new Error('Tree is unbalanced at node ' + this.key) } | ||||
|  | ||||
|     if (this.left) { this.left.checkBalanceFactors() } | ||||
|     if (this.right) { this.right.checkBalanceFactors() } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * When checking if the BST conditions are met, also check that the heights are correct | ||||
|    * and the tree is balanced | ||||
|    */ | ||||
|   checkIsAVLT () { | ||||
|     super.checkIsBST() | ||||
|     this.checkHeightCorrect() | ||||
|     this.checkBalanceFactors() | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Perform a right rotation of the tree if possible | ||||
|    * and return the root of the resulting tree | ||||
|    * The resulting tree's nodes' heights are also updated | ||||
|    */ | ||||
|   rightRotation () { | ||||
|     const q = this | ||||
|     const p = this.left | ||||
|  | ||||
|     if (!p) return q // No change | ||||
|  | ||||
|     const b = p.right | ||||
|  | ||||
|     // Alter tree structure | ||||
|     if (q.parent) { | ||||
|       p.parent = q.parent | ||||
|       if (q.parent.left === q) q.parent.left = p | ||||
|       else q.parent.right = p | ||||
|     } else { | ||||
|       p.parent = null | ||||
|     } | ||||
|     p.right = q | ||||
|     q.parent = p | ||||
|     q.left = b | ||||
|     if (b) { b.parent = q } | ||||
|  | ||||
|     // Update heights | ||||
|     const ah = p.left ? p.left.height : 0 | ||||
|     const bh = b ? b.height : 0 | ||||
|     const ch = q.right ? q.right.height : 0 | ||||
|     q.height = Math.max(bh, ch) + 1 | ||||
|     p.height = Math.max(ah, q.height) + 1 | ||||
|  | ||||
|     return p | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Perform a left rotation of the tree if possible | ||||
|    * and return the root of the resulting tree | ||||
|    * The resulting tree's nodes' heights are also updated | ||||
|    */ | ||||
|   leftRotation () { | ||||
|     const p = this | ||||
|     const q = this.right | ||||
|  | ||||
|     if (!q) { return this } // No change | ||||
|  | ||||
|     const b = q.left | ||||
|  | ||||
|     // Alter tree structure | ||||
|     if (p.parent) { | ||||
|       q.parent = p.parent | ||||
|       if (p.parent.left === p) p.parent.left = q | ||||
|       else p.parent.right = q | ||||
|     } else { | ||||
|       q.parent = null | ||||
|     } | ||||
|     q.left = p | ||||
|     p.parent = q | ||||
|     p.right = b | ||||
|     if (b) { b.parent = p } | ||||
|  | ||||
|     // Update heights | ||||
|     const ah = p.left ? p.left.height : 0 | ||||
|     const bh = b ? b.height : 0 | ||||
|     const ch = q.right ? q.right.height : 0 | ||||
|     p.height = Math.max(ah, bh) + 1 | ||||
|     q.height = Math.max(ch, p.height) + 1 | ||||
|  | ||||
|     return q | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Modify the tree if its right subtree is too small compared to the left | ||||
|    * Return the new root if any | ||||
|    */ | ||||
|   rightTooSmall () { | ||||
|     if (this.balanceFactor() <= 1) return this // Right is not too small, don't change | ||||
|  | ||||
|     if (this.left.balanceFactor() < 0) this.left.leftRotation() | ||||
|  | ||||
|     return this.rightRotation() | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Modify the tree if its left subtree is too small compared to the right | ||||
|    * Return the new root if any | ||||
|    */ | ||||
|   leftTooSmall () { | ||||
|     if (this.balanceFactor() >= -1) { return this } // Left is not too small, don't change | ||||
|  | ||||
|     if (this.right.balanceFactor() > 0) this.right.rightRotation() | ||||
|  | ||||
|     return this.leftRotation() | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Rebalance the tree along the given path. The path is given reversed (as he was calculated | ||||
|    * in the insert and delete functions). | ||||
|    * Returns the new root of the tree | ||||
|    * Of course, the first element of the path must be the root of the tree | ||||
|    */ | ||||
|   rebalanceAlongPath (path) { | ||||
|     let newRoot = this | ||||
|     let rotated | ||||
|     let i | ||||
|  | ||||
|     if (!Object.prototype.hasOwnProperty.call(this, 'key')) { | ||||
|       delete this.height | ||||
|       return this | ||||
|     } // Empty tree | ||||
|  | ||||
|     // Rebalance the tree and update all heights | ||||
|     for (i = path.length - 1; i >= 0; i -= 1) { | ||||
|       path[i].height = 1 + Math.max(path[i].left ? path[i].left.height : 0, path[i].right ? path[i].right.height : 0) | ||||
|  | ||||
|       if (path[i].balanceFactor() > 1) { | ||||
|         rotated = path[i].rightTooSmall() | ||||
|         if (i === 0) newRoot = rotated | ||||
|       } | ||||
|  | ||||
|       if (path[i].balanceFactor() < -1) { | ||||
|         rotated = path[i].leftTooSmall() | ||||
|         if (i === 0) newRoot = rotated | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return newRoot | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Insert a key, value pair in the tree while maintaining the AVL tree height constraint | ||||
|    * Return a pointer to the root node, which may have changed | ||||
|    */ | ||||
|   insert (key, value) { | ||||
|     const insertPath = [] | ||||
|     let currentNode = this | ||||
|  | ||||
|     // Empty tree, insert as root | ||||
|     if (!Object.prototype.hasOwnProperty.call(this, 'key')) { | ||||
|       this.key = key | ||||
|       this.data.push(value) | ||||
|       this.height = 1 | ||||
|       return this | ||||
|     } | ||||
|  | ||||
|     // Insert new leaf at the right place | ||||
|     while (true) { | ||||
|       // Same key: no change in the tree structure | ||||
|       if (currentNode.compareKeys(currentNode.key, key) === 0) { | ||||
|         if (currentNode.unique) { | ||||
|           const err = new Error(`Can't insert key ${JSON.stringify(key)}, it violates the unique constraint`) | ||||
|           err.key = key | ||||
|           err.errorType = 'uniqueViolated' | ||||
|           throw err | ||||
|         } else currentNode.data.push(value) | ||||
|         return this | ||||
|       } | ||||
|  | ||||
|       insertPath.push(currentNode) | ||||
|  | ||||
|       if (currentNode.compareKeys(key, currentNode.key) < 0) { | ||||
|         if (!currentNode.left) { | ||||
|           insertPath.push(currentNode.createLeftChild({ key: key, value: value })) | ||||
|           break | ||||
|         } else currentNode = currentNode.left | ||||
|       } else { | ||||
|         if (!currentNode.right) { | ||||
|           insertPath.push(currentNode.createRightChild({ key: key, value: value })) | ||||
|           break | ||||
|         } else currentNode = currentNode.right | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return this.rebalanceAlongPath(insertPath) | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Delete a key or just a value and return the new root of the tree | ||||
|    * @param {Key} key | ||||
|    * @param {Value} value Optional. If not set, the whole key is deleted. If set, only this value is deleted | ||||
|    */ | ||||
|   delete (key, value) { | ||||
|     const newData = [] | ||||
|     let replaceWith | ||||
|     let currentNode = this | ||||
|     const deletePath = [] | ||||
|  | ||||
|     if (!Object.prototype.hasOwnProperty.call(this, 'key')) return this // Empty tree | ||||
|  | ||||
|     // Either no match is found and the function will return from within the loop | ||||
|     // Or a match is found and deletePath will contain the path from the root to the node to delete after the loop | ||||
|     while (true) { | ||||
|       if (currentNode.compareKeys(key, currentNode.key) === 0) { break } | ||||
|  | ||||
|       deletePath.push(currentNode) | ||||
|  | ||||
|       if (currentNode.compareKeys(key, currentNode.key) < 0) { | ||||
|         if (currentNode.left) { | ||||
|           currentNode = currentNode.left | ||||
|         } else return this // Key not found, no modification | ||||
|       } else { | ||||
|         // currentNode.compareKeys(key, currentNode.key) is > 0 | ||||
|         if (currentNode.right) { | ||||
|           currentNode = currentNode.right | ||||
|         } else return this // Key not found, no modification | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Delete only a value (no tree modification) | ||||
|     if (currentNode.data.length > 1 && value !== undefined) { | ||||
|       currentNode.data.forEach(function (d) { | ||||
|         if (!currentNode.checkValueEquality(d, value)) newData.push(d) | ||||
|       }) | ||||
|       currentNode.data = newData | ||||
|       return this | ||||
|     } | ||||
|  | ||||
|     // Delete a whole node | ||||
|  | ||||
|     // Leaf | ||||
|     if (!currentNode.left && !currentNode.right) { | ||||
|       if (currentNode === this) { // This leaf is also the root | ||||
|         delete currentNode.key | ||||
|         currentNode.data = [] | ||||
|         delete currentNode.height | ||||
|         return this | ||||
|       } else { | ||||
|         if (currentNode.parent.left === currentNode) currentNode.parent.left = null | ||||
|         else currentNode.parent.right = null | ||||
|         return this.rebalanceAlongPath(deletePath) | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Node with only one child | ||||
|     if (!currentNode.left || !currentNode.right) { | ||||
|       replaceWith = currentNode.left ? currentNode.left : currentNode.right | ||||
|  | ||||
|       if (currentNode === this) { // This node is also the root | ||||
|         replaceWith.parent = null | ||||
|         return replaceWith // height of replaceWith is necessarily 1 because the tree was balanced before deletion | ||||
|       } else { | ||||
|         if (currentNode.parent.left === currentNode) { | ||||
|           currentNode.parent.left = replaceWith | ||||
|           replaceWith.parent = currentNode.parent | ||||
|         } else { | ||||
|           currentNode.parent.right = replaceWith | ||||
|           replaceWith.parent = currentNode.parent | ||||
|         } | ||||
|  | ||||
|         return this.rebalanceAlongPath(deletePath) | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Node with two children | ||||
|     // Use the in-order predecessor (no need to randomize since we actively rebalance) | ||||
|     deletePath.push(currentNode) | ||||
|     replaceWith = currentNode.left | ||||
|  | ||||
|     // Special case: the in-order predecessor is right below the node to delete | ||||
|     if (!replaceWith.right) { | ||||
|       currentNode.key = replaceWith.key | ||||
|       currentNode.data = replaceWith.data | ||||
|       currentNode.left = replaceWith.left | ||||
|       if (replaceWith.left) { replaceWith.left.parent = currentNode } | ||||
|       return this.rebalanceAlongPath(deletePath) | ||||
|     } | ||||
|  | ||||
|     // After this loop, replaceWith is the right-most leaf in the left subtree | ||||
|     // and deletePath the path from the root (inclusive) to replaceWith (exclusive) | ||||
|     while (true) { | ||||
|       if (replaceWith.right) { | ||||
|         deletePath.push(replaceWith) | ||||
|         replaceWith = replaceWith.right | ||||
|       } else break | ||||
|     } | ||||
|  | ||||
|     currentNode.key = replaceWith.key | ||||
|     currentNode.data = replaceWith.data | ||||
|  | ||||
|     replaceWith.parent.right = replaceWith.left | ||||
|     if (replaceWith.left) replaceWith.left.parent = replaceWith.parent | ||||
|  | ||||
|     return this.rebalanceAlongPath(deletePath) | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Keep a pointer to the internal tree constructor for testing purposes | ||||
|  */ | ||||
| AVLTree._AVLTree = _AVLTree; | ||||
|  | ||||
| /** | ||||
|  * Other functions we want to use on an AVLTree as if it were the internal _AVLTree | ||||
|  */ | ||||
| ['getNumberOfKeys', 'search', 'betweenBounds', 'prettyPrint', 'executeOnEveryNode'].forEach(function (fn) { | ||||
|   AVLTree.prototype[fn] = function () { | ||||
|     return this.tree[fn].apply(this.tree, arguments) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| // Interface | ||||
| module.exports = AVLTree | ||||
							
								
								
									
										452
									
								
								node_modules/@seald-io/binary-search-tree/lib/bst.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										452
									
								
								node_modules/@seald-io/binary-search-tree/lib/bst.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,452 @@ | ||||
| /** | ||||
|  * Simple binary search tree | ||||
|  */ | ||||
| const customUtils = require('./customUtils') | ||||
|  | ||||
| class BinarySearchTree { | ||||
|   /** | ||||
|    * Constructor | ||||
|    * @param {Object} options Optional | ||||
|    * @param {Boolean}  options.unique Whether to enforce a 'unique' constraint on the key or not | ||||
|    * @param {Key}      options.key Initialize this BST's key with key | ||||
|    * @param {Value}    options.value Initialize this BST's data with [value] | ||||
|    * @param {Function} options.compareKeys Initialize this BST's compareKeys | ||||
|    */ | ||||
|   constructor (options) { | ||||
|     options = options || {} | ||||
|  | ||||
|     this.left = null | ||||
|     this.right = null | ||||
|     this.parent = options.parent !== undefined ? options.parent : null | ||||
|     if (Object.prototype.hasOwnProperty.call(options, 'key')) { this.key = options.key } | ||||
|     this.data = Object.prototype.hasOwnProperty.call(options, 'value') ? [options.value] : [] | ||||
|     this.unique = options.unique || false | ||||
|  | ||||
|     this.compareKeys = options.compareKeys || customUtils.defaultCompareKeysFunction | ||||
|     this.checkValueEquality = options.checkValueEquality || customUtils.defaultCheckValueEquality | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get the descendant with max key | ||||
|    */ | ||||
|   getMaxKeyDescendant () { | ||||
|     if (this.right) return this.right.getMaxKeyDescendant() | ||||
|     else return this | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get the maximum key | ||||
|    */ | ||||
|   getMaxKey () { | ||||
|     return this.getMaxKeyDescendant().key | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get the descendant with min key | ||||
|    */ | ||||
|   getMinKeyDescendant () { | ||||
|     if (this.left) return this.left.getMinKeyDescendant() | ||||
|     else return this | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get the minimum key | ||||
|    */ | ||||
|   getMinKey () { | ||||
|     return this.getMinKeyDescendant().key | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Check that all nodes (incl. leaves) fullfil condition given by fn | ||||
|    * test is a function passed every (key, data) and which throws if the condition is not met | ||||
|    */ | ||||
|   checkAllNodesFullfillCondition (test) { | ||||
|     if (!Object.prototype.hasOwnProperty.call(this, 'key')) return | ||||
|  | ||||
|     test(this.key, this.data) | ||||
|     if (this.left) this.left.checkAllNodesFullfillCondition(test) | ||||
|     if (this.right) this.right.checkAllNodesFullfillCondition(test) | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Check that the core BST properties on node ordering are verified | ||||
|    * Throw if they aren't | ||||
|    */ | ||||
|   checkNodeOrdering () { | ||||
|     if (!Object.prototype.hasOwnProperty.call(this, 'key')) return | ||||
|  | ||||
|     if (this.left) { | ||||
|       this.left.checkAllNodesFullfillCondition(k => { | ||||
|         if (this.compareKeys(k, this.key) >= 0) throw new Error(`Tree with root ${this.key} is not a binary search tree`) | ||||
|       }) | ||||
|       this.left.checkNodeOrdering() | ||||
|     } | ||||
|  | ||||
|     if (this.right) { | ||||
|       this.right.checkAllNodesFullfillCondition(k => { | ||||
|         if (this.compareKeys(k, this.key) <= 0) throw new Error(`Tree with root ${this.key} is not a binary search tree`) | ||||
|       }) | ||||
|       this.right.checkNodeOrdering() | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Check that all pointers are coherent in this tree | ||||
|    */ | ||||
|   checkInternalPointers () { | ||||
|     if (this.left) { | ||||
|       if (this.left.parent !== this) throw new Error(`Parent pointer broken for key ${this.key}`) | ||||
|       this.left.checkInternalPointers() | ||||
|     } | ||||
|  | ||||
|     if (this.right) { | ||||
|       if (this.right.parent !== this) throw new Error(`Parent pointer broken for key ${this.key}`) | ||||
|       this.right.checkInternalPointers() | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Check that a tree is a BST as defined here (node ordering and pointer references) | ||||
|    */ | ||||
|   checkIsBST () { | ||||
|     this.checkNodeOrdering() | ||||
|     this.checkInternalPointers() | ||||
|     if (this.parent) throw new Error("The root shouldn't have a parent") | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get number of keys inserted | ||||
|    */ | ||||
|   getNumberOfKeys () { | ||||
|     let res | ||||
|  | ||||
|     if (!Object.prototype.hasOwnProperty.call(this, 'key')) return 0 | ||||
|  | ||||
|     res = 1 | ||||
|     if (this.left) res += this.left.getNumberOfKeys() | ||||
|     if (this.right) res += this.right.getNumberOfKeys() | ||||
|  | ||||
|     return res | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Create a BST similar (i.e. same options except for key and value) to the current one | ||||
|    * Use the same constructor (i.e. BinarySearchTree, AVLTree etc) | ||||
|    * @param {Object} options see constructor | ||||
|    */ | ||||
|   createSimilar (options) { | ||||
|     options = options || {} | ||||
|     options.unique = this.unique | ||||
|     options.compareKeys = this.compareKeys | ||||
|     options.checkValueEquality = this.checkValueEquality | ||||
|  | ||||
|     return new this.constructor(options) | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Create the left child of this BST and return it | ||||
|    */ | ||||
|   createLeftChild (options) { | ||||
|     const leftChild = this.createSimilar(options) | ||||
|     leftChild.parent = this | ||||
|     this.left = leftChild | ||||
|  | ||||
|     return leftChild | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Create the right child of this BST and return it | ||||
|    */ | ||||
|   createRightChild (options) { | ||||
|     const rightChild = this.createSimilar(options) | ||||
|     rightChild.parent = this | ||||
|     this.right = rightChild | ||||
|  | ||||
|     return rightChild | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Insert a new element | ||||
|    */ | ||||
|   insert (key, value) { | ||||
|     // Empty tree, insert as root | ||||
|     if (!Object.prototype.hasOwnProperty.call(this, 'key')) { | ||||
|       this.key = key | ||||
|       this.data.push(value) | ||||
|       return | ||||
|     } | ||||
|  | ||||
|     // Same key as root | ||||
|     if (this.compareKeys(this.key, key) === 0) { | ||||
|       if (this.unique) { | ||||
|         const err = new Error(`Can't insert key ${JSON.stringify(key)}, it violates the unique constraint`) | ||||
|         err.key = key | ||||
|         err.errorType = 'uniqueViolated' | ||||
|         throw err | ||||
|       } else this.data.push(value) | ||||
|       return | ||||
|     } | ||||
|  | ||||
|     if (this.compareKeys(key, this.key) < 0) { | ||||
|       // Insert in left subtree | ||||
|       if (this.left) this.left.insert(key, value) | ||||
|       else this.createLeftChild({ key: key, value: value }) | ||||
|     } else { | ||||
|       // Insert in right subtree | ||||
|       if (this.right) this.right.insert(key, value) | ||||
|       else this.createRightChild({ key: key, value: value }) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Search for all data corresponding to a key | ||||
|    */ | ||||
|   search (key) { | ||||
|     if (!Object.prototype.hasOwnProperty.call(this, 'key')) return [] | ||||
|  | ||||
|     if (this.compareKeys(this.key, key) === 0) return this.data | ||||
|  | ||||
|     if (this.compareKeys(key, this.key) < 0) { | ||||
|       if (this.left) return this.left.search(key) | ||||
|       else return [] | ||||
|     } else { | ||||
|       if (this.right) return this.right.search(key) | ||||
|       else return [] | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Return a function that tells whether a given key matches a lower bound | ||||
|    */ | ||||
|   getLowerBoundMatcher (query) { | ||||
|     // No lower bound | ||||
|     if (!Object.prototype.hasOwnProperty.call(query, '$gt') && !Object.prototype.hasOwnProperty.call(query, '$gte')) return () => true | ||||
|  | ||||
|     if (Object.prototype.hasOwnProperty.call(query, '$gt') && Object.prototype.hasOwnProperty.call(query, '$gte')) { | ||||
|       if (this.compareKeys(query.$gte, query.$gt) === 0) return key => this.compareKeys(key, query.$gt) > 0 | ||||
|  | ||||
|       if (this.compareKeys(query.$gte, query.$gt) > 0) return key => this.compareKeys(key, query.$gte) >= 0 | ||||
|       else return key => this.compareKeys(key, query.$gt) > 0 | ||||
|     } | ||||
|  | ||||
|     if (Object.prototype.hasOwnProperty.call(query, '$gt')) return key => this.compareKeys(key, query.$gt) > 0 | ||||
|     else return key => this.compareKeys(key, query.$gte) >= 0 | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Return a function that tells whether a given key matches an upper bound | ||||
|    */ | ||||
|   getUpperBoundMatcher (query) { | ||||
|     // No lower bound | ||||
|     if (!Object.prototype.hasOwnProperty.call(query, '$lt') && !Object.prototype.hasOwnProperty.call(query, '$lte')) return () => true | ||||
|  | ||||
|     if (Object.prototype.hasOwnProperty.call(query, '$lt') && Object.prototype.hasOwnProperty.call(query, '$lte')) { | ||||
|       if (this.compareKeys(query.$lte, query.$lt) === 0) return key => this.compareKeys(key, query.$lt) < 0 | ||||
|  | ||||
|       if (this.compareKeys(query.$lte, query.$lt) < 0) return key => this.compareKeys(key, query.$lte) <= 0 | ||||
|       else return key => this.compareKeys(key, query.$lt) < 0 | ||||
|     } | ||||
|  | ||||
|     if (Object.prototype.hasOwnProperty.call(query, '$lt')) return key => this.compareKeys(key, query.$lt) < 0 | ||||
|     else return key => this.compareKeys(key, query.$lte) <= 0 | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get all data for a key between bounds | ||||
|    * Return it in key order | ||||
|    * @param {Object} query Mongo-style query where keys are $lt, $lte, $gt or $gte (other keys are not considered) | ||||
|    * @param {Functions} lbm/ubm matching functions calculated at the first recursive step | ||||
|    */ | ||||
|   betweenBounds (query, lbm, ubm) { | ||||
|     const res = [] | ||||
|  | ||||
|     if (!Object.prototype.hasOwnProperty.call(this, 'key')) return [] // Empty tree | ||||
|  | ||||
|     lbm = lbm || this.getLowerBoundMatcher(query) | ||||
|     ubm = ubm || this.getUpperBoundMatcher(query) | ||||
|  | ||||
|     if (lbm(this.key) && this.left) append(res, this.left.betweenBounds(query, lbm, ubm)) | ||||
|     if (lbm(this.key) && ubm(this.key)) append(res, this.data) | ||||
|     if (ubm(this.key) && this.right) append(res, this.right.betweenBounds(query, lbm, ubm)) | ||||
|  | ||||
|     return res | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Delete the current node if it is a leaf | ||||
|    * Return true if it was deleted | ||||
|    */ | ||||
|   deleteIfLeaf () { | ||||
|     if (this.left || this.right) return false | ||||
|  | ||||
|     // The leaf is itself a root | ||||
|     if (!this.parent) { | ||||
|       delete this.key | ||||
|       this.data = [] | ||||
|       return true | ||||
|     } | ||||
|  | ||||
|     if (this.parent.left === this) this.parent.left = null | ||||
|     else this.parent.right = null | ||||
|  | ||||
|     return true | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Delete the current node if it has only one child | ||||
|    * Return true if it was deleted | ||||
|    */ | ||||
|   deleteIfOnlyOneChild () { | ||||
|     let child | ||||
|  | ||||
|     if (this.left && !this.right) child = this.left | ||||
|     if (!this.left && this.right) child = this.right | ||||
|     if (!child) return false | ||||
|  | ||||
|     // Root | ||||
|     if (!this.parent) { | ||||
|       this.key = child.key | ||||
|       this.data = child.data | ||||
|  | ||||
|       this.left = null | ||||
|       if (child.left) { | ||||
|         this.left = child.left | ||||
|         child.left.parent = this | ||||
|       } | ||||
|  | ||||
|       this.right = null | ||||
|       if (child.right) { | ||||
|         this.right = child.right | ||||
|         child.right.parent = this | ||||
|       } | ||||
|  | ||||
|       return true | ||||
|     } | ||||
|  | ||||
|     if (this.parent.left === this) { | ||||
|       this.parent.left = child | ||||
|       child.parent = this.parent | ||||
|     } else { | ||||
|       this.parent.right = child | ||||
|       child.parent = this.parent | ||||
|     } | ||||
|  | ||||
|     return true | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Delete a key or just a value | ||||
|    * @param {Key} key | ||||
|    * @param {Value} value Optional. If not set, the whole key is deleted. If set, only this value is deleted | ||||
|    */ | ||||
|   delete (key, value) { | ||||
|     const newData = [] | ||||
|     let replaceWith | ||||
|  | ||||
|     if (!Object.prototype.hasOwnProperty.call(this, 'key')) return | ||||
|  | ||||
|     if (this.compareKeys(key, this.key) < 0) { | ||||
|       if (this.left) this.left.delete(key, value) | ||||
|       return | ||||
|     } | ||||
|  | ||||
|     if (this.compareKeys(key, this.key) > 0) { | ||||
|       if (this.right) this.right.delete(key, value) | ||||
|       return | ||||
|     } | ||||
|  | ||||
|     if (!this.compareKeys(key, this.key) === 0) return | ||||
|  | ||||
|     // Delete only a value | ||||
|     if (this.data.length > 1 && value !== undefined) { | ||||
|       this.data.forEach(d => { | ||||
|         if (!this.checkValueEquality(d, value)) newData.push(d) | ||||
|       }) | ||||
|       this.data = newData | ||||
|       return | ||||
|     } | ||||
|  | ||||
|     // Delete the whole node | ||||
|     if (this.deleteIfLeaf()) return | ||||
|  | ||||
|     if (this.deleteIfOnlyOneChild()) return | ||||
|  | ||||
|     // We are in the case where the node to delete has two children | ||||
|     if (Math.random() >= 0.5) { // Randomize replacement to avoid unbalancing the tree too much | ||||
|       // Use the in-order predecessor | ||||
|       replaceWith = this.left.getMaxKeyDescendant() | ||||
|  | ||||
|       this.key = replaceWith.key | ||||
|       this.data = replaceWith.data | ||||
|  | ||||
|       if (this === replaceWith.parent) { // Special case | ||||
|         this.left = replaceWith.left | ||||
|         if (replaceWith.left) replaceWith.left.parent = replaceWith.parent | ||||
|       } else { | ||||
|         replaceWith.parent.right = replaceWith.left | ||||
|         if (replaceWith.left) replaceWith.left.parent = replaceWith.parent | ||||
|       } | ||||
|     } else { | ||||
|       // Use the in-order successor | ||||
|       replaceWith = this.right.getMinKeyDescendant() | ||||
|  | ||||
|       this.key = replaceWith.key | ||||
|       this.data = replaceWith.data | ||||
|  | ||||
|       if (this === replaceWith.parent) { // Special case | ||||
|         this.right = replaceWith.right | ||||
|         if (replaceWith.right) replaceWith.right.parent = replaceWith.parent | ||||
|       } else { | ||||
|         replaceWith.parent.left = replaceWith.right | ||||
|         if (replaceWith.right) replaceWith.right.parent = replaceWith.parent | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Execute a function on every node of the tree, in key order | ||||
|    * @param {Function} fn Signature: node. Most useful will probably be node.key and node.data | ||||
|    */ | ||||
|   executeOnEveryNode (fn) { | ||||
|     if (this.left) this.left.executeOnEveryNode(fn) | ||||
|     fn(this) | ||||
|     if (this.right) this.right.executeOnEveryNode(fn) | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Pretty print a tree | ||||
|    * @param {Boolean} printData To print the nodes' data along with the key | ||||
|    */ | ||||
|   prettyPrint (printData, spacing) { | ||||
|     spacing = spacing || '' | ||||
|  | ||||
|     console.log(`${spacing}* ${this.key}`) | ||||
|     if (printData) console.log(`${spacing}* ${this.data}`) | ||||
|  | ||||
|     if (!this.left && !this.right) return | ||||
|  | ||||
|     if (this.left) this.left.prettyPrint(printData, `${spacing}  `) | ||||
|     else console.log(`${spacing}  *`) | ||||
|  | ||||
|     if (this.right) this.right.prettyPrint(printData, `${spacing}  `) | ||||
|     else console.log(`${spacing}  *`) | ||||
|   } | ||||
| } | ||||
|  | ||||
| // ================================ | ||||
| // Methods used to test the tree | ||||
| // ================================ | ||||
|  | ||||
| // ============================================ | ||||
| // Methods used to actually work on the tree | ||||
| // ============================================ | ||||
|  | ||||
| // Append all elements in toAppend to array | ||||
| function append (array, toAppend) { | ||||
|   for (let i = 0; i < toAppend.length; i += 1) { | ||||
|     array.push(toAppend[i]) | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Interface | ||||
| module.exports = BinarySearchTree | ||||
							
								
								
									
										38
									
								
								node_modules/@seald-io/binary-search-tree/lib/customUtils.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								node_modules/@seald-io/binary-search-tree/lib/customUtils.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| /** | ||||
|  * Return an array with the numbers from 0 to n-1, in a random order | ||||
|  */ | ||||
| const getRandomArray = n => { | ||||
|   if (n === 0) return [] | ||||
|   if (n === 1) return [0] | ||||
|  | ||||
|   const res = getRandomArray(n - 1) | ||||
|   const next = Math.floor(Math.random() * n) | ||||
|   res.splice(next, 0, n - 1) // Add n-1 at a random position in the array | ||||
|  | ||||
|   return res | ||||
| } | ||||
|  | ||||
| module.exports.getRandomArray = getRandomArray | ||||
|  | ||||
| /* | ||||
|  * Default compareKeys function will work for numbers, strings and dates | ||||
|  */ | ||||
| const defaultCompareKeysFunction = (a, b) => { | ||||
|   if (a < b) return -1 | ||||
|   if (a > b) return 1 | ||||
|   if (a === b) return 0 | ||||
|  | ||||
|   const err = new Error("Couldn't compare elements") | ||||
|   err.a = a | ||||
|   err.b = b | ||||
|   throw err | ||||
| } | ||||
|  | ||||
| module.exports.defaultCompareKeysFunction = defaultCompareKeysFunction | ||||
|  | ||||
| /** | ||||
|  * Check whether two values are equal (used in non-unique deletion) | ||||
|  */ | ||||
| const defaultCheckValueEquality = (a, b) => a === b | ||||
|  | ||||
| module.exports.defaultCheckValueEquality = defaultCheckValueEquality | ||||
							
								
								
									
										51
									
								
								node_modules/@seald-io/binary-search-tree/package.json
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								node_modules/@seald-io/binary-search-tree/package.json
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| { | ||||
|   "name": "@seald-io/binary-search-tree", | ||||
|   "version": "1.0.3", | ||||
|   "author": { | ||||
|     "name": "Timothée Rebours", | ||||
|     "email": "tim@seald.io", | ||||
|     "url": "https://www.seald.io/" | ||||
|   }, | ||||
|   "files": [ | ||||
|     "lib/**/*.js", | ||||
|     "index.js" | ||||
|   ], | ||||
|   "contributors": [ | ||||
|     { | ||||
|       "name": "Louis Chatriot", | ||||
|       "email": "louis.chatriot@gmail.com" | ||||
|     }, | ||||
|     { | ||||
|       "name": "Timothée Rebours", | ||||
|       "email": "tim@seald.io", | ||||
|       "url": "https://www.seald.io/" | ||||
|     } | ||||
|   ], | ||||
|   "description": "Different binary search tree implementations, including a self-balancing one (AVL)", | ||||
|   "keywords": [ | ||||
|     "AVL tree", | ||||
|     "binary search tree", | ||||
|     "self-balancing", | ||||
|     "AVL tree" | ||||
|   ], | ||||
|   "homepage": "https://github.com/seald/node-binary-search-tree", | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "git@github.com:seald/node-binary-search-tree.git" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "chai": "^4.3.4", | ||||
|     "mocha": "^8.4.0", | ||||
|     "semver": "^7.3.5", | ||||
|     "standard": "^16.0.3" | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "test": "mocha --reporter spec --timeout 10000", | ||||
|     "lint": "standard" | ||||
|   }, | ||||
|   "main": "index.js", | ||||
|   "licence": "MIT", | ||||
|   "publishConfig": { | ||||
|     "access": "public" | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user