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 59f6273bf2..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) @@ -285,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) @@ -397,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/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 070a8479e3..92f888acea 100644 --- a/Maths/test/GetEuclidGCD.test.js +++ b/Maths/test/GetEuclidGCD.test.js @@ -1,25 +1,22 @@ import { GetEuclidGCD, GetEuclidGCDRecursive } from '../GetEuclidGCD' -describe.each([GetEuclidGCD, GetEuclidGCDRecursive])( - '%# GetEuclidGCD', - (gcdFunction) => { - it.each([ - [5, 20, 5], - [109, 902, 1], - [290, 780, 10], - [104, 156, 52], - [0, 100, 100], - [-5, 50, 5], - [0, 0, 0], - [1, 1234567, 1] - ])('returns correct result for %i and %j', (inputA, inputB, expected) => { - expect(gcdFunction(inputA, inputB)).toBe(expected) - expect(gcdFunction(inputB, inputA)).toBe(expected) - }) +describe.each([GetEuclidGCD, GetEuclidGCDRecursive])('%o', (gcdFunction) => { + it.each([ + [5, 20, 5], + [109, 902, 1], + [290, 780, 10], + [104, 156, 52], + [0, 100, 100], + [-5, 50, 5], + [0, 0, 0], + [1, 1234567, 1] + ])('returns correct result for %i and %j', (inputA, inputB, 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(() => gcdFunction('1', 2)).toThrowError() - expect(() => gcdFunction(1, '2')).toThrowError() - }) - } -) + it('should throw when any of the inputs is not a number', () => { + 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/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 },