diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..15e494ec86 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +# Keep GitHub Actions up to date with Dependabot... +# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/Ci.yml b/.github/workflows/Ci.yml index 571b8a0fa8..99e8f7831f 100644 --- a/.github/workflows/Ci.yml +++ b/.github/workflows/Ci.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm - name: 📦 Install dependencies diff --git a/.github/workflows/UpdateDirectory.yml b/.github/workflows/UpdateDirectory.yml index cb649e1c8b..437ab55b91 100644 --- a/.github/workflows/UpdateDirectory.yml +++ b/.github/workflows/UpdateDirectory.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm - name: 📦 Install dependencies diff --git a/.github/workflows/UploadCoverageReport.yml b/.github/workflows/UploadCoverageReport.yml index 4dcad584bf..3f8fee4256 100644 --- a/.github/workflows/UploadCoverageReport.yml +++ b/.github/workflows/UploadCoverageReport.yml @@ -8,6 +8,9 @@ name: UploadCoverageReport - master pull_request: +env: + REPORT_PATH: "coverage/coverage-final.json" + jobs: UploadCoverageReport: runs-on: ubuntu-latest @@ -16,7 +19,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm - name: Install dependencies @@ -25,9 +28,18 @@ jobs: - name: Generate coverage report run: npm test -- --coverage - - name: Upload coverage to codecov - uses: codecov/codecov-action@v3 + - name: Upload coverage to codecov (tokenless) + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository + uses: codecov/codecov-action@v4 + with: + files: "${{ env.REPORT_PATH }}" + fail_ci_if_error: true + + - name: Upload coverage to codecov (with token) + if: "! github.event.pull_request.head.repo.fork " + uses: codecov/codecov-action@v4 with: - files: "coverage/coverage-final.json" + token: ${{ secrets.CODECOV_TOKEN }} + files: "${{ env.REPORT_PATH }}" fail_ci_if_error: true ... diff --git a/Backtracking/tests/RatInAMaze.test.js b/Backtracking/tests/RatInAMaze.test.js index 6cc5b31aae..52f620027b 100644 --- a/Backtracking/tests/RatInAMaze.test.js +++ b/Backtracking/tests/RatInAMaze.test.js @@ -6,7 +6,6 @@ describe('RatInAMaze', () => { for (const value of values) { // we deliberately want to check whether this constructor call fails or not - // eslint-disable-next-line no-new expect(() => { new RatInAMaze(value) }).toThrow() @@ -15,7 +14,6 @@ describe('RatInAMaze', () => { it('should fail for an empty array', () => { // we deliberately want to check whether this constructor call fails or not - // eslint-disable-next-line no-new expect(() => { new RatInAMaze([]) }).toThrow() @@ -28,7 +26,6 @@ describe('RatInAMaze', () => { ] // we deliberately want to check whether this constructor call fails or not - // eslint-disable-next-line no-new expect(() => { new RatInAMaze(array) }).toThrow() @@ -39,7 +36,6 @@ describe('RatInAMaze', () => { for (const value of values) { // we deliberately want to check whether this constructor call fails or not - // eslint-disable-next-line no-new expect(() => { new RatInAMaze(value) }).toThrow() diff --git a/Backtracking/tests/Sudoku.test.js b/Backtracking/tests/Sudoku.test.js index 8cbe187089..c70f7de67a 100644 --- a/Backtracking/tests/Sudoku.test.js +++ b/Backtracking/tests/Sudoku.test.js @@ -27,7 +27,6 @@ const solved = [ describe('Sudoku', () => { it('should create a valid board successfully', () => { // we deliberately want to check whether this constructor call fails or not - // eslint-disable-next-line no-new expect(() => { new Sudoku(data) }).not.toThrow() diff --git a/Compression/RLE.js b/Compression/RLE.js new file mode 100644 index 0000000000..81a1538646 --- /dev/null +++ b/Compression/RLE.js @@ -0,0 +1,38 @@ +/* + * RLE (Run Length Encoding) is a simple form of data compression. + * The basic idea is to represent repeated successive characters as a single count and character. + * For example, the string "AAAABBBCCDAA" would be encoded as "4A3B2C1D2A". + * + * @author - [ddaniel27](https://github.com/ddaniel27) + */ + +function Compress(str) { + let compressed = '' + let count = 1 + + for (let i = 0; i < str.length; i++) { + if (str[i] !== str[i + 1]) { + compressed += count + str[i] + count = 1 + continue + } + + count++ + } + + return compressed +} + +function Decompress(str) { + let decompressed = '' + let match = [...str.matchAll(/(\d+)(\D)/g)] // match all groups of digits followed by a non-digit character + + match.forEach((item) => { + let [count, char] = [item[1], item[2]] + decompressed += char.repeat(count) + }) + + return decompressed +} + +export { Compress, Decompress } diff --git a/Compression/test/RLE.test.js b/Compression/test/RLE.test.js new file mode 100644 index 0000000000..0094b5b7e2 --- /dev/null +++ b/Compression/test/RLE.test.js @@ -0,0 +1,13 @@ +import { Compress, Decompress } from '../RLE' + +describe('Test RLE Compressor/Decompressor', () => { + it('Test - 1, Pass long repetitive strings', () => { + expect(Compress('AAAAAAAAAAAAAA')).toBe('14A') + expect(Compress('AAABBQQQQQFG')).toBe('3A2B5Q1F1G') + }) + + it('Test - 2, Pass compressed strings', () => { + expect(Decompress('14A')).toBe('AAAAAAAAAAAAAA') + expect(Decompress('3A2B5Q1F1G')).toBe('AAABBQQQQQFG') + }) +}) diff --git a/Conversions/DateDayDifference.js b/Conversions/DateDayDifference.js index fef242568d..726a634253 100644 --- a/Conversions/DateDayDifference.js +++ b/Conversions/DateDayDifference.js @@ -7,6 +7,7 @@ */ import { isLeapYear } from '../Maths/LeapYear' +import { parseDate } from '../Timing-Functions/ParseDate' const DateToDay = (dd, mm, yyyy) => { return ( @@ -20,32 +21,13 @@ const DateToDay = (dd, mm, yyyy) => { ) } -const CheckDayAndMonth = (inDay, inMonth) => { - if (inDay <= 0 || inDay > 31 || inMonth <= 0 || inMonth > 12) { - throw new TypeError('Date is not valid.') - } -} - const DateDayDifference = (date1, date2) => { - // firstly, check that both input are string or not. - if (typeof date1 !== 'string' || typeof date2 !== 'string') { - throw new TypeError('Argument is not a string.') - } - // extract the first date - const [firstDateDay, firstDateMonth, firstDateYear] = date1 - .split('/') - .map((ele) => Number(ele)) - // extract the second date - const [secondDateDay, secondDateMonth, secondDateYear] = date2 - .split('/') - .map((ele) => Number(ele)) - // check the both data are valid or not. - CheckDayAndMonth(firstDateDay, firstDateMonth) - CheckDayAndMonth(secondDateDay, secondDateMonth) + const firstDate = parseDate(date1) + const secondDate = parseDate(date2) return Math.abs( - DateToDay(secondDateDay, secondDateMonth, secondDateYear) - - DateToDay(firstDateDay, firstDateMonth, firstDateYear) + DateToDay(secondDate.day, secondDate.month, secondDate.year) - + DateToDay(firstDate.day, firstDate.month, firstDate.year) ) } diff --git a/Conversions/DateToDay.js b/Conversions/DateToDay.js index f360c9c737..96ec01e82d 100644 --- a/Conversions/DateToDay.js +++ b/Conversions/DateToDay.js @@ -12,6 +12,8 @@ Algorithm & Explanation : https://en.wikipedia.org/wiki/Zeller%27s_congruence */ +import { parseDate } from '../Timing-Functions/ParseDate' + // Array holding name of the day: Saturday - Sunday - Friday => 0 - 1 - 6 const daysNameArr = [ 'Saturday', @@ -25,15 +27,10 @@ const daysNameArr = [ const DateToDay = (date) => { // firstly, check that input is a string or not. - if (typeof date !== 'string') { - throw new TypeError('Argument is not a string.') - } - // extract the date - let [day, month, year] = date.split('/').map((x) => Number(x)) - // check the data are valid or not. - if (day < 1 || day > 31 || month > 12 || month < 1) { - throw new TypeError('Date is not valid.') - } + const dateStruct = parseDate(date) + let year = dateStruct.year + let month = dateStruct.month + let day = dateStruct.day // In case of Jan and Feb: // Year: we consider it as previous year diff --git a/Conversions/HexToDecimal.js b/Conversions/HexToDecimal.js index 31ae13932f..e402421399 100644 --- a/Conversions/HexToDecimal.js +++ b/Conversions/HexToDecimal.js @@ -1,4 +1,7 @@ function hexToInt(hexNum) { + if (!/^[0-9A-F]+$/.test(hexNum)) { + throw new Error('Invalid hex string.') + } const numArr = hexNum.split('') // converts number to array return numArr.map((item, index) => { switch (item) { @@ -29,4 +32,4 @@ function hexToDecimal(hexNum) { }, 0) } -export { hexToInt, hexToDecimal } +export { hexToDecimal } diff --git a/Conversions/RailwayTimeConversion.js b/Conversions/RailwayTimeConversion.js index 15f837b0da..b499023223 100644 --- a/Conversions/RailwayTimeConversion.js +++ b/Conversions/RailwayTimeConversion.js @@ -24,8 +24,8 @@ const RailwayTimeConversion = (timeString) => { const [hour, minute, secondWithShift] = timeString.split(':') // split second and shift value. const [second, shift] = [ - secondWithShift.substr(0, 2), - secondWithShift.substr(2) + secondWithShift.substring(0, 2), + secondWithShift.substring(2) ] // convert shifted time to not-shift time(Railway time) by using the above explanation. if (shift === 'PM') { diff --git a/Conversions/test/HexToDecimal.test.js b/Conversions/test/HexToDecimal.test.js new file mode 100644 index 0000000000..816c70511d --- /dev/null +++ b/Conversions/test/HexToDecimal.test.js @@ -0,0 +1,24 @@ +import { hexToDecimal } from '../HexToDecimal' + +describe('Testing HexToDecimal', () => { + it.each([ + ['0', 0], + ['1', 1], + ['A', 10], + ['B', 11], + ['C', 12], + ['D', 13], + ['E', 14], + ['F', 15], + ['10', 16], + ['859', 2137], + ['4D2', 1234], + ['81323ABD92', 554893491602] + ])('check with %s', (hexStr, expected) => { + expect(hexToDecimal(hexStr)).toBe(expected) + }) + + it.each(['a', '-1', 'G', ''])('throws for %s', (hexStr) => { + expect(() => hexToDecimal(hexStr)).toThrowError() + }) +}) diff --git a/DIRECTORY.md b/DIRECTORY.md index 8b51ce3bf7..5e8e1f401a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -35,6 +35,8 @@ * [ROT13](Ciphers/ROT13.js) * [VigenereCipher](Ciphers/VigenereCipher.js) * [XORCipher](Ciphers/XORCipher.js) +* **Compression** + * [RLE](Compression/RLE.js) * **Conversions** * [ArbitraryBase](Conversions/ArbitraryBase.js) * [ArrayBufferToBase64](Conversions/ArrayBufferToBase64.js) @@ -252,7 +254,6 @@ * [RowEchelon](Maths/RowEchelon.js) * [ShorsAlgorithm](Maths/ShorsAlgorithm.js) * [SieveOfEratosthenes](Maths/SieveOfEratosthenes.js) - * [SieveOfEratosthenesIntArray](Maths/SieveOfEratosthenesIntArray.js) * [Signum](Maths/Signum.js) * [SimpsonIntegration](Maths/SimpsonIntegration.js) * [Softmax](Maths/Softmax.js) @@ -260,7 +261,6 @@ * [SquareRootLogarithmic](Maths/SquareRootLogarithmic.js) * [SumOfDigits](Maths/SumOfDigits.js) * [SumOfGeometricProgression](Maths/SumOfGeometricProgression.js) - * [TwinPrime](Maths/TwinPrime.js) * [TwoSum](Maths/TwoSum.js) * [Volume](Maths/Volume.js) * [WhileLoopFactorial](Maths/WhileLoopFactorial.js) @@ -286,6 +286,7 @@ * [Problem016](Project-Euler/Problem016.js) * [Problem017](Project-Euler/Problem017.js) * [Problem018](Project-Euler/Problem018.js) + * [Problem019](Project-Euler/Problem019.js) * [Problem020](Project-Euler/Problem020.js) * [Problem021](Project-Euler/Problem021.js) * [Problem023](Project-Euler/Problem023.js) @@ -296,7 +297,6 @@ * **Recursive** * [BinaryEquivalent](Recursive/BinaryEquivalent.js) * [BinarySearch](Recursive/BinarySearch.js) - * [EucledianGCD](Recursive/EucledianGCD.js) * [Factorial](Recursive/Factorial.js) * [FibonacciNumberRecursive](Recursive/FibonacciNumberRecursive.js) * [FloodFill](Recursive/FloodFill.js) @@ -399,6 +399,7 @@ * **Timing-Functions** * [GetMonthDays](Timing-Functions/GetMonthDays.js) * [IntervalTimer](Timing-Functions/IntervalTimer.js) + * [ParseDate](Timing-Functions/ParseDate.js) * **Trees** * [BreadthFirstTreeTraversal](Trees/BreadthFirstTreeTraversal.js) * [DepthFirstSearch](Trees/DepthFirstSearch.js) diff --git a/Data-Structures/Array/QuickSelect.js b/Data-Structures/Array/QuickSelect.js index d01555ed95..53c8c8e855 100644 --- a/Data-Structures/Array/QuickSelect.js +++ b/Data-Structures/Array/QuickSelect.js @@ -12,7 +12,6 @@ */ function QuickSelect(items, kth) { - // eslint-disable-line no-unused-vars if (kth < 1 || kth > items.length) { throw new RangeError('Index Out of Bound') } diff --git a/Data-Structures/Array/Reverse.js b/Data-Structures/Array/Reverse.js index 79a789c017..ca08f35f8a 100644 --- a/Data-Structures/Array/Reverse.js +++ b/Data-Structures/Array/Reverse.js @@ -7,11 +7,9 @@ const Reverse = (arr) => { // limit specifies the amount of Reverse actions - for (let i = 0, j = arr.length - 1; i < arr.length / 2; i++, j--) { - const temp = arr[i] - arr[i] = arr[j] - arr[j] = temp - } + for (let i = 0, j = arr.length - 1; i < arr.length / 2; i++, j--) + [arr[i], arr[j]] = [arr[j], arr[i]] + return arr } export { Reverse } diff --git a/Data-Structures/Queue/CircularQueue.js b/Data-Structures/Queue/CircularQueue.js index 27f2196780..c716251668 100644 --- a/Data-Structures/Queue/CircularQueue.js +++ b/Data-Structures/Queue/CircularQueue.js @@ -77,7 +77,7 @@ class CircularQueue { // Displays the length of queue length() { - return this.queue.length - 1 + return this.checkEmpty() ? 0 : this.queue.length - 1 } // Display the top most value of queue diff --git a/Data-Structures/Queue/QueueUsing2Stacks.js b/Data-Structures/Queue/QueueUsing2Stacks.js index 256f11060d..9a51ee3a72 100644 --- a/Data-Structures/Queue/QueueUsing2Stacks.js +++ b/Data-Structures/Queue/QueueUsing2Stacks.js @@ -29,24 +29,6 @@ class Queue { return top } } - - // display elements of the inputstack - listIn(output = (value) => console.log(value)) { - let i = 0 - while (i < this.inputStack.length) { - output(this.inputStack[i]) - i++ - } - } - - // display element of the outputstack - listOut(output = (value) => console.log(value)) { - let i = 0 - while (i < this.outputStack.length) { - output(this.outputStack[i]) - i++ - } - } } export { Queue } diff --git a/Data-Structures/Stack/Stack.js b/Data-Structures/Stack/Stack.js index d3001e8020..d8531fdebf 100644 --- a/Data-Structures/Stack/Stack.js +++ b/Data-Structures/Stack/Stack.js @@ -8,8 +8,8 @@ // Functions: push, pop, peek, view, length // Creates a stack constructor -const Stack = (function () { - function Stack() { +class Stack { + constructor() { // The top of the Stack this.top = 0 // The array representation of the stack @@ -17,13 +17,13 @@ const Stack = (function () { } // Adds a value onto the end of the stack - Stack.prototype.push = function (value) { + push(value) { this.stack[this.top] = value this.top++ } // Removes and returns the value at the end of the stack - Stack.prototype.pop = function () { + pop() { if (this.top === 0) { return 'Stack is Empty' } @@ -35,23 +35,21 @@ const Stack = (function () { } // Returns the size of the stack - Stack.prototype.size = function () { + size() { return this.top } // Returns the value at the end of the stack - Stack.prototype.peek = function () { + peek() { return this.stack[this.top - 1] } // To see all the elements in the stack - Stack.prototype.view = function (output = (value) => console.log(value)) { + view(output = (value) => console.log(value)) { for (let i = 0; i < this.top; i++) { output(this.stack[i]) } } - - return Stack -})() +} export { Stack } diff --git a/Data-Structures/Tree/AVLTree.js b/Data-Structures/Tree/AVLTree.js index e5abbf3e55..dd673a9330 100644 --- a/Data-Structures/Tree/AVLTree.js +++ b/Data-Structures/Tree/AVLTree.js @@ -31,8 +31,8 @@ let utils * @argument comp - A function used by AVL Tree For Comparison * If no argument is sent it uses utils.comparator */ -const AVLTree = (function () { - function _avl(comp) { +class AVLTree { + constructor(comp) { /** @public comparator function */ this._comp = undefined this._comp = comp !== undefined ? comp : utils.comparator() @@ -43,162 +43,6 @@ const AVLTree = (function () { this.size = 0 } - // creates new Node Object - const Node = function (val) { - this._val = val - this._left = null - this._right = null - this._height = 1 - } - - // get height of a node - const getHeight = function (node) { - if (node == null) { - return 0 - } - return node._height - } - - // height difference or balance factor of a node - const getHeightDifference = function (node) { - return node == null ? 0 : getHeight(node._left) - getHeight(node._right) - } - - // update height of a node based on children's heights - const updateHeight = function (node) { - if (node == null) { - return - } - node._height = Math.max(getHeight(node._left), getHeight(node._right)) + 1 - } - - // Helper: To check if the balanceFactor is valid - const isValidBalanceFactor = (balanceFactor) => - [0, 1, -1].includes(balanceFactor) - - // rotations of AVL Tree - const leftRotate = function (node) { - const temp = node._right - node._right = temp._left - temp._left = node - updateHeight(node) - updateHeight(temp) - return temp - } - const rightRotate = function (node) { - const temp = node._left - node._left = temp._right - temp._right = node - updateHeight(node) - updateHeight(temp) - return temp - } - - // check if tree is balanced else balance it for insertion - const insertBalance = function (node, _val, balanceFactor, tree) { - if (balanceFactor > 1 && tree._comp(_val, node._left._val) < 0) { - return rightRotate(node) // Left Left Case - } - if (balanceFactor < 1 && tree._comp(_val, node._right._val) > 0) { - return leftRotate(node) // Right Right Case - } - if (balanceFactor > 1 && tree._comp(_val, node._left._val) > 0) { - node._left = leftRotate(node._left) // Left Right Case - return rightRotate(node) - } - node._right = rightRotate(node._right) - return leftRotate(node) - } - - // check if tree is balanced after deletion - const delBalance = function (node) { - const balanceFactor1 = getHeightDifference(node) - if (isValidBalanceFactor(balanceFactor1)) { - return node - } - if (balanceFactor1 > 1) { - if (getHeightDifference(node._left) >= 0) { - return rightRotate(node) // Left Left - } - node._left = leftRotate(node._left) - return rightRotate(node) // Left Right - } - if (getHeightDifference(node._right) > 0) { - node._right = rightRotate(node._right) - return leftRotate(node) // Right Left - } - return leftRotate(node) // Right Right - } - - // implement avl tree insertion - const insert = function (root, val, tree) { - if (root == null) { - tree.size++ - return new Node(val) - } - if (tree._comp(root._val, val) < 0) { - root._right = insert(root._right, val, tree) - } else if (tree._comp(root._val, val) > 0) { - root._left = insert(root._left, val, tree) - } else { - return root - } - updateHeight(root) - const balanceFactor = getHeightDifference(root) - return isValidBalanceFactor(balanceFactor) - ? root - : insertBalance(root, val, balanceFactor, tree) - } - - // delete am element - const deleteElement = function (root, _val, tree) { - if (root == null) { - return root - } - if (tree._comp(root._val, _val) === 0) { - // key found case - if (root._left === null && root._right === null) { - root = null - tree.size-- - } else if (root._left === null) { - root = root._right - tree.size-- - } else if (root._right === null) { - root = root._left - tree.size-- - } else { - let temp = root._right - while (temp._left != null) { - temp = temp._left - } - root._val = temp._val - root._right = deleteElement(root._right, temp._val, tree) - } - } else { - if (tree._comp(root._val, _val) < 0) { - root._right = deleteElement(root._right, _val, tree) - } else { - root._left = deleteElement(root._left, _val, tree) - } - } - updateHeight(root) - root = delBalance(root) - return root - } - // search tree for a element - const searchAVLTree = function (root, val, tree) { - if (root == null) { - return null - } - if (tree._comp(root._val, val) === 0) { - return root - } - if (tree._comp(root._val, val) < 0) { - return searchAVLTree(root._right, val, tree) - } - return searchAVLTree(root._left, val, tree) - } - /* Public Functions */ /** * For Adding Elements to AVL Tree @@ -207,20 +51,22 @@ const AVLTree = (function () { * if a element exists it return false * @returns {Boolean} element added or not */ - _avl.prototype.add = function (_val) { + add(_val) { const prevSize = this.size this.root = insert(this.root, _val, this) return this.size !== prevSize } + /** * TO check is a particular element exists or not * @param {any} _val * @returns {Boolean} exists or not */ - _avl.prototype.find = function (_val) { + find(_val) { const temp = searchAVLTree(this.root, _val, this) return temp != null } + /** * * @param {any} _val @@ -228,13 +74,170 @@ const AVLTree = (function () { * in that case it return false * @returns {Boolean} if element was found and deleted */ - _avl.prototype.remove = function (_val) { + remove(_val) { const prevSize = this.size this.root = deleteElement(this.root, _val, this) return prevSize !== this.size } - return _avl -})() +} + +// creates new Node Object +class Node { + constructor(val) { + this._val = val + this._left = null + this._right = null + this._height = 1 + } +} + +// get height of a node +const getHeight = function (node) { + if (node == null) { + return 0 + } + return node._height +} + +// height difference or balance factor of a node +const getHeightDifference = function (node) { + return node == null ? 0 : getHeight(node._left) - getHeight(node._right) +} + +// update height of a node based on children's heights +const updateHeight = function (node) { + if (node == null) { + return + } + node._height = Math.max(getHeight(node._left), getHeight(node._right)) + 1 +} + +// Helper: To check if the balanceFactor is valid +const isValidBalanceFactor = (balanceFactor) => + [0, 1, -1].includes(balanceFactor) + +// rotations of AVL Tree +const leftRotate = function (node) { + const temp = node._right + node._right = temp._left + temp._left = node + updateHeight(node) + updateHeight(temp) + return temp +} +const rightRotate = function (node) { + const temp = node._left + node._left = temp._right + temp._right = node + updateHeight(node) + updateHeight(temp) + return temp +} + +// check if tree is balanced else balance it for insertion +const insertBalance = function (node, _val, balanceFactor, tree) { + if (balanceFactor > 1 && tree._comp(_val, node._left._val) < 0) { + return rightRotate(node) // Left Left Case + } + if (balanceFactor < 1 && tree._comp(_val, node._right._val) > 0) { + return leftRotate(node) // Right Right Case + } + if (balanceFactor > 1 && tree._comp(_val, node._left._val) > 0) { + node._left = leftRotate(node._left) // Left Right Case + return rightRotate(node) + } + node._right = rightRotate(node._right) + return leftRotate(node) +} + +// check if tree is balanced after deletion +const delBalance = function (node) { + const balanceFactor1 = getHeightDifference(node) + if (isValidBalanceFactor(balanceFactor1)) { + return node + } + if (balanceFactor1 > 1) { + if (getHeightDifference(node._left) >= 0) { + return rightRotate(node) // Left Left + } + node._left = leftRotate(node._left) + return rightRotate(node) // Left Right + } + if (getHeightDifference(node._right) > 0) { + node._right = rightRotate(node._right) + return leftRotate(node) // Right Left + } + return leftRotate(node) // Right Right +} + +// implement avl tree insertion +const insert = function (root, val, tree) { + if (root == null) { + tree.size++ + return new Node(val) + } + if (tree._comp(root._val, val) < 0) { + root._right = insert(root._right, val, tree) + } else if (tree._comp(root._val, val) > 0) { + root._left = insert(root._left, val, tree) + } else { + return root + } + updateHeight(root) + const balanceFactor = getHeightDifference(root) + return isValidBalanceFactor(balanceFactor) + ? root + : insertBalance(root, val, balanceFactor, tree) +} + +// delete am element +const deleteElement = function (root, _val, tree) { + if (root == null) { + return root + } + if (tree._comp(root._val, _val) === 0) { + // key found case + if (root._left === null && root._right === null) { + root = null + tree.size-- + } else if (root._left === null) { + root = root._right + tree.size-- + } else if (root._right === null) { + root = root._left + tree.size-- + } else { + let temp = root._right + while (temp._left != null) { + temp = temp._left + } + root._val = temp._val + root._right = deleteElement(root._right, temp._val, tree) + } + } else { + if (tree._comp(root._val, _val) < 0) { + root._right = deleteElement(root._right, _val, tree) + } else { + root._left = deleteElement(root._left, _val, tree) + } + } + updateHeight(root) + root = delBalance(root) + return root +} +// search tree for a element +const searchAVLTree = function (root, val, tree) { + if (root == null) { + return null + } + if (tree._comp(root._val, val) === 0) { + return root + } + if (tree._comp(root._val, val) < 0) { + return searchAVLTree(root._right, val, tree) + } + return searchAVLTree(root._left, val, tree) +} /** * A Code for Testing the AVLTree diff --git a/Data-Structures/Tree/BinarySearchTree.js b/Data-Structures/Tree/BinarySearchTree.js index c86a2995c0..8a65c8e650 100644 --- a/Data-Structures/Tree/BinarySearchTree.js +++ b/Data-Structures/Tree/BinarySearchTree.js @@ -13,77 +13,79 @@ // class Node const Node = (function Node() { // Node in the tree - function Node(val) { - this.value = val - this.left = null - this.right = null - } - - // Search the tree for a value - Node.prototype.search = function (val) { - if (this.value === val) { - return this - } else if (val < this.value && this.left !== null) { - return this.left.search(val) - } else if (val > this.value && this.right !== null) { - return this.right.search(val) + class Node { + constructor(val) { + this.value = val + this.left = null + this.right = null } - return null - } - // Visit a node - Node.prototype.visit = function (output = (value) => console.log(value)) { - // Recursively go left - if (this.left !== null) { - this.left.visit() - } - // Print out value - output(this.value) - // Recursively go right - if (this.right !== null) { - this.right.visit() + // Search the tree for a value + search(val) { + if (this.value === val) { + return this + } else if (val < this.value && this.left !== null) { + return this.left.search(val) + } else if (val > this.value && this.right !== null) { + return this.right.search(val) + } + return null } - } - // Add a node - Node.prototype.addNode = function (n) { - if (n.value < this.value) { - if (this.left === null) { - this.left = n - } else { - this.left.addNode(n) + // Visit a node + visit(output = (value) => console.log(value)) { + // Recursively go left + if (this.left !== null) { + this.left.visit(output) } - } else if (n.value > this.value) { - if (this.right === null) { - this.right = n - } else { - this.right.addNode(n) + // Print out value + output(this.value) + // Recursively go right + if (this.right !== null) { + this.right.visit(output) } } - } - // remove a node - Node.prototype.removeNode = function (val) { - if (val === this.value) { - if (!this.left && !this.right) { - return null - } else { - if (this.left) { - const leftMax = maxVal(this.left) - this.value = leftMax - this.left = this.left.removeNode(leftMax) + // Add a node + addNode(n) { + if (n.value < this.value) { + if (this.left === null) { + this.left = n + } else { + this.left.addNode(n) + } + } else if (n.value > this.value) { + if (this.right === null) { + this.right = n } else { - const rightMin = minVal(this.right) - this.value = rightMin - this.right = this.right.removeNode(rightMin) + this.right.addNode(n) } } - } else if (val < this.value) { - this.left = this.left && this.left.removeNode(val) - } else if (val > this.value) { - this.right = this.right && this.right.removeNode(val) } - return this + + // remove a node + removeNode(val) { + if (val === this.value) { + if (!this.left && !this.right) { + return null + } else { + if (this.left) { + const leftMax = maxVal(this.left) + this.value = leftMax + this.left = this.left.removeNode(leftMax) + } else { + const rightMin = minVal(this.right) + this.value = rightMin + this.right = this.right.removeNode(rightMin) + } + } + } else if (val < this.value) { + this.left = this.left && this.left.removeNode(val) + } else if (val > this.value) { + this.right = this.right && this.right.removeNode(val) + } + return this + } } // find maximum value in the tree @@ -107,44 +109,49 @@ const Node = (function Node() { // class Tree const Tree = (function () { - function Tree() { - // Just store the root - this.root = null - } + class Tree { + constructor() { + // Just store the root + this.root = null + } - // Inorder traversal - Tree.prototype.traverse = function () { - if (!this.root) { - // No nodes are there in the tree till now - return + // Inorder traversal + traverse(output = (value) => console.log(value)) { + if (!this.root) { + // No nodes are there in the tree till now + return + } + this.root.visit(output) } - this.root.visit() - } - // Start by searching the root - Tree.prototype.search = function (val) { - const found = this.root.search(val) - if (found !== null) { - return found.value + // Start by searching the root + search(val) { + if (this.root) { + const found = this.root.search(val) + if (found !== null) { + return found.value + } + } + + // not found + return null } - // not found - return null - } - // Add a new value to the tree - Tree.prototype.addValue = function (val) { - const n = new Node(val) - if (this.root === null) { - this.root = n - } else { - this.root.addNode(n) + // Add a new value to the tree + addValue(val) { + const n = new Node(val) + if (this.root === null) { + this.root = n + } else { + this.root.addNode(n) + } } - } - // remove a value from the tree - Tree.prototype.removeValue = function (val) { - // remove something if root exists - this.root = this.root && this.root.removeNode(val) + // remove a value from the tree + removeValue(val) { + // remove something if root exists + this.root = this.root && this.root.removeNode(val) + } } // returns the constructor diff --git a/Data-Structures/Tree/Trie.js b/Data-Structures/Tree/Trie.js index ea59e53846..0d4018f74f 100644 --- a/Data-Structures/Tree/Trie.js +++ b/Data-Structures/Tree/Trie.js @@ -1,129 +1,132 @@ -const TrieNode = function TrieNode(key, parent) { - this.key = key - this.count = 0 - this.children = Object.create(null) - if (parent === undefined) { - this.parent = null - } else { - this.parent = parent +class TrieNode { + constructor(key, parent) { + this.key = key + this.count = 0 + this.children = Object.create(null) + if (parent === undefined) { + this.parent = null + } else { + this.parent = parent + } } } -function Trie() { - // create only root with null key and parent - this.root = new TrieNode(null, null) -} +class Trie { + constructor() { + // create only root with null key and parent + this.root = new TrieNode(null, null) + } -// Recursively finds the occurrence of all words in a given node -Trie.findAllWords = function (root, word, output) { - if (root === null) return - if (root.count > 0) { - if (typeof output === 'object') { - output.push({ word, count: root.count }) + // Recursively finds the occurrence of all words in a given node + static findAllWords(root, word, output) { + if (root === null) return + if (root.count > 0) { + if (typeof output === 'object') { + output.push({ word, count: root.count }) + } + } + let key + for (key in root.children) { + word += key + this.findAllWords(root.children[key], word, output) + word = word.slice(0, -1) } } - let key - for (key in root.children) { - word += key - this.findAllWords(root.children[key], word, output) - word = word.slice(0, -1) - } -} -Trie.prototype.insert = function (word) { - if (typeof word !== 'string') return - if (word === '') { - this.root.count += 1 - return - } - let node = this.root - const len = word.length - let i - for (i = 0; i < len; i++) { - if (node.children[word.charAt(i)] === undefined) { - node.children[word.charAt(i)] = new TrieNode(word.charAt(i), node) + insert(word) { + if (typeof word !== 'string') return + if (word === '') { + this.root.count += 1 + return + } + let node = this.root + const len = word.length + let i + for (i = 0; i < len; i++) { + if (node.children[word.charAt(i)] === undefined) { + node.children[word.charAt(i)] = new TrieNode(word.charAt(i), node) + } + node = node.children[word.charAt(i)] } - node = node.children[word.charAt(i)] + node.count += 1 } - node.count += 1 -} -Trie.prototype.findPrefix = function (word) { - if (typeof word !== 'string') return null - let node = this.root - const len = word.length - let i - // After end of this loop node will be at desired prefix - for (i = 0; i < len; i++) { - if (node.children[word.charAt(i)] === undefined) return null // No such prefix exists - node = node.children[word.charAt(i)] + findPrefix(word) { + if (typeof word !== 'string') return null + let node = this.root + const len = word.length + let i + // After end of this loop node will be at desired prefix + for (i = 0; i < len; i++) { + if (node.children[word.charAt(i)] === undefined) return null // No such prefix exists + node = node.children[word.charAt(i)] + } + return node } - return node -} -Trie.prototype.remove = function (word, count) { - if (typeof word !== 'string') return - if (typeof count !== 'number') count = 1 - else if (count <= 0) return + remove(word, count) { + if (typeof word !== 'string') return + if (typeof count !== 'number') count = 1 + else if (count <= 0) return - // for empty string just delete count of root - if (word === '') { - if (this.root.count >= count) this.root.count -= count - else this.root.count = 0 - return - } + // for empty string just delete count of root + if (word === '') { + if (this.root.count >= count) this.root.count -= count + else this.root.count = 0 + return + } - let child = this.root - const len = word.length - let i, key - // child: node which is to be deleted - for (i = 0; i < len; i++) { - key = word.charAt(i) - if (child.children[key] === undefined) return - child = child.children[key] - } + let child = this.root + const len = word.length + let i, key + // child: node which is to be deleted + for (i = 0; i < len; i++) { + key = word.charAt(i) + if (child.children[key] === undefined) return + child = child.children[key] + } - // Delete no of occurrences specified - if (child.count >= count) child.count -= count - else child.count = 0 + // Delete no of occurrences specified + if (child.count >= count) child.count -= count + else child.count = 0 - // If some occurrences are left we don't delete it or else - // if the object forms some other objects prefix we don't delete it - // For checking an empty object - // https://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object - if ( - child.count <= 0 && - Object.keys(child.children).length && - child.children.constructor === Object - ) { - child.parent.children[child.key] = undefined + // If some occurrences are left we don't delete it or else + // if the object forms some other objects prefix we don't delete it + // For checking an empty object + // https://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object + if ( + child.count <= 0 && + Object.keys(child.children).length && + child.children.constructor === Object + ) { + child.parent.children[child.key] = undefined + } } -} -Trie.prototype.findAllWords = function (prefix) { - const output = [] - // find the node with provided prefix - const node = this.findPrefix(prefix) - // No such prefix exists - if (node === null) return output - Trie.findAllWords(node, prefix, output) - return output -} - -Trie.prototype.contains = function (word) { - // find the node with given prefix - const node = this.findPrefix(word) - // No such word exists + findAllWords(prefix) { + const output = [] + // find the node with provided prefix + const node = this.findPrefix(prefix) + // No such prefix exists + if (node === null) return output + Trie.findAllWords(node, prefix, output) + return output + } - return node !== null && node.count !== 0 -} + contains(word) { + // find the node with given prefix + const node = this.findPrefix(word) + // No such word exists + return node !== null && node.count !== 0 + } -Trie.prototype.findOccurrences = function (word) { - // find the node with given prefix - const node = this.findPrefix(word) - // No such word exists - if (node === null) return 0 - return node.count + findOccurrences(word) { + // find the node with given prefix + const node = this.findPrefix(word) + // No such word exists + if (node === null) return 0 + return node.count + } } export { Trie } diff --git a/Data-Structures/Tree/test/BinarySearchTree.test.js b/Data-Structures/Tree/test/BinarySearchTree.test.js new file mode 100644 index 0000000000..4c6c353592 --- /dev/null +++ b/Data-Structures/Tree/test/BinarySearchTree.test.js @@ -0,0 +1,66 @@ +import { Tree } from '../BinarySearchTree.js' + +describe('Binary Search Tree', () => { + let tree + + beforeEach(() => { + tree = new Tree() + tree.addValue(10) + tree.addValue(5) + tree.addValue(15) + tree.addValue(3) + tree.addValue(8) + }) + + test('should add values to the tree', () => { + tree.addValue(12) + + expect(tree.search(12)).toBe(12) + expect(tree.search(5)).toBe(5) + expect(tree.search(15)).toBe(15) + }) + + test('should perform in-order traversal', () => { + const values = [] + const output = (val) => values.push(val) + tree.traverse(output) + expect(values).toEqual([3, 5, 8, 10, 15]) + }) + + test('should remove leaf nodes correctly', () => { + tree.removeValue(5) + expect(tree.search(5)).toBeNull() + }) + + test('should remove nodes with one child correctly', () => { + tree.addValue(12) + tree.removeValue(15) + + expect(tree.search(15)).toBeNull() + expect(tree.search(12)).toBe(12) + }) + + test('should remove nodes with two children correctly', () => { + tree.addValue(18) + tree.removeValue(15) + + expect(tree.search(15)).toBeNull() + expect(tree.search(18)).toBe(18) + }) + + test('should return null for non-existent values', () => { + expect(tree.search(20)).toBeNull() + expect(tree.search(0)).toBeNull() + }) + + test('should handle removal of root node correctly', () => { + tree.removeValue(10) + expect(tree.search(10)).toBeNull() + }) + + test('should handle empty tree gracefully', () => { + const newTree = new Tree() + newTree.removeValue(22) // Should not throw + expect(newTree.search(22)).toBeNull() + }) +}) diff --git a/Dynamic-Programming/LongestIncreasingSubsequence.js b/Dynamic-Programming/LongestIncreasingSubsequence.js index b9319db586..b8e1847cd8 100644 --- a/Dynamic-Programming/LongestIncreasingSubsequence.js +++ b/Dynamic-Programming/LongestIncreasingSubsequence.js @@ -6,6 +6,9 @@ // Return the length of the Longest Increasing Subsequence, given array x function longestIncreasingSubsequence(x) { const length = x.length + if (length == 0) { + return 0 + } const dp = Array(length).fill(1) let res = 1 diff --git a/Dynamic-Programming/NumberOfSubsetEqualToGivenSum.js b/Dynamic-Programming/NumberOfSubsetEqualToGivenSum.js index dee12f8de9..fd8e70c4d6 100644 --- a/Dynamic-Programming/NumberOfSubsetEqualToGivenSum.js +++ b/Dynamic-Programming/NumberOfSubsetEqualToGivenSum.js @@ -1,12 +1,19 @@ /* -Given an array of non-negative integers and a value sum, +Given an array of positive integers and a value sum, determine the total number of the subset with sum equal to the given sum. */ /* - Given solution is O(n*sum) Time complexity and O(sum) Space complexity + Given solution is O(n*sum) Time complexity and O(sum) Space complexity */ function NumberOfSubsetSum(array, sum) { + if (sum < 0) { + throw new Error('The sum must be non-negative.') + } + + if (!array.every((num) => num > 0)) { + throw new Error('All of the inputs of the array must be positive.') + } const dp = [] // create an dp array where dp[i] denote number of subset with sum equal to i for (let i = 1; i <= sum; i++) { dp[i] = 0 @@ -23,10 +30,4 @@ function NumberOfSubsetSum(array, sum) { return dp[sum] } -// example - -// const array = [1, 1, 2, 2, 3, 1, 1] -// const sum = 4 -// const result = NumberOfSubsetSum(array, sum) - export { NumberOfSubsetSum } diff --git a/Dynamic-Programming/tests/LongestIncreasingSubsequence.test.js b/Dynamic-Programming/tests/LongestIncreasingSubsequence.test.js new file mode 100644 index 0000000000..9a8024aa95 --- /dev/null +++ b/Dynamic-Programming/tests/LongestIncreasingSubsequence.test.js @@ -0,0 +1,24 @@ +import { longestIncreasingSubsequence } from '../LongestIncreasingSubsequence' + +describe('Testing longestIncreasingSubsequence', () => { + it.each([ + [[], 0], + [[1], 1], + [[2, 2], 1], + [[3, 3, 3], 1], + [[4, 4, 4, 4], 1], + [[1, 2], 2], + [[1, 2, 2, 2, 2], 2], + [[1, 0, 2], 2], + [[1, 10, 2, 30], 3], + [[5, 8, 3, 7, 9, 1], 3], + [[10, 9, 2, 5, 3, 7, 101, 18], 4], + [[10, 10, 9, 9, 2, 2, 5, 5, 3, 3, 7, 7, 101, 101, 18, 18], 4], + [[0, 1, 0, 3, 2, 3], 4], + [[1, 1, 2, 2, 2], 2], + [[1, 1, 2, 2, 2, 3, 3, 3, 3], 3], + [[0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15], 6] + ])('check with %j', (input, expected) => { + expect(longestIncreasingSubsequence(input)).toBe(expected) + }) +}) diff --git a/Dynamic-Programming/tests/NumberOfSubsetEqualToGivenSum.test.js b/Dynamic-Programming/tests/NumberOfSubsetEqualToGivenSum.test.js new file mode 100644 index 0000000000..23eed33ebe --- /dev/null +++ b/Dynamic-Programming/tests/NumberOfSubsetEqualToGivenSum.test.js @@ -0,0 +1,25 @@ +import { NumberOfSubsetSum } from '../NumberOfSubsetEqualToGivenSum' + +describe('Testing NumberOfSubsetSum', () => { + it.each([ + [[], 0, 1], + [[], 1, 0], + [[1], 2, 0], + [[1, 2, 3, 4, 5], 0, 1], + [[1, 1, 1, 1, 1], 5, 1], + [[1, 1, 1, 1, 1], 4, 5], + [[1, 2, 3, 3], 6, 3], + [[10, 20, 30, 1], 31, 2], + [[1, 1, 2, 2, 3, 1, 1], 4, 18] + ])('check with %j and %i', (arr, sum, expected) => { + expect(NumberOfSubsetSum(arr, sum)).toBe(expected) + }) + + it.each([ + [[1, 2], -1], + [[0, 2], 2], + [[1, -1], 0] + ])('throws for %j and %i', (arr, sum) => { + expect(() => NumberOfSubsetSum(arr, sum)).toThrowError() + }) +}) diff --git a/Maths/AverageMean.js b/Maths/AverageMean.js index 75f7b1b58e..8ae3b55992 100644 --- a/Maths/AverageMean.js +++ b/Maths/AverageMean.js @@ -13,11 +13,7 @@ const mean = (nums) => { throw new TypeError('Invalid Input') } - // This loop sums all values in the 'nums' array using forEach loop - const sum = nums.reduce((sum, cur) => sum + cur, 0) - - // Divide sum by the length of the 'nums' array. - return sum / nums.length + return nums.reduce((sum, cur) => sum + cur, 0) / nums.length } export { mean } diff --git a/Maths/BisectionMethod.js b/Maths/BisectionMethod.js index 49b8c8ecc0..4539e6d466 100644 --- a/Maths/BisectionMethod.js +++ b/Maths/BisectionMethod.js @@ -23,7 +23,7 @@ const findRoot = (a, b, func, numberOfIterations) => { // Bolzano theorem const hasRoot = (a, b, func) => { - return func(a) * func(b) < 0 + return func(a) * func(b) <= 0 } if (hasRoot(a, b, func) === false) { throw Error( @@ -45,10 +45,9 @@ const findRoot = (a, b, func, numberOfIterations) => { const prod2 = fm * func(b) // Depending on the sign of the products above, decide which position will m fill (a's or b's) - if (prod1 > 0 && prod2 < 0) return findRoot(m, b, func, --numberOfIterations) - else if (prod1 < 0 && prod2 > 0) - return findRoot(a, m, func, --numberOfIterations) - else throw Error('Unexpected behavior') + if (prod2 <= 0) return findRoot(m, b, func, --numberOfIterations) + + return findRoot(a, m, func, --numberOfIterations) } export { findRoot } diff --git a/Maths/GetEuclidGCD.js b/Maths/GetEuclidGCD.js index 31eeab42ec..42a30a6042 100644 --- a/Maths/GetEuclidGCD.js +++ b/Maths/GetEuclidGCD.js @@ -1,3 +1,9 @@ +function CheckInput(a, b) { + if (typeof a !== 'number' || typeof b !== 'number') { + throw new TypeError('Arguments must be numbers') + } +} + /** * GetEuclidGCD Euclidean algorithm to determine the GCD of two numbers * @param {Number} a integer (may be negative) @@ -5,9 +11,7 @@ * @returns {Number} Greatest Common Divisor gcd(a, b) */ export function GetEuclidGCD(a, b) { - if (typeof a !== 'number' || typeof b !== 'number') { - throw new TypeError('Arguments must be numbers') - } + CheckInput(a, b) a = Math.abs(a) b = Math.abs(b) while (b !== 0) { @@ -17,3 +21,19 @@ export function GetEuclidGCD(a, b) { } return a } + +/** + * Recursive version of GetEuclidGCD + * @param {Number} a integer (may be negative) + * @param {Number} b integer (may be negative) + * @returns {Number} Greatest Common Divisor gcd(a, b) + */ +export function GetEuclidGCDRecursive(a, b) { + CheckInput(a, b) + a = Math.abs(a) + b = Math.abs(b) + if (b == 0) { + return a + } + return GetEuclidGCDRecursive(b, a % b) +} diff --git a/Maths/SieveOfEratosthenes.js b/Maths/SieveOfEratosthenes.js index 01e141f2f0..681d8ba904 100644 --- a/Maths/SieveOfEratosthenes.js +++ b/Maths/SieveOfEratosthenes.js @@ -1,25 +1,26 @@ -const sieveOfEratosthenes = (n) => { - /* - * Calculates prime numbers till a number n - * :param n: Number up to which to calculate primes - * :return: A boolean list containing only primes - */ - const primes = new Array(n + 1) - primes.fill(true) // set all as true initially - primes[0] = primes[1] = false // Handling case for 0 and 1 - const sqrtn = Math.ceil(Math.sqrt(n)) - for (let i = 2; i <= sqrtn; i++) { - if (primes[i]) { - for (let j = i * i; j <= n; j += i) { - /* - Optimization. - Let j start from i * i, not 2 * i, because smaller multiples of i have been marked false. +/** + * @function sieveOfEratosthenes + * @description Function to get all the prime numbers below a given number using sieve of eratosthenes algorithm + * @param {Number} max The limit below which all the primes are required to be + * @returns {Number[]} An array of all the prime numbers below max + * @see [Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) + * @example + * sieveOfEratosthenes(1) // ====> [] + * @example + * sieveOfEratosthenes(20) // ====> [2, 3, 5, 7, 11, 13, 17, 19] + * + */ +function sieveOfEratosthenes(max) { + const sieve = [] + const primes = [] - For example, let i = 4. - We do not have to check from 8(4 * 2) to 12(4 * 3) - because they have been already marked false when i=2 and i=3. - */ - primes[j] = false + for (let i = 2; i <= max; ++i) { + if (!sieve[i]) { + // If i has not been marked then it is prime + primes.push(i) + for (let j = i << 1; j <= max; j += i) { + // Mark all multiples of i as non-prime + sieve[j] = true } } } diff --git a/Maths/SieveOfEratosthenesIntArray.js b/Maths/SieveOfEratosthenesIntArray.js deleted file mode 100644 index 56336ce7d8..0000000000 --- a/Maths/SieveOfEratosthenesIntArray.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Function to get all prime numbers below a given number - * This function returns an array of prime numbers - * @see {@link https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes} - */ - -function sieveOfEratosthenes(max) { - const sieve = [] - const primes = [] - - for (let i = 2; i <= max; ++i) { - if (!sieve[i]) { - // If i has not been marked then it is prime - primes.push(i) - for (let j = i << 1; j <= max; j += i) { - // Mark all multiples of i as non-prime - sieve[j] = true - } - } - } - return primes -} - -export { sieveOfEratosthenes } diff --git a/Maths/test/BisectionMethod.test.js b/Maths/test/BisectionMethod.test.js index ad865b6ad6..4a49e8f6a4 100644 --- a/Maths/test/BisectionMethod.test.js +++ b/Maths/test/BisectionMethod.test.js @@ -1,14 +1,7 @@ import { findRoot } from '../BisectionMethod' test('Equation f(x) = x^2 - 3*x + 2 = 0, has root x = 1 in [a, b] = [0, 1.5]', () => { - const root = findRoot( - 0, - 1.5, - (x) => { - return Math.pow(x, 2) - 3 * x + 2 - }, - 8 - ) + const root = findRoot(0, 1.5, (x) => x ** 2 - 3 * x + 2, 8) expect(root).toBe(0.9990234375) }) @@ -35,3 +28,12 @@ test('Equation f(x) = sqrt(x) + e^(2*x) - 8*x = 0, has root x = 0.93945851 in [a ) expect(Number(Number(root).toPrecision(8))).toBe(0.93945851) }) + +test('Equation f(x) = x^3 = 0, has root x = 0.0 in [a, b] = [-1.0, 1.0]', () => { + const root = findRoot(-1.0, 1.0, (x) => x ** 3, 32) + expect(root).toBeCloseTo(0.0, 5) +}) + +test('Throws an error when function does not change sign', () => { + expect(() => findRoot(-1.0, 1.0, (x) => x ** 2, 10)).toThrowError() +}) diff --git a/Maths/test/EulerMethod.manual-test.js b/Maths/test/EulerMethod.manual-test.js index 27b4631a80..e1959280a5 100644 --- a/Maths/test/EulerMethod.manual-test.js +++ b/Maths/test/EulerMethod.manual-test.js @@ -15,7 +15,6 @@ function plotLine(label, points, width, height) { // Chart-class from chartjs const chart = new Chart(canvas, { - // eslint-disable-line type: 'scatter', data: { datasets: [ diff --git a/Maths/test/FindMinIterator.test.js b/Maths/test/FindMinIterator.test.js index 7b7229b106..792cb7695e 100644 --- a/Maths/test/FindMinIterator.test.js +++ b/Maths/test/FindMinIterator.test.js @@ -22,13 +22,12 @@ describe('FindMinIterator', () => { }) test('given empty generator then min is undefined', () => { - const src = function* () {} // eslint-disable-line + const src = function* () {} expect(FindMinIterator(src())).toBeUndefined() }) test('given generator then min is found', () => { const src = function* () { - // eslint-disable-line yield 1 yield -1 yield 0 @@ -38,7 +37,6 @@ describe('FindMinIterator', () => { test('given string generator then min string length is found', () => { const src = function* () { - // eslint-disable-line yield 'abc' yield 'de' yield 'qwerty' diff --git a/Maths/test/GetEuclidGCD.test.js b/Maths/test/GetEuclidGCD.test.js index a6c7cb22e6..92f888acea 100644 --- a/Maths/test/GetEuclidGCD.test.js +++ b/Maths/test/GetEuclidGCD.test.js @@ -1,6 +1,6 @@ -import { GetEuclidGCD } from '../GetEuclidGCD' +import { GetEuclidGCD, GetEuclidGCDRecursive } from '../GetEuclidGCD' -describe('GetEuclidGCD', () => { +describe.each([GetEuclidGCD, GetEuclidGCDRecursive])('%o', (gcdFunction) => { it.each([ [5, 20, 5], [109, 902, 1], @@ -11,12 +11,12 @@ describe('GetEuclidGCD', () => { [0, 0, 0], [1, 1234567, 1] ])('returns correct result for %i and %j', (inputA, inputB, expected) => { - expect(GetEuclidGCD(inputA, inputB)).toBe(expected) - expect(GetEuclidGCD(inputB, inputA)).toBe(expected) + expect(gcdFunction(inputA, inputB)).toBe(expected) + expect(gcdFunction(inputB, inputA)).toBe(expected) }) it('should throw when any of the inputs is not a number', () => { - expect(() => GetEuclidGCD('1', 2)).toThrowError() - expect(() => GetEuclidGCD(1, '2')).toThrowError() + expect(() => gcdFunction('1', 2)).toThrowError() + expect(() => gcdFunction(1, '2')).toThrowError() }) }) diff --git a/Maths/test/SieveOfEratosthenes.test.js b/Maths/test/SieveOfEratosthenes.test.js index 056693d39b..1a10b8bc7f 100644 --- a/Maths/test/SieveOfEratosthenes.test.js +++ b/Maths/test/SieveOfEratosthenes.test.js @@ -1,14 +1,29 @@ import { sieveOfEratosthenes } from '../SieveOfEratosthenes' -import { PrimeCheck } from '../PrimeCheck' - -describe('should return an array of prime booleans', () => { - it('should have each element in the array as a prime boolean', () => { - const n = 30 - const primes = sieveOfEratosthenes(n) - primes.forEach((primeBool, index) => { - if (primeBool) { - expect(PrimeCheck(index)).toBeTruthy() - } - }) + +describe('sieveOfEratosthenes', () => { + test('returns an empty array for max < 2', () => { + expect(sieveOfEratosthenes(1)).toEqual([]) + }) + + test('returns [2] for max = 2', () => { + expect(sieveOfEratosthenes(2)).toEqual([2]) + }) + + test('returns [2, 3] for max = 3', () => { + expect(sieveOfEratosthenes(3)).toEqual([2, 3]) + }) + + test('returns [2, 3, 5, 7] for max = 10', () => { + expect(sieveOfEratosthenes(10)).toEqual([2, 3, 5, 7]) + }) + + test('returns [2, 3, 5, 7, 11, 13, 17, 19] for max = 20', () => { + expect(sieveOfEratosthenes(20)).toEqual([2, 3, 5, 7, 11, 13, 17, 19]) + }) + + test('returns [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] for max = 30', () => { + expect(sieveOfEratosthenes(30)).toEqual([ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 + ]) }) }) diff --git a/Maths/test/SieveOfEratosthenesIntArray.test.js b/Maths/test/SieveOfEratosthenesIntArray.test.js deleted file mode 100644 index e3a3be3002..0000000000 --- a/Maths/test/SieveOfEratosthenesIntArray.test.js +++ /dev/null @@ -1,12 +0,0 @@ -import { sieveOfEratosthenes } from '../SieveOfEratosthenesIntArray' -import { PrimeCheck } from '../PrimeCheck' - -describe('should return an array of prime numbers', () => { - it('should have each element in the array as a prime numbers', () => { - const n = 100 - const primes = sieveOfEratosthenes(n) - primes.forEach((prime) => { - expect(PrimeCheck(prime)).toBeTruthy() - }) - }) -}) diff --git a/Project-Euler/Problem004.js b/Project-Euler/Problem004.js index 34fa87471d..7c85dfdb85 100644 --- a/Project-Euler/Problem004.js +++ b/Project-Euler/Problem004.js @@ -1,6 +1,6 @@ // https://projecteuler.net/problem=4 /* A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99. - Find the largest palindrome made from the product of two 3-digit numbers. + Find the largest palindrome made from the product of two 3-digit numbers. */ export const largestPalindromic = (digits) => { let i diff --git a/Project-Euler/Problem005.js b/Project-Euler/Problem005.js index fe8901c94c..92f3df9b68 100644 --- a/Project-Euler/Problem005.js +++ b/Project-Euler/Problem005.js @@ -5,11 +5,9 @@ Smallest multiple What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20? */ -export const findSmallestMultiple = () => { - const divisors = [ - 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 - ] - let num = 21 +export const findSmallestMultiple = (maxDivisor) => { + const divisors = Array.from({ length: maxDivisor }, (_, i) => i + 1) + let num = maxDivisor + 1 let result while (!result) { diff --git a/Project-Euler/Problem019.js b/Project-Euler/Problem019.js new file mode 100644 index 0000000000..5b488c7f96 --- /dev/null +++ b/Project-Euler/Problem019.js @@ -0,0 +1,48 @@ +/** + * Problem 19 - Counting Sundays + * + * @see {@link https://projecteuler.net/problem=19} + * + * You are given the following information, but you may prefer to do some research for yourself. + * 1 Jan 1900 was a Monday. + * Thirty days has September, + * April, June and November. + * All the rest have thirty-one, + * Saving February alone, + * Which has twenty-eight, rain or shine. + * And on leap years, twenty-nine. + * A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400. + * How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)? + * + * @author ddaniel27 + */ +import { isLeapYear } from '../Maths/LeapYear' + +function problem19() { + let sundaysCount = 0 // Count of Sundays + let dayOfWeek = 2 // 1st Jan 1900 was a Monday, so 1st Jan 1901 was a Tuesday + + for (let year = 1901; year <= 2000; year++) { + for (let month = 1; month <= 12; month++) { + if (dayOfWeek === 0) { + // If it's a Sunday (0 is Sunday, 1 is Monday, ..., 6 is Saturday) + sundaysCount++ + } + + let daysInMonth = 31 + if (month === 4 || month === 6 || month === 9 || month === 11) { + // April, June, September, November + daysInMonth = 30 + } else if (month === 2) { + // February + daysInMonth = isLeapYear(year) ? 29 : 28 + } + + dayOfWeek = (dayOfWeek + daysInMonth) % 7 // Calculate the day of the week + } + } + + return sundaysCount +} + +export { problem19 } diff --git a/Project-Euler/Problem035.js b/Project-Euler/Problem035.js index c877acba5a..0b11cd0357 100644 --- a/Project-Euler/Problem035.js +++ b/Project-Euler/Problem035.js @@ -9,7 +9,7 @@ * * @author ddaniel27 */ -import { sieveOfEratosthenes } from '../Maths/SieveOfEratosthenesIntArray' +import { sieveOfEratosthenes } from '../Maths/SieveOfEratosthenes' function problem35(n) { if (n < 2) { diff --git a/Project-Euler/test/Problem005.test.js b/Project-Euler/test/Problem005.test.js new file mode 100644 index 0000000000..f3ac1b03d8 --- /dev/null +++ b/Project-Euler/test/Problem005.test.js @@ -0,0 +1,12 @@ +import { expect } from 'vitest' +import { findSmallestMultiple } from '../Problem005.js' + +describe.concurrent('Find smallest multiple', () => { + test.each([ + [10, 2520], + [15, 360360], + [20, 232792560] + ])('max divisor -> %i, smallest multiple -> %i', (a, expected) => { + expect(findSmallestMultiple(a)).toBe(expected) + }) +}) diff --git a/Project-Euler/test/Problem014.test.js b/Project-Euler/test/Problem014.test.js new file mode 100644 index 0000000000..ff464dd42d --- /dev/null +++ b/Project-Euler/test/Problem014.test.js @@ -0,0 +1,15 @@ +import { expect } from 'vitest' +import { findLongestCollatzSequence } from '../Problem014.js' + +describe('Longest Collatz Sequence', () => { + test.each([ + [2, 1], + [13, 9], + [1000000, 837799] + ])( + 'if limit is %i, then the Longest Collatz Sequence will be %i', + (a, expected) => { + expect(findLongestCollatzSequence(a)).toBe(expected) + } + ) +}) diff --git a/Project-Euler/test/Problem019.test.js b/Project-Euler/test/Problem019.test.js new file mode 100644 index 0000000000..8845e5a0ac --- /dev/null +++ b/Project-Euler/test/Problem019.test.js @@ -0,0 +1,8 @@ +import { problem19 } from '../Problem019.js' + +describe('checking sundays during the twentieth century', () => { + // Project Euler Challenge Check + test('result should be 171', () => { + expect(problem19()).toBe(171) + }) +}) diff --git a/Recursive/EucledianGCD.js b/Recursive/EucledianGCD.js deleted file mode 100644 index e0cc15ed56..0000000000 --- a/Recursive/EucledianGCD.js +++ /dev/null @@ -1,30 +0,0 @@ -function euclideanGCDRecursive(first, second) { - /* - Calculates GCD of two numbers using Euclidean Recursive Algorithm - :param first: First number - :param second: Second number - :return: GCD of the numbers - */ - if (second === 0) { - return first - } else { - return euclideanGCDRecursive(second, first % second) - } -} - -function euclideanGCDIterative(first, second) { - /* - Calculates GCD of two numbers using Euclidean Iterative Algorithm - :param first: First number - :param second: Second number - :return: GCD of the numbers - */ - while (second !== 0) { - const temp = second - second = first % second - first = temp - } - return first -} - -export { euclideanGCDIterative, euclideanGCDRecursive } diff --git a/Recursive/FloodFill.js b/Recursive/FloodFill.js index 33ea6025ad..5143b8f4ff 100644 --- a/Recursive/FloodFill.js +++ b/Recursive/FloodFill.js @@ -9,7 +9,7 @@ * @see https://www.techiedelight.com/flood-fill-algorithm/ */ -const neighbors = [ +const neighborOffsets = [ [-1, -1], [-1, 0], [-1, 1], @@ -20,6 +20,27 @@ const neighbors = [ [1, 1] ] +function isInside(rgbData, location) { + const x = location[0] + const y = location[1] + return x >= 0 && x < rgbData.length && y >= 0 && y < rgbData[0].length +} + +function checkLocation(rgbData, location) { + if (!isInside(rgbData, location)) { + throw new Error('location should point to a pixel within the rgbData') + } +} + +function* neighbors(rgbData, location) { + for (const offset of neighborOffsets) { + const neighborLocation = [location[0] + offset[0], location[1] + offset[1]] + if (isInside(rgbData, neighborLocation)) { + yield neighborLocation + } + } +} + /** * Implements the flood fill algorithm through a breadth-first approach using a queue. * @@ -34,14 +55,7 @@ export function breadthFirstSearch( targetColor, replacementColor ) { - if ( - location[0] < 0 || - location[0] >= rgbData.length || - location[1] < 0 || - location[1] >= rgbData[0].length - ) { - throw new Error('location should point to a pixel within the rgbData') - } + checkLocation(rgbData, location) const queue = [] queue.push(location) @@ -65,14 +79,7 @@ export function depthFirstSearch( targetColor, replacementColor ) { - if ( - location[0] < 0 || - location[0] >= rgbData.length || - location[1] < 0 || - location[1] >= rgbData[0].length - ) { - throw new Error('location should point to a pixel within the rgbData') - } + checkLocation(rgbData, location) depthFirstFill(rgbData, location, targetColor, replacementColor) } @@ -98,13 +105,8 @@ function breadthFirstFill( if (rgbData[currentLocation[0]][currentLocation[1]] === targetColor) { rgbData[currentLocation[0]][currentLocation[1]] = replacementColor - - for (let i = 0; i < neighbors.length; i++) { - const x = currentLocation[0] + neighbors[i][0] - const y = currentLocation[1] + neighbors[i][1] - if (x >= 0 && x < rgbData.length && y >= 0 && y < rgbData[0].length) { - queue.push([x, y]) - } + for (const neighborLocation of neighbors(rgbData, currentLocation)) { + queue.push(neighborLocation) } } } @@ -120,13 +122,8 @@ function breadthFirstFill( function depthFirstFill(rgbData, location, targetColor, replacementColor) { if (rgbData[location[0]][location[1]] === targetColor) { rgbData[location[0]][location[1]] = replacementColor - - for (let i = 0; i < neighbors.length; i++) { - const x = location[0] + neighbors[i][0] - const y = location[1] + neighbors[i][1] - if (x >= 0 && x < rgbData.length && y >= 0 && y < rgbData[0].length) { - depthFirstFill(rgbData, [x, y], targetColor, replacementColor) - } + for (const neighborLocation of neighbors(rgbData, location)) { + depthFirstFill(rgbData, neighborLocation, targetColor, replacementColor) } } } diff --git a/Recursive/test/FloodFill.test.js b/Recursive/test/FloodFill.test.js index 291788addd..eb44e75e09 100644 --- a/Recursive/test/FloodFill.test.js +++ b/Recursive/test/FloodFill.test.js @@ -21,6 +21,19 @@ describe('FloodFill', () => { }) }) +describe.each([breadthFirstSearch, depthFirstSearch])('%o', (floodFillFun) => { + it.each([ + [1, -1], + [-1, 1], + [0, 7], + [7, 0] + ])('throws for start position [%i, %i]', (location) => { + expect(() => + floodFillFun(generateTestRgbData(), location, green, orange) + ).toThrowError() + }) +}) + /** * Utility-function to test the function "breadthFirstSearch". * @@ -56,7 +69,6 @@ function testDepthFirst( replacementColor, testLocation ) { - // eslint-disable-line const rgbData = generateTestRgbData() depthFirstSearch(rgbData, fillLocation, targetColor, replacementColor) return rgbData[testLocation[0]][testLocation[1]] diff --git a/Search/LinearSearch.js b/Search/LinearSearch.js index 637ebc1589..96a9d1fa34 100644 --- a/Search/LinearSearch.js +++ b/Search/LinearSearch.js @@ -3,6 +3,8 @@ * value within a list. It sequentially checks each element of the list * for the target value until a match is found or until all the elements * have been searched. + * + * @see https://en.wikipedia.org/wiki/Linear_search */ function SearchArray(searchNum, ar, output = (v) => console.log(v)) { const position = Search(ar, searchNum) diff --git a/Search/test/LinearSearch.test.js b/Search/test/LinearSearch.test.js new file mode 100644 index 0000000000..d593d9aa1c --- /dev/null +++ b/Search/test/LinearSearch.test.js @@ -0,0 +1,35 @@ +import { Search as linearSearch } from '../LinearSearch' + +const tests = [ + { + test: { + arr: [1, 2, 300, 401, 450, 504, 800, 821, 855, 900, 1002], + target: 900 + }, + expectedValue: 9 + }, + { + test: { + arr: [1, 104, 110, 4, 44, 55, 56, 78], + target: 104 + }, + expectedValue: 1 + }, + { + test: { + arr: [-4, 5, 50, 77, 821, 85, 99, 100], + target: 192 + }, + expectedValue: -1 + } +] + +describe('Linear Search', () => { + it.each(tests)( + 'linearSearch($test.arr, $test.target) => $expectedValue', + ({ test, expectedValue }) => { + const { arr, target } = test + expect(linearSearch(arr, target)).toBe(expectedValue) + } + ) +}) diff --git a/Timing-Functions/ParseDate.js b/Timing-Functions/ParseDate.js new file mode 100644 index 0000000000..67f4e4cd0e --- /dev/null +++ b/Timing-Functions/ParseDate.js @@ -0,0 +1,27 @@ +import { getMonthDays } from './GetMonthDays' + +function checkDate(date) { + if (date.day < 1 || date.day > getMonthDays(date.month, date.year)) { + throw new Error('Invalid day value.') + } +} + +function parseDate(dateString) { + const regex = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/ + + const match = dateString.match(regex) + + if (!match) { + throw new Error("Invalid date format. Please use 'dd/mm/yyyy'.") + } + + const res = { + day: parseInt(match[1], 10), + month: parseInt(match[2], 10), + year: parseInt(match[3], 10) + } + checkDate(res) + return res +} + +export { parseDate } diff --git a/Timing-Functions/test/ParseDate.test.js b/Timing-Functions/test/ParseDate.test.js new file mode 100644 index 0000000000..3b807bb8a5 --- /dev/null +++ b/Timing-Functions/test/ParseDate.test.js @@ -0,0 +1,40 @@ +import { parseDate } from '../ParseDate' + +describe('parseDate', () => { + it.each([ + ['18/03/2024', { year: 2024, month: 3, day: 18 }], + ['29/02/2024', { year: 2024, month: 2, day: 29 }], + ['28/02/2023', { year: 2023, month: 2, day: 28 }], + ['01/12/2024', { year: 2024, month: 12, day: 1 }], + ['1/12/2024', { year: 2024, month: 12, day: 1 }], + ['10/1/2024', { year: 2024, month: 1, day: 10 }] + ])('Returns correct output for %s', (dateString, expected) => { + expect(parseDate(dateString)).toStrictEqual(expected) + }) + + it.each([ + '18-03-2024', + '18.03.2024', + '03/2024', + '01/02/03/2024', + '123/03/2024' + ])('Throws for %s', (wrongDateString) => { + expect(() => { + parseDate(wrongDateString) + }).toThrow() + }) + + it.each([ + '40/03/2024', + '30/02/2024', + '29/02/2023', + '31/04/2023', + '00/01/2024', + '01/00/2024', + '01/13/2024' + ])('Throws for %s', (wrongDateString) => { + expect(() => { + parseDate(wrongDateString) + }).toThrow() + }) +}) diff --git a/Trees/DepthFirstSearch.js b/Trees/DepthFirstSearch.js index 7c67afc95e..f4ce2cfed5 100644 --- a/Trees/DepthFirstSearch.js +++ b/Trees/DepthFirstSearch.js @@ -44,30 +44,4 @@ function searchDFS(tree, value) { return null } -const tree = [ - { value: 6, left: 1, right: 2 }, - { value: 5, left: 3, right: 4 }, - { value: 7, left: null, right: 5 }, - { value: 3, left: 6, right: null }, - { value: 4, left: null, right: null }, - { value: 9, left: 7, right: 8 }, - { value: 2, left: 9, right: null }, - { value: 8, left: null, right: null }, - { value: 10, left: null, right: null }, - { value: 1, left: null, right: null } -] -searchDFS(tree, 9) // { value: 9, left: 7, right: 8 } -searchDFS(tree, 200) // null -traverseDFS(tree, 6) // [ 1, 2, 3, 4, 5, 8, 10, 9, 7, 6 ] -traverseDFS(tree, 200) // [] - -// 6 -// / \ -// 5 7 -// / \ \ -// 3 4 9 -// / / \ -// 2 8 10 -// / -// 1 export { searchDFS, traverseDFS } diff --git a/package-lock.json b/package-lock.json index a4efa09c1b..5c38ba06a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -76,13 +76,270 @@ "dev": true, "license": "MIT" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.12", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -91,6 +348,102 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "dev": true, @@ -174,30 +527,214 @@ "node": ">= 8" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", + "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz", + "integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz", + "integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz", + "integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz", + "integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz", + "integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz", + "integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz", + "integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz", + "integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz", + "integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz", + "integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.9.6", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz", + "integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.9.6", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz", + "integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz", + "integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz", + "integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz", + "integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@types/estree": { "version": "1.0.5", "dev": true, @@ -463,11 +1000,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -566,10 +1104,11 @@ } }, "node_modules/esbuild": { - "version": "0.19.12", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -577,29 +1116,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.12", - "@esbuild/android-arm": "0.19.12", - "@esbuild/android-arm64": "0.19.12", - "@esbuild/android-x64": "0.19.12", - "@esbuild/darwin-arm64": "0.19.12", - "@esbuild/darwin-x64": "0.19.12", - "@esbuild/freebsd-arm64": "0.19.12", - "@esbuild/freebsd-x64": "0.19.12", - "@esbuild/linux-arm": "0.19.12", - "@esbuild/linux-arm64": "0.19.12", - "@esbuild/linux-ia32": "0.19.12", - "@esbuild/linux-loong64": "0.19.12", - "@esbuild/linux-mips64el": "0.19.12", - "@esbuild/linux-ppc64": "0.19.12", - "@esbuild/linux-riscv64": "0.19.12", - "@esbuild/linux-s390x": "0.19.12", - "@esbuild/linux-x64": "0.19.12", - "@esbuild/netbsd-x64": "0.19.12", - "@esbuild/openbsd-x64": "0.19.12", - "@esbuild/sunos-x64": "0.19.12", - "@esbuild/win32-arm64": "0.19.12", - "@esbuild/win32-ia32": "0.19.12", - "@esbuild/win32-x64": "0.19.12" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/estree-walker": { @@ -634,9 +1173,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, - "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -649,6 +1189,20 @@ "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/get-func-name": { "version": "2.0.2", "dev": true, @@ -786,8 +1340,9 @@ }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -990,6 +1545,8 @@ }, "node_modules/nanoid": { "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -997,7 +1554,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -1051,9 +1607,10 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "dev": true, - "license": "ISC" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", @@ -1077,7 +1634,9 @@ } }, "node_modules/postcss": { - "version": "8.4.33", + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "dev": true, "funding": [ { @@ -1093,11 +1652,10 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -1151,9 +1709,10 @@ } }, "node_modules/rollup": { - "version": "4.9.6", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", + "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "1.0.5" }, @@ -1165,19 +1724,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.6", - "@rollup/rollup-android-arm64": "4.9.6", - "@rollup/rollup-darwin-arm64": "4.9.6", - "@rollup/rollup-darwin-x64": "4.9.6", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.6", - "@rollup/rollup-linux-arm64-gnu": "4.9.6", - "@rollup/rollup-linux-arm64-musl": "4.9.6", - "@rollup/rollup-linux-riscv64-gnu": "4.9.6", - "@rollup/rollup-linux-x64-gnu": "4.9.6", - "@rollup/rollup-linux-x64-musl": "4.9.6", - "@rollup/rollup-win32-arm64-msvc": "4.9.6", - "@rollup/rollup-win32-ia32-msvc": "4.9.6", - "@rollup/rollup-win32-x64-msvc": "4.9.6", + "@rollup/rollup-android-arm-eabi": "4.22.4", + "@rollup/rollup-android-arm64": "4.22.4", + "@rollup/rollup-darwin-arm64": "4.22.4", + "@rollup/rollup-darwin-x64": "4.22.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.22.4", + "@rollup/rollup-linux-arm-musleabihf": "4.22.4", + "@rollup/rollup-linux-arm64-gnu": "4.22.4", + "@rollup/rollup-linux-arm64-musl": "4.22.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.22.4", + "@rollup/rollup-linux-riscv64-gnu": "4.22.4", + "@rollup/rollup-linux-s390x-gnu": "4.22.4", + "@rollup/rollup-linux-x64-gnu": "4.22.4", + "@rollup/rollup-linux-x64-musl": "4.22.4", + "@rollup/rollup-win32-arm64-msvc": "4.22.4", + "@rollup/rollup-win32-ia32-msvc": "4.22.4", + "@rollup/rollup-win32-x64-msvc": "4.22.4", "fsevents": "~2.3.2" } }, @@ -1236,9 +1798,10 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -1319,8 +1882,9 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -1367,13 +1931,14 @@ "license": "MIT" }, "node_modules/vite": { - "version": "5.0.12", + "version": "5.4.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", + "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", "dev": true, - "license": "MIT", "dependencies": { - "esbuild": "^0.19.3", - "postcss": "^8.4.32", - "rollup": "^4.2.0" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" @@ -1392,6 +1957,7 @@ "less": "*", "lightningcss": "^1.21.0", "sass": "*", + "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -1409,6 +1975,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy