From 75ed75e0139ad8aafb90025389f0f96034ca1841 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 17 Nov 2022 19:07:26 +0100 Subject: [PATCH 001/107] chore: upgrade GitHub Actions (#78) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a8f7e02..a84c9fa0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,9 +10,9 @@ jobs: test: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: "16.x" + node-version: "18.x" - run: npm ci - run: npm test From 0b8f3d3ed074e19da64bbbeff4cd6003d44d40a0 Mon Sep 17 00:00:00 2001 From: Yuzuki Arai Date: Mon, 21 Nov 2022 20:20:00 +0900 Subject: [PATCH 002/107] feat: add `parseNestedBrackets` (#79) --- other/parse_nested_brackets.ts | 47 ++++++++++++++++++++++++ other/test/parse_nested_brackets.test.ts | 24 ++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 other/parse_nested_brackets.ts create mode 100644 other/test/parse_nested_brackets.test.ts diff --git a/other/parse_nested_brackets.ts b/other/parse_nested_brackets.ts new file mode 100644 index 00000000..dce1ef37 --- /dev/null +++ b/other/parse_nested_brackets.ts @@ -0,0 +1,47 @@ +/** + * @function parseNestedBrackets + * @description Parse nested brackets algorithm for a string. + * @param {string} text - text to parse + * @param {string} openBrackets - open brackets + * @param {string} closingBrackets - closing brackets + * @returns {string[]} - array of the tags + * @example parseNestedBrackets(`
`) => [ '
', '' ] + * @example parseNestedBrackets( + * `THIS IS SAMPLE TEXT(MAIN hoge 0.1 fuga(ITEM fuga hoge)hoge(ITEM2 nogami(ABBR)))`, + * { openBrackets: '(', closingBrackets: ')' }) => + * [ + '(MAIN hoge 0.1 fuga(ITEM fuga hoge)hoge(ITEM2 nogami(ABBR)))', + '(ITEM fuga hoge)', + '(ITEM2 nogami(ABBR))', + '(ABBR)' + ] + */ + export const parseNestedBrackets = ( + text: string, + openBrackets = "<", + closingBrackets = ">" + ) => { + let array: string[] = []; // The array of the tags in this present floor. + let prFloor = 0; // The present floor. + let begin = 0, // The begin index of the tag. + end = 0; // The end index of the tag. + for (let i = 0; i < text.length; i++) { + if (text[i] === openBrackets) { + prFloor++; + if (prFloor === 1) begin = i; + } else if (text[i] === closingBrackets) { + if (prFloor === 1) { + end = i; + const tag = text.slice(begin + 1, end); + // push the tag in this present floor. + array.push(`${openBrackets}${tag}${closingBrackets}`); + // push the array of the tags in the next floor. + array = array.concat( + parseNestedBrackets(tag, openBrackets, closingBrackets) + ); + } + prFloor--; + } + } + return array; + }; diff --git a/other/test/parse_nested_brackets.test.ts b/other/test/parse_nested_brackets.test.ts new file mode 100644 index 00000000..751e8651 --- /dev/null +++ b/other/test/parse_nested_brackets.test.ts @@ -0,0 +1,24 @@ +import { parseNestedBrackets } from "../parse_nested_brackets"; + +describe("parseNestedBrackets", () => { + it("should return an array of the tags", () => { + expect(parseNestedBrackets("
")).toEqual([ + "
", + "", + ]); + }); + it("should return an array of the tags (nested)", () => { + expect( + parseNestedBrackets( + `THIS IS SAMPLE TEXT(MAIN hoge 0.1 fuga(ITEM fuga hoge)hoge(ITEM2 nogami(ABBR)))`, + "(", + ")" + ) + ).toEqual([ + "(MAIN hoge 0.1 fuga(ITEM fuga hoge)hoge(ITEM2 nogami(ABBR)))", + "(ITEM fuga hoge)", + "(ITEM2 nogami(ABBR))", + "(ABBR)", + ]); + }); +}); From d097f69d18100348e4e0d1d27f56116e858c81cc Mon Sep 17 00:00:00 2001 From: Defective Detective <71999854+SpiderMath@users.noreply.github.com> Date: Thu, 1 Dec 2022 23:42:09 +0530 Subject: [PATCH 003/107] feat: Add hexagonal numbers (#80) --- DIRECTORY.md | 67 ++++++++++++--------- maths/series/hexagonal_numbers.ts | 27 +++++++++ maths/series/test/hexagonal_numbers.test.ts | 15 +++++ 3 files changed, 80 insertions(+), 29 deletions(-) create mode 100644 maths/series/hexagonal_numbers.ts create mode 100644 maths/series/test/hexagonal_numbers.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 53d56eaf..1d94594b 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -1,41 +1,50 @@ ## Ciphers - * [Xor Cipher](https://github.com/TheAlgorithms/TypeScript/blob/master/ciphers/xor_cipher.ts) + * [Xor Cipher](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/ciphers/xor_cipher.ts) ## Data Structures - * [Stack](https://github.com/TheAlgorithms/TypeScript/blob/master/data_structures/stack.ts) + * [Stack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack.ts) ## Dynamic Programming - * [Knapsack](https://github.com/TheAlgorithms/TypeScript/blob/master/dynamic_programming/knapsack.ts) + * [Knapsack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/knapsack.ts) ## Maths - * [Absolute Value](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/absolute_value.ts) - * [Aliquot Sum](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/aliquot_sum.ts) - * [Armstrong Number](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/armstrong_number.ts) - * [Binary Convert](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/binary_convert.ts) - * [Calculate Mean](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/calculate_mean.ts) - * [Degrees To Radians](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/degrees_to_radians.ts) - * [Digit Sum](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/digit_sum.ts) - * [Factorial](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/factorial.ts) - * [Fibonacci](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/fibonacci.ts) - * [Find Min](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/find_min.ts) - * [Greatest Common Factor](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/greatest_common_factor.ts) - * [Is Divisible](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/is_divisible.ts) - * [Is Even](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/is_even.ts) - * [Is Leap Year](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/is_leap_year.ts) - * [Is Odd](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/is_odd.ts) - * [Lowest Common Multiple](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/lowest_common_multiple.ts) - * [Perfect Square](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/perfect_square.ts) - * [Radians To Degrees](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/radians_to_degrees.ts) - * [Sieve Of Eratosthenes](https://github.com/TheAlgorithms/TypeScript/blob/master/maths/sieve_of_eratosthenes.ts) + * [Absolute Value](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/absolute_value.ts) + * [Aliquot Sum](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/aliquot_sum.ts) + * [Armstrong Number](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/armstrong_number.ts) + * [Binary Convert](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/binary_convert.ts) + * [Calculate Mean](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/calculate_mean.ts) + * [Degrees To Radians](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/degrees_to_radians.ts) + * [Digit Sum](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/digit_sum.ts) + * [Factorial](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/factorial.ts) + * [Fibonacci](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/fibonacci.ts) + * [Find Min](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/find_min.ts) + * [Greatest Common Factor](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/greatest_common_factor.ts) + * [Is Divisible](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_divisible.ts) + * [Is Even](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_even.ts) + * [Is Leap Year](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_leap_year.ts) + * [Is Odd](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_odd.ts) + * [Lowest Common Multiple](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/lowest_common_multiple.ts) + * [Perfect Square](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_square.ts) + * [Radians To Degrees](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/radians_to_degrees.ts) + * Series + * [Hexagonal Numbers](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/series/hexagonal_numbers.ts) + * Test + * [Hexagonal Numbers.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/series/test/hexagonal_numbers.test.ts) + * [Sieve Of Eratosthenes](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/sieve_of_eratosthenes.ts) + +## Other + * [Parse Nested Brackets](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/other/parse_nested_brackets.ts) + * Test + * [Parse Nested Brackets.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/other/test/parse_nested_brackets.test.ts) ## Search - * [Binary Search](https://github.com/TheAlgorithms/TypeScript/blob/master/search/binary_search.ts) - * [Linear Search](https://github.com/TheAlgorithms/TypeScript/blob/master/search/linear_search.ts) + * [Binary Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/binary_search.ts) + * [Linear Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/linear_search.ts) ## Sorts - * [Bubble Sort](https://github.com/TheAlgorithms/TypeScript/blob/master/sorts/bubble_sort.ts) - * [Gnome Sort](https://github.com/TheAlgorithms/TypeScript/blob/master/sorts/gnome_sort.ts) - * [Insertion Sort](https://github.com/TheAlgorithms/TypeScript/blob/master/sorts/insertion_sort.ts) - * [Merge Sort](https://github.com/TheAlgorithms/TypeScript/blob/master/sorts/merge_sort.ts) - * [Quick Sort](https://github.com/TheAlgorithms/TypeScript/blob/master/sorts/quick_sort.ts) + * [Bubble Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/bubble_sort.ts) + * [Gnome Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/gnome_sort.ts) + * [Insertion Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/insertion_sort.ts) + * [Merge Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/merge_sort.ts) + * [Quick Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/quick_sort.ts) diff --git a/maths/series/hexagonal_numbers.ts b/maths/series/hexagonal_numbers.ts new file mode 100644 index 00000000..d0856fc2 --- /dev/null +++ b/maths/series/hexagonal_numbers.ts @@ -0,0 +1,27 @@ +/** + * @function HexagonalNumbers + * @description To generate the requested number of hexagonal numbers + * @summary A hexagonal number, hₙ, is a figurate number which represents the number + * of distinct dots in a pattern of dots consisting of the outlines of regular + * hexagons with sides upto 'n' dots, when the hexagons are overlaid so that they share a common vertex + * + * The nth hexagonal number, hₙ, is calculated by the formula: + * hₙ = n * (2n - 1) + * @see [Wikipedia](https://en.wikipedia.org/wiki/Hexagonal_number) + * @see [OEIS](https://oeis.org/A000384) + * @param {number} n - The number of Hexagonal numbers to generate + * @returns {number[]} - An array containing first 'n' hexagonal numbers + * @example HexagonalNumbers(10) = [ 1, 6, 15, 28, 45, 66, 91, 120, 153, 190 ] + * @example HexagonalNumbers(15) = [ 1, 6, 15, 28, 45, 66, 91, 120, 153, 190, 231, 276, 325, 378, 435 ] + */ +export const HexagonalNumbers = (n: number): number[] => { + if (isNaN(n)) throw new Error('The input needs to be a number') + if (!Number.isInteger(n) || n < 0) throw new Error('The input needs to be a non-negative integer') + const hexagonalNumbers = [] + + for (let i = 1; i <= n; i++) { + hexagonalNumbers.push(i * (2 * i - 1)) + } + + return hexagonalNumbers +} diff --git a/maths/series/test/hexagonal_numbers.test.ts b/maths/series/test/hexagonal_numbers.test.ts new file mode 100644 index 00000000..f06467f9 --- /dev/null +++ b/maths/series/test/hexagonal_numbers.test.ts @@ -0,0 +1,15 @@ +import { HexagonalNumbers } from "../hexagonal_numbers"; + +describe("HexagonalNumbers", () => { + it("should return the first 10 hexagonal numbers", () => { + expect(HexagonalNumbers(10)).toStrictEqual([1, 6, 15, 28, 45, 66, 91, 120, 153, 190]); + }) + + it("should return the first 5 hexagonal numbers", () => { + expect(HexagonalNumbers(5)).toStrictEqual([1, 6, 15, 28, 45]) + }) + + it("should return zero hexagonal numbers", () => { + expect(HexagonalNumbers(0)).toStrictEqual([]) + }) +}) From 03244a2e26ffdfd4abe2abbcc1948698e50315c1 Mon Sep 17 00:00:00 2001 From: Defective Detective <71999854+SpiderMath@users.noreply.github.com> Date: Thu, 8 Dec 2022 18:53:20 +0530 Subject: [PATCH 004/107] feat: Added signum (#81) --- DIRECTORY.md | 1 + maths/signum.ts | 22 ++++++++++++++++++++++ maths/test/signum.test.ts | 5 +++++ 3 files changed, 28 insertions(+) create mode 100644 maths/signum.ts create mode 100644 maths/test/signum.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 1d94594b..6ad6b372 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -32,6 +32,7 @@ * Test * [Hexagonal Numbers.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/series/test/hexagonal_numbers.test.ts) * [Sieve Of Eratosthenes](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/sieve_of_eratosthenes.ts) + * [Signum](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/signum.ts) ## Other * [Parse Nested Brackets](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/other/parse_nested_brackets.ts) diff --git a/maths/signum.ts b/maths/signum.ts new file mode 100644 index 00000000..d712c149 --- /dev/null +++ b/maths/signum.ts @@ -0,0 +1,22 @@ +/** + * @function Signum + * @description Returns the sign of a number + * @summary The signum function is an odd mathematical function, which returns the + * sign of the provided real number. + * It can return 3 values: 1 for values greater than zero, 0 for zero itself, + * and -1 for values less than zero + * @param {Number} input + * @returns {-1 | 0 | 1 | NaN} sign of input (and NaN if the input is not a number) + * @see [Wikipedia](https://en.wikipedia.org/wiki/Sign_function) + * @example Signum(10) = 1 + * @example Signum(0) = 0 + * @example Signum(-69) = -1 + * @example Signum("hello world") = NaN + */ +export const Signum = (num: number) => { + if (num === 0) return 0 + if (num > 0) return 1 + if (num < 0) return -1 + + return NaN +} diff --git a/maths/test/signum.test.ts b/maths/test/signum.test.ts new file mode 100644 index 00000000..2764ca9c --- /dev/null +++ b/maths/test/signum.test.ts @@ -0,0 +1,5 @@ +import { Signum } from "../signum"; + +test.each([[10, 1], [0, 0], [-69, -1], [NaN, NaN]])("The sign of %i is %i", (num, expected) => { + expect(Signum(num)).toBe(expected) +}) From ca4cf6d9fce1f05b8278d8d6cae03bff597c43da Mon Sep 17 00:00:00 2001 From: Defective Detective <71999854+SpiderMath@users.noreply.github.com> Date: Tue, 13 Dec 2022 18:29:24 +0530 Subject: [PATCH 005/107] algorithm: pronic number (#82) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added implementation for Pronic Number 😁 * Update DIRECTORY.md Co-authored-by: autoprettier --- DIRECTORY.md | 1 + maths/pronic_number.ts | 24 ++++++++++++++++++++++++ maths/test/pronic_number.test.ts | 5 +++++ 3 files changed, 30 insertions(+) create mode 100644 maths/pronic_number.ts create mode 100644 maths/test/pronic_number.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 6ad6b372..731d3433 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -26,6 +26,7 @@ * [Is Odd](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_odd.ts) * [Lowest Common Multiple](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/lowest_common_multiple.ts) * [Perfect Square](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_square.ts) + * [Pronic Number](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/pronic_number.ts) * [Radians To Degrees](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/radians_to_degrees.ts) * Series * [Hexagonal Numbers](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/series/hexagonal_numbers.ts) diff --git a/maths/pronic_number.ts b/maths/pronic_number.ts new file mode 100644 index 00000000..3709c6b5 --- /dev/null +++ b/maths/pronic_number.ts @@ -0,0 +1,24 @@ +/** + * @function PronicNumber + * @description Checks whether a given number is a pronic number or not + * @summary Pronic numbers, or oblong numbers as they are often referred to as, + * are numbers which are the product of two consecutive integers. That is, + * they are numbers of the form n*(n+1) + * + * For example, 20 is a pronic number since 20 = 4 * 5 + * @param num The number to check for being pronic + * @returns {boolean} Whether the number is pronic or not + * @see [Wikipedia](https://en.wikipedia.org/wiki/Pronic_number) + * @example PronicNumber(20) = true + * @example PronicNumber(30) = true + * @example PronicNumber(49) = false + */ +const PronicNumber = (n: number) => { + if (isNaN(n)) throw new Error('The input needs to be a number') + if (!Number.isInteger(n) || n < 0) throw new Error('The input needs to be a non-negative integer') + if (n === 0) return true + + return !Number.isInteger(Math.sqrt(n)) && Math.floor(Math.sqrt(n)) * Math.ceil(Math.sqrt(n)) === n +} + +export { PronicNumber } diff --git a/maths/test/pronic_number.test.ts b/maths/test/pronic_number.test.ts new file mode 100644 index 00000000..80b5a1fc --- /dev/null +++ b/maths/test/pronic_number.test.ts @@ -0,0 +1,5 @@ +import { PronicNumber } from '../pronic_number' + +test.each([[0, true], [10, false], [30, true], [69, false], [420, true]])('Pronic Number', (number, result) => { + expect(PronicNumber(number)).toBe(result) +}) From 6f3ea82e2f3500cefbff5454442c66ff38aea89d Mon Sep 17 00:00:00 2001 From: Defective Detective <71999854+SpiderMath@users.noreply.github.com> Date: Thu, 15 Dec 2022 21:21:09 +0530 Subject: [PATCH 006/107] algorithm: Added Hamming Distance (#83) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added hamming distance algorithm implementation🐹 * Fixed some style issues * Update DIRECTORY.md Co-authored-by: autoprettier --- DIRECTORY.md | 1 + maths/hamming_distance.ts | 25 +++++++++++++++++++++++++ maths/test/hamming_distance.test.ts | 5 +++++ 3 files changed, 31 insertions(+) create mode 100644 maths/hamming_distance.ts create mode 100644 maths/test/hamming_distance.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 731d3433..71d04f08 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -20,6 +20,7 @@ * [Fibonacci](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/fibonacci.ts) * [Find Min](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/find_min.ts) * [Greatest Common Factor](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/greatest_common_factor.ts) + * [Hamming Distance](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/hamming_distance.ts) * [Is Divisible](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_divisible.ts) * [Is Even](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_even.ts) * [Is Leap Year](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_leap_year.ts) diff --git a/maths/hamming_distance.ts b/maths/hamming_distance.ts new file mode 100644 index 00000000..a7eac5be --- /dev/null +++ b/maths/hamming_distance.ts @@ -0,0 +1,25 @@ +/** + * @function HammingDistance + * @description Returns the Hamming distance between two strings of equal length + * @summary The Hamming distance between two strings of equal length is the + * number of positions at which the corresponding symbols are different. In other words, + * it measures the minimum number of substitutions required, to change one string to the other + * It is one of the several sring metrics, used fror measuring the edit distance between two sequences + * and is named after the American mathematician Richard Hamming + * @param str1 One of the strings to compare to the other + * @param str2 One of the strings to compare to the other + * @returns {number} + * @see [Wikipedia](https://en.wikipedia.org/wiki/Hamming_distance) + * @example HammingDistance('happy', 'homie') + */ +const HammingDistance = (str1: string, str2: string) => { + if (str1.length !== str2.length) throw new Error('Strings must of the same length.') + + let dist = 0 + + for (let i = 0; i < str1.length; i++) if (str1[i] !== str2[i]) dist++ + + return dist +} + +export { HammingDistance } diff --git a/maths/test/hamming_distance.test.ts b/maths/test/hamming_distance.test.ts new file mode 100644 index 00000000..64641172 --- /dev/null +++ b/maths/test/hamming_distance.test.ts @@ -0,0 +1,5 @@ +import { HammingDistance } from "../hamming_distance" + +test.each([['happy', 'homie', 4], ['hole', 'home', 1], ['cathrine', 'caroline', 3], ['happiness', 'dizziness', 4]])('Hamming Distance', (str1, str2, result) => { + expect(HammingDistance(str1, str2)).toBe(result) +}) From 55cd754f28760f57b852dfe7f033f832f8bc5088 Mon Sep 17 00:00:00 2001 From: Noah <70114451+zFl4wless@users.noreply.github.com> Date: Wed, 28 Dec 2022 22:45:17 +0100 Subject: [PATCH 007/107] structure: queue (#84) * feat: implements the data structure queue * fix: resolves requested changes - The removed element is now returned in `dequeue()` - Files have been renamed - Time complexity note has been added - Adjusted tests accordingly --- data_structures/array_queue.ts | 63 ++++++++++++++++++++++++ data_structures/test/array_queue.test.ts | 60 ++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 data_structures/array_queue.ts create mode 100644 data_structures/test/array_queue.test.ts diff --git a/data_structures/array_queue.ts b/data_structures/array_queue.ts new file mode 100644 index 00000000..242c64d3 --- /dev/null +++ b/data_structures/array_queue.ts @@ -0,0 +1,63 @@ +/** + * This is an array-based implementation of a Queue. + * A Queue is a data structure that follows the FIFO (First In First Out) principle. + * It means that the first element that was added to the queue will be the first one to be removed. + * The time complexity of the operations is O(n). + */ +export class ArrayQueue { + private queue: T[] = []; + + /** + * Returns the number of items in the queue. + * + * @returns {number} The number of items in the queue. + */ + length(): number { + return this.queue.length; + } + + /** + * Checks if the queue is empty. + * + * @returns {boolean} Whether the queue is empty or not. + */ + isEmpty(): boolean { + return this.queue.length === 0; + } + + /** + * Adds an item to the queue. + * + * @param item The item being added to the queue. + */ + enqueue(item: T): void { + this.queue.push(item); + } + + /** + * Removes an item from the queue and returns it. + * + * @throws Queue Underflow if the queue is empty. + * @returns The item that was removed from the queue. + */ + dequeue(): T { + if (this.isEmpty()) { + throw new Error("Queue Underflow"); + } + + return this.queue.shift() as T; + } + + /** + * Returns the item at the front of the queue. + * + * @returns The item at the front of the queue or null if the queue is empty. + */ + front(): T | null { + if (this.isEmpty()) { + return null; + } + + return this.queue[0]; + } +} diff --git a/data_structures/test/array_queue.test.ts b/data_structures/test/array_queue.test.ts new file mode 100644 index 00000000..34c74fd5 --- /dev/null +++ b/data_structures/test/array_queue.test.ts @@ -0,0 +1,60 @@ +import { ArrayQueue } from "../array_queue"; + +describe("Testing Queue data structure", () => { + it("enqueue should add a new element to the queue", () => { + const queue = new ArrayQueue(); + queue.enqueue(1); + + expect(queue.length()).toBe(1); + }); + + it("isEmpty should return true on empty queue", () => { + const queue = new ArrayQueue(); + expect(queue.isEmpty()).toBeTruthy(); + }); + + it("isEmpty should return false on not empty queue", () => { + const queue = new ArrayQueue(); + queue.enqueue(1); + + expect(queue.isEmpty()).toBeFalsy(); + }); + + it("front should return the first value", () => { + const queue = new ArrayQueue(); + queue.enqueue(1); + + expect(queue.front()).toBe(1); + }); + + it("front should return null when the queue is empty", () => { + const queue = new ArrayQueue(); + + expect(queue.front()).toBe(null); + }); + + it("length should return the number of elements in the queue", () => { + const queue = new ArrayQueue(); + queue.enqueue(1); + queue.enqueue(1); + queue.enqueue(1); + + expect(queue.length()).toBe(3); + }); + + it("dequeue should remove the first element", () => { + const queue = new ArrayQueue(); + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + queue.dequeue(); + + expect(queue.length()).toBe(2); + }); + + it("dequeue should throw error on empty queue", () => { + const queue = new ArrayQueue(); + + expect(() => queue.dequeue()).toThrow("Queue Underflow"); + }); +}); From a97a3b25f138cd39ed7654de3fd0e09f006384be Mon Sep 17 00:00:00 2001 From: Cobby Date: Thu, 5 Jan 2023 06:20:55 +0000 Subject: [PATCH 008/107] docs: add missing algorithm in `DIRECTORY.md} (#86) --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 71d04f08..2e003e91 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -4,6 +4,7 @@ ## Data Structures * [Stack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack.ts) + * [Array Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/array_queue.ts) ## Dynamic Programming * [Knapsack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/knapsack.ts) From 124890c73e5cb188d13d26a2c619c160364d982e Mon Sep 17 00:00:00 2001 From: Cobby Date: Sun, 8 Jan 2023 14:07:27 +0000 Subject: [PATCH 009/107] feat: add Linked Queue (#88) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add Array Queue to Directory.md * feat: add linkedlist Queue * feat: add test for linkedlist queue * feat: update Directory.md * fixed typos and formatting * BREAKING CHANGE: change front to peek * fix: added the queue interface * fix: duplication of queue interface and minor bug * fix: queue test problem * fix: change filename to match naming convention * fix: leading newline and time complexity * feat: add jsDoc comments * Rename Queue.test.ts to queue.test.ts * Update queue.test.ts * Update array_queue.test.ts * Update and rename linkedlist_queue.test.ts to linked_queue.test.ts * Update and rename linkedlist_queue.ts to linked_queue.ts * Update linked_queue.test.ts * Update linked_queue.test.ts * Rename queue.test.ts to queue.ts * Update array_queue.test.ts * Update linked_queue.test.ts Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- DIRECTORY.md | 1 + data_structures/array_queue.ts | 5 +- data_structures/linked_queue.ts | 95 +++++++++++++++++++++++ data_structures/queue.ts | 7 ++ data_structures/test/array_queue.test.ts | 60 +------------- data_structures/test/linked_queue.test.ts | 4 + data_structures/test/queue.ts | 53 +++++++++++++ 7 files changed, 165 insertions(+), 60 deletions(-) create mode 100644 data_structures/linked_queue.ts create mode 100644 data_structures/queue.ts create mode 100644 data_structures/test/linked_queue.test.ts create mode 100644 data_structures/test/queue.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 2e003e91..b96d789d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -5,6 +5,7 @@ ## Data Structures * [Stack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack.ts) * [Array Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/array_queue.ts) + * [Linkedlist Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/linkedlist_queue.ts) ## Dynamic Programming * [Knapsack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/knapsack.ts) diff --git a/data_structures/array_queue.ts b/data_structures/array_queue.ts index 242c64d3..19027768 100644 --- a/data_structures/array_queue.ts +++ b/data_structures/array_queue.ts @@ -4,7 +4,8 @@ * It means that the first element that was added to the queue will be the first one to be removed. * The time complexity of the operations is O(n). */ -export class ArrayQueue { +import { Queue } from './queue' +export class ArrayQueue implements Queue{ private queue: T[] = []; /** @@ -53,7 +54,7 @@ export class ArrayQueue { * * @returns The item at the front of the queue or null if the queue is empty. */ - front(): T | null { + peek(): T | null { if (this.isEmpty()) { return null; } diff --git a/data_structures/linked_queue.ts b/data_structures/linked_queue.ts new file mode 100644 index 00000000..c67c8285 --- /dev/null +++ b/data_structures/linked_queue.ts @@ -0,0 +1,95 @@ +import { Queue } from "./queue"; + +type Node = { + value: T, + next?: Node, +} + +/** + * This is a LinkedList-like implementation of a Queue, + * allowing the operations to be implemented in constant time. + * A Queue is a data structure that follows the FIFO (First-In First-Out) principle: + * The first element that was added to the queue will be the first one to be removed. + */ +export class LinkedQueue implements Queue { + + public size: number; + public head?: Node; + private tail?: Node; + + constructor() { + this.head = this.tail = undefined; + this.size = 0; + } + + /** + * Adds an item to the queue. + * + * @param item The item being added to the queue. + */ + enqueue(item: T): void { + const node = { value: item } as Node; // Creates a new node + this.size++ // Increase the length of the Queue + + + if (!this.tail) { + this.tail = this.head = node; + return; + } + this.tail.next = node; // Updates the next tail to the node created + this.tail = node; // The tail of the Queue then becomes the node created!! + + } + + + /** + * Removes an item from the queue and returns it. + * + * @throws Queue Underflow if the queue is empty. + * @returns The item that was removed from the queue. + */ + dequeue(): T | undefined { + + if (!this.head) { + throw new Error("Queue Underflow"); + } + + this.size--; + let head = this.head; // We store the head in order not to lose track of it + this.head = this.head.next; // Update the the head to the next node + return head.value; // Return the value of the head + } + + + /** + * Returns the item at the front of the queue. + * + * @returns The item at the front of the queue or null if the queue is empty. + */ + peek(): T | undefined | null { + + if (this.isEmpty()) { + return null; + } + return this.head?.value; + } + + /** + * Checks if the queue is empty. + * + * @returns {boolean} Whether the queue is empty or not. + */ + isEmpty(): boolean { + return this.size === 0 + } + + /** + * Returns the number of items in the queue. + * + * @returns {number} The number of items in the queue. + */ + length(): number { + return this.size; + } +} + diff --git a/data_structures/queue.ts b/data_structures/queue.ts new file mode 100644 index 00000000..81b3c61f --- /dev/null +++ b/data_structures/queue.ts @@ -0,0 +1,7 @@ +export interface Queue { + enqueue(item: T): void + dequeue(): T | undefined + peek(): T | undefined | null + isEmpty(): boolean + length(): number +} \ No newline at end of file diff --git a/data_structures/test/array_queue.test.ts b/data_structures/test/array_queue.test.ts index 34c74fd5..9bc6f48f 100644 --- a/data_structures/test/array_queue.test.ts +++ b/data_structures/test/array_queue.test.ts @@ -1,60 +1,4 @@ import { ArrayQueue } from "../array_queue"; +import { testQueue } from './queue' -describe("Testing Queue data structure", () => { - it("enqueue should add a new element to the queue", () => { - const queue = new ArrayQueue(); - queue.enqueue(1); - - expect(queue.length()).toBe(1); - }); - - it("isEmpty should return true on empty queue", () => { - const queue = new ArrayQueue(); - expect(queue.isEmpty()).toBeTruthy(); - }); - - it("isEmpty should return false on not empty queue", () => { - const queue = new ArrayQueue(); - queue.enqueue(1); - - expect(queue.isEmpty()).toBeFalsy(); - }); - - it("front should return the first value", () => { - const queue = new ArrayQueue(); - queue.enqueue(1); - - expect(queue.front()).toBe(1); - }); - - it("front should return null when the queue is empty", () => { - const queue = new ArrayQueue(); - - expect(queue.front()).toBe(null); - }); - - it("length should return the number of elements in the queue", () => { - const queue = new ArrayQueue(); - queue.enqueue(1); - queue.enqueue(1); - queue.enqueue(1); - - expect(queue.length()).toBe(3); - }); - - it("dequeue should remove the first element", () => { - const queue = new ArrayQueue(); - queue.enqueue(1); - queue.enqueue(2); - queue.enqueue(3); - queue.dequeue(); - - expect(queue.length()).toBe(2); - }); - - it("dequeue should throw error on empty queue", () => { - const queue = new ArrayQueue(); - - expect(() => queue.dequeue()).toThrow("Queue Underflow"); - }); -}); +describe("Array Queue", () => testQueue(ArrayQueue)); diff --git a/data_structures/test/linked_queue.test.ts b/data_structures/test/linked_queue.test.ts new file mode 100644 index 00000000..408c1aa7 --- /dev/null +++ b/data_structures/test/linked_queue.test.ts @@ -0,0 +1,4 @@ +import { testQueue } from './queue' +import { LinkedQueue } from '../linked_queue'; + +describe("Linked Queue", () => testQueue(LinkedQueue)); diff --git a/data_structures/test/queue.ts b/data_structures/test/queue.ts new file mode 100644 index 00000000..1dc7eaec --- /dev/null +++ b/data_structures/test/queue.ts @@ -0,0 +1,53 @@ +import { Queue } from '../queue'; +type QueueConstructor = new () => Queue +export function testQueue(Queue: QueueConstructor) { + it("enqueue should add a new element to the queue", () => { + const queue = new Queue(); + queue.enqueue(1); + expect(queue.length()).toBe(1); + }); + + it("isEmpty should return true on empty queue", () => { + const queue = new Queue(); + expect(queue.isEmpty()).toBeTruthy(); + }); + + it("isEmpty should return false on not empty queue", () => { + const queue = new Queue(); + queue.enqueue(1); + expect(queue.isEmpty()).toBeFalsy(); + }); + + it("front should return the first value", () => { + const queue = new Queue(); + queue.enqueue(1); + expect(queue.peek()).toBe(1); + }); + + it("front should return null when the queue is empty", () => { + const queue = new Queue(); + expect(queue.peek()).toBe(null); + }); + + it("length should return the number of elements in the queue", () => { + const queue = new Queue(); + queue.enqueue(1); + queue.enqueue(1); + queue.enqueue(1); + expect(queue.length()).toBe(3); + }); + + it("dequeue should remove the first element", () => { + const queue = new Queue(); + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + queue.dequeue(); + expect(queue.length()).toBe(2); + }); + + it("dequeue should throw error on empty queue", () => { + const queue = new Queue(); + expect(() => queue.dequeue()).toThrow("Queue Underflow"); + }); +} From da6b1a9dfafb7f30a0ecb1600e619b2d986a1b10 Mon Sep 17 00:00:00 2001 From: Ajesh DS Date: Tue, 10 Jan 2023 22:35:18 +0530 Subject: [PATCH 010/107] feat: add queue implementation using two stacks (#89) --- data_structures/stack_queue.ts | 92 ++++++++++++++++++++++++ data_structures/test/stack_queue.test.ts | 4 ++ 2 files changed, 96 insertions(+) create mode 100644 data_structures/stack_queue.ts create mode 100644 data_structures/test/stack_queue.test.ts diff --git a/data_structures/stack_queue.ts b/data_structures/stack_queue.ts new file mode 100644 index 00000000..cd27a391 --- /dev/null +++ b/data_structures/stack_queue.ts @@ -0,0 +1,92 @@ +/** + * A Stack Based Queue Implementation. + * The Queue data structure which follows the FIFO (First in First Out) rule. + * The dequeue operation in a normal stack based queue would be o(n), as the entire has to be shifted + * With the help of two stacks, the time complexity of this can be brought down to amortized-O(1). + * Here, one stack acts as an Enqueue stack where elements are added. + * The other stack acts as a dequeue stack which helps in dequeuing the elements + */ + +import { Queue } from './queue'; +import { Stack } from './stack'; + +export class StackQueue implements Queue{ + + private enqueueStack: Stack = new Stack(); + private dequeueStack: Stack = new Stack(); + + /** + * Returns the length of the Queue + * + * @returns {number} the length of the Queue + */ + length(): number { + return this.enqueueStack.length() + this.dequeueStack.length(); + } + + /** + * Checks if the queue is empty. + * + * @returns {boolean} Whether the queue is empty or not. + */ + isEmpty(): boolean { + return this.enqueueStack.isEmpty() && this.dequeueStack.isEmpty(); + } + + /** + * Adds an item to the queue. + * We always add a new item to the enqueueStack. + * @param item The item being added to the queue. + */ + enqueue(item: T): void { + this.enqueueStack.push(item); + } + + /** + * Shifts the elements from the enqueueStack to the dequeueStack + * In the worst case, all the elements from the enqueue stack needs to shifted, which needs O(n) time. + * However, after the shift, elements can de dequeued at O(1). + * This helps in dequeuing the elements in amortized O(1) time. + */ + private shift(): void { + while (!this.enqueueStack.isEmpty()) { + const enqueueStackTop = this.enqueueStack.pop(); + this.dequeueStack.push(enqueueStackTop); + } + } + + /** + * Removes an item from the queue and returns it. + * + * @throws Queue Underflow if the queue is empty. + * @returns The item that was removed from the queue. + */ + dequeue(): T { + if (this.isEmpty()) { + throw new Error("Queue Underflow"); + } + + if (this.dequeueStack.isEmpty()) { + this.shift(); + } + + return this.dequeueStack.pop(); + } + + /** + * Returns the item at the front of the queue. + * + * @returns The item at the front of the queue or null if the queue is empty. + */ + peek(): T | null { + if (this.isEmpty()) { + return null; + } + + if (this.dequeueStack.isEmpty()) { + this.shift(); + } + + return this.dequeueStack.top(); + } +} diff --git a/data_structures/test/stack_queue.test.ts b/data_structures/test/stack_queue.test.ts new file mode 100644 index 00000000..ab8240bf --- /dev/null +++ b/data_structures/test/stack_queue.test.ts @@ -0,0 +1,4 @@ +import { testQueue } from './queue'; +import { StackQueue } from '../stack_queue'; + +describe("Stack Based Queue", () => testQueue(StackQueue)); \ No newline at end of file From c609dab416160c76e2abd4f752d02ae60c397979 Mon Sep 17 00:00:00 2001 From: Cobby Date: Wed, 11 Jan 2023 07:00:45 +0000 Subject: [PATCH 011/107] feat: add Convential Commits link to Contribution Guidelines (#91) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e81cefe3..920486e7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,7 +62,7 @@ should add unique value. #### Commit Messages Formatting -- Prefer to use the following format: `: `. If necessary, put any extra information in the description. +- Prefer to use the [Conventional Commits](https://www.conventionalcommits.org/) format: `: `. If necessary, put any extra information in the description. - Commit types include (but are not limited to): - **docs**: Documentation only changes - **feat**: A new feature From b1ac5d67669073ce378e4904faca97145bf30bd1 Mon Sep 17 00:00:00 2001 From: Mohd Faisal Date: Fri, 27 Jan 2023 15:53:01 +0530 Subject: [PATCH 012/107] feat: Function to check a number is Square free (#94) * Update DIRECTORY.md * feat: Function to check a number is Square free * Update DIRECTORY.md Co-authored-by: autoprettier --- DIRECTORY.md | 7 +++++-- maths/is_square_free.ts | 24 ++++++++++++++++++++++++ maths/test/is_square_free.test.ts | 11 +++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 maths/is_square_free.ts create mode 100644 maths/test/is_square_free.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index b96d789d..3f34cc78 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -3,9 +3,11 @@ * [Xor Cipher](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/ciphers/xor_cipher.ts) ## Data Structures - * [Stack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack.ts) * [Array Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/array_queue.ts) - * [Linkedlist Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/linkedlist_queue.ts) + * [Linked Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/linked_queue.ts) + * [Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue.ts) + * [Stack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack.ts) + * [Stack Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack_queue.ts) ## Dynamic Programming * [Knapsack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/knapsack.ts) @@ -27,6 +29,7 @@ * [Is Even](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_even.ts) * [Is Leap Year](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_leap_year.ts) * [Is Odd](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_odd.ts) + * [Is Square Free](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_square_free.ts) * [Lowest Common Multiple](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/lowest_common_multiple.ts) * [Perfect Square](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_square.ts) * [Pronic Number](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/pronic_number.ts) diff --git a/maths/is_square_free.ts b/maths/is_square_free.ts new file mode 100644 index 00000000..0e55ab7f --- /dev/null +++ b/maths/is_square_free.ts @@ -0,0 +1,24 @@ +/** + * @function isSquareFree + * @description A number is said to be square-free if no prime factor divides it more than once, i.e., the largest power of a prime factor that divides n is one. + * @param {number} n - A number. + * @return {boolean} - True if given number is a square free. + * @see https://www.geeksforgeeks.org/square-free-number/ + * @example isSquareFree(10) = true + * @example isSquareFree(20) = false + */ + +export const isSquareFree = (n: number): boolean => { + + if (n < 0) throw new Error("number must be a natural number > 0"); + if (n % 2 === 0) n = n / 2; + if (n % 2 === 0) return false; + + for (let i: number = 3; i < Math.sqrt(n); i = i + 2) { + if (n % i === 0) { + n = n / i; + if (n % i === 0) return false; + } + } + return true; +} \ No newline at end of file diff --git a/maths/test/is_square_free.test.ts b/maths/test/is_square_free.test.ts new file mode 100644 index 00000000..bbb16991 --- /dev/null +++ b/maths/test/is_square_free.test.ts @@ -0,0 +1,11 @@ +import { isSquareFree } from '../is_square_free'; + +describe('isSquareFree', () => { + test('should return correct boolean value', () => { + expect(isSquareFree(1)).toBe(true); + expect(isSquareFree(10)).toBe(true); + expect(isSquareFree(20)).toBe(false); + expect(isSquareFree(26)).toBe(true); + expect(isSquareFree(48)).toBe(false); + }); +}); \ No newline at end of file From 9bec2679a7a73b863f09f99bae5bc8cffe834ca9 Mon Sep 17 00:00:00 2001 From: Muhammad Awais <75579534+Awais-019@users.noreply.github.com> Date: Fri, 3 Feb 2023 15:27:33 +0500 Subject: [PATCH 013/107] feat: add selection sort. closes #95 (#96) --- sorts/selection_sort.ts | 33 +++++++++++++++++++++++++++++++ sorts/test/selection_sort.test.ts | 21 ++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 sorts/selection_sort.ts create mode 100644 sorts/test/selection_sort.test.ts diff --git a/sorts/selection_sort.ts b/sorts/selection_sort.ts new file mode 100644 index 00000000..bd4cfb6d --- /dev/null +++ b/sorts/selection_sort.ts @@ -0,0 +1,33 @@ +/** + * @function selectionSort + * @description Selection sort algorithm is simple and easy. In selection sort the smallest value is selected from the unsorted part and placed at the beginning. This algorithm is not suitable for large data sets as its average and worst-case time complexity is quite high. + * @Complexity_Analysis + * Space complexity - O(1) + * Time complexity + *      Best case   -   O(n^2) + * The best case occurs when an array is already sorted. + *      Worst case  -   O(n^2) + * The worst case occurs when an array is reverse sorted. + *      Average case -  O(n^2) + * The average case occurs when an array is reverse sorted. + * + * @param {number[]} items - The input array + * @return {number[]} - The sorted array. + * @see [Selection Sort](https://www.javatpoint.com/selection-sort) + * @example selectionSort([12, 29, 25, 8, 32, 17, 40]) = [8, 12, 17, 25, 29, 32, 40] + */ + +export const selectionSort = (items: number[]) => { + for (let i = 0; i < items.length; i++) { + let min = i; + for (let j = i + 1; j < items.length; j++) { + if (items[j] < items[min]) { + min = j; + } + } + if (i !== min) { + [items[i], items[min]] = [items[min], items[i]]; + } + } + return items; +}; diff --git a/sorts/test/selection_sort.test.ts b/sorts/test/selection_sort.test.ts new file mode 100644 index 00000000..9ed5a322 --- /dev/null +++ b/sorts/test/selection_sort.test.ts @@ -0,0 +1,21 @@ +import { selectionSort } from "../selection_sort"; + +describe("Testing Selection sort", () => { + const testCases: number[][] = []; + + for (let i = 0; i < 10; i++) { + const arr = []; + for (let j = 0; j < 100; j++) { + arr.push(Math.floor(Math.random() * 100)); + } + testCases.push(arr); + } + test.each(testCases)( + "should return the correct value for test case: %#", + (...arr: number[]) => { + expect(selectionSort([...arr])).toStrictEqual( + [...arr].sort((a: number, b: number) => a - b) + ); + } + ); +}); From 54d6e9732ef4bd4bc0083bbb2b48cef5f4a0ae96 Mon Sep 17 00:00:00 2001 From: Nishant Racherla Date: Mon, 13 Feb 2023 10:47:25 -0800 Subject: [PATCH 014/107] feat(maths): added NumberOfDigits (#101) * feat(maths): added NumberOfDigits * fix: handled 0 input in NumberOfDigits --- maths/number_of_digits.ts | 18 ++++++++++++++++++ maths/test/number_of_digits.test.ts | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 maths/number_of_digits.ts create mode 100644 maths/test/number_of_digits.test.ts diff --git a/maths/number_of_digits.ts b/maths/number_of_digits.ts new file mode 100644 index 00000000..0a21aa52 --- /dev/null +++ b/maths/number_of_digits.ts @@ -0,0 +1,18 @@ +/** + * @function NumberOfDigits + * @description Calculate the number of digits of a natural number. + * @param {number} num - A natural number. + * @return {number} - Number of digits of given natural number. + * @see https://math.stackexchange.com/a/231745/518862 + * @example NumberOfDigits(18) = 2 + * @example NumberOfDigits(294568) = 6 + * @example NumberOfDigits(128798319794) = 12 + */ + +export const NumberOfDigits = (num: number): number => { + if (num <= 0 || !Number.isInteger(num)) { + throw new Error("only natural numbers are supported"); + } + + return Math.floor(Math.log10(num)) + 1; +}; \ No newline at end of file diff --git a/maths/test/number_of_digits.test.ts b/maths/test/number_of_digits.test.ts new file mode 100644 index 00000000..58d9b2ba --- /dev/null +++ b/maths/test/number_of_digits.test.ts @@ -0,0 +1,19 @@ +import { NumberOfDigits } from "../number_of_digits"; + +describe("NumberOfDigits", () => { + test.each([-890, -5.56, -7, 0, 0.73, 4.2, NaN, -Infinity, Infinity])( + "should throw an error for non natural number %d", + (num) => { + expect(() => NumberOfDigits(num)).toThrowError( + "only natural numbers are supported", + ); + }, + ); + + test.each([[1, 1], [18, 2], [549, 3], [7293, 4], [1234567890, 10]])( + "of %i should be %i", + (num, expected) => { + expect(NumberOfDigits(num)).toBe(expected); + }, + ); +}); From ad574491014217dddce3dc435914a5b052bfaa6c Mon Sep 17 00:00:00 2001 From: Nishant Racherla Date: Tue, 14 Feb 2023 05:40:09 -0800 Subject: [PATCH 015/107] feat(maths): added IsPrime (#102) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(maths): added IsPrime * Fix `IsPrime` for perfect squares * Add perfect square to the tests --------- Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- maths/is_prime.ts | 28 ++++++++++++++++++++++++++++ maths/test/is_prime.test.ts | 19 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 maths/is_prime.ts create mode 100644 maths/test/is_prime.test.ts diff --git a/maths/is_prime.ts b/maths/is_prime.ts new file mode 100644 index 00000000..2835091a --- /dev/null +++ b/maths/is_prime.ts @@ -0,0 +1,28 @@ +/** + * @function IsPrime + * @description Determine if given number is prime. + * @param {number} num - A natural number. + * @return {boolean} - Whether the given number is prime. + * @see https://en.wikipedia.org/wiki/Prime_number + * @example IsPrime(2) = false + * @example IsPrime(3) = true + */ + +export const IsPrime = (num: number): boolean => { + // raise corresponding errors upon invalid inputs + if (num <= 0 || !Number.isInteger(num)) { + throw new Error("only natural numbers are supported"); + } + + // handle input being 1 + if (num === 1) return false; + + // iterate from 2 to the square root of num to find a factor + // return false upon finding a factor + for (let i = 2; i <= Math.sqrt(num); i++) { + if (num % i === 0) return false; + } + + // if the entire loop runs without finding a factor, return true + return true; +}; diff --git a/maths/test/is_prime.test.ts b/maths/test/is_prime.test.ts new file mode 100644 index 00000000..2a2c7ca6 --- /dev/null +++ b/maths/test/is_prime.test.ts @@ -0,0 +1,19 @@ +import { IsPrime } from "../is_prime"; + +describe("IsPrime", () => { + test.each([[1, false], [2, true], [3, true], [3*3, false], [13, true], [24, false]])( + "correct output for %i", + (nums, expected) => { + expect(IsPrime(nums)).toBe(expected); + }, + ); + + test.each([-890, -5.56, -7, 0.73, 4.2, NaN, -Infinity, Infinity])( + "should throw an error for non natural number %d", + (num) => { + expect(() => IsPrime(num)).toThrowError( + "only natural numbers are supported", + ); + }, + ); +}); From f2c0c368da7bc5d7773a303fc0fc69e1ef4651c7 Mon Sep 17 00:00:00 2001 From: Noah <70114451+zFl4wless@users.noreply.github.com> Date: Sat, 25 Feb 2023 10:11:29 +0100 Subject: [PATCH 016/107] structure: doubly linked list (#85) * structure: doubly linked list * resolves requested changes and adjusts tests * reorganizes tests --- data_structures/doubly_linked_list.ts | 294 ++++++++++++++++++ .../test/doubly_linked_list.test.ts | 118 +++++++ 2 files changed, 412 insertions(+) create mode 100644 data_structures/doubly_linked_list.ts create mode 100644 data_structures/test/doubly_linked_list.test.ts diff --git a/data_structures/doubly_linked_list.ts b/data_structures/doubly_linked_list.ts new file mode 100644 index 00000000..67e3dda8 --- /dev/null +++ b/data_structures/doubly_linked_list.ts @@ -0,0 +1,294 @@ +/** + * This is an implementation of a Doubly Linked List. + * A Doubly Linked List is a data structure that contains a head, tail and length property. + * Linked Lists consist of nodes, and each node has a value and a pointer to the next and previous node (can be null). + * + * @see https://www.geeksforgeeks.org/doubly-linked-list/ + * + * @template T The type of the value of the nodes. + * @property head The head of the list. + * @property tail The tail of the list. + * @property length The length of the list. + */ +export class DoublyLinkedList { + private head?: DoublyLinkedListNode = undefined; + private tail?: DoublyLinkedListNode = undefined; + private length: number = 0; + + /** + * Checks if the list is empty. + * + * @returns {boolean} Whether the list is empty or not. + */ + isEmpty(): boolean { + return !this.head; + } + + /** + * Gets a value of a node at a specific index. + * Time complexity: O(n) + * + * @param index The index of the node. + * @returns The value of a node at the specified index. + */ + get(index: number): T | null { + if (index < 0 || index >= this.length) { + return null; + } + + let currentNode: DoublyLinkedListNode | undefined = this.head; + for (let i: number = 0; i < index; i++) { + currentNode = currentNode?.next; + } + + return currentNode?.value ?? null; + } + + /** + * Inserts a node at the head of the list. + * Time complexity: O(1) + * + * @param value The value of the node being inserted. + */ + push(value: T): void { + const newNode = new DoublyLinkedListNode(value); + + if (!this.head) { + this.head = newNode; + this.tail = newNode; + } else { + this.head.prev = newNode; + newNode.next = this.head; + this.head = newNode; + } + + this.length++; + } + + /** + * Removes a node from the head of the list. + * Time complexity: O(1) + * + * @returns The value of the node that was removed. + * @throws Index out of bounds if the list is empty. + */ + pop(): T { + if (!this.head) { + throw new Error("Index out of bounds"); + } + + const removedNode = this.head; + + if (this.head === this.tail) { + this.tail = undefined; + } else { + this.head.next!.prev = undefined; + } + + this.head = this.head.next; + this.length--; + + return removedNode.value; + } + + /** + * Inserts a node at the tail of the list. + * Time complexity: O(1) + * + * @param value The value of the node being inserted. + */ + append(value: T): void { + const newNode = new DoublyLinkedListNode(value); + + if (!this.head) { + this.head = newNode; + } else { + this.tail!.next = newNode; + newNode.prev = this.tail; + } + + this.tail = newNode; + this.length++; + } + + /** + * Removes a node from the tail of the list. + * Time complexity: O(1) + * + * @returns The value of the node that was removed. + * @throws Index out of bounds if the list is empty. + */ + removeTail(): T { + if (!this.head) { + throw new Error("Index out of bounds"); + } + + const removedNode = this.tail; + + if (this.head === this.tail) { + this.head = undefined; + } else { + this.tail!.prev!.next = undefined; + } + + this.tail = this.tail!.prev; + this.length--; + + return removedNode!.value; + } + + /** + * Inserts a node at a specific index. + * Time complexity: O(n) + * + * @param index The index where the node will be inserted. + * @param value The value of the node being inserted. + * @throws Index out of bounds if the index is not valid. + */ + insertAt(index: number, value: T): void { + if (index < 0 || index > this.length) { + throw new Error("Index out of bounds"); + } + + if (index === 0) { + this.push(value); + return; + } + + if (index === this.length) { + this.append(value); + return; + } + + const newNode = new DoublyLinkedListNode(value); + let prevNode: DoublyLinkedListNode | undefined = this.head; + for (let i: number = 0; i < index - 1; i++) { + prevNode = prevNode?.next; + } + const nextNode = prevNode?.next; + + prevNode!.next = newNode; + newNode.prev = prevNode; + newNode.next = nextNode; + nextNode!.prev = newNode; + + this.length++; + } + + /** + * Removes a node at a specific index. + * Time complexity: O(n) + * + * @param index The index of the node to be removed. + * @returns The value of the node that was removed. + * @throws Index out of bounds if the index is not valid. + */ + removeAt(index: number): T { + if (index < 0 || index >= this.length) { + throw new Error("Index out of bounds"); + } + + if (index === 0) { + return this.pop(); + } + + if (index === this.length - 1) { + return this.removeTail(); + } + + let removedNode: DoublyLinkedListNode | undefined = this.head; + for (let i: number = 0; i < index; i++) { + removedNode = removedNode?.next; + } + removedNode!.prev!.next = removedNode!.next; + removedNode!.next!.prev = removedNode!.prev; + + this.length--; + + return removedNode!.value; + } + + /** + * Reverses the list. + * Time complexity: O(n) + * + * @returns The reversed list or null if the list is empty. + */ + reverse(): DoublyLinkedList | null { + if (!this.head) { + return null; + } + + let currentNode: DoublyLinkedListNode | undefined = this.head; + let nextNode: DoublyLinkedListNode | undefined = undefined; + let prevNode: DoublyLinkedListNode | undefined = undefined; + + while (currentNode) { + nextNode = currentNode.next; + prevNode = currentNode.prev; + + currentNode.next = prevNode; + currentNode.prev = nextNode; + + prevNode = currentNode; + currentNode = nextNode; + } + + this.tail = this.head; + this.head = prevNode; + + return this; + } + + /** + * Clears the list. + */ + clear(): void { + this.head = undefined; + this.tail = undefined; + this.length = 0; + } + + /** + * Converts the list to an array. + * + * @returns The array representation of the list. + */ + toArray(): T[] { + const array: T[] = []; + + let currentNode: DoublyLinkedListNode | undefined = this.head; + + while (currentNode) { + array.push(currentNode.value); + currentNode = currentNode.next; + } + + return array; + } + + /** + * Gets the length of the list. + * + * @returns The length of the list. + */ + getLength(): number { + return this.length; + } +} + +/** + * Represents a node in a doubly linked list. + * + * @template T The type of the value stored in the node. + * @property value The value stored in the node. + * @property next The next node after this node. + * @property prev The previous node before this node. + */ +class DoublyLinkedListNode { + constructor( + public value: T, + public next?: DoublyLinkedListNode, + public prev?: DoublyLinkedListNode + ) {} +} diff --git a/data_structures/test/doubly_linked_list.test.ts b/data_structures/test/doubly_linked_list.test.ts new file mode 100644 index 00000000..085b06d4 --- /dev/null +++ b/data_structures/test/doubly_linked_list.test.ts @@ -0,0 +1,118 @@ +import { DoublyLinkedList } from "../doubly_linked_list"; + +describe("DoublyLinkedList", () => { + describe("with filled list (push)", () => { + let list: DoublyLinkedList; + + beforeEach(() => { + list = new DoublyLinkedList(); + list.push(1); + list.push(2); + list.push(3); + }); + + it("should return false for isEmpty when list is not empty", () => { + expect(list.isEmpty()).toBeFalsy(); + }); + + it("should return correct node for get", () => { + expect(list.get(1)).toBe(2); + }); + + it("should push nodes to the list and return correct head and tail", () => { + expect(list.get(0)).toBe(3); + expect(list.get(2)).toBe(1); + }); + + it("should pop nodes from the list and return correct head and tail", () => { + expect(list.pop()).toBe(3); + expect(list.get(0)).toBe(2); + expect(list.get(1)).toBe(1); + }); + }); + + describe("with filled list (append)", () => { + let list: DoublyLinkedList; + + beforeEach(() => { + list = new DoublyLinkedList(); + list.append(1); + list.append(2); + list.append(3); + }); + + it("should append nodes to the list and return correct head and tail", () => { + expect(list.get(0)).toBe(1); + expect(list.get(2)).toBe(3); + }); + + it("should remove tail from the list and return correct head and tail", () => { + expect(list.removeTail()).toBe(3); + expect(list.get(0)).toBe(1); + expect(list.get(1)).toBe(2); + }); + + it("should insert nodes at the correct index", () => { + list.insertAt(1, 4); + + expect(list.get(1)).toBe(4); + }); + + it("should remove nodes at the correct index", () => { + expect(list.removeAt(1)).toBe(2); + }); + + it("should return null for removeAt when index is out of bounds", () => { + expect(() => list.removeAt(3)).toThrowError("Index out of bounds"); + }); + + it("should reverse the list", () => { + list.reverse(); + + expect(list.get(0)).toBe(3); + expect(list.get(1)).toBe(2); + }); + + it("should clear the list", () => { + list.clear(); + + expect(list.isEmpty()).toBeTruthy(); + }); + + it("should convert the list to an array", () => { + expect(list.toArray()).toEqual([1, 2, 3]); + }); + + it("should return correct length", () => { + expect(list.getLength()).toBe(3); + }); + }); + + describe("with empty list", () => { + let list: DoublyLinkedList; + + beforeEach(() => { + list = new DoublyLinkedList(); + }); + + it("should return true for isEmpty when list is empty", () => { + expect(list.isEmpty()).toBeTruthy(); + }); + + it("should return null for get when index is out of bounds", () => { + expect(list.get(1)).toBeNull(); + }); + + it("should throw error for pop when list is empty", () => { + expect(() => list.pop()).toThrowError("Index out of bounds"); + }); + + it("should return null for removeTail when list is empty", () => { + expect(() => list.removeTail()).toThrowError("Index out of bounds"); + }); + + it("should return null for reverse when list is empty", () => { + expect(list.reverse()).toBeNull(); + }); + }); +}); From 957100c00b8fa172d35571922277d26a170e5dbb Mon Sep 17 00:00:00 2001 From: Sunil Pandey <64631561+sunilbpandey@users.noreply.github.com> Date: Fri, 3 Mar 2023 03:09:10 -0800 Subject: [PATCH 017/107] feat: Add Zeller's congruence algorithm (#105) --- maths/test/zellers_congruence.test.ts | 112 ++++++++++++++++++++++++++ maths/zellers_congruence.ts | 68 ++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 maths/test/zellers_congruence.test.ts create mode 100644 maths/zellers_congruence.ts diff --git a/maths/test/zellers_congruence.test.ts b/maths/test/zellers_congruence.test.ts new file mode 100644 index 00000000..19432a10 --- /dev/null +++ b/maths/test/zellers_congruence.test.ts @@ -0,0 +1,112 @@ +import { Calendar, GetWeekday } from "../zellers_congruence"; + +describe("Zeller's congruence", () => { + test.each([ + { year: 2000, month: 1, day: 1, expected: 6 }, + { year: 2000, month: 2, day: 1, expected: 2 }, + { year: 2000, month: 3, day: 1, expected: 3 }, + { year: 2000, month: 4, day: 1, expected: 6 }, + { year: 2000, month: 5, day: 1, expected: 1 }, + { year: 2000, month: 6, day: 1, expected: 4 }, + { year: 2000, month: 7, day: 1, expected: 6 }, + { year: 2000, month: 8, day: 1, expected: 2 }, + { year: 2000, month: 9, day: 1, expected: 5 }, + { year: 2000, month: 10, day: 1, expected: 0 }, + { year: 2000, month: 11, day: 1, expected: 3 }, + { year: 2000, month: 12, day: 1, expected: 5 }, + { year: 1, month: 1, day: 1, expected: 1 }, + { year: 23, month: 2, day: 28, expected: 2 }, + { year: 456, month: 3, day: 31, expected: 5 }, + { year: 1850, month: 4, day: 1, expected: 1 }, + { year: 2100, month: 12, day: 31, expected: 5 }, + { year: 3000, month: 12, day: 31, expected: 3 }, + ])( + `The weekday of $year-$month-$day in the default calendar is $expected`, + ({ year, month, day, expected }) => { + expect(GetWeekday(year, month, day)).toEqual(expected); + } + ); + + test.each([ + { year: 1500, month: 1, day: 1, expected: 3 }, + { year: 1500, month: 2, day: 1, expected: 6 }, + { year: 1500, month: 3, day: 1, expected: 0 }, + { year: 1500, month: 4, day: 1, expected: 3 }, + { year: 1500, month: 5, day: 1, expected: 5 }, + { year: 1500, month: 6, day: 1, expected: 1 }, + { year: 1500, month: 7, day: 1, expected: 3 }, + { year: 1500, month: 8, day: 1, expected: 6 }, + { year: 1500, month: 9, day: 1, expected: 2 }, + { year: 1500, month: 10, day: 1, expected: 4 }, + { year: 1500, month: 11, day: 1, expected: 0 }, + { year: 1500, month: 12, day: 1, expected: 2 }, + { year: 1, month: 1, day: 1, expected: 6 }, + { year: 23, month: 2, day: 28, expected: 0 }, + { year: 456, month: 3, day: 31, expected: 6 }, + { year: 1582, month: 2, day: 1, expected: 4 }, + ])( + `The weekday of $year-$month-$day in the Julian calendar is $expected`, + ({ year, month, day, expected }) => { + expect(GetWeekday(year, month, day, Calendar.Julian)).toEqual(expected); + } + ); + + test(`The default calendar is Gregorian`, () => { + expect(GetWeekday(1, 1, 1)).toEqual(1); + }); + + test.each([ + { year: 1, month: 1, day: 1, expected: 1 }, + { year: 23, month: 2, day: 28, expected: 2 }, + { year: 456, month: 3, day: 31, expected: 5 }, + { year: 1850, month: 4, day: 1, expected: 1 }, + { year: 2000, month: 1, day: 1, expected: 6 }, + { year: 2100, month: 12, day: 31, expected: 5 }, + { year: 3000, month: 12, day: 31, expected: 3 }, + ])( + `The weekday for $year-$month-$day in the default calendar matches getUTCDay`, + ({ year, month, day }) => { + // Convert to a string to avoid Date constructor mapping 1 to year 1901 + const dateString = `${year.toString().padStart(4, "0")}-${month + .toString() + .padStart(2, "0")}-${day.toString().padStart(2, "0")}`; + expect(GetWeekday(year, month, day)).toEqual( + new Date(dateString).getUTCDay() + ); + } + ); + + test.each([ + { year: 0, month: 1, day: 1 }, + { year: -5, month: 1, day: 1 }, + { year: 12.2, month: 1, day: 1 }, + ])(`Should throw an error for invalid year $year`, ({ year, month, day }) => { + expect(() => GetWeekday(year, month, day)).toThrow( + "Year must be an integer greater than 0" + ); + }); + + test.each([ + { year: 2001, month: -5, day: 1 }, + { year: 2001, month: 0, day: 1 }, + { year: 2001, month: 13, day: 1 }, + { year: 2001, month: 9.3, day: 1 }, + ])( + `Should throw an error for invalid month $month`, + ({ year, month, day }) => { + expect(() => GetWeekday(year, month, day)).toThrow( + "Month must be an integer between 1 and 12" + ); + } + ); + + test.each([ + { year: 2001, month: 1, day: -5 }, + { year: 2001, month: 1, day: 0 }, + { year: 2001, month: 1, day: 32 }, + ])(`Should throw an error for invalid day $day`, ({ year, month, day }) => { + expect(() => GetWeekday(year, month, day)).toThrow( + "Day must be an integer between 1 and 31" + ); + }); +}); diff --git a/maths/zellers_congruence.ts b/maths/zellers_congruence.ts new file mode 100644 index 00000000..bda69700 --- /dev/null +++ b/maths/zellers_congruence.ts @@ -0,0 +1,68 @@ +export enum Calendar { + Gregorian, + Julian, +} + +/** + * @function GetWeekday + * @description Calculate the day of the week for any Julian or Gregorian calendar date. + * @param {number} year - Year with century. + * @param {number} month - Month of the year (1-12). + * @param {number} day - Day of the month (1-31). + * @return {number} Day of the week, where 0 represents Sunday. + * @see https://en.wikipedia.org/wiki/Zeller's_congruence + * @example GetWeekday(2000, 1, 1) = 6 + * @example GetWeekday(1500, 1, 1, Calendar.Julian) = 3 + */ +export const GetWeekday = ( + year: number, + month: number, + day: number, + calendar: Calendar = Calendar.Gregorian +): number => { + // Input validation + if (!Number.isInteger(year) || year < 1) { + throw new Error("Year must be an integer greater than 0"); + } + + if (!Number.isInteger(month) || month < 1 || month > 12) { + throw new Error("Month must be an integer between 1 and 12"); + } + + if (!Number.isInteger(day) || day < 1 || day > 31) { + throw new Error("Day must be an integer between 1 and 31"); + } + + // Move January and February to the end of the previous year + if (month < 3) { + month += 12; + year--; + } + + const century = Math.floor(year / 100); + year %= 100; + + let weekday: number | undefined = undefined; + if (calendar === Calendar.Gregorian) { + weekday = + (day + + Math.floor(2.6 * (month + 1)) + + year + + Math.floor(year / 4) + + Math.floor(century / 4) + + 5 * century) % + 7; + } else { + weekday = + (day + + Math.floor(2.6 * (month + 1)) + + year + + Math.floor(year / 4) + + 5 + + 6 * century) % + 7; + } + + // Convert to Sunday being 0 + return (weekday + 6) % 7; +}; From 6fffa79122c69d06a6ed3ae9ad8366add9474ab6 Mon Sep 17 00:00:00 2001 From: Noah <70114451+zFl4wless@users.noreply.github.com> Date: Thu, 9 Mar 2023 14:26:27 +0100 Subject: [PATCH 018/107] structure: hash table (#108) * structure: hash table * fix: requested changes & dynamic capacity * feat: adds test for overwriting existing values --- data_structures/hashing/hash_table.ts | 235 ++++++++++++++++++ .../hashing/test/hash_table.test.ts | 91 +++++++ 2 files changed, 326 insertions(+) create mode 100644 data_structures/hashing/hash_table.ts create mode 100644 data_structures/hashing/test/hash_table.test.ts diff --git a/data_structures/hashing/hash_table.ts b/data_structures/hashing/hash_table.ts new file mode 100644 index 00000000..1b63b6f1 --- /dev/null +++ b/data_structures/hashing/hash_table.ts @@ -0,0 +1,235 @@ +/** + * Represents a hash table. + * Time complexity: + * - Set, Get, Delete, Has: O(1) on average, O(n) in the worst case. + * - Clear: O(m) where m is the number of buckets. + * - Keys, Values, Entires: O(n + m). + * + * @template K The key type. + * @template V The value type. + * @param size The size of the hash table. + * @param buckets The buckets in which to store the key-value pairs. + * @param loadFactor The load factor to determine when to resize the hash table. + */ +export class HashTable { + private size!: number; + private buckets!: HashTableEntry[][]; + private readonly loadFactor = 0.75; + + constructor() { + this.clear(); + } + + /** + * Gets the size. + * + * @returns The size. + */ + getSize(): number { + return this.size; + } + + /** + * Sets a key-value pair. + * + * @param key The key. + * @param value The value. + */ + set(key: K, value: V): void { + const loadFactor = this.size / this.buckets.length; + if (loadFactor > this.loadFactor) { + this.resize(); + } + + const index = this.hash(key); + const bucket = this.buckets[index]; + + if (bucket.length === 0) { + bucket.push(new HashTableEntry(key, value)); + this.size++; + return; + } + + for (const entry of bucket) { + if (entry.key === key) { + entry.value = value; + return; + } + } + + bucket.push(new HashTableEntry(key, value)); + this.size++; + } + + /** + * Gets a value. + * + * @param key The key to get the value for. + * @returns The value or null if the key does not exist. + */ + get(key: K): V | null { + const index = this.hash(key); + const bucket = this.buckets[index]; + + for (const entry of bucket) { + if (entry.key === key) { + return entry.value; + } + } + + return null; + } + + /** + * Deletes a key-value pair. + * + * @param key The key whose key-value pair to delete. + */ + delete(key: K): void { + const index = this.hash(key); + const bucket = this.buckets[index]; + + for (const entry of bucket) { + if (entry.key === key) { + bucket.splice(bucket.indexOf(entry), 1); + this.size--; + return; + } + } + } + + /** + * Checks if a key exists. + * + * @param key The key. + * @returns Whether the key exists. + */ + has(key: K): boolean { + const index = this.hash(key); + const bucket = this.buckets[index]; + + for (const entry of bucket) { + if (entry.key === key) { + return true; + } + } + + return false; + } + + /** + * Clears the hash table. + */ + clear(): void { + this.size = 0; + this.initializeBuckets(16); + } + + /** + * Gets all keys. + * + * @returns The keys. + */ + keys(): K[] { + const keys: K[] = []; + for (const bucket of this.buckets) { + for (const entry of bucket) { + keys.push(entry.key); + } + } + + return keys; + } + + /** + * Gets all values. + * + * @returns The values. + */ + values(): V[] { + const values: V[] = []; + for (const bucket of this.buckets) { + for (const entry of bucket) { + values.push(entry.value); + } + } + + return values; + } + + /** + * Gets all entries. + * + * @returns The entries. + */ + entries(): HashTableEntry[] { + const entries: HashTableEntry[] = []; + for (const bucket of this.buckets) { + for (const entry of bucket) { + entries.push(entry); + } + } + + return entries; + } + + /** + * Initializes the buckets. + * + * @param amount The amount of buckets to initialize. + */ + private initializeBuckets(amount: number): void { + this.buckets = []; + for (let i = 0; i < amount; i++) { + this.buckets.push([]); + } + } + + /** + * Hashes a key to an index. + * This implementation uses the djb2 algorithm, which might not be the best. + * Feel free to change it to something else. + * + * @param key The key. + * @return The index. + */ + protected hash(key: K): number { + let hash = 0; + + for (let i = 0; i < String(key).length; i++) { + hash = (hash << 5) - hash + String(key).charCodeAt(i); + } + + return hash % this.buckets.length; + } + + /** + * Resizes the hash table by doubling the amount of buckets. + */ + private resize(): void { + this.initializeBuckets(this.buckets.length * 2); + this.size = 0; + + for (const entry of this.entries()) { + this.set(entry.key, entry.value); + } + } +} + +/** + * Represents a key-value pair. + * + * @template K The type of the key. + * @template V The type of the value. + * @param key The key. + * @param value The value. + */ +class HashTableEntry { + key: K; + value: V; + + constructor(key: K, value: V) { + this.key = key; + this.value = value; + } +} diff --git a/data_structures/hashing/test/hash_table.test.ts b/data_structures/hashing/test/hash_table.test.ts new file mode 100644 index 00000000..d54190a8 --- /dev/null +++ b/data_structures/hashing/test/hash_table.test.ts @@ -0,0 +1,91 @@ +import { HashTable } from "../hash_table"; + +describe("Hash Table", () => { + let hashTable: HashTable; + beforeEach(() => { + hashTable = new HashTable(); + }); + + it("should set a value", () => { + hashTable.set("a", 1); + + expect(hashTable.values()).toEqual([1]); + }); + + it("should override a value", () => { + hashTable.set("a", 1); + hashTable.set("a", 2); + + expect(hashTable.values()).toEqual([2]); + }); + + it("should get a value", () => { + hashTable.set("a", 1); + + expect(hashTable.get("a")).toBe(1); + }); + + it("should get null if key does not exist", () => { + expect(hashTable.get("a")).toBeNull(); + }); + + it("should delete a value", () => { + hashTable.set("a", 1); + hashTable.delete("a"); + + expect(hashTable.get("a")).toBeNull(); + }); + + it("should do nothing on delete if key does not exist", () => { + hashTable.delete("a"); + + expect(hashTable.get("a")).toBeNull(); + }); + + it("should return true if key exists", () => { + hashTable.set("a", 1); + + expect(hashTable.has("a")).toBe(true); + }); + + it("should return false if key does not exist", () => { + expect(hashTable.has("a")).toBe(false); + }); + + it("should clear the hash table", () => { + hashTable.set("a", 1); + hashTable.set("b", 2); + hashTable.set("c", 3); + hashTable.clear(); + + expect(hashTable.getSize()).toBe(0); + }); + + it("should return all keys", () => { + hashTable.set("a", 1); + hashTable.set("b", 2); + hashTable.set("c", 3); + + expect(hashTable.keys()).toEqual(["a", "b", "c"]); + }); + + it("should return all values", () => { + hashTable.set("a", 1); + hashTable.set("b", 2); + hashTable.set("c", 3); + + expect(hashTable.values()).toEqual([1, 2, 3]); + }); + + it("should return all key-value pairs", () => { + hashTable.set("a", 1); + hashTable.set("b", 2); + hashTable.set("c", 3); + + expect(hashTable.entries()).toEqual([ + { key: "a", value: 1 }, + { key: "b", value: 2 }, + { key: "c", value: 3 }, + ]); + }); +}); From 8e83941ab5f831dfb7fd50f1f2dbbec6a7152938 Mon Sep 17 00:00:00 2001 From: Maik <58326890+zFlxw@users.noreply.github.com> Date: Thu, 9 Mar 2023 14:27:55 +0100 Subject: [PATCH 019/107] feat(maths): recursive calculating of Fibonacci numbers (#107) * feat(maths): improve fibonacci number function * feat(maths): makes recursive fibonacci an extra function * fix: improve tests * test: improves tests --- maths/fibonacci.ts | 49 ++++++++++++++++++++++++++++++------ maths/test/fibonacci.test.ts | 22 ++++++++-------- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/maths/fibonacci.ts b/maths/fibonacci.ts index b924c91a..33013d68 100644 --- a/maths/fibonacci.ts +++ b/maths/fibonacci.ts @@ -1,19 +1,26 @@ /** - * A function to get nth Fibonacci number - * @param number The input integer - * @return {number} Fibonacci number of `number` + * A function to get nth Fibonacci number. + * + * Time Complexity: linear (O(n)) + * + * @param number The index of the number in the Fibonacci sequence. + * @return The Fibonacci number on the nth index in the sequence. + * * @example nthFibonacci(4) => 3 | nthFibonacci(6) => 8 * @see https://en.m.wikipedia.org/wiki/Fibonacci_number * @author MohdFaisalBidda */ - export const nthFibonacci = (number: number): number => { - if (number < 0) throw "Number should be greater than 0"; - - if (number === 0) return 0; + if (number < 0) { + throw 'Number should be greater than 0'; + } - let a = 0, b = 1; + if (number === 0) { + return 0; + } + let a = 0, + b = 1; for (let i = 1; i < number; ++i) { const c = a + b; @@ -23,3 +30,29 @@ export const nthFibonacci = (number: number): number => { return b; }; + +/** + * A function to get nth Fibonacci number recursively. **Note: This recursive approach increases the time complexity** + * + * Time Complexity: exponential (O(ϕ^n)) + * + * @param number The index of the number in the Fibonacci sequence. + * @return The Fibonacci number on the nth index in the sequence. + * + * @example nthFibonacci(4) => 3 | nthFibonacci(6) => 8 + * @see https://en.m.wikipedia.org/wiki/Fibonacci_number + * @author zFlxw + */ +export const nthFibonacciRecursively = (number: number): number => { + if (number === 0) { + return 0; + } + + if (number <= 2) { + return 1; + } + + return ( + nthFibonacciRecursively(number - 1) + nthFibonacciRecursively(number - 2) + ); +}; diff --git a/maths/test/fibonacci.test.ts b/maths/test/fibonacci.test.ts index 578d7b79..e0a8d14b 100644 --- a/maths/test/fibonacci.test.ts +++ b/maths/test/fibonacci.test.ts @@ -1,11 +1,13 @@ -import {nthFibonacci} from '../fibonacci'; +import { nthFibonacci, nthFibonacciRecursively } from '../fibonacci'; -describe('nthFibonacci', () => { - test('should return correct value', () => { - expect(nthFibonacci(0)).toBe(0); - expect(nthFibonacci(1)).toBe(1); - expect(nthFibonacci(5)).toBe(5); - expect(nthFibonacci(4)).toBe(3); - expect(nthFibonacci(0)).toBe(0); - }); -}); \ No newline at end of file +const test = (func: (n: number) => number) => + it.each([ + [0, 0], + [1, 1], + [2, 1], + [5, 5], + [10, 55], + [15, 610], + ])('fib(%i) = %i', (n, expected) => expect(func(n)).toBe(expected)); +describe('Fibonacci iterative', () => test(nthFibonacci)); +describe('Fibonacci recursive', () => test(nthFibonacciRecursively)); From 1ff8f204e1169aff78386899e344214b2c256063 Mon Sep 17 00:00:00 2001 From: Maik <58326890+zFlxw@users.noreply.github.com> Date: Thu, 9 Mar 2023 16:42:43 +0100 Subject: [PATCH 020/107] feat(data-struct): binary search tree (#106) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(data-struct): binary search tree * fix: improvements part 1 * fix: improvements part 2 * Fix failing tests --------- Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- data_structures/binary_search_tree.ts | 225 ++++++++++++++++++ .../test/binary_search_tree.test.ts | 55 +++++ 2 files changed, 280 insertions(+) create mode 100644 data_structures/binary_search_tree.ts create mode 100644 data_structures/test/binary_search_tree.test.ts diff --git a/data_structures/binary_search_tree.ts b/data_structures/binary_search_tree.ts new file mode 100644 index 00000000..f9e4afdc --- /dev/null +++ b/data_structures/binary_search_tree.ts @@ -0,0 +1,225 @@ +/** + * Represents a node of a binary search tree. + * + * @template T The type of the value stored in the node. + */ +class TreeNode { + constructor( + public data: T, + public leftChild?: TreeNode, + public rightChild?: TreeNode, + ) {} +} + +/** + * An implementation of a binary search tree. + * + * A binary tree is a tree with only two children per node. A binary search tree on top sorts the children according + * to following rules: + * - left child < parent node + * - right child > parent node + * - all children on the left side < root node + * - all children on the right side > root node + * + * For profound information about trees + * @see https://www.geeksforgeeks.org/introduction-to-tree-data-structure-and-algorithm-tutorials/ + * + * @template T The data type of the values in the binary tree. + */ +export class BinarySearchTree { + rootNode?: TreeNode; + + /** + * Instantiates the binary search tree. + * + * @param rootNode The root node. + */ + constructor() { + this.rootNode = undefined; + } + + /** + * Checks, if the binary search tree is empty, i. e. has no root node. + * + * @returns Whether the binary search tree is empty. + */ + isEmpty(): boolean { + return this.rootNode === undefined; + } + + /** + * Checks whether the tree has the given data or not. + * + * @param data The data to check for. + */ + has(data: T): boolean { + if (!this.rootNode) { + return false; + } + + let currentNode = this.rootNode; + while (currentNode.data !== data) { + if (data > currentNode.data) { + if (!currentNode.rightChild) { + return false; + } + + currentNode = currentNode.rightChild; + } else { + if (!currentNode.leftChild) { + return false; + } + + currentNode = currentNode.leftChild; + } + } + + return true; + } + + /** + * Inserts the given data into the binary search tree. + * + * @param data The data to be stored in the binary search tree. + * @returns + */ + insert(data: T): void { + if (!this.rootNode) { + this.rootNode = new TreeNode(data); + return; + } + + let currentNode: TreeNode = this.rootNode; + while (true) { + if (data > currentNode.data) { + if (currentNode.rightChild) { + currentNode = currentNode.rightChild; + } else { + currentNode.rightChild = new TreeNode(data); + return; + } + } else { + if (currentNode.leftChild) { + currentNode = currentNode.leftChild; + } else { + currentNode.leftChild = new TreeNode(data); + return; + } + } + } + } + + /** + * Finds the minimum value of the binary search tree. + * + * @returns The minimum value of the binary search tree + */ + findMin(): T { + if (!this.rootNode) { + throw new Error('Empty tree.'); + } + + const traverse = (node: TreeNode): T => { + return !node.leftChild ? node.data : traverse(node.leftChild); + }; + + return traverse(this.rootNode); + } + + /** + * Finds the maximum value of the binary search tree. + * + * @returns The maximum value of the binary search tree + */ + findMax(): T { + if (!this.rootNode) { + throw new Error('Empty tree.'); + } + + const traverse = (node: TreeNode): T => { + return !node.rightChild ? node.data : traverse(node.rightChild); + }; + + return traverse(this.rootNode); + } + + /** + * Traverses to the binary search tree in in-order, i. e. it follow the schema of: + * Left Node -> Root Node -> Right Node + * + * @param array The already found node data for recursive access. + * @returns + */ + inOrderTraversal(array: T[] = []): T[] { + if (!this.rootNode) { + return array; + } + + const traverse = (node?: TreeNode, array: T[] = []): T[] => { + if (!node) { + return array; + } + + traverse(node.leftChild, array); + array.push(node.data); + traverse(node.rightChild, array); + return array; + }; + + return traverse(this.rootNode); + } + + /** + * Traverses to the binary search tree in pre-order, i. e. it follow the schema of: + * Root Node -> Left Node -> Right Node + * + * @param array The already found node data for recursive access. + * @returns + */ + preOrderTraversal(array: T[] = []): T[] { + if (!this.rootNode) { + return array; + } + + const traverse = (node?: TreeNode, array: T[] = []): T[] => { + if (!node) { + return array; + } + + array.push(node.data); + traverse(node.leftChild, array); + traverse(node.rightChild, array); + + return array; + }; + + return traverse(this.rootNode); + } + + /** + * Traverses to the binary search tree in post-order, i. e. it follow the schema of: + * Left Node -> Right Node -> Root Node + * + * @param array The already found node data for recursive access. + * @returns + */ + postOrderTraversal(array: T[] = []): T[] { + if (!this.rootNode) { + return array; + } + + const traverse = (node?: TreeNode, array: T[] = []): T[] => { + if (!node) { + return array; + } + + traverse(node.leftChild, array); + traverse(node.rightChild, array); + array.push(node.data); + + return array; + }; + + return traverse(this.rootNode); + } +} diff --git a/data_structures/test/binary_search_tree.test.ts b/data_structures/test/binary_search_tree.test.ts new file mode 100644 index 00000000..69121985 --- /dev/null +++ b/data_structures/test/binary_search_tree.test.ts @@ -0,0 +1,55 @@ +import { BinarySearchTree } from '../binary_search_tree'; + +describe('BinarySearchTree', () => { + describe('with filled binary search tree (insert)', () => { + let binarySearchTree: BinarySearchTree; + + beforeEach(() => { + binarySearchTree = new BinarySearchTree(); + binarySearchTree.insert(25); + binarySearchTree.insert(80); + binarySearchTree.insert(12); + binarySearchTree.insert(5); + binarySearchTree.insert(64); + }); + + it('should return false for isEmpty when binary search tree is not empty', () => { + expect(binarySearchTree.isEmpty()).toBeFalsy(); + }); + + it('should return correct root node for search', () => { + expect(binarySearchTree.rootNode?.data).toBe(25); + }); + + it('should return whether an element is in the set', () => { + expect(binarySearchTree.has(5)).toBe(true); + expect(binarySearchTree.has(42)).toBe(false); + }); + + it('should traverse in in-order through the tree', () => { + expect(binarySearchTree.inOrderTraversal()).toStrictEqual([5, 12, 25, 64, 80]); + }); + + it('should traverse in pre-order through the tree', () => { + console.log(binarySearchTree.preOrderTraversal()); + + expect( + binarySearchTree.preOrderTraversal(), + ).toStrictEqual([25, 12, 5, 80, 64]); + }); + + it('should traverse in post-order through the tree', () => { + expect( + binarySearchTree.postOrderTraversal(), + ).toStrictEqual([5, 12, 64, 80, 25]); + }); + + it('should return the minimum value of the binary search tree', () => { + expect(binarySearchTree.findMin()).toBe(5); + }); + + it('should return the maximum value of the binary search tree', () => { + expect(binarySearchTree.findMax()).toBe(80); + }); + }); +}); From 4c5469f77ecb819c3e407a323ed3bb44941eaf95 Mon Sep 17 00:00:00 2001 From: Maik <58326890+zFlxw@users.noreply.github.com> Date: Sun, 12 Mar 2023 02:20:47 +0100 Subject: [PATCH 021/107] feat: stack with linked list (#110) * feat: singly linked list * feat: stack with linked list * feat: combine test cases * fix: tests now work properly --- data_structures/doubly_linked_list.ts | 4 +- data_structures/linked_list.ts | 16 + data_structures/linked_list_stack.ts | 82 ++++++ data_structures/singly_linked_list.ts | 275 ++++++++++++++++++ .../test/doubly_linked_list.test.ts | 126 +------- data_structures/test/linked_list.ts | 109 +++++++ .../test/linked_list_stack.test.ts | 32 ++ .../test/singly_linked_list.test.ts | 4 + 8 files changed, 537 insertions(+), 111 deletions(-) create mode 100644 data_structures/linked_list.ts create mode 100644 data_structures/linked_list_stack.ts create mode 100644 data_structures/singly_linked_list.ts create mode 100644 data_structures/test/linked_list.ts create mode 100644 data_structures/test/linked_list_stack.test.ts create mode 100644 data_structures/test/singly_linked_list.test.ts diff --git a/data_structures/doubly_linked_list.ts b/data_structures/doubly_linked_list.ts index 67e3dda8..7ed7447f 100644 --- a/data_structures/doubly_linked_list.ts +++ b/data_structures/doubly_linked_list.ts @@ -1,3 +1,5 @@ +import { LinkedList } from "./linked_list"; + /** * This is an implementation of a Doubly Linked List. * A Doubly Linked List is a data structure that contains a head, tail and length property. @@ -10,7 +12,7 @@ * @property tail The tail of the list. * @property length The length of the list. */ -export class DoublyLinkedList { +export class DoublyLinkedList implements LinkedList { private head?: DoublyLinkedListNode = undefined; private tail?: DoublyLinkedListNode = undefined; private length: number = 0; diff --git a/data_structures/linked_list.ts b/data_structures/linked_list.ts new file mode 100644 index 00000000..596af23b --- /dev/null +++ b/data_structures/linked_list.ts @@ -0,0 +1,16 @@ +/** + * An interface for linked lists, which shares the common methods. + */ +export interface LinkedList { + isEmpty(): boolean; + get(index: number): T | null | undefined; + push(data: T): void; + pop(): T | undefined; + append(data: T): void; + removeTail(): T | undefined; + insertAt(index: number, data: T): void; + removeAt(index: number): T | undefined; + clear(): void; + toArray(): (T | undefined)[]; + getLength(): number; +} diff --git a/data_structures/linked_list_stack.ts b/data_structures/linked_list_stack.ts new file mode 100644 index 00000000..800a4150 --- /dev/null +++ b/data_structures/linked_list_stack.ts @@ -0,0 +1,82 @@ +import { SinglyLinkedList } from "./singly_linked_list"; + +/** + * This is an implementation of a stack, based on a linked list. + * A stack is a linear data structure that works with the LIFO (Last-In-First-Out) principle. + * A linked list is a linear data structure that works with the FIFO (First-In-First-Out) principle and uses references + * to determine which element is next in the list. + */ +export class LinkedListStack { + private list: SinglyLinkedList; + private limit: number; + + /** + * Creates a new stack object. + */ + constructor(limit: number = Number.MAX_VALUE) { + this.list = new SinglyLinkedList(); + this.limit = limit; + } + + /** + * Gets the top element of the stack. + * Time complexity: constant (O(1)) + * + * @returns The top element of the stack. + */ + top(): T | null { + if (this.list.isEmpty()) { + return null; + } + + return this.list.get(0)!; + } + + /** + * Inserts a new element on the top of the stack. + * Time complexity: constant (O(1)) + * + * @param data The data of the element to insert. + * @throws Stack overflow, if the new element does not fit in the limit. + */ + push(data: T): void { + if (this.list.getLength() + 1 > this.limit) { + throw new Error('Stack overflow') + } + + this.list.push(data); + } + + /** + * Removes the top element from the stack. + * Time complexity: constant (O(1)) + * + * @returns The previous top element. + * @throws Stack underflow, if the stack has no elements to pop. + */ + pop(): T { + if (this.list.isEmpty()) { + throw new Error('Stack underflow') + } + + return this.list.pop(); + } + + /** + * Gets the amount of elements in the stack. + * + * @returns The amount of elements in the stack. + */ + length(): number { + return this.list.getLength(); + } + + /** + * Gets whether the stack is empty or not. + * + * @returns Whether the stack is empty or not. + */ + isEmpty(): boolean { + return this.list.isEmpty(); + } +} \ No newline at end of file diff --git a/data_structures/singly_linked_list.ts b/data_structures/singly_linked_list.ts new file mode 100644 index 00000000..56172a8c --- /dev/null +++ b/data_structures/singly_linked_list.ts @@ -0,0 +1,275 @@ +import { LinkedList } from "./linked_list"; + +/** + * Represents a node in a linked list. + * + * @template T The type of the data stored in the node. + * @property data The data stored in the node. + * @property next A reference to the next node in the list. Can reference to null, if there is no next element. + */ +class ListNode { + constructor(public data: T, public next?: ListNode) {} +} + +/** + * This is an implementation of a (singly) linked list. + * A linked list is a data structure that stores each element with a pointer (or reference) to the next element + * in the list. Therefore, it is a linear data structure, which can be resized dynamically during runtime, as there is + * no fixed memory block allocated. + * + * @template T The type of the value of the nodes. + * @property head The head of the list. + * @property tail The tail of the list. + * @property length The length of the list. + */ +export class SinglyLinkedList implements LinkedList { + private head?: ListNode; + private tail?: ListNode; + private length: number; + + /** + * Creates a new, empty linked list. + */ + constructor() { + this.head = undefined; + this.tail = undefined; + this.length = 0; + } + + /** + * Checks, if the list is empty. + * + * @returns Whether the list is empty or not. + */ + isEmpty(): boolean { + return !this.head; + } + + /** + * Gets the data of the node at the given index. + * Time complexity: linear (O(n)) + * + * @param index The index of the node. + * @returns The data of the node at the given index or null, if no data is present. + */ + get(index: number): T | null { + if (index < 0 || index >= this.length) { + return null; + } + + if (this.isEmpty()) { + return null; + } + + let currentNode: ListNode = this.head!; + for (let i: number = 0; i < index; i++) { + if (!currentNode.next) { + return null; + } + + currentNode = currentNode.next; + } + + return currentNode.data; + } + + /** + * Inserts the given data as the first node of the list. + * Time complexity: constant (O(1)) + * + * @param data The data to be inserted. + */ + push(data: T): void { + const node: ListNode = new ListNode(data); + + if (this.isEmpty()) { + this.head = node; + this.tail = node; + } else { + node.next = this.head; + this.head = node; + } + + this.length++; + } + + /** + * Removes the first node of the list. + * Time complexity: constant (O(1)) + * + * @returns The data of the node that was removed. + * @throws Index out of bounds if the list is empty. + */ + pop(): T { + if (this.isEmpty()) { + throw new Error('Index out of bounds'); + } + + const node: ListNode = this.head!; + this.head = this.head!.next; + this.length--; + + return node.data; + } + + /** + * Inserts the given data as a new node after the current TAIL. + * Time complexity: constant (O(1)) + * + * @param data The data of the node being inserted. + */ + append(data: T): void { + const node: ListNode = new ListNode(data); + + if (this.isEmpty()) { + this.head = node; + } else { + this.tail!.next = node; + } + + this.tail = node; + this.length++; + } + + /** + * Removes the current TAIL of the list. + * Time complexity: linear (O(n)) + * + * @returns The data of the former TAIL. + * @throws Index out of bounds if the list is empty. + */ + removeTail(): T { + if (!this.head) { + throw new Error('Index out of bounds'); + } + + const currentTail = this.tail; + if (this.head === this.tail) { + this.head = undefined; + this.tail = undefined; + this.length--; + + return currentTail!.data; + } + + let currentNode: ListNode = this.head; + while (currentNode.next !== currentTail) { + currentNode = currentNode.next!; + } + + this.tail = currentNode; + this.length--; + + return currentTail!.data; + } + + /** + * Inserts the data as a new node at the given index. + * Time complexity: O(n) + * + * @param index The index where the node is to be inserted. + * @param data The data to insert. + * @throws Index out of bounds, when given an invalid index. + */ + insertAt(index: number, data: T): void { + if (index < 0 || index > this.length) { + throw new Error('Index out of bounds'); + } + + if (index === 0) { + this.push(data); + + return; + } + + if (index === this.length) { + this.append(data); + + return; + } + + const newNode = new ListNode(data); + let currentNode: ListNode | undefined = this.head; + for (let i: number = 0; i < index - 1; i++) { + currentNode = currentNode?.next; + } + + const nextNode = currentNode?.next; + currentNode!.next = newNode; + newNode.next = nextNode; + + this.length++; + } + + /** + * Removes the node at the given index. + * Time complexity: O(n) + * + * @param index The index of the node to be removed. + * @returns The data of the removed node. + * @throws Index out of bounds, when given an invalid index. + */ + removeAt(index: number): T { + if (index < 0 || index >= this.length) { + throw new Error('Index out of bounds'); + } + + if (index === 0) { + return this.pop(); + } + + if (index === this.length - 1) { + return this.removeTail(); + } + + let previousNode: ListNode | undefined; + let currentNode: ListNode | undefined = this.head; + for (let i: number = 0; i < index; i++) { + if (i === index - 1) { + previousNode = currentNode; + } + + currentNode = currentNode?.next; + } + + previousNode!.next = currentNode?.next; + this.length--; + + return currentNode!.data; + } + + /** + * Clears the list. + */ + clear(): void { + this.head = undefined; + this.tail = undefined; + this.length = 0; + } + + /** + * Converts the list to an array. + * + * @returns The array representation of the list. + */ + toArray(): T[] { + const array: T[] = []; + let currentNode: ListNode | undefined = this.head; + + while (currentNode) { + array.push(currentNode.data); + currentNode = currentNode.next; + } + + return array; + } + + /** + * Gets the length of the list. + * + * @returns The length of the list. + */ + getLength(): number { + return this.length; + } +} diff --git a/data_structures/test/doubly_linked_list.test.ts b/data_structures/test/doubly_linked_list.test.ts index 085b06d4..492af254 100644 --- a/data_structures/test/doubly_linked_list.test.ts +++ b/data_structures/test/doubly_linked_list.test.ts @@ -1,118 +1,24 @@ -import { DoublyLinkedList } from "../doubly_linked_list"; +import { DoublyLinkedList } from '../doubly_linked_list'; +import { testLinkedList } from './linked_list'; describe("DoublyLinkedList", () => { - describe("with filled list (push)", () => { - let list: DoublyLinkedList; + testLinkedList(DoublyLinkedList); - beforeEach(() => { - list = new DoublyLinkedList(); - list.push(1); - list.push(2); - list.push(3); - }); + it("should reverse the list", () => { + const list: DoublyLinkedList = new DoublyLinkedList(); - it("should return false for isEmpty when list is not empty", () => { - expect(list.isEmpty()).toBeFalsy(); - }); + list.append(1); + list.append(2); + list.append(3); + list.reverse(); - it("should return correct node for get", () => { - expect(list.get(1)).toBe(2); - }); + expect(list.get(0)).toBe(3); + expect(list.get(1)).toBe(2); + }); - it("should push nodes to the list and return correct head and tail", () => { - expect(list.get(0)).toBe(3); - expect(list.get(2)).toBe(1); - }); + it('should return null for reverse when list is empty', () => { + const list: DoublyLinkedList = new DoublyLinkedList(); - it("should pop nodes from the list and return correct head and tail", () => { - expect(list.pop()).toBe(3); - expect(list.get(0)).toBe(2); - expect(list.get(1)).toBe(1); - }); - }); - - describe("with filled list (append)", () => { - let list: DoublyLinkedList; - - beforeEach(() => { - list = new DoublyLinkedList(); - list.append(1); - list.append(2); - list.append(3); - }); - - it("should append nodes to the list and return correct head and tail", () => { - expect(list.get(0)).toBe(1); - expect(list.get(2)).toBe(3); - }); - - it("should remove tail from the list and return correct head and tail", () => { - expect(list.removeTail()).toBe(3); - expect(list.get(0)).toBe(1); - expect(list.get(1)).toBe(2); - }); - - it("should insert nodes at the correct index", () => { - list.insertAt(1, 4); - - expect(list.get(1)).toBe(4); - }); - - it("should remove nodes at the correct index", () => { - expect(list.removeAt(1)).toBe(2); - }); - - it("should return null for removeAt when index is out of bounds", () => { - expect(() => list.removeAt(3)).toThrowError("Index out of bounds"); - }); - - it("should reverse the list", () => { - list.reverse(); - - expect(list.get(0)).toBe(3); - expect(list.get(1)).toBe(2); - }); - - it("should clear the list", () => { - list.clear(); - - expect(list.isEmpty()).toBeTruthy(); - }); - - it("should convert the list to an array", () => { - expect(list.toArray()).toEqual([1, 2, 3]); - }); - - it("should return correct length", () => { - expect(list.getLength()).toBe(3); - }); - }); - - describe("with empty list", () => { - let list: DoublyLinkedList; - - beforeEach(() => { - list = new DoublyLinkedList(); - }); - - it("should return true for isEmpty when list is empty", () => { - expect(list.isEmpty()).toBeTruthy(); - }); - - it("should return null for get when index is out of bounds", () => { - expect(list.get(1)).toBeNull(); - }); - - it("should throw error for pop when list is empty", () => { - expect(() => list.pop()).toThrowError("Index out of bounds"); - }); - - it("should return null for removeTail when list is empty", () => { - expect(() => list.removeTail()).toThrowError("Index out of bounds"); - }); - - it("should return null for reverse when list is empty", () => { - expect(list.reverse()).toBeNull(); - }); - }); + expect(list.reverse()).toBeNull(); + }); }); diff --git a/data_structures/test/linked_list.ts b/data_structures/test/linked_list.ts new file mode 100644 index 00000000..5717ab15 --- /dev/null +++ b/data_structures/test/linked_list.ts @@ -0,0 +1,109 @@ +import { LinkedList } from "../linked_list"; + +type LinkedListConstructor = new () => LinkedList; + +export function testLinkedList(LinkedList: LinkedListConstructor) { + describe('with filled list (push)', () => { + let list: LinkedList = new LinkedList; + + beforeEach(() => { + list = new LinkedList(); + list.push(1); + list.push(2); + list.push(3); + }); + + it('should return false for isEmpty when list is not empty', () => { + expect(list.isEmpty()).toBeFalsy(); + }); + + it('should return correct node for get', () => { + expect(list.get(1)).toBe(2); + }); + + it('should push nodes to the list and return correct head and tail', () => { + expect(list.get(0)).toBe(3); + expect(list.get(2)).toBe(1); + }); + + it('should pop nodes from the list and return correct head and tail', () => { + expect(list.pop()).toBe(3); + expect(list.get(0)).toBe(2); + expect(list.get(1)).toBe(1); + }); + }); + + describe('with filled list (append)', () => { + let list: LinkedList = new LinkedList(); + + beforeEach(() => { + list = new LinkedList(); + list.append(1); + list.append(2); + list.append(3); + }); + + it('should append nodes to the list and return correct head and tail', () => { + expect(list.get(0)).toBe(1); + expect(list.get(2)).toBe(3); + }); + + it('should remove tail from the list and return correct head and tail', () => { + expect(list.removeTail()).toBe(3); + expect(list.get(0)).toBe(1); + expect(list.get(1)).toBe(2); + }); + + it('should insert nodes at the correct index', () => { + list.insertAt(1, 4); + + expect(list.get(1)).toBe(4); + }); + + it('should remove nodes at the correct index', () => { + expect(list.removeAt(1)).toBe(2); + }); + + it('should return null for removeAt when index is out of bounds', () => { + expect(() => list.removeAt(3)).toThrowError('Index out of bounds'); + }); + + it('should clear the list', () => { + list.clear(); + + expect(list.isEmpty()).toBeTruthy(); + }); + + it('should convert the list to an array', () => { + expect(list.toArray()).toEqual([1, 2, 3]); + }); + + it('should return correct length', () => { + expect(list.getLength()).toBe(3); + }); + }); + + describe('with empty list', () => { + let list: LinkedList; + + beforeEach(() => { + list = new LinkedList(); + }); + + it('should return true for isEmpty when list is empty', () => { + expect(list.isEmpty()).toBeTruthy(); + }); + + it('should return null for get when index is out of bounds', () => { + expect(list.get(1)).toBeNull(); + }); + + it('should throw error for pop when list is empty', () => { + expect(() => list.pop()).toThrowError('Index out of bounds'); + }); + + it('should return null for removeTail when list is empty', () => { + expect(() => list.removeTail()).toThrowError('Index out of bounds'); + }); + }); +} \ No newline at end of file diff --git a/data_structures/test/linked_list_stack.test.ts b/data_structures/test/linked_list_stack.test.ts new file mode 100644 index 00000000..2efc03d3 --- /dev/null +++ b/data_structures/test/linked_list_stack.test.ts @@ -0,0 +1,32 @@ +import { LinkedListStack } from "../linked_list_stack"; + +describe("Linked List Stack", () => { + let stack: LinkedListStack = new LinkedListStack(4); + + stack.push(1); + stack.push(2); + stack.push(3); + + it("should get the top element from the stack", () => { + expect(stack.top()).toBe(3); + }); + + it("should remove the top element from the stack and give the new top element", () => { + expect(stack.pop()).toBe(3); + expect(stack.top()).toBe(2); + }); + + it("should add a new element on top", () => { + expect(stack.push(4)); + }); + + it("should fail to add the second element on top, because of a stack overflow", () => { + stack.push(4); + expect(() => stack.push(5)).toThrowError('Stack overflow'); + }); + + it('should fail to pop the top element on an empty stack', () => { + const s: LinkedListStack = new LinkedListStack(); + expect(() => s.pop()).toThrowError('Stack underflow'); + }); +}); \ No newline at end of file diff --git a/data_structures/test/singly_linked_list.test.ts b/data_structures/test/singly_linked_list.test.ts new file mode 100644 index 00000000..0754c5e6 --- /dev/null +++ b/data_structures/test/singly_linked_list.test.ts @@ -0,0 +1,4 @@ +import { SinglyLinkedList } from "../singly_linked_list"; +import { testLinkedList } from "./linked_list"; + +describe("Singly linked list", () => testLinkedList(SinglyLinkedList)); \ No newline at end of file From 77334fc2b78d187b2d55187f4173e1b363b433e7 Mon Sep 17 00:00:00 2001 From: Noah <70114451+zFl4wless@users.noreply.github.com> Date: Sun, 12 Mar 2023 02:23:08 +0100 Subject: [PATCH 022/107] feat(maths): finishes Factors (#112) * feat(maths): added Factors * fix: fixed test cases for Factors * fix(maths): renamed Factors to FindFactors and minor optimizations * fix(maths): fixed square root bug * feat: improvements & resolves requested changes * fix: removes not needed check * improvement: replaces while with for loop --------- Co-authored-by: Nishant Racherla --- maths/factors.ts | 28 ++++++++++++++++++++++++++++ maths/test/factors.test.ts | 25 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 maths/factors.ts create mode 100644 maths/test/factors.test.ts diff --git a/maths/factors.ts b/maths/factors.ts new file mode 100644 index 00000000..b9177684 --- /dev/null +++ b/maths/factors.ts @@ -0,0 +1,28 @@ +/** + * @function FindFactors + * @description Find all the factors of a natural number. + * @param {number} num - A natural number. + * @return {Set} - A set of all the factors of given natural number. + * @see https://en.wikipedia.org/wiki/Divisor + * @example FindFactors(1) = [1] + * @example FindFactors(4) = [1,2,4] + * @example FindFactors(16) = [1,3,5,15] + */ +export const FindFactors = (num: number): Set => { + if (num <= 0 || !Number.isInteger(num)) { + throw new Error("Only natural numbers are supported."); + } + + const res: Set = new Set(); + // Iterates from 1 to square root of num & pushes factors into the res set. + for (let i = 1; i * i <= num; i++) { + if (num % i === 0) { + res.add(i); + + const sqrtFactor = Math.floor(num / i); + res.add(sqrtFactor); + } + } + + return res; +}; diff --git a/maths/test/factors.test.ts b/maths/test/factors.test.ts new file mode 100644 index 00000000..7bcc4c46 --- /dev/null +++ b/maths/test/factors.test.ts @@ -0,0 +1,25 @@ +import { FindFactors } from "../factors"; + +describe("FindFactors", () => { + test.each([-890, -5.56, -7, 0, 0.73, 4.2, NaN, -Infinity, Infinity])( + "should throw an error for non natural number %d", + (num) => { + expect(() => FindFactors(num)).toThrowError( + "Only natural numbers are supported." + ); + } + ); + + test.each([ + [1, new Set([1])], + [2, new Set([1, 2])], + [4, new Set([1, 2, 4])], + [6, new Set([1, 2, 3, 6])], + [16, new Set([1, 2, 4, 8, 16])], + ])( + "of %i should return the correct set of its factors", + (num, expected) => { + expect(FindFactors(num)).toStrictEqual(expected); + } + ); +}); From 63cbf8f3bde1fce4218a34b17b62ae6252c8341f Mon Sep 17 00:00:00 2001 From: Noah <70114451+zFl4wless@users.noreply.github.com> Date: Sun, 12 Mar 2023 16:17:06 +0100 Subject: [PATCH 023/107] structure: set (#111) * structure: set * fix: hash_set implements isolated set interface * improvement: adds general abstraction * fix: renames & refactors testing * feat: resolves requested changes --- .../hashing/{hash_table.ts => hash_map.ts} | 26 +++--- data_structures/hashing/hash_map_set.ts | 24 +++++ data_structures/hashing/test/hash_map.test.ts | 91 +++++++++++++++++++ .../hashing/test/hash_table.test.ts | 91 ------------------- data_structures/map.ts | 16 ++++ data_structures/map_set.ts | 75 +++++++++++++++ data_structures/set.ts | 11 +++ 7 files changed, 231 insertions(+), 103 deletions(-) rename data_structures/hashing/{hash_table.ts => hash_map.ts} (90%) create mode 100644 data_structures/hashing/hash_map_set.ts create mode 100644 data_structures/hashing/test/hash_map.test.ts delete mode 100644 data_structures/hashing/test/hash_table.test.ts create mode 100644 data_structures/map.ts create mode 100644 data_structures/map_set.ts create mode 100644 data_structures/set.ts diff --git a/data_structures/hashing/hash_table.ts b/data_structures/hashing/hash_map.ts similarity index 90% rename from data_structures/hashing/hash_table.ts rename to data_structures/hashing/hash_map.ts index 1b63b6f1..3e976553 100644 --- a/data_structures/hashing/hash_table.ts +++ b/data_structures/hashing/hash_map.ts @@ -1,5 +1,7 @@ +import { Map } from "../map"; + /** - * Represents a hash table. + * Represents a hash map. * Time complexity: * - Set, Get, Delete, Has: O(1) on average, O(n) in the worst case. * - Clear: O(m) where m is the number of buckets. @@ -7,13 +9,13 @@ * * @template K The key type. * @template V The value type. - * @param size The size of the hash table. + * @param size The size of the hash map. * @param buckets The buckets in which to store the key-value pairs. - * @param loadFactor The load factor to determine when to resize the hash table. + * @param loadFactor The load factor to determine when to resize the hash map. */ -export class HashTable { +export class HashMap implements Map { private size!: number; - private buckets!: HashTableEntry[][]; + private buckets!: HashMapEntry[][]; private readonly loadFactor = 0.75; constructor() { @@ -45,7 +47,7 @@ export class HashTable { const bucket = this.buckets[index]; if (bucket.length === 0) { - bucket.push(new HashTableEntry(key, value)); + bucket.push(new HashMapEntry(key, value)); this.size++; return; } @@ -57,7 +59,7 @@ export class HashTable { } } - bucket.push(new HashTableEntry(key, value)); + bucket.push(new HashMapEntry(key, value)); this.size++; } @@ -118,7 +120,7 @@ export class HashTable { } /** - * Clears the hash table. + * Clears the hash map. */ clear(): void { this.size = 0; @@ -162,8 +164,8 @@ export class HashTable { * * @returns The entries. */ - entries(): HashTableEntry[] { - const entries: HashTableEntry[] = []; + entries(): HashMapEntry[] { + const entries: HashMapEntry[] = []; for (const bucket of this.buckets) { for (const entry of bucket) { entries.push(entry); @@ -204,7 +206,7 @@ export class HashTable { } /** - * Resizes the hash table by doubling the amount of buckets. + * Resizes the hash map by doubling the amount of buckets. */ private resize(): void { this.initializeBuckets(this.buckets.length * 2); @@ -224,7 +226,7 @@ export class HashTable { * @param key The key. * @param value The value. */ -class HashTableEntry { +export class HashMapEntry { key: K; value: V; diff --git a/data_structures/hashing/hash_map_set.ts b/data_structures/hashing/hash_map_set.ts new file mode 100644 index 00000000..35bfaf2b --- /dev/null +++ b/data_structures/hashing/hash_map_set.ts @@ -0,0 +1,24 @@ +import { Map } from "../map"; +import { MapSet } from "../map_set"; +import { HashMap } from "./hash_map"; + +/** + * This class is a representation of the Set data structure based on a hash map. + * + * @template K The value type. + * @extends MapSet + */ +export class HashMapSet extends MapSet { + constructor() { + super(); + } + + /** + * Initializes the map used to store the set. + * + * @returns {Map} The map used to store the set. + */ + protected initMap(): Map { + return new HashMap(); + } +} diff --git a/data_structures/hashing/test/hash_map.test.ts b/data_structures/hashing/test/hash_map.test.ts new file mode 100644 index 00000000..acec9732 --- /dev/null +++ b/data_structures/hashing/test/hash_map.test.ts @@ -0,0 +1,91 @@ +import { HashMap } from "../hash_map"; + +describe("Hash Map", () => { + let hashMap: HashMap; + beforeEach(() => { + hashMap = new HashMap(); + }); + + it("should set a value", () => { + hashMap.set("a", 1); + + expect(hashMap.values()).toEqual([1]); + }); + + it("should override a value", () => { + hashMap.set("a", 1); + hashMap.set("a", 2); + + expect(hashMap.values()).toEqual([2]); + }); + + it("should get a value", () => { + hashMap.set("a", 1); + + expect(hashMap.get("a")).toBe(1); + }); + + it("should get null if key does not exist", () => { + expect(hashMap.get("a")).toBeNull(); + }); + + it("should delete a value", () => { + hashMap.set("a", 1); + hashMap.delete("a"); + + expect(hashMap.get("a")).toBeNull(); + }); + + it("should do nothing on delete if key does not exist", () => { + hashMap.delete("a"); + + expect(hashMap.get("a")).toBeNull(); + }); + + it("should return true if key exists", () => { + hashMap.set("a", 1); + + expect(hashMap.has("a")).toBe(true); + }); + + it("should return false if key does not exist", () => { + expect(hashMap.has("a")).toBe(false); + }); + + it("should clear the hash table", () => { + hashMap.set("a", 1); + hashMap.set("b", 2); + hashMap.set("c", 3); + hashMap.clear(); + + expect(hashMap.getSize()).toBe(0); + }); + + it("should return all keys", () => { + hashMap.set("a", 1); + hashMap.set("b", 2); + hashMap.set("c", 3); + + expect(hashMap.keys()).toEqual(["a", "b", "c"]); + }); + + it("should return all values", () => { + hashMap.set("a", 1); + hashMap.set("b", 2); + hashMap.set("c", 3); + + expect(hashMap.values()).toEqual([1, 2, 3]); + }); + + it("should return all key-value pairs", () => { + hashMap.set("a", 1); + hashMap.set("b", 2); + hashMap.set("c", 3); + + expect(hashMap.entries()).toEqual([ + { key: "a", value: 1 }, + { key: "b", value: 2 }, + { key: "c", value: 3 }, + ]); + }); +}); diff --git a/data_structures/hashing/test/hash_table.test.ts b/data_structures/hashing/test/hash_table.test.ts deleted file mode 100644 index d54190a8..00000000 --- a/data_structures/hashing/test/hash_table.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { HashTable } from "../hash_table"; - -describe("Hash Table", () => { - let hashTable: HashTable; - beforeEach(() => { - hashTable = new HashTable(); - }); - - it("should set a value", () => { - hashTable.set("a", 1); - - expect(hashTable.values()).toEqual([1]); - }); - - it("should override a value", () => { - hashTable.set("a", 1); - hashTable.set("a", 2); - - expect(hashTable.values()).toEqual([2]); - }); - - it("should get a value", () => { - hashTable.set("a", 1); - - expect(hashTable.get("a")).toBe(1); - }); - - it("should get null if key does not exist", () => { - expect(hashTable.get("a")).toBeNull(); - }); - - it("should delete a value", () => { - hashTable.set("a", 1); - hashTable.delete("a"); - - expect(hashTable.get("a")).toBeNull(); - }); - - it("should do nothing on delete if key does not exist", () => { - hashTable.delete("a"); - - expect(hashTable.get("a")).toBeNull(); - }); - - it("should return true if key exists", () => { - hashTable.set("a", 1); - - expect(hashTable.has("a")).toBe(true); - }); - - it("should return false if key does not exist", () => { - expect(hashTable.has("a")).toBe(false); - }); - - it("should clear the hash table", () => { - hashTable.set("a", 1); - hashTable.set("b", 2); - hashTable.set("c", 3); - hashTable.clear(); - - expect(hashTable.getSize()).toBe(0); - }); - - it("should return all keys", () => { - hashTable.set("a", 1); - hashTable.set("b", 2); - hashTable.set("c", 3); - - expect(hashTable.keys()).toEqual(["a", "b", "c"]); - }); - - it("should return all values", () => { - hashTable.set("a", 1); - hashTable.set("b", 2); - hashTable.set("c", 3); - - expect(hashTable.values()).toEqual([1, 2, 3]); - }); - - it("should return all key-value pairs", () => { - hashTable.set("a", 1); - hashTable.set("b", 2); - hashTable.set("c", 3); - - expect(hashTable.entries()).toEqual([ - { key: "a", value: 1 }, - { key: "b", value: 2 }, - { key: "c", value: 3 }, - ]); - }); -}); diff --git a/data_structures/map.ts b/data_structures/map.ts new file mode 100644 index 00000000..46d3e8ac --- /dev/null +++ b/data_structures/map.ts @@ -0,0 +1,16 @@ +import { HashMapEntry } from "./hashing/hash_map"; + +/** + * This interface is a representation of the Map data structure. + */ +export interface Map { + getSize(): number; + set(key: K, value: V): void; + get(key: K): V | null; + delete(key: K): void; + has(key: K): boolean; + clear(): void; + keys(): K[]; + values(): V[]; + entries(): HashMapEntry[]; +} diff --git a/data_structures/map_set.ts b/data_structures/map_set.ts new file mode 100644 index 00000000..11e8c2f2 --- /dev/null +++ b/data_structures/map_set.ts @@ -0,0 +1,75 @@ +import { Map } from "./map"; +import { Set } from "./set"; + +/** + * This class is a representation of the Set data structure based on a hash map. + * + * @template K The value type. + * @implements Set + * @property {Map} map The map used to store the set. + */ +export abstract class MapSet implements Set { + private map: Map; + + constructor() { + this.map = this.initMap(); + } + + /** + * Initializes the map used to store the set. + */ + protected abstract initMap(): Map; + + /** + * Adds a new element to the set. + * + * @param value The value to add to the set. + */ + add(value: K): void { + this.map.set(value, null); + } + + /** + * Removes an element from the set. + * + * @param value The value to remove from the set. + */ + delete(value: K): void { + this.map.delete(value); + } + + /** + * Checks if the set contains a given value. + * + * @param value The value to check for. + * @returns Whether the set contains the value. + */ + has(value: K): boolean { + return this.map.has(value); + } + + /** + * Removes all elements from the set. + */ + clear(): void { + this.map.clear(); + } + + /** + * Returns an array of all the values in the set. + * + * @returns An array of all the values in the set. + */ + values(): K[] { + return this.map.keys(); + } + + /** + * Returns the number of elements in the set. + * + * @returns The number of elements in the set. + */ + getSize(): number { + return this.map.getSize(); + } +} diff --git a/data_structures/set.ts b/data_structures/set.ts new file mode 100644 index 00000000..3d814d41 --- /dev/null +++ b/data_structures/set.ts @@ -0,0 +1,11 @@ +/** + * This interface is a representation of the Set data structure. + */ +export interface Set { + getSize(): number; + add(value: K): void; + delete(value: K): void; + has(value: K): boolean; + clear(): void; + values(): K[]; +} From 4a60b9ac079f3e9f8a1821d7225156e0263c3e22 Mon Sep 17 00:00:00 2001 From: Noah <70114451+zFl4wless@users.noreply.github.com> Date: Mon, 13 Mar 2023 18:38:45 +0100 Subject: [PATCH 024/107] refactor: groups all data structures (#113) * refactor: groups all data structures * refactor: groups hashing files in set/map folder --- .../{ => list}/doubly_linked_list.ts | 0 data_structures/{ => list}/linked_list.ts | 0 .../{ => list}/singly_linked_list.ts | 0 .../list/test/doubly_linked_list.test.ts | 24 +++++++++++++++++++ .../{ => list}/test/linked_list.ts | 0 .../test/singly_linked_list.test.ts | 0 data_structures/{hashing => map}/hash_map.ts | 2 +- data_structures/{ => map}/map.ts | 2 +- .../{hashing => map}/test/hash_map.test.ts | 2 +- data_structures/{ => queue}/array_queue.ts | 0 data_structures/{ => queue}/linked_queue.ts | 0 data_structures/{ => queue}/queue.ts | 0 data_structures/{ => queue}/stack_queue.ts | 19 +++++++-------- .../{ => queue}/test/array_queue.test.ts | 0 .../{ => queue}/test/linked_queue.test.ts | 0 data_structures/{ => queue}/test/queue.ts | 1 + .../{ => queue}/test/stack_queue.test.ts | 0 .../{hashing => set}/hash_map_set.ts | 6 ++--- data_structures/{ => set}/map_set.ts | 0 data_structures/{ => set}/set.ts | 0 .../{ => stack}/linked_list_stack.ts | 2 +- data_structures/{ => stack}/stack.ts | 0 .../test/linked_list_stack.test.ts | 0 .../{ => stack}/test/stack.test.ts | 0 .../test/doubly_linked_list.test.ts | 24 ------------------- .../{ => tree}/binary_search_tree.ts | 0 .../test/binary_search_tree.test.ts | 0 27 files changed, 41 insertions(+), 41 deletions(-) rename data_structures/{ => list}/doubly_linked_list.ts (100%) rename data_structures/{ => list}/linked_list.ts (100%) rename data_structures/{ => list}/singly_linked_list.ts (100%) create mode 100644 data_structures/list/test/doubly_linked_list.test.ts rename data_structures/{ => list}/test/linked_list.ts (100%) rename data_structures/{ => list}/test/singly_linked_list.test.ts (100%) rename data_structures/{hashing => map}/hash_map.ts (99%) rename data_structures/{ => map}/map.ts (86%) rename data_structures/{hashing => map}/test/hash_map.test.ts (97%) rename data_structures/{ => queue}/array_queue.ts (100%) rename data_structures/{ => queue}/linked_queue.ts (100%) rename data_structures/{ => queue}/queue.ts (100%) rename data_structures/{ => queue}/stack_queue.ts (89%) rename data_structures/{ => queue}/test/array_queue.test.ts (100%) rename data_structures/{ => queue}/test/linked_queue.test.ts (100%) rename data_structures/{ => queue}/test/queue.ts (99%) rename data_structures/{ => queue}/test/stack_queue.test.ts (100%) rename data_structures/{hashing => set}/hash_map_set.ts (80%) rename data_structures/{ => set}/map_set.ts (100%) rename data_structures/{ => set}/set.ts (100%) rename data_structures/{ => stack}/linked_list_stack.ts (97%) rename data_structures/{ => stack}/stack.ts (100%) rename data_structures/{ => stack}/test/linked_list_stack.test.ts (100%) rename data_structures/{ => stack}/test/stack.test.ts (100%) delete mode 100644 data_structures/test/doubly_linked_list.test.ts rename data_structures/{ => tree}/binary_search_tree.ts (100%) rename data_structures/{ => tree}/test/binary_search_tree.test.ts (100%) diff --git a/data_structures/doubly_linked_list.ts b/data_structures/list/doubly_linked_list.ts similarity index 100% rename from data_structures/doubly_linked_list.ts rename to data_structures/list/doubly_linked_list.ts diff --git a/data_structures/linked_list.ts b/data_structures/list/linked_list.ts similarity index 100% rename from data_structures/linked_list.ts rename to data_structures/list/linked_list.ts diff --git a/data_structures/singly_linked_list.ts b/data_structures/list/singly_linked_list.ts similarity index 100% rename from data_structures/singly_linked_list.ts rename to data_structures/list/singly_linked_list.ts diff --git a/data_structures/list/test/doubly_linked_list.test.ts b/data_structures/list/test/doubly_linked_list.test.ts new file mode 100644 index 00000000..2e41d3af --- /dev/null +++ b/data_structures/list/test/doubly_linked_list.test.ts @@ -0,0 +1,24 @@ +import { DoublyLinkedList } from "../doubly_linked_list"; +import { testLinkedList } from "./linked_list"; + +describe("DoublyLinkedList", () => { + testLinkedList(DoublyLinkedList); + + it("should reverse the list", () => { + const list: DoublyLinkedList = new DoublyLinkedList(); + + list.append(1); + list.append(2); + list.append(3); + list.reverse(); + + expect(list.get(0)).toBe(3); + expect(list.get(1)).toBe(2); + }); + + it("should return null for reverse when list is empty", () => { + const list: DoublyLinkedList = new DoublyLinkedList(); + + expect(list.reverse()).toBeNull(); + }); +}); diff --git a/data_structures/test/linked_list.ts b/data_structures/list/test/linked_list.ts similarity index 100% rename from data_structures/test/linked_list.ts rename to data_structures/list/test/linked_list.ts diff --git a/data_structures/test/singly_linked_list.test.ts b/data_structures/list/test/singly_linked_list.test.ts similarity index 100% rename from data_structures/test/singly_linked_list.test.ts rename to data_structures/list/test/singly_linked_list.test.ts diff --git a/data_structures/hashing/hash_map.ts b/data_structures/map/hash_map.ts similarity index 99% rename from data_structures/hashing/hash_map.ts rename to data_structures/map/hash_map.ts index 3e976553..e4ad04b6 100644 --- a/data_structures/hashing/hash_map.ts +++ b/data_structures/map/hash_map.ts @@ -1,4 +1,4 @@ -import { Map } from "../map"; +import { Map } from "./map"; /** * Represents a hash map. diff --git a/data_structures/map.ts b/data_structures/map/map.ts similarity index 86% rename from data_structures/map.ts rename to data_structures/map/map.ts index 46d3e8ac..1e15c893 100644 --- a/data_structures/map.ts +++ b/data_structures/map/map.ts @@ -1,4 +1,4 @@ -import { HashMapEntry } from "./hashing/hash_map"; +import { HashMapEntry } from "./hash_map"; /** * This interface is a representation of the Map data structure. diff --git a/data_structures/hashing/test/hash_map.test.ts b/data_structures/map/test/hash_map.test.ts similarity index 97% rename from data_structures/hashing/test/hash_map.test.ts rename to data_structures/map/test/hash_map.test.ts index acec9732..ef561d97 100644 --- a/data_structures/hashing/test/hash_map.test.ts +++ b/data_structures/map/test/hash_map.test.ts @@ -1,4 +1,4 @@ -import { HashMap } from "../hash_map"; +import { HashMap } from "../../map/hash_map"; describe("Hash Map", () => { let hashMap: HashMap; diff --git a/data_structures/array_queue.ts b/data_structures/queue/array_queue.ts similarity index 100% rename from data_structures/array_queue.ts rename to data_structures/queue/array_queue.ts diff --git a/data_structures/linked_queue.ts b/data_structures/queue/linked_queue.ts similarity index 100% rename from data_structures/linked_queue.ts rename to data_structures/queue/linked_queue.ts diff --git a/data_structures/queue.ts b/data_structures/queue/queue.ts similarity index 100% rename from data_structures/queue.ts rename to data_structures/queue/queue.ts diff --git a/data_structures/stack_queue.ts b/data_structures/queue/stack_queue.ts similarity index 89% rename from data_structures/stack_queue.ts rename to data_structures/queue/stack_queue.ts index cd27a391..e6f129d0 100644 --- a/data_structures/stack_queue.ts +++ b/data_structures/queue/stack_queue.ts @@ -1,17 +1,16 @@ /** - * A Stack Based Queue Implementation. - * The Queue data structure which follows the FIFO (First in First Out) rule. - * The dequeue operation in a normal stack based queue would be o(n), as the entire has to be shifted - * With the help of two stacks, the time complexity of this can be brought down to amortized-O(1). - * Here, one stack acts as an Enqueue stack where elements are added. + * A Stack Based Queue Implementation. + * The Queue data structure which follows the FIFO (First in First Out) rule. + * The dequeue operation in a normal stack based queue would be o(n), as the entire has to be shifted + * With the help of two stacks, the time complexity of this can be brought down to amortized-O(1). + * Here, one stack acts as an Enqueue stack where elements are added. * The other stack acts as a dequeue stack which helps in dequeuing the elements */ -import { Queue } from './queue'; -import { Stack } from './stack'; - -export class StackQueue implements Queue{ +import { Stack } from "../stack/stack"; +import { Queue } from "./queue"; +export class StackQueue implements Queue { private enqueueStack: Stack = new Stack(); private dequeueStack: Stack = new Stack(); @@ -44,7 +43,7 @@ export class StackQueue implements Queue{ /** * Shifts the elements from the enqueueStack to the dequeueStack - * In the worst case, all the elements from the enqueue stack needs to shifted, which needs O(n) time. + * In the worst case, all the elements from the enqueue stack needs to shifted, which needs O(n) time. * However, after the shift, elements can de dequeued at O(1). * This helps in dequeuing the elements in amortized O(1) time. */ diff --git a/data_structures/test/array_queue.test.ts b/data_structures/queue/test/array_queue.test.ts similarity index 100% rename from data_structures/test/array_queue.test.ts rename to data_structures/queue/test/array_queue.test.ts diff --git a/data_structures/test/linked_queue.test.ts b/data_structures/queue/test/linked_queue.test.ts similarity index 100% rename from data_structures/test/linked_queue.test.ts rename to data_structures/queue/test/linked_queue.test.ts diff --git a/data_structures/test/queue.ts b/data_structures/queue/test/queue.ts similarity index 99% rename from data_structures/test/queue.ts rename to data_structures/queue/test/queue.ts index 1dc7eaec..5fb57564 100644 --- a/data_structures/test/queue.ts +++ b/data_structures/queue/test/queue.ts @@ -1,4 +1,5 @@ import { Queue } from '../queue'; + type QueueConstructor = new () => Queue export function testQueue(Queue: QueueConstructor) { it("enqueue should add a new element to the queue", () => { diff --git a/data_structures/test/stack_queue.test.ts b/data_structures/queue/test/stack_queue.test.ts similarity index 100% rename from data_structures/test/stack_queue.test.ts rename to data_structures/queue/test/stack_queue.test.ts diff --git a/data_structures/hashing/hash_map_set.ts b/data_structures/set/hash_map_set.ts similarity index 80% rename from data_structures/hashing/hash_map_set.ts rename to data_structures/set/hash_map_set.ts index 35bfaf2b..ade41cbb 100644 --- a/data_structures/hashing/hash_map_set.ts +++ b/data_structures/set/hash_map_set.ts @@ -1,6 +1,6 @@ -import { Map } from "../map"; -import { MapSet } from "../map_set"; -import { HashMap } from "./hash_map"; +import { Map } from "../map/map"; +import { HashMap } from "../map/hash_map"; +import { MapSet } from "./map_set"; /** * This class is a representation of the Set data structure based on a hash map. diff --git a/data_structures/map_set.ts b/data_structures/set/map_set.ts similarity index 100% rename from data_structures/map_set.ts rename to data_structures/set/map_set.ts diff --git a/data_structures/set.ts b/data_structures/set/set.ts similarity index 100% rename from data_structures/set.ts rename to data_structures/set/set.ts diff --git a/data_structures/linked_list_stack.ts b/data_structures/stack/linked_list_stack.ts similarity index 97% rename from data_structures/linked_list_stack.ts rename to data_structures/stack/linked_list_stack.ts index 800a4150..11b1dbd9 100644 --- a/data_structures/linked_list_stack.ts +++ b/data_structures/stack/linked_list_stack.ts @@ -1,4 +1,4 @@ -import { SinglyLinkedList } from "./singly_linked_list"; +import { SinglyLinkedList } from "../list/singly_linked_list"; /** * This is an implementation of a stack, based on a linked list. diff --git a/data_structures/stack.ts b/data_structures/stack/stack.ts similarity index 100% rename from data_structures/stack.ts rename to data_structures/stack/stack.ts diff --git a/data_structures/test/linked_list_stack.test.ts b/data_structures/stack/test/linked_list_stack.test.ts similarity index 100% rename from data_structures/test/linked_list_stack.test.ts rename to data_structures/stack/test/linked_list_stack.test.ts diff --git a/data_structures/test/stack.test.ts b/data_structures/stack/test/stack.test.ts similarity index 100% rename from data_structures/test/stack.test.ts rename to data_structures/stack/test/stack.test.ts diff --git a/data_structures/test/doubly_linked_list.test.ts b/data_structures/test/doubly_linked_list.test.ts deleted file mode 100644 index 492af254..00000000 --- a/data_structures/test/doubly_linked_list.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { DoublyLinkedList } from '../doubly_linked_list'; -import { testLinkedList } from './linked_list'; - -describe("DoublyLinkedList", () => { - testLinkedList(DoublyLinkedList); - - it("should reverse the list", () => { - const list: DoublyLinkedList = new DoublyLinkedList(); - - list.append(1); - list.append(2); - list.append(3); - list.reverse(); - - expect(list.get(0)).toBe(3); - expect(list.get(1)).toBe(2); - }); - - it('should return null for reverse when list is empty', () => { - const list: DoublyLinkedList = new DoublyLinkedList(); - - expect(list.reverse()).toBeNull(); - }); -}); diff --git a/data_structures/binary_search_tree.ts b/data_structures/tree/binary_search_tree.ts similarity index 100% rename from data_structures/binary_search_tree.ts rename to data_structures/tree/binary_search_tree.ts diff --git a/data_structures/test/binary_search_tree.test.ts b/data_structures/tree/test/binary_search_tree.test.ts similarity index 100% rename from data_structures/test/binary_search_tree.test.ts rename to data_structures/tree/test/binary_search_tree.test.ts From ea783b961d7ffeb1b65d2d9f4d46fba8047f4a9a Mon Sep 17 00:00:00 2001 From: Noah <70114451+zFl4wless@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:38:55 +0100 Subject: [PATCH 025/107] feat(maths): finishes calculate median (#114) * feat: add calculate median * Resolving comments * feat: improvements & resolves requested changes --------- Co-authored-by: syedjafer --- Maths/CalculateMedian.ts | 25 +++++++++++++++++++++++++ Maths/test/CalculateMedian.test.ts | 23 +++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 Maths/CalculateMedian.ts create mode 100644 Maths/test/CalculateMedian.test.ts diff --git a/Maths/CalculateMedian.ts b/Maths/CalculateMedian.ts new file mode 100644 index 00000000..5a6c98bc --- /dev/null +++ b/Maths/CalculateMedian.ts @@ -0,0 +1,25 @@ +/** + * @function calculateMedian + * @description This function will find the median value of an array of numbers. + * @param {number[]} numbers Sorted array of numeric values. + * @return {number} The median of input numbers. + * @see https://en.wikipedia.org/wiki/Median + * @example calculateMedian([1, 2, 4, 5, 8]) = 4 + * @example calculateMedian([1, 2, 4, 5]) = 3 + */ + +export const calculateMedian = (numbers: number[]): number => { + if (numbers.length < 1) { + throw new TypeError("Input array must contain at least one number."); + } + + const totalNumbers = numbers.length; + + if (totalNumbers % 2 === 0) { + let index = totalNumbers / 2; + return (numbers[index - 1] + numbers[index]) / 2; + } else { + let index = (totalNumbers + 1) / 2; + return numbers[index - 1]; + } +}; diff --git a/Maths/test/CalculateMedian.test.ts b/Maths/test/CalculateMedian.test.ts new file mode 100644 index 00000000..e34a71e1 --- /dev/null +++ b/Maths/test/CalculateMedian.test.ts @@ -0,0 +1,23 @@ +import { calculateMedian } from "../CalculateMedian"; + +describe("Tests for CalculateMedian", () => { + it("should be a function", () => { + expect(typeof calculateMedian).toEqual("function"); + }); + + it("should throw error for invalid input", () => { + expect(() => calculateMedian([])).toThrowError( + "Input array must contain at least one number." + ); + }); + + it("should return the median of an array of numbers - even length", () => { + const medianFunction = calculateMedian([1, 2, 3, 4]); + expect(medianFunction).toBe(2.5); + }); + + it("should return the median of an array of numbers - odd length", () => { + const medianFunction = calculateMedian([1, 2, 3, 4, 6, 8, 9]); + expect(medianFunction).toBe(4); + }); +}); From 2ac83c894ac966591fb1e51217177fb2da741220 Mon Sep 17 00:00:00 2001 From: Noah <70114451+zFl4wless@users.noreply.github.com> Date: Wed, 22 Mar 2023 05:33:06 +0100 Subject: [PATCH 026/107] feat(structure): implements circular queue (#116) * feat(structure): implements circular queue * feat: circular queue no longer implements queue interface --- data_structures/queue/circular_queue.ts | 109 ++++++++++++++++++ .../queue/test/circular_queue.test.ts | 65 +++++++++++ 2 files changed, 174 insertions(+) create mode 100644 data_structures/queue/circular_queue.ts create mode 100644 data_structures/queue/test/circular_queue.test.ts diff --git a/data_structures/queue/circular_queue.ts b/data_structures/queue/circular_queue.ts new file mode 100644 index 00000000..ce42e059 --- /dev/null +++ b/data_structures/queue/circular_queue.ts @@ -0,0 +1,109 @@ +/** + * Circular Queue implementation using array. + * + * @template T The type of the elements in the queue. + * @param {T[]} queue The array that holds the elements of the queue. + * @param {number} frontIndex The index of the front element of the queue. + * @param {number} rearIndex The index of the rear element of the queue. + * @param {number} size The size of the queue. + */ +export class CircularQueue { + private queue: T[]; + private frontIndex: number; + private rearIndex: number; + private size: number; + + constructor(size: number) { + this.queue = new Array(size); + this.frontIndex = -1; + this.rearIndex = -1; + this.size = size; + } + + /** + * Adds an item to the queue. + * + * @param item The item being added to the queue. + */ + enqueue(item: T): void { + if ( + (this.frontIndex == 0 && this.rearIndex == this.size - 1) || + this.rearIndex == (this.frontIndex - 1) % (this.size - 1) + ) { + throw new Error("Queue is full"); + } else if (this.frontIndex == -1) { + this.frontIndex = 0; + this.rearIndex = 0; + this.queue[this.rearIndex] = item; + } else if (this.rearIndex == this.size - 1 && this.frontIndex != 0) { + this.rearIndex = 0; + this.queue[this.rearIndex] = item; + } else { + this.rearIndex++; + this.queue[this.rearIndex] = item; + } + } + + /** + * Removes an item from the queue and returns it. + * + * @throws Queue Underflow if the queue is empty. + * @returns The item that was removed from the queue. + */ + dequeue(): T | undefined { + if (this.frontIndex == -1) { + throw new Error("Queue is empty"); + } + + const item = this.queue[this.frontIndex]; + if (this.frontIndex == this.rearIndex) { + this.frontIndex = -1; + this.rearIndex = -1; + } else if (this.frontIndex == this.size - 1) { + this.frontIndex = 0; + } else { + this.frontIndex++; + } + + return item; + } + + /** + * Returns the item at the front of the queue. + * + * @returns The item at the front of the queue or null if the queue is empty. + */ + peek(): T | null | undefined { + if (this.frontIndex == -1) { + return null; + } + + return this.queue[this.frontIndex]; + } + + /** + * Checks if the queue is empty. + * + * @returns {boolean} Whether the queue is empty or not. + */ + isEmpty(): boolean { + return this.frontIndex == -1; + } + + /** + * Returns the number of items in the queue. + * + * @returns {number} The number of items in the queue. + */ + length(): number { + if (this.frontIndex == -1) { + return 0; + } + + if (this.rearIndex >= this.frontIndex) { + return this.rearIndex - this.frontIndex + 1; + } + + return this.size - (this.frontIndex - this.rearIndex - 1); + } +} diff --git a/data_structures/queue/test/circular_queue.test.ts b/data_structures/queue/test/circular_queue.test.ts new file mode 100644 index 00000000..042e5d81 --- /dev/null +++ b/data_structures/queue/test/circular_queue.test.ts @@ -0,0 +1,65 @@ +import { CircularQueue } from "../circular_queue"; + +describe("Circular Queue", () => { + let queue: CircularQueue; + + beforeEach(() => { + queue = new CircularQueue(5); + }); + + it("should enqueue an element", () => { + queue.enqueue(1); + + expect(queue.peek()).toBe(1); + }); + + it("should throw an error on enqueue when queue is full", () => { + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + queue.enqueue(4); + queue.enqueue(5); + + expect(() => queue.enqueue(6)).toThrowError("Queue is full"); + }); + + it("should dequeue an element", () => { + queue.enqueue(1); + queue.enqueue(2); + + expect(queue.dequeue()).toBe(1); + }); + + it("should throw an error on dequeue when queue is empty", () => { + expect(() => queue.dequeue()).toThrowError("Queue is empty"); + }); + + it("should peek an element", () => { + queue.enqueue(1); + queue.enqueue(2); + + expect(queue.peek()).toBe(1); + }); + + it("should return null on peek when queue is empty", () => { + expect(queue.peek()).toBeNull(); + }); + + it("should return true on isEmpty when queue is empty", () => { + expect(queue.isEmpty()).toBeTruthy(); + }); + + it("should return false on isEmpty when queue is not empty", () => { + queue.enqueue(1); + + expect(queue.isEmpty()).toBeFalsy(); + }); + + it("should return the correct length", () => { + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + + expect(queue.length()).toBe(3); + }); +}); From 7e23e1e75c82eb367bf3af6ee21ff74824adcec9 Mon Sep 17 00:00:00 2001 From: Noah <70114451+zFl4wless@users.noreply.github.com> Date: Sun, 26 Mar 2023 06:46:22 +0200 Subject: [PATCH 027/107] feat(maths): is palindrome number (#118) * Is Palindrome Number * Is Palindrome Number update * Added tests and updated Directory.md * updated Directory.md * feat(maths): improvements & resolved changes * feat: improves algorithm & adjusts tests * feat: documents limitation --------- Co-authored-by: Fatima --- DIRECTORY.md | 1 + maths/is_palindrome.ts | 21 +++++++++++++++++++++ maths/test/is_palindrome.test.ts | 10 ++++++++++ 3 files changed, 32 insertions(+) create mode 100644 maths/is_palindrome.ts create mode 100644 maths/test/is_palindrome.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 3f34cc78..a86803d1 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -29,6 +29,7 @@ * [Is Even](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_even.ts) * [Is Leap Year](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_leap_year.ts) * [Is Odd](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_odd.ts) + * [Is Palindrome](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_palindrome.ts) * [Is Square Free](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_square_free.ts) * [Lowest Common Multiple](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/lowest_common_multiple.ts) * [Perfect Square](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_square.ts) diff --git a/maths/is_palindrome.ts b/maths/is_palindrome.ts new file mode 100644 index 00000000..f093d9be --- /dev/null +++ b/maths/is_palindrome.ts @@ -0,0 +1,21 @@ +/** + * A function to see if a number is a palindrome. + * Note that if the reversed number is larger than MAX_SAFE_INTEGER, rounding errors may occur and the result may be incorrect. + * Time Complexity: O(log(n)) + * + * @param number The input number. + * @return {boolean} Wether the number is a Palindrome or not. + */ +export const IsPalindrome = (number: number): boolean => { + if (number < 0 || (number % 10 === 0 && number !== 0)) { + return false; + } + + let reversed: number = 0; + while (number > reversed) { + reversed = reversed * 10 + (number % 10); + number = Math.floor(number / 10); + } + + return number === reversed || number === Math.floor(reversed / 10); +}; diff --git a/maths/test/is_palindrome.test.ts b/maths/test/is_palindrome.test.ts new file mode 100644 index 00000000..fa375f73 --- /dev/null +++ b/maths/test/is_palindrome.test.ts @@ -0,0 +1,10 @@ +import { IsPalindrome } from "../is_palindrome"; + +describe("IsPalindrome", () => { + test.each([[5, true], [1234, false], [12321, true], [31343, false]])( + "correct output for %i", + (nums, expected) => { + expect(IsPalindrome(nums)).toBe(expected); + }, + ); +}); \ No newline at end of file From 23c96de75cedd1ea1f60d19bb79b574cfedc881d Mon Sep 17 00:00:00 2001 From: Noah <70114451+zFl4wless@users.noreply.github.com> Date: Fri, 31 Mar 2023 07:10:16 +0200 Subject: [PATCH 028/107] fix(core): double math folder & naming conventions (#119) --- Maths/CalculateMedian.ts => maths/calculate_median.ts | 0 .../test/calculate_median.test.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename Maths/CalculateMedian.ts => maths/calculate_median.ts (100%) rename Maths/test/CalculateMedian.test.ts => maths/test/calculate_median.test.ts (93%) diff --git a/Maths/CalculateMedian.ts b/maths/calculate_median.ts similarity index 100% rename from Maths/CalculateMedian.ts rename to maths/calculate_median.ts diff --git a/Maths/test/CalculateMedian.test.ts b/maths/test/calculate_median.test.ts similarity index 93% rename from Maths/test/CalculateMedian.test.ts rename to maths/test/calculate_median.test.ts index e34a71e1..b9aa345e 100644 --- a/Maths/test/CalculateMedian.test.ts +++ b/maths/test/calculate_median.test.ts @@ -1,4 +1,4 @@ -import { calculateMedian } from "../CalculateMedian"; +import { calculateMedian } from "../calculate_median"; describe("Tests for CalculateMedian", () => { it("should be a function", () => { From 05d876de28c153511754ac645314e64b7f382417 Mon Sep 17 00:00:00 2001 From: Maik <58326890+zFlxw@users.noreply.github.com> Date: Fri, 31 Mar 2023 07:10:49 +0200 Subject: [PATCH 029/107] feat(maths): juggler sequence (#120) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(data-struct): binary search tree * fix: improvements part 1 * fix: improvements part 2 * Fix failing tests * feat: juggler sequence * refactor: changes if statement to ternary operator --------- Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- maths/juggler_sequence.ts | 23 +++++++++++++++++++++++ maths/test/juggler_sequence.test.ts | 12 ++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 maths/juggler_sequence.ts create mode 100644 maths/test/juggler_sequence.test.ts diff --git a/maths/juggler_sequence.ts b/maths/juggler_sequence.ts new file mode 100644 index 00000000..6ddddd16 --- /dev/null +++ b/maths/juggler_sequence.ts @@ -0,0 +1,23 @@ +/** + * The juggler sequence is a integer sequence that starts with an positive integer a and the subsequent terms are + * described as following: + * if a_k is even: + * a_k+1 = floor(sqrt(a_k)) + * else: + * a_k+1 = floor(sqrt(a_k^3)) + * + * Time Complexity: linear (O(n)) + * + * @param a The number to start with + * @param n The index of the searched number in the sequence. + * @returns The number at index n in the sequence. + * @see https://en.wikipedia.org/wiki/Juggler_sequence + */ +export const jugglerSequence = (a: number, n: number) => { + let k: number = a; + for (let i: number = 0; i < n; i++) { + k = Math.floor(Math.pow(k, (k % 2 === 0 ? 1 : 3) / 2)); + } + + return k; +}; diff --git a/maths/test/juggler_sequence.test.ts b/maths/test/juggler_sequence.test.ts new file mode 100644 index 00000000..038c7011 --- /dev/null +++ b/maths/test/juggler_sequence.test.ts @@ -0,0 +1,12 @@ +import { jugglerSequence } from '../juggler_sequence'; + +describe('jugglerSequence', () => { + it.each([ + [3, 3, 36], + [3, 5, 2], + [7, 3, 2], + [5, 1, 11], + ])('%i at index %i should equal %i', (a, n, k) => { + expect(jugglerSequence(a, n)).toBe(k); + }); +}); From e85ea1b427840f3a75cef88c58e526ffff07ca88 Mon Sep 17 00:00:00 2001 From: Maik <58326890+zFlxw@users.noreply.github.com> Date: Mon, 3 Apr 2023 08:00:32 +0200 Subject: [PATCH 030/107] feat: Pascal's Triangle (#121) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(data-struct): binary search tree * fix: improvements part 1 * fix: improvements part 2 * Fix failing tests * feat: pascals triangle --------- Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- maths/pascals_triangle.ts | 40 +++++++++++++++++++++++++++++ maths/test/pascals_triangle.test.ts | 11 ++++++++ 2 files changed, 51 insertions(+) create mode 100644 maths/pascals_triangle.ts create mode 100644 maths/test/pascals_triangle.test.ts diff --git a/maths/pascals_triangle.ts b/maths/pascals_triangle.ts new file mode 100644 index 00000000..cce4bfd1 --- /dev/null +++ b/maths/pascals_triangle.ts @@ -0,0 +1,40 @@ +/** + * Pascal's Triangle is an array of binomial coefficients. It can be used for unwrapping terms like + * (a + b)^5. + * To construct Pascal's Triangle you add the numbers above the child entry together. Here are the first five rows: + * 1 + * 1 1 + * 1 2 1 + * 1 3 3 1 + * 1 4 6 4 1 + * + * Time Complexity: quadratic (O(n^2)). + * + * @param n The exponent / The index of the searched row. + * @returns The nth row of Pascal's Triangle + * @see https://en.wikipedia.org/wiki/Pascal's_triangle + */ +export const pascalsTriangle = (n: number): number[] => { + let arr: number[][] = []; + for (let i: number = 0; i < n; i++) { + if (i === 0) { + arr.push([1]); + continue; + } + + let lastRow: number[] = arr[i - 1]; + let temp: number[] = []; + for (let j: number = 0; j < lastRow.length + 1; j++) { + if (j === 0 || j === lastRow.length) { + temp.push(1); + continue; + } + + temp.push(lastRow[j - 1] + lastRow[j]); + } + + arr.push(temp); + } + + return arr[arr.length - 1]; +}; diff --git a/maths/test/pascals_triangle.test.ts b/maths/test/pascals_triangle.test.ts new file mode 100644 index 00000000..7091ce13 --- /dev/null +++ b/maths/test/pascals_triangle.test.ts @@ -0,0 +1,11 @@ +import { pascalsTriangle } from "../pascals_triangle"; + +describe('pascalsTriangle', () => { + it.each([ + [2, [1, 1]], + [4, [1, 3, 3, 1]], + [6, [1, 5, 10, 10, 5, 1]], + ])('The %i th row should equal to %i', (n, expectation) => { + expect(pascalsTriangle(n)).toEqual(expectation); + }); +}); From 4b953f3349e5e655a3e2cf146870acf905e350c5 Mon Sep 17 00:00:00 2001 From: Oke Ebiyomare <31276573+codeazq@users.noreply.github.com> Date: Mon, 3 Apr 2023 07:01:52 +0100 Subject: [PATCH 031/107] feat: add min heap and max heap data structure (#117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add min heap and max heap data structure * fix: extract common heap operations to base class * add check for heap invariant * move check operations to _check, throw error when check fails * `return` and `&&` are superfluous now * Fix return types * Missed a `return true` --------- Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- data_structures/heap/heap.ts | 121 +++++++++++++++++++++ data_structures/heap/max_heap.ts | 40 +++++++ data_structures/heap/min_heap.ts | 40 +++++++ data_structures/heap/test/max_heap.test.ts | 29 +++++ data_structures/heap/test/min_heap.test.ts | 29 +++++ 5 files changed, 259 insertions(+) create mode 100644 data_structures/heap/heap.ts create mode 100644 data_structures/heap/max_heap.ts create mode 100644 data_structures/heap/min_heap.ts create mode 100644 data_structures/heap/test/max_heap.test.ts create mode 100644 data_structures/heap/test/min_heap.test.ts diff --git a/data_structures/heap/heap.ts b/data_structures/heap/heap.ts new file mode 100644 index 00000000..1782aabd --- /dev/null +++ b/data_structures/heap/heap.ts @@ -0,0 +1,121 @@ +export abstract class Heap { + protected heap: T[]; + + constructor(elements: T[] = []) { + this.heap = []; + for (let element of elements) { + this.insert(element); + } + } + + /** + * Compares the value at parentIndex with the value at childIndex + * In a maxHeap the value at parentIndex should be larger than the value at childIndex + * In a minHeap the value at parentIndex should be smaller than the value at childIndex + * + */ + protected abstract isRightlyPlaced( + childIndex: number, + parentIndex: number + ): boolean; + + /** + * In a maxHeap the the index with the larger value in returned + * In a maxHeap the the index with the larger value in returned + */ + protected abstract getChildIndexToSwap( + leftChildIndex: number, + rightChildIndex: number + ): number; + + public insert(value: T): void { + this.heap.push(value); + this.bubbleUp(); + } + + public extract(): T { + let maxElement = this.heap[0]; + this.heap[0] = this.heap[this.size() - 1]; + this.heap.pop(); + this.sinkDown(); + return maxElement; + } + + public size(): number { + return this.heap.length; + } + + public isEmpty(): boolean { + return this.size() === 0; + } + + protected bubbleUp(): void { + let index = this.size() - 1; + let parentIndex; + + while (index > 0) { + parentIndex = Math.floor((index - 1) / 2); + if (this.isRightlyPlaced(index, parentIndex)) break; + [this.heap[parentIndex], this.heap[index]] = [ + this.heap[index], + this.heap[parentIndex], + ]; + index = parentIndex; + } + } + + protected sinkDown(): void { + let index = 0; + let leftChildIndex = this.getLeftChildIndex(index); + let rightChildIndex = this.getRightChildIndex(index); + let childIndexToSwap; + + while (this.heap[leftChildIndex] || this.heap[rightChildIndex]) { + childIndexToSwap = this.getChildIndexToSwap( + leftChildIndex, + rightChildIndex + ); + if (this.isRightlyPlaced(childIndexToSwap, index)) break; + [this.heap[childIndexToSwap], this.heap[index]] = [ + this.heap[index], + this.heap[childIndexToSwap], + ]; + index = childIndexToSwap; + leftChildIndex = this.getLeftChildIndex(index); + rightChildIndex = this.getRightChildIndex(index); + } + } + + protected getLeftChildIndex(index: number): number { + return index * 2 + 1; + } + + protected getRightChildIndex(index: number): number { + return index * 2 + 2; + } + + public check(): void { + return this._check(); + } + + protected _check(index: number = 0): void { + if (!this.heap[index]) return; + const leftChildIndex = this.getLeftChildIndex(index); + const rightChildIndex = this.getRightChildIndex(index); + + if ( + this.heap[leftChildIndex] && + !this.isRightlyPlaced(leftChildIndex, index) + ) + throw new Error("Heap does not adhere to heap invariant"); + + if ( + this.heap[rightChildIndex] && + !this.isRightlyPlaced(rightChildIndex, index) + ) + throw new Error("Heap does not adhere to heap invariant"); + + this._check(leftChildIndex); + this._check(rightChildIndex); + } +} diff --git a/data_structures/heap/max_heap.ts b/data_structures/heap/max_heap.ts new file mode 100644 index 00000000..e5307bfc --- /dev/null +++ b/data_structures/heap/max_heap.ts @@ -0,0 +1,40 @@ +import { Heap } from "./heap"; + +/** + * A heap is a complete binary tree + * In a complete binary tree each level is filled before lower levels are added + * Each level is filled from left to right + * + * In a max heap the value of every node is greater than that if its children + * + * The heap if often implemented using an array structure. + * In the array implementation, the relationship between a parent index and its two children + * are ((parentindex * 2) + 1) and ((parentindex * 2) + 2) + * + */ +export class MaxHeap extends Heap { + constructor(elements: T[] = []) { + super(elements); + } + + /** + * Checks if the value at the parent index is larger than or equal to + * the value at the child index + */ + protected isRightlyPlaced(childIndex: number, parentIndex: number): boolean { + return this.heap[parentIndex] >= this.heap[childIndex]; + } + + /** + * Returns the child index that stores a larger value + */ + protected getChildIndexToSwap( + leftChildIndex: number, + rightChildIndex: number + ): number { + return (this.heap[leftChildIndex] || -Infinity) > + (this.heap[rightChildIndex] || -Infinity) + ? leftChildIndex + : rightChildIndex; + } +} diff --git a/data_structures/heap/min_heap.ts b/data_structures/heap/min_heap.ts new file mode 100644 index 00000000..fa50a0a0 --- /dev/null +++ b/data_structures/heap/min_heap.ts @@ -0,0 +1,40 @@ +import { Heap } from "./heap"; + +/** + * A heap is a complete binary tree + * In a complete binary tree each level is filled before lower levels are added + * Each level is filled from left to right + * + * In a min heap the value of every node is smaller than that if its children + * + * The heap if often implemented using an array structure. + * In the array implementation, the relationship between a parent index and its two children + * are ((parentindex * 2) + 1) and ((parentindex * 2) + 2) + * + */ +export class MinHeap extends Heap { + constructor(elements: T[] = []) { + super(elements); + } + + /** + * Checks if the value at the parent index is lesser than or equal to + * the value at the child index + */ + protected isRightlyPlaced(childIndex: number, parentIndex: number): boolean { + return this.heap[parentIndex] <= this.heap[childIndex]; + } + + /** + * Returns the child index that stores a smaller value + */ + protected getChildIndexToSwap( + leftChildIndex: number, + rightChildIndex: number + ): number { + return (this.heap[leftChildIndex] || -Infinity) < + (this.heap[rightChildIndex] || -Infinity) + ? leftChildIndex + : rightChildIndex; + } +} diff --git a/data_structures/heap/test/max_heap.test.ts b/data_structures/heap/test/max_heap.test.ts new file mode 100644 index 00000000..0f49f876 --- /dev/null +++ b/data_structures/heap/test/max_heap.test.ts @@ -0,0 +1,29 @@ +import { MaxHeap } from "../max_heap"; + +describe("MaxHeap", () => { + let heap: MaxHeap; + + beforeAll(() => { + const elements: number[] = [ + 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18, + ]; + heap = new MaxHeap(elements); + }); + + it("should initialize a heap from input array", () => { + expect(heap.isEmpty()).toEqual(false); + heap.check(); + }); + + it("should remove and return the max element in the heap", () => { + const maxValue = heap.extract(); + + expect(maxValue).toEqual(81); + heap.check(); + }); + + it("should insert a new element and bubble Up the element to it correct index in the heap", () => { + heap.insert(61); + heap.check(); + }); +}); diff --git a/data_structures/heap/test/min_heap.test.ts b/data_structures/heap/test/min_heap.test.ts new file mode 100644 index 00000000..8132a05c --- /dev/null +++ b/data_structures/heap/test/min_heap.test.ts @@ -0,0 +1,29 @@ +import { MinHeap } from "../min_heap"; + +describe("MinHeap", () => { + let heap: MinHeap; + + beforeAll(() => { + const elements: number[] = [ + 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18, + ]; + heap = new MinHeap(elements); + }); + + it("should initialize a heap from input array", () => { + expect(heap.isEmpty()).toEqual(false); + heap.check(); + }); + + it("should remove and return the min element in the heap", () => { + const minValue = heap.extract(); + + expect(minValue).toEqual(1); + heap.check(); + }); + + it("should insert a new element and bubble Up the element to it correct index in the heap", () => { + heap.insert(24); + heap.check(); + }); +}); From ee9727f2ab3d6157ddac6ff327de357418a4e333 Mon Sep 17 00:00:00 2001 From: Maik <58326890+zFlxw@users.noreply.github.com> Date: Thu, 6 Apr 2023 19:40:41 +0200 Subject: [PATCH 032/107] feat: perfect cube (#122) * feat: perfect cube * fix: errors due to floating-point approximation --- maths/perfect_cube.ts | 9 +++++++++ maths/test/perfect_cube.test.ts | 15 +++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 maths/perfect_cube.ts create mode 100644 maths/test/perfect_cube.test.ts diff --git a/maths/perfect_cube.ts b/maths/perfect_cube.ts new file mode 100644 index 00000000..5f76b539 --- /dev/null +++ b/maths/perfect_cube.ts @@ -0,0 +1,9 @@ +/** + * A number is a perfect cube, if the cube root is an integer. + * + * @param n The number to check. + */ + +export const perfectCube = (n: number): boolean => { + return Math.round(n ** (1 / 3)) ** 3 === n; +}; diff --git a/maths/test/perfect_cube.test.ts b/maths/test/perfect_cube.test.ts new file mode 100644 index 00000000..731ec67f --- /dev/null +++ b/maths/test/perfect_cube.test.ts @@ -0,0 +1,15 @@ +import { perfectCube } from "../perfect_cube"; + +describe('perfect cube tests', () => { + it.each([ + [27, true], + [9, false], + [8, true], + [12, false], + [64, true], + [151, false], + [125, true], + ])('The return value of %i should be %s', (n, expectation) => { + expect(perfectCube(n)).toBe(expectation); + }); +}); From 3787b3832ca64b119d8290df919b924e5855991a Mon Sep 17 00:00:00 2001 From: Horza <81642088+21Horza@users.noreply.github.com> Date: Wed, 12 Apr 2023 23:22:42 +0800 Subject: [PATCH 033/107] feat: add shell sort (#124) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add shell sort algorithm * feat: add shell sort algorithm * fix: shell sort test * Use shifts instead of floor(x / 2), add some comments --------- Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- sorts/shell_sort.ts | 31 +++++++++++++++++++++++++++++++ sorts/test/shell_sort.test.ts | 15 +++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 sorts/shell_sort.ts create mode 100644 sorts/test/shell_sort.test.ts diff --git a/sorts/shell_sort.ts b/sorts/shell_sort.ts new file mode 100644 index 00000000..f9012ee6 --- /dev/null +++ b/sorts/shell_sort.ts @@ -0,0 +1,31 @@ +/** + * @function shellSort + * @description Shell sort algorithm is the optimization for insertion sort algorithm. + * @Complexity_Analysis + * Space complexity - O(1) + * Time complexity + * Best case - Ω(n log(n)) + * Worst case - O(n^2) + * Average case - O(n log(n)^2) + * + * @param {T[]} arr - The input array + * @return {Array} - The sorted array. + * @see [Shell Sort] (https://www.geeksforgeeks.org/shellsort/) + * @example shellSort([4, 1, 8, 10, 3, 2, 5, 0, 7, 6, 9]) = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + */ +export function shellSort(arr: T[]): Array { + // start with the biggest gap, reduce gap twice on each step + for (let gap = arr.length >> 1; gap > 0; gap >>= 1) { + for (let i = gap; i < arr.length; i++) { + const temp = arr[i]; + let j = i; // index for compared element on the left side + // shift larger elements down + while (j >= gap && arr[j - gap] > temp) { + arr[j] = arr[j - gap]; + j -= gap; + } + arr[j] = temp; // place i-th element at appropriate position + } + } + return arr; +} diff --git a/sorts/test/shell_sort.test.ts b/sorts/test/shell_sort.test.ts new file mode 100644 index 00000000..695050f4 --- /dev/null +++ b/sorts/test/shell_sort.test.ts @@ -0,0 +1,15 @@ +import { shellSort } from "../shell_sort"; + +describe("Shell Sort", () => { + it("should return the correct value for average case", () => { + expect(shellSort([4, 1, 8, 10, 3, 2, 5, 0, 7, 6, 9])).toStrictEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); + + it("should return the correct value for worst case", () => { + expect(shellSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0])).toStrictEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); + + it("should return the correct value for best case", () => { + expect(shellSort([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])).toStrictEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); +}); \ No newline at end of file From 2603b2245ce073e18f096d3484335eb12b9d072c Mon Sep 17 00:00:00 2001 From: Benben Weng <61361198+benben6515@users.noreply.github.com> Date: Mon, 1 May 2023 14:40:00 +0800 Subject: [PATCH 034/107] feat: update merge_sort.ts (#126) * Update merge_sort.ts - use JavaScript ES6 syntax - use `let`, `const` instead of `var` - make it more "clean", I supposed * fix: merge_sort.ts and mroe - fix merge_sort with return copy of array - rename merge_sort.ts `MergeSrot` => `mergeSort` - rename quick_sort.ts `QuickSrot` => `quickSort` - rename merge_sort.test.ts `MergeSrot` => `mergeSort` - rename quick_sort.test.ts `QuickSrot` => `quickSort` * fix: update merge_sort.ts * fix: update merge_sort.ts * fix: convert naming of quick_sort.ts * fix: convert naming of quick_sort.ts --- package.json | 1 - sorts/merge_sort.ts | 67 ++++++++++++++++------------------- sorts/test/merge_sort.test.ts | 29 ++++++++------- 3 files changed, 44 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index c0495f29..b3a21669 100644 --- a/package.json +++ b/package.json @@ -19,4 +19,3 @@ "author": "TheAlgorithms", "license": "MIT" } - \ No newline at end of file diff --git a/sorts/merge_sort.ts b/sorts/merge_sort.ts index 6a719226..a4f164ef 100644 --- a/sorts/merge_sort.ts +++ b/sorts/merge_sort.ts @@ -5,52 +5,45 @@ * @example MergeSort([8, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 8] * @Complexity_Analysis * Space complexity - O(n) - * Time complexity + * Time complexity * Best case - O(nlogn) * Worst case - O(nlogn) * Average case - O(nlogn) - * - * Merge Sort is a recursive algorithm and time complexity can be expressed as following recurrence relation. - * T(n) = 2T(n/2) + O(n) + * + * Merge Sort is a recursive algorithm and time complexity can be expressed as following recurrence relation. + * T(n) = 2T(n/2) + O(n) * The solution of the above recurrence is O(nLogn). */ - export const MergeSort = (items: number[]): number[] => { - var halfLength = Math.ceil(items.length / 2); - var low = items.slice(0, halfLength); - var high = items.slice(halfLength); - if (halfLength > 1) { - low = MergeSort(low); - high = MergeSort(high); - } - return merge(low, high); -}; +export function mergeSort(array: number[]): number[] { + if (array.length <= 1) return array.slice() -export const merge = (low: number[], high: number[]): number[] => { - let indexLow = 0; - let indexHigh = 0; - let curIndex = 0; - let merged = Array(low.length + high.length); + const midIndex = Math.floor(array.length / 2) + const left = array.slice(0, midIndex) + const right = array.slice(midIndex, array.length) - while (indexLow < low.length && indexHigh < high.length) { + return merge(mergeSort(left), mergeSort(right)) +} - if (low[indexLow] <= high[indexHigh]) { - merged[curIndex++] = low[indexLow]; - indexLow++; - } else { - merged[curIndex++] = high[indexHigh]; - indexHigh++; - } - } +function merge(left: number[], right: number[]): number[] { + const result = Array(left.length + right.length) + let curIndex = 0 + let leftIndex = 0 + let rightIndex = 0 - while (indexLow < low.length) { - merged[curIndex++] = low[indexLow]; - indexLow++; + while (leftIndex < left.length && rightIndex < right.length) { + if (left[leftIndex] < right[rightIndex]) { + result[curIndex++] = left[leftIndex++] + } else { + result[curIndex++] = right[rightIndex++] } + } + while (leftIndex < left.length) { + result[curIndex++] = left[leftIndex++] + } + while (rightIndex < right.length) { + result[curIndex++] = right[rightIndex++] + } - while (indexHigh < high.length) { - merged[curIndex++] = high[indexHigh]; - indexHigh++; - } - return merged; -}; + return result +} diff --git a/sorts/test/merge_sort.test.ts b/sorts/test/merge_sort.test.ts index 8b85c712..5b6f81fc 100644 --- a/sorts/test/merge_sort.test.ts +++ b/sorts/test/merge_sort.test.ts @@ -1,19 +1,18 @@ -import { MergeSort } from "../merge_sort"; +import { mergeSort } from "../merge_sort" describe("Merge Sort", () => { - it("generating array with variable length and comparing with sorted array", () => { - let arrLenArr = [10, 200, 40000]; + it("generating array with variable length and comparing with sorted array", () => { + let arrLenArr = [10, 200, 40000] - arrLenArr.forEach((arrLen: number) => { - - let inBuiltSortArr = Array(arrLen) - for (let i = 0; i < arrLen; i++) { inBuiltSortArr[i] = Math.random() * 10000 } - let mergeSortArray = inBuiltSortArr.slice(); - - inBuiltSortArr.sort((a, b) => a - b); - expect(MergeSort(mergeSortArray)).toStrictEqual(inBuiltSortArr); - - }) - }); -}); + arrLenArr.forEach((arrLen: number) => { + let inBuiltSortArr = Array(arrLen) + for (let i = 0; i < arrLen; i++) { + inBuiltSortArr[i] = Math.random() * 10000 + } + let mergeSortArray = inBuiltSortArr.slice() + inBuiltSortArr.sort((a, b) => a - b) + expect(mergeSort(mergeSortArray)).toStrictEqual(inBuiltSortArr) + }) + }) +}) From 23e9dc04dbd77f9c5ccbd8fe98964ac07a429f3d Mon Sep 17 00:00:00 2001 From: Samuel David Suarez Rodriguez <42628316+samueldsr99@users.noreply.github.com> Date: Fri, 5 May 2023 00:31:47 -0400 Subject: [PATCH 035/107] Add `DisjointSet` algorithm (#127) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add disjoint set algorithm * test: add tests for disjoint set * chore: Fix comments * doc: improve complexity documentation * Explain what alpha is * Fix typos, undo previous oops --------- Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- data_structures/disjoint_set/disjoint_set.ts | 71 +++++++++++++++++++ .../disjoint_set/test/disjoint_set.test.ts | 24 +++++++ 2 files changed, 95 insertions(+) create mode 100644 data_structures/disjoint_set/disjoint_set.ts create mode 100644 data_structures/disjoint_set/test/disjoint_set.test.ts diff --git a/data_structures/disjoint_set/disjoint_set.ts b/data_structures/disjoint_set/disjoint_set.ts new file mode 100644 index 00000000..f627e8ec --- /dev/null +++ b/data_structures/disjoint_set/disjoint_set.ts @@ -0,0 +1,71 @@ +/** + * A Disjoint Set is a data structure that keeps track of a set of elements + * partitioned into a number of disjoint (non-overlapping) subsets. + * Elements are uniquely represented by an index (0-based). + * + * The find operation uses path compression. + * This allows the time complexity of the find operation be O(alpha(n)). + * alpha(n) being the inverse Ackermann function. + * + * The join operation uses union by size: The smaller set is joined to the bigger one. + * + * You can perform the following operations on the disjoint set: + * - find: Determine which subset a particular element is in - O(alpha(n)) + * - join: Join two subsets into a single subset - O(1) + * - isSame: Check if two elements are in the same subset - O(1) + */ +export class DisjointSet { + /** Direct parent for an element */ + private head: number[]; + + /** Size of the subtree above an element */ + private size: number[]; + + constructor(n: number) { + // Initially each set has its own id element + this.head = Array.from({ length: n }, (_, index) => index); + this.size = Array(n).fill(1); + } + + /** + * Find the representative index for an element + */ + find(index: number): number { + if (this.head[index] != index) { + // Use path compression (set an edge between the element and its head) + this.head[index] = this.find(this.head[index]); + } + return this.head[index]; + } + + + /** + * Join two sets + */ + join(first: number, second: number): void { + // Get the root of each set to join + let firstHead = this.find(first); + let secondHead = this.find(second); + + // If they're the same (same set) + if (firstHead === secondHead) return; + + // Keep the bigger set in firstHead + if (this.size[firstHead] < this.size[secondHead]) { + [firstHead, secondHead] = [secondHead, firstHead]; + } + + // Join the smallest set with the bigger one + this.head[secondHead] = firstHead; + + // Update size of the bigger set after join + this.size[firstHead] += this.size[secondHead]; + } + + /** + * Check whether two elements are in the same set + */ + isSame(first: number, second: number): boolean { + return this.find(first) === this.find(second); + } +} diff --git a/data_structures/disjoint_set/test/disjoint_set.test.ts b/data_structures/disjoint_set/test/disjoint_set.test.ts new file mode 100644 index 00000000..3409426a --- /dev/null +++ b/data_structures/disjoint_set/test/disjoint_set.test.ts @@ -0,0 +1,24 @@ +import { DisjointSet } from "../disjoint_set" + +describe("DisjointSet", () => { + let ds: DisjointSet; + + beforeEach(() => { + // Ensure create a new DisjoinSet instance on every test + ds = new DisjointSet(10); + }); + + it("should show proper head element after join", () => { + expect(ds.find(0)).toEqual(0); + + ds.join(1, 4); + ds.join(2, 3); + expect(ds.isSame(1, 4)).toEqual(true); + expect(ds.isSame(2, 3)).toEqual(true); + expect(ds.isSame(1, 3)).toEqual(false); + + ds.join(4, 3); + expect(ds.isSame(1, 3)).toEqual(true); + expect(ds.isSame(2, 9)).toEqual(false); + }); +}) From 1cc8c9823ac01092f6cbbbb89ef2efbd23a9401e Mon Sep 17 00:00:00 2001 From: Rahul Rao <63695122+rahulrao0209@users.noreply.github.com> Date: Wed, 10 May 2023 02:08:15 +0530 Subject: [PATCH 036/107] chore: Fixed a comment in heap.ts (#129) --- data_structures/heap/heap.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_structures/heap/heap.ts b/data_structures/heap/heap.ts index 1782aabd..71f03be3 100644 --- a/data_structures/heap/heap.ts +++ b/data_structures/heap/heap.ts @@ -20,8 +20,8 @@ export abstract class Heap { ): boolean; /** - * In a maxHeap the the index with the larger value in returned - * In a maxHeap the the index with the larger value in returned + * In a maxHeap the index with the larger value is returned + * In a minHeap the index with the smaller value is returned */ protected abstract getChildIndexToSwap( leftChildIndex: number, From 724d246889ac0d1d9c50e26fcaa823e3893f1a55 Mon Sep 17 00:00:00 2001 From: BSzmolke <40246238+BSzmolke@users.noreply.github.com> Date: Mon, 22 May 2023 07:10:31 +0200 Subject: [PATCH 037/107] feat: add cycle sort implementation (#132) * feat: add cycle sort implementation * feat: add cycle sort implementation - post review changes --- DIRECTORY.md | 1 + sorts/cycle_sort.ts | 63 +++++++++++++++++++++++++++++++++++ sorts/test/cycle_sort.test.ts | 15 +++++++++ 3 files changed, 79 insertions(+) create mode 100644 sorts/cycle_sort.ts create mode 100644 sorts/test/cycle_sort.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index a86803d1..9e988910 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -53,6 +53,7 @@ ## Sorts * [Bubble Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/bubble_sort.ts) + * [Cycle Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/cycle_sort.ts) * [Gnome Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/gnome_sort.ts) * [Insertion Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/insertion_sort.ts) * [Merge Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/merge_sort.ts) diff --git a/sorts/cycle_sort.ts b/sorts/cycle_sort.ts new file mode 100644 index 00000000..a43f8873 --- /dev/null +++ b/sorts/cycle_sort.ts @@ -0,0 +1,63 @@ +/** + * @function cycleSort + * @description Cycle sort is an in-place, unstable sorting algorithm, a comparison sort that is theoretically optimal in terms of the total number of writes to the original array, unlike any other in-place sorting algorithm. It is based on the idea that the permutation to be sorted can be factored into cycles, which can individually be rotated to give a sorted result. + * @param {number[]}array - The input array + * @return {number[]} - The sorted array. + * @see [CycleSort] https://en.wikipedia.org/wiki/Cycle_sort + * @example cycleSort([8, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 8] + */ + +export const cycleSort = (array: number[]) => { + for (let i: number = 0; i < array.length - 1; i++) { + MoveCycle(array, i); + } + return array; +}; + +function MoveCycle(array: number[], startIndex: number) : void { + + let currentItem: number = array[startIndex]; + let nextChangeIndex: number = startIndex + CountSmallerItems(array, startIndex, currentItem); + if(nextChangeIndex == startIndex) + { + return; + } + + nextChangeIndex = SkipDuplicates(array, nextChangeIndex, currentItem); + + let tmp: number = array[nextChangeIndex]; + array[nextChangeIndex] = currentItem; + currentItem = tmp; + + while (nextChangeIndex != startIndex) + { + nextChangeIndex = startIndex + CountSmallerItems(array, startIndex, currentItem); + nextChangeIndex = SkipDuplicates(array, nextChangeIndex, currentItem); + + tmp = array[nextChangeIndex]; + array[nextChangeIndex] = currentItem; + currentItem = tmp; + } +} + +function CountSmallerItems(array: number[], startIndex: number, currentItem: number) : number{ + let elementsCount: number = 0; + + for (let i: number = startIndex + 1; i < array.length; i++) { + if(currentItem > array[i]) + { + elementsCount++; + } + } + + return elementsCount; +} + +function SkipDuplicates(array: number[], currentPosition: number, currentItem: number): number { + while (array[currentPosition] == currentItem) { + currentPosition++; + } + + return currentPosition; +} + diff --git a/sorts/test/cycle_sort.test.ts b/sorts/test/cycle_sort.test.ts new file mode 100644 index 00000000..08772456 --- /dev/null +++ b/sorts/test/cycle_sort.test.ts @@ -0,0 +1,15 @@ +import { cycleSort } from "../cycle_sort"; + +describe("Cycle Sort", () => { + it("should return the correct value for average case", () => { + expect(cycleSort([1, 4, 2, 5, 9, 6, 3, 8, 10, 7])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); + + it("should return the correct value for worst case", () => { + expect(cycleSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); + + it("should return the correct value for best case", () => { + expect(cycleSort([1, 4, 2, 9, 5, 7, 3, 8, 10, 6])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); + }); \ No newline at end of file From dba31e3a06941326f0c7b4af86df1a4bc75f3628 Mon Sep 17 00:00:00 2001 From: BSzmolke <40246238+BSzmolke@users.noreply.github.com> Date: Tue, 30 May 2023 21:00:07 +0200 Subject: [PATCH 038/107] feat: Add implementation of jump serach algorithm in typescript (#133) * feat: add jump search * feat: add jump serach to directory.md * feat: jumpSearch test fix --- DIRECTORY.md | 1 + search/jump_search.ts | 47 +++++++++++++++++++++++++++++++++ search/test/jump_search.test.ts | 14 ++++++++++ 3 files changed, 62 insertions(+) create mode 100644 search/jump_search.ts create mode 100644 search/test/jump_search.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 9e988910..88c729ed 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -49,6 +49,7 @@ ## Search * [Binary Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/binary_search.ts) + * [Jump Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/jump_search.ts) * [Linear Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/linear_search.ts) ## Sorts diff --git a/search/jump_search.ts b/search/jump_search.ts new file mode 100644 index 00000000..45b44e02 --- /dev/null +++ b/search/jump_search.ts @@ -0,0 +1,47 @@ +/** + * @function jumpSearch + * @description Jump search algorithm for a sorted array. + * + * Jump search is a searching algorithm for sorted arrays that checks elements + * by jumping ahead by fixed steps. The optimal step size is the square root of the array length. + * + * The algorithm works as follows: + * 1.Start from the first element and jump by step size until finding an element that is greater than or equal to the target value. + * 2.Go back one step and perform a linear search from there until finding the target value or reaching the end of the subarray. + * 3.If the target value is found, return its index. Otherwise, return -1 to indicate that it is not in the array. + * + * @param {number[]} array - sorted list of numbers + * @param {number} target - target number to search for + * @return {number} - index of the target number in the list, or -1 if not found + * @see [JumpSearch](https://www.geeksforgeeks.org/jump-search/) + * @example jumpSearch([1,2,3], 2) => 1 + * @example jumpSearch([4,5,6], 2) => -1 + */ + +export const jumpSearch = (array: number[], target: number): number => { + if (array.length === 0) return -1; + + // declare pointers for the current and next indexes and step size + let currentIdx: number = 0, + stepSize: number = Math.floor(Math.sqrt(array.length)), + nextIdx: number = stepSize; + + while (array[nextIdx - 1] < target) { + currentIdx = nextIdx; + nextIdx += stepSize; + + if (nextIdx >= array.length) { + nextIdx = array.length - 1; + break; + } + } + + for (let index = currentIdx; index < nextIdx; index++) { + if(array[index] == target) + { + return index; + } + } + + return -1; +} \ No newline at end of file diff --git a/search/test/jump_search.test.ts b/search/test/jump_search.test.ts new file mode 100644 index 00000000..59737bdf --- /dev/null +++ b/search/test/jump_search.test.ts @@ -0,0 +1,14 @@ +import { jumpSearch } from "../jump_search"; + +describe("Jump search", () => { + test.each([ + [[], 1, -1], + [[1, 2, 3, 4, 5], 4, 3], + [[1, 3, 5, 8, 9], 4, -1], + ])( + "of %o , searching for %o, expected %i", + (array: any[], target: any, index: number) => { + expect(jumpSearch(array, target)).toStrictEqual(index) + }, + ); +}); From 839efc75119edc7de78d846ab948e39e5a682432 Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Sun, 11 Jun 2023 23:16:57 -0700 Subject: [PATCH 039/107] feat: add bellman-ford algorithm (#136) --- graph/bellman_ford.ts | 45 +++++++++++++++++ graph/test/bellman_ford.test.ts | 88 +++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 graph/bellman_ford.ts create mode 100644 graph/test/bellman_ford.test.ts diff --git a/graph/bellman_ford.ts b/graph/bellman_ford.ts new file mode 100644 index 00000000..70e326d2 --- /dev/null +++ b/graph/bellman_ford.ts @@ -0,0 +1,45 @@ +/** + * @function bellmanFord + * @description Compute the shortest path from a source node to all other nodes. If there is negative weight cycle, returns undefined. The input graph is in adjacency list form. It is a multidimensional array of edges. graph[i] holds the edges for the i'th node. Each edge is a 2-tuple where the 0'th item is the destination node, and the 1'th item is the edge weight. + * @Complexity_Analysis + * Time complexity: O(E*V) + * Space Complexity: O(V) + * @param {[number, number][][]} graph - The graph in adjacency list form + * @param {number} start - The source node + * @return {number[] | undefined} - The shortest path to each node, undefined if there is negative weight cycle + * @see https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm + */ +export const bellmanFord = (graph: [number, number][][], start: number): number[] | undefined => { + // We save the shortest distance to each node in `distances`. If a node is + // unreachable from the start node, its distance is Infinity. + let distances = Array(graph.length).fill(Infinity); + distances[start] = 0; + + // On the i'th iteration, we compute all shortest paths that consists of i+1 + // nodes. If we compute this V-1 times, we will have computed all simple + // shortest paths in the graph because a shortest path has at most V nodes. + for (let i = 0; i < graph.length - 1; ++i) { + for (let node = 0; node < graph.length; ++node) { + for (const [child, weight] of graph[node]) { + const new_distance = distances[node] + weight; + if (new_distance < distances[child]) { + distances[child] = new_distance + } + } + } + } + + // Look through all edges. If the shortest path to a destination node d is + // larger than the distance to source node s and weight(s->d), then the path + // to s must have a negative weight cycle. + for (let node = 0; node < graph.length; ++node) { + for (const [child, weight] of graph[node]) { + if (distances[child] > distances[node] + weight) { + return undefined; + } + } + } + + return distances; +} + diff --git a/graph/test/bellman_ford.test.ts b/graph/test/bellman_ford.test.ts new file mode 100644 index 00000000..77928a63 --- /dev/null +++ b/graph/test/bellman_ford.test.ts @@ -0,0 +1,88 @@ +import { bellmanFord } from "../bellman_ford"; + +const init_graph = (N: number): [number, number][][] => { + let graph = Array(N); + for (let i = 0; i < N; ++i) { + graph[i] = []; + } + return graph; +} + +describe("bellmanFord", () => { + + const add_edge = (graph: [number, number][][], a: number, b: number, weight: number) => { + graph[a].push([b, weight]); + graph[b].push([a, weight]); + } + + it("should return the correct value", () => { + let graph = init_graph(9); + add_edge(graph, 0, 1, 4); + add_edge(graph, 0, 7, 8); + add_edge(graph, 1, 2, 8); + add_edge(graph, 1, 7, 11); + add_edge(graph, 2, 3, 7); + add_edge(graph, 2, 5, 4); + add_edge(graph, 2, 8, 2); + add_edge(graph, 3, 4, 9); + add_edge(graph, 3, 5, 14); + add_edge(graph, 4, 5, 10); + add_edge(graph, 5, 6, 2); + add_edge(graph, 6, 7, 1); + add_edge(graph, 6, 8, 6); + add_edge(graph, 7, 8, 7); + expect(bellmanFord(graph, 0)).toStrictEqual([0, 4, 12, 19, 21, 11, 9, 8, 14]); + }); + + it("should return the correct value for single element graph", () => { + expect(bellmanFord([[]], 0)).toStrictEqual([0]); + }); + + let linear_graph = init_graph(4); + add_edge(linear_graph, 0, 1, 1); + add_edge(linear_graph, 1, 2, 2); + add_edge(linear_graph, 2, 3, 3); + test.each([[0, [0, 1, 3, 6]], [1, [1, 0, 2, 5]], [2, [3, 2, 0, 3]], [3, [6, 5, 3, 0]]])( + "correct result for linear graph with source node %i", + (source, result) => { + expect(bellmanFord(linear_graph, source)).toStrictEqual(result); + } + ); + + let unreachable_graph = init_graph(3); + add_edge(unreachable_graph, 0, 1, 1); + test.each([[0, [0, 1, Infinity]], [1, [1, 0, Infinity]], [2, [Infinity, Infinity, 0]]])( + "correct result for graph with unreachable nodes with source node %i", + (source, result) => { + expect(bellmanFord(unreachable_graph, source)).toStrictEqual(result); + } + ); +}) + +describe("bellmanFord negative cycle graphs", () => { + it("should returned undefined for 2-node graph with negative cycle", () => { + let basic = init_graph(2); + basic[0].push([1, 2]); + basic[1].push([0, -3]); + expect(bellmanFord(basic, 0)).toStrictEqual(undefined); + expect(bellmanFord(basic, 1)).toStrictEqual(undefined); + }); + + it("should returned undefined for graph with negative cycle", () => { + let negative = init_graph(5); + negative[0].push([1, 6]); + negative[0].push([3, 7]); + negative[1].push([2, 5]); + negative[1].push([3, 8]); + negative[1].push([4, -4]); + negative[2].push([1, -4]); + negative[3].push([2, -3]); + negative[3].push([4, 9]); + negative[4].push([0, 3]); + negative[4].push([2, 7]); + for (let i = 0; i < 5; ++i) { + expect(bellmanFord(negative, i)).toStrictEqual(undefined); + } + }); +}); + From b738c805cbed42021c48f6dda6735090cfe6c5a0 Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Sun, 11 Jun 2023 23:42:53 -0700 Subject: [PATCH 040/107] fix, test: Fix MinHeap sinkDown implementation, increase test coverage (#135) --- data_structures/heap/max_heap.ts | 2 +- data_structures/heap/min_heap.ts | 4 +-- data_structures/heap/test/max_heap.test.ts | 30 +++++++++++++++++++--- data_structures/heap/test/min_heap.test.ts | 30 +++++++++++++++++++--- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/data_structures/heap/max_heap.ts b/data_structures/heap/max_heap.ts index e5307bfc..34f2068f 100644 --- a/data_structures/heap/max_heap.ts +++ b/data_structures/heap/max_heap.ts @@ -32,7 +32,7 @@ export class MaxHeap extends Heap { leftChildIndex: number, rightChildIndex: number ): number { - return (this.heap[leftChildIndex] || -Infinity) > + return this.heap[leftChildIndex] > (this.heap[rightChildIndex] || -Infinity) ? leftChildIndex : rightChildIndex; diff --git a/data_structures/heap/min_heap.ts b/data_structures/heap/min_heap.ts index fa50a0a0..ec71572a 100644 --- a/data_structures/heap/min_heap.ts +++ b/data_structures/heap/min_heap.ts @@ -32,8 +32,8 @@ export class MinHeap extends Heap { leftChildIndex: number, rightChildIndex: number ): number { - return (this.heap[leftChildIndex] || -Infinity) < - (this.heap[rightChildIndex] || -Infinity) + return this.heap[leftChildIndex] < + (this.heap[rightChildIndex] || Infinity) ? leftChildIndex : rightChildIndex; } diff --git a/data_structures/heap/test/max_heap.test.ts b/data_structures/heap/test/max_heap.test.ts index 0f49f876..9a251de9 100644 --- a/data_structures/heap/test/max_heap.test.ts +++ b/data_structures/heap/test/max_heap.test.ts @@ -2,11 +2,11 @@ import { MaxHeap } from "../max_heap"; describe("MaxHeap", () => { let heap: MaxHeap; + const elements: number[] = [ + 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18, + ]; - beforeAll(() => { - const elements: number[] = [ - 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18, - ]; + beforeEach(() => { heap = new MaxHeap(elements); }); @@ -26,4 +26,26 @@ describe("MaxHeap", () => { heap.insert(61); heap.check(); }); + + const extract_all = (heap: MaxHeap) => { + [...elements].sort((a, b) => b - a).forEach((element: number) => { + expect(heap.extract()).toEqual(element); + }); + heap.check(); + expect(heap.size()).toEqual(0); + } + + it("should remove and return the max elements in order", () => { + extract_all(heap); + }); + + it("should insert all, then remove and return the max elements in order", () => { + heap = new MaxHeap(); + elements.forEach((element: number) => { + heap.insert(element); + }); + heap.check(); + expect(heap.size()).toEqual(elements.length); + extract_all(heap); + }); }); diff --git a/data_structures/heap/test/min_heap.test.ts b/data_structures/heap/test/min_heap.test.ts index 8132a05c..07f10b1e 100644 --- a/data_structures/heap/test/min_heap.test.ts +++ b/data_structures/heap/test/min_heap.test.ts @@ -2,11 +2,11 @@ import { MinHeap } from "../min_heap"; describe("MinHeap", () => { let heap: MinHeap; + const elements: number[] = [ + 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18, + ]; - beforeAll(() => { - const elements: number[] = [ - 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18, - ]; + beforeEach(() => { heap = new MinHeap(elements); }); @@ -26,4 +26,26 @@ describe("MinHeap", () => { heap.insert(24); heap.check(); }); + + const extract_all = (heap: MinHeap) => { + [...elements].sort((a, b) => a - b).forEach((element: number) => { + expect(heap.extract()).toEqual(element); + }); + heap.check(); + expect(heap.size()).toEqual(0); + } + + it("should remove and return the min elements in order", () => { + extract_all(heap); + }); + + it("should insert all, then remove and return the min elements in order", () => { + heap = new MinHeap(); + elements.forEach((element: number) => { + heap.insert(element); + }); + heap.check(); + expect(heap.size()).toEqual(elements.length); + extract_all(heap); + }); }); From 55a01f20d583535c8cd0af4ebd29d19b93c8f082 Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Fri, 16 Jun 2023 13:20:28 -0700 Subject: [PATCH 041/107] feat: add kruskal algorithm (#137) * feat: add kruskal algorithm * Rewrite existing tests and add test for minimum spanning forest --- graph/kruskal.ts | 45 +++++++++++++++ graph/test/kruskal.test.ts | 109 +++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 graph/kruskal.ts create mode 100644 graph/test/kruskal.test.ts diff --git a/graph/kruskal.ts b/graph/kruskal.ts new file mode 100644 index 00000000..073b62b1 --- /dev/null +++ b/graph/kruskal.ts @@ -0,0 +1,45 @@ +import { DisjointSet } from '../data_structures/disjoint_set/disjoint_set'; + +/** + * @function kruskal + * @description Compute a minimum spanning forest of a weighted undirected graph + * @Complexity_Analysis + * Time complexity: O(Elog(V)) + * Space Complexity: O(V) + * @param {Edge[]} edges - The edges of the graph + * @param {number} num_vertices - The number of vertices in the graph + * @return {Edge[], number} - [The edges of the minimum spanning tree, the sum of the weights of the edges in the tree] + * @see https://en.wikipedia.org/wiki/Kruskal%27s_algorithm + */ +export const kruskal = (edges: Edge[], num_vertices: number): [Edge[], number] => { + let cost = 0; + let minimum_spanning_tree = []; + + // Use a disjoint set to quickly join sets and find if vertices live in different sets + let sets = new DisjointSet(num_vertices); + + // Sort the edges in ascending order by weight so that we can greedily add cheaper edges to the tree + edges.sort((a, b) => a.weight - b.weight); + + for (let edge of edges) { + if (sets.find(edge.a) !== sets.find(edge.b)) { + // Node A and B live in different sets. Add edge(a, b) to the tree and join the nodes' sets together. + minimum_spanning_tree.push(edge); + cost += edge.weight; + sets.join(edge.a, edge.b); + } + } + + return [minimum_spanning_tree, cost]; +} + +export class Edge { + a: number = 0; + b: number = 0; + weight: number = 0; + constructor(a: number, b: number, weight: number) { + this.a = a; + this.b = b; + this.weight = weight; + } +} diff --git a/graph/test/kruskal.test.ts b/graph/test/kruskal.test.ts new file mode 100644 index 00000000..7f3db6c0 --- /dev/null +++ b/graph/test/kruskal.test.ts @@ -0,0 +1,109 @@ +import { Edge, kruskal } from "../kruskal"; + +let test_graph = (expected_tree_edges: Edge[], other_edges: Edge[], num_vertices: number, expected_cost: number) => { + let [tree_edges, cost] = kruskal(expected_tree_edges.concat(other_edges), num_vertices); + expect(cost).toStrictEqual(expected_cost); + for (let expected_edge of expected_tree_edges) { + expect(tree_edges.includes(expected_edge)).toBeTruthy(); + } + for (let unexpected_edge of other_edges) { + expect(tree_edges.includes(unexpected_edge)).toBeFalsy(); + } +}; + + +describe("kruskal", () => { + + it("should return empty tree for empty graph", () => { + expect(kruskal([], 0)).toStrictEqual([[], 0]); + }); + + it("should return empty tree for single element graph", () => { + expect(kruskal([], 1)).toStrictEqual([[], 0]); + }); + + it("should return correct value for two element graph", () => { + const edge = new Edge(0, 1, 5); + expect(kruskal([edge], 2)).toStrictEqual([[edge], 5]); + }); + + it("should return the correct value", () => { + let expected_tree_edges = [ + new Edge(0, 1, 1), + new Edge(1, 3, 2), + new Edge(2, 3, 3), + ]; + + let other_edges = [ + new Edge(0, 2, 4), + new Edge(0, 3, 5), + new Edge(1, 2, 6), + ]; + + test_graph(expected_tree_edges, other_edges, 7, 6); + }); + + it("should return the correct value", () => { + let expected_tree_edges = [ + new Edge(0, 2, 2), + new Edge(1, 3, 9), + new Edge(2, 6, 74), + new Edge(2, 7, 8), + new Edge(3, 4, 3), + new Edge(4, 9, 9), + new Edge(5, 7, 5), + new Edge(7, 9, 4), + new Edge(8, 9, 2), + ] + + let other_edges = [ + new Edge(0, 1, 10), + new Edge(2, 4, 47), + new Edge(4, 5, 42), + ]; + + test_graph(expected_tree_edges, other_edges, 10, 116); + }); + +}) + +describe("kruskal forest", () => { + it("should return empty tree for forest of 2 node trees", () => { + let edges = [new Edge(0, 1, 10), new Edge(2, 3, 15)]; + test_graph(edges, [], 4, 25); + }); + + it("should return the correct value", () => { + let expected_tree_edges = [ + // Tree 1 + new Edge(0, 2, 2), + new Edge(1, 3, 9), + new Edge(2, 6, 74), + new Edge(2, 7, 8), + new Edge(3, 4, 3), + new Edge(4, 9, 9), + new Edge(5, 7, 5), + new Edge(7, 9, 4), + new Edge(8, 9, 2), + + // Tree 2 + new Edge(10, 11, 1), + new Edge(11, 13, 2), + new Edge(12, 13, 3), + ] + + let other_edges = [ + // Tree 1 + new Edge(0, 1, 10), + new Edge(2, 4, 47), + new Edge(4, 5, 42), + + // Tree 2 + new Edge(10, 12, 4), + new Edge(10, 13, 5), + new Edge(11, 12, 6), + ]; + + test_graph(expected_tree_edges, other_edges, 14, 122); + }); +}); From 10e98a9cdc952d69cb8d8d14b67bc145bb2a20c2 Mon Sep 17 00:00:00 2001 From: He JinChao Date: Sat, 17 Jun 2023 04:20:56 +0800 Subject: [PATCH 042/107] fix(hash_map): keep entries when trigger resize (#130) --- data_structures/map/hash_map.ts | 4 +++- data_structures/map/test/hash_map.test.ts | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/data_structures/map/hash_map.ts b/data_structures/map/hash_map.ts index e4ad04b6..3a57d759 100644 --- a/data_structures/map/hash_map.ts +++ b/data_structures/map/hash_map.ts @@ -209,10 +209,12 @@ export class HashMap implements Map { * Resizes the hash map by doubling the amount of buckets. */ private resize(): void { + const entries = this.entries(); + this.initializeBuckets(this.buckets.length * 2); this.size = 0; - for (const entry of this.entries()) { + for (const entry of entries) { this.set(entry.key, entry.value); } } diff --git a/data_structures/map/test/hash_map.test.ts b/data_structures/map/test/hash_map.test.ts index ef561d97..16640e97 100644 --- a/data_structures/map/test/hash_map.test.ts +++ b/data_structures/map/test/hash_map.test.ts @@ -88,4 +88,22 @@ describe("Hash Map", () => { { key: "c", value: 3 }, ]); }); + + it("should keep entries when trigger resize", () => { + hashMap.set('a', 1); + hashMap.set('b', 2); + hashMap.set('c', 3); + hashMap.set('d', 4); + hashMap.set('e', 5); + hashMap.set('f', 6); + hashMap.set('g', 7); + hashMap.set('h', 8); + hashMap.set('i', 9); + hashMap.set('j', 10); + hashMap.set('k', 11); + hashMap.set('l', 12); + hashMap.set('m', 13); + hashMap.set('n', 14); + expect(hashMap.getSize()).toBe(14); + }) }); From 112ea29a4210ead7bb851d0e685735bac6970404 Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Fri, 16 Jun 2023 13:21:57 -0700 Subject: [PATCH 043/107] chore: combine min/max heap. allow custom compare function. (#138) --- data_structures/heap/heap.ts | 61 ++++++++++++++++------ data_structures/heap/max_heap.ts | 40 -------------- data_structures/heap/min_heap.ts | 40 -------------- data_structures/heap/test/max_heap.test.ts | 2 +- data_structures/heap/test/min_heap.test.ts | 2 +- 5 files changed, 48 insertions(+), 97 deletions(-) delete mode 100644 data_structures/heap/max_heap.ts delete mode 100644 data_structures/heap/min_heap.ts diff --git a/data_structures/heap/heap.ts b/data_structures/heap/heap.ts index 71f03be3..a5def710 100644 --- a/data_structures/heap/heap.ts +++ b/data_structures/heap/heap.ts @@ -1,8 +1,24 @@ +/** + * A heap is a complete binary tree + * In a complete binary tree each level is filled before lower levels are added + * Each level is filled from left to right + * + * In a (min|max) heap the value of every node is (less|greater) than that if its children + * + * The heap if often implemented using an array structure. + * In the array implementation, the relationship between a parent index and its two children + * are ((parentindex * 2) + 1) and ((parentindex * 2) + 2) + * + */ + export abstract class Heap { - protected heap: T[]; + private heap: T[]; + // A comparison function. Returns true if a should be the parent of b. + private compare: (a: any, b: any) => boolean; - constructor(elements: T[] = []) { + constructor(elements: T[] = [], compare: (a: T, b: T) => boolean) { this.heap = []; + this.compare = compare; for (let element of elements) { this.insert(element); } @@ -14,19 +30,22 @@ export abstract class Heap { * In a minHeap the value at parentIndex should be smaller than the value at childIndex * */ - protected abstract isRightlyPlaced( - childIndex: number, - parentIndex: number - ): boolean; + private isRightlyPlaced( childIndex: number, parentIndex: number) { + return this.compare(this.heap[parentIndex], this.heap[childIndex]); + } /** * In a maxHeap the index with the larger value is returned * In a minHeap the index with the smaller value is returned */ - protected abstract getChildIndexToSwap( - leftChildIndex: number, - rightChildIndex: number - ): number; + private getChildIndexToSwap(leftChildIndex: number, rightChildIndex: number): number { + if (rightChildIndex >= this.size()) { + return leftChildIndex; + } + return this.compare(this.heap[leftChildIndex], this.heap[rightChildIndex]) + ? leftChildIndex + : rightChildIndex; + } public insert(value: T): void { this.heap.push(value); @@ -49,7 +68,7 @@ export abstract class Heap { return this.size() === 0; } - protected bubbleUp(): void { + private bubbleUp(): void { let index = this.size() - 1; let parentIndex; @@ -64,7 +83,7 @@ export abstract class Heap { } } - protected sinkDown(): void { + private sinkDown(): void { let index = 0; let leftChildIndex = this.getLeftChildIndex(index); let rightChildIndex = this.getRightChildIndex(index); @@ -86,11 +105,11 @@ export abstract class Heap { } } - protected getLeftChildIndex(index: number): number { + private getLeftChildIndex(index: number): number { return index * 2 + 1; } - protected getRightChildIndex(index: number): number { + private getRightChildIndex(index: number): number { return index * 2 + 2; } @@ -98,7 +117,7 @@ export abstract class Heap { return this._check(); } - protected _check(index: number = 0): void { + private _check(index: number = 0): void { if (!this.heap[index]) return; const leftChildIndex = this.getLeftChildIndex(index); const rightChildIndex = this.getRightChildIndex(index); @@ -119,3 +138,15 @@ export abstract class Heap { this._check(rightChildIndex); } } + +export class MinHeap extends Heap { + constructor(elements: T[] = [], compare = (a: T, b: T) => { return a < b }) { + super(elements, compare); + } +} + +export class MaxHeap extends Heap { + constructor(elements: T[] = [], compare = (a: T, b: T) => { return a > b }) { + super(elements, compare); + } +} diff --git a/data_structures/heap/max_heap.ts b/data_structures/heap/max_heap.ts deleted file mode 100644 index 34f2068f..00000000 --- a/data_structures/heap/max_heap.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Heap } from "./heap"; - -/** - * A heap is a complete binary tree - * In a complete binary tree each level is filled before lower levels are added - * Each level is filled from left to right - * - * In a max heap the value of every node is greater than that if its children - * - * The heap if often implemented using an array structure. - * In the array implementation, the relationship between a parent index and its two children - * are ((parentindex * 2) + 1) and ((parentindex * 2) + 2) - * - */ -export class MaxHeap extends Heap { - constructor(elements: T[] = []) { - super(elements); - } - - /** - * Checks if the value at the parent index is larger than or equal to - * the value at the child index - */ - protected isRightlyPlaced(childIndex: number, parentIndex: number): boolean { - return this.heap[parentIndex] >= this.heap[childIndex]; - } - - /** - * Returns the child index that stores a larger value - */ - protected getChildIndexToSwap( - leftChildIndex: number, - rightChildIndex: number - ): number { - return this.heap[leftChildIndex] > - (this.heap[rightChildIndex] || -Infinity) - ? leftChildIndex - : rightChildIndex; - } -} diff --git a/data_structures/heap/min_heap.ts b/data_structures/heap/min_heap.ts deleted file mode 100644 index ec71572a..00000000 --- a/data_structures/heap/min_heap.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Heap } from "./heap"; - -/** - * A heap is a complete binary tree - * In a complete binary tree each level is filled before lower levels are added - * Each level is filled from left to right - * - * In a min heap the value of every node is smaller than that if its children - * - * The heap if often implemented using an array structure. - * In the array implementation, the relationship between a parent index and its two children - * are ((parentindex * 2) + 1) and ((parentindex * 2) + 2) - * - */ -export class MinHeap extends Heap { - constructor(elements: T[] = []) { - super(elements); - } - - /** - * Checks if the value at the parent index is lesser than or equal to - * the value at the child index - */ - protected isRightlyPlaced(childIndex: number, parentIndex: number): boolean { - return this.heap[parentIndex] <= this.heap[childIndex]; - } - - /** - * Returns the child index that stores a smaller value - */ - protected getChildIndexToSwap( - leftChildIndex: number, - rightChildIndex: number - ): number { - return this.heap[leftChildIndex] < - (this.heap[rightChildIndex] || Infinity) - ? leftChildIndex - : rightChildIndex; - } -} diff --git a/data_structures/heap/test/max_heap.test.ts b/data_structures/heap/test/max_heap.test.ts index 9a251de9..8ba7c398 100644 --- a/data_structures/heap/test/max_heap.test.ts +++ b/data_structures/heap/test/max_heap.test.ts @@ -1,4 +1,4 @@ -import { MaxHeap } from "../max_heap"; +import { MaxHeap } from "../heap"; describe("MaxHeap", () => { let heap: MaxHeap; diff --git a/data_structures/heap/test/min_heap.test.ts b/data_structures/heap/test/min_heap.test.ts index 07f10b1e..4401d5c0 100644 --- a/data_structures/heap/test/min_heap.test.ts +++ b/data_structures/heap/test/min_heap.test.ts @@ -1,4 +1,4 @@ -import { MinHeap } from "../min_heap"; +import { MinHeap } from "../heap"; describe("MinHeap", () => { let heap: MinHeap; From 0fa510bd60713200e85ba5f20dc0edc5fc3dae54 Mon Sep 17 00:00:00 2001 From: prisojacques <76072668+prisojacques@users.noreply.github.com> Date: Sat, 1 Jul 2023 07:26:24 +0200 Subject: [PATCH 044/107] feat: add quick select algorithm and test #6 (#140) * feat: add quick select algorithm and test #6 * feat: update quick select algorithm and test #6 --- sorts/quick_select.ts | 40 +++++++++++++++++++++++++++++++++ sorts/test/quick_select.test.ts | 29 ++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 sorts/quick_select.ts create mode 100644 sorts/test/quick_select.test.ts diff --git a/sorts/quick_select.ts b/sorts/quick_select.ts new file mode 100644 index 00000000..23381ee2 --- /dev/null +++ b/sorts/quick_select.ts @@ -0,0 +1,40 @@ +import {partition} from "./quick_sort"; +/** + * @function QuickSelect + * @description is an algorithm based on the QuickSort approach that selects the kth smallest element from an array + * @param {number[]} array - The array from which to select the element + * @param {number} k - The index representing the kth smallest element to find + * @param {number} left - The left boundary of the array or subarray to consider (default: 0) + * @param {number} right - The right boundary of the array or subarray to consider (default: array.length - 1) + * @returns {number} - The kth smallest element from the array + * @throws {Error} - If k is out of bounds (less than 0 or greater than or equal to array.length) + */ + +export const QuickSelect = ( + array: number[], + k: number, + left: number = 0, + right: number = array.length - 1 +):number => { + if(k < 0 || k >= array.length) { + throw new Error('k is out of bounds'); + } + if (left === right) { + // If the list contains only one element, return that element + return array[left]; + } + + // Partition the array + let pivotIndex = partition(array, left, right); + + // The pivot is in its final sorted position + if (k === pivotIndex) { + return array[k]; + } else if (k < pivotIndex) { + // If k is less than the pivot index, look left + return QuickSelect(array, k, left, pivotIndex - 1); + } else { + // If k is greater than the pivot index, look right + return QuickSelect(array, k, pivotIndex + 1, right); + } +}; diff --git a/sorts/test/quick_select.test.ts b/sorts/test/quick_select.test.ts new file mode 100644 index 00000000..885ed5e1 --- /dev/null +++ b/sorts/test/quick_select.test.ts @@ -0,0 +1,29 @@ +import { QuickSelect } from "../quick_select"; + +describe('QuickSelect', () => { + test('should return the kth smallest element in an array', () => { + const array = [8, 3, 5, 1, 4, 2]; + expect(QuickSelect(array, 0)).toBe(1); + expect(QuickSelect(array, 1)).toBe(2); + expect(QuickSelect(array, 2)).toBe(3); + expect(QuickSelect(array, 3)).toBe(4); + expect(QuickSelect(array, 4)).toBe(5); + expect(QuickSelect(array, 5)).toBe(8); + }); + + test('should work with arrays of size 1', () => { + const array = [4]; + expect(QuickSelect(array, 0)).toBe(4); + }); + + test('should work with large arrays', () => { + const array = Array.from({length: 1000}, (_, i) => i + 1); + expect(QuickSelect(array, 499)).toBe(500); + }); + + test('should throw error when k is out of bounds', () => { + const array = [8, 3, 5, 1, 4, 2]; + expect(() => QuickSelect(array, -1)).toThrow(); + expect(() => QuickSelect(array, 6)).toThrow(); + }); +}); From 24c861fb8550f95c37f19c1d831150aaa6e75c39 Mon Sep 17 00:00:00 2001 From: Tcheumen <107006692+Tcheumen@users.noreply.github.com> Date: Mon, 3 Jul 2023 19:01:28 +0200 Subject: [PATCH 045/107] feat: added binomial coefficient function and the corresponding test #10 (#141) --- maths/binomial_coefficient.ts | 24 +++++++++++++++++ maths/test/binomial_coefficient.test.ts | 34 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 maths/binomial_coefficient.ts create mode 100644 maths/test/binomial_coefficient.test.ts diff --git a/maths/binomial_coefficient.ts b/maths/binomial_coefficient.ts new file mode 100644 index 00000000..cc522c3b --- /dev/null +++ b/maths/binomial_coefficient.ts @@ -0,0 +1,24 @@ +import { Factorial } from "./factorial"; +/** + * @function BinomialCoefficient + * @description Calculate the binomial coefficient (n choose k) of two input numbers. + * @param {number} n - the total number of items + * @param {number} k - the number of items to be chosen + * @return {number} - Binomial coefficient (n choose k) + * @see https://en.wikipedia.org/wiki/Binomial_coefficient + * @example BinomialCoefficient(5, 2) = 10 + * @example BinomialCoefficient(10, 3) = 120 + * @example BinomialCoefficient(6, 0) = 1 + */ + +export const BinomialCoefficient = (n: number, k: number): number => { + // Check if k is larger than n or negative + if (k > n || k < 0) { + return 0; + } + + // Calculate the binomial coefficient using the implemented factorial + const numerator = Factorial(n); + const denominator = Factorial(k) * Factorial(n - k); + return numerator / denominator; +}; diff --git a/maths/test/binomial_coefficient.test.ts b/maths/test/binomial_coefficient.test.ts new file mode 100644 index 00000000..ca677264 --- /dev/null +++ b/maths/test/binomial_coefficient.test.ts @@ -0,0 +1,34 @@ +import { BinomialCoefficient } from '../binomial_coefficient'; + +describe('BinomialCoefficient', () => { + it('should calculate the correct binomial coefficient', () => { + // Test cases with expected results + const testCases: [number, number, number][] = [ + [5, 2, 10], + [10, 3, 120], + [6, 0, 1], + [4, 4, 1], + [7, 5, 21], + [10, 10, 1], + ]; + + // Iterate through each test case and verify the result + testCases.forEach(([n, k, expected]) => { + const result = BinomialCoefficient(n, k); + expect(result).toEqual(expected); + }); + }); + + it('should return 0 if k is larger than n or negative', () => { + const invalidCases: [number, number][] = [ + [5, 6], // k is larger than n + [10, -3], // k is negative + [5, 10], // k is larger than n + ]; + + invalidCases.forEach(([n, k]) => { + const result = BinomialCoefficient(n, k); + expect(result).toEqual(0); + }); + }); +}); From 8deeca2d8f2067dc3995edebfabcc9ef88b067ac Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Mon, 3 Jul 2023 10:02:07 -0700 Subject: [PATCH 046/107] feat: add dijkstra with adjacency list and heap increasePriority (#134) * feat: add dijkstra with adjacency matrix * Renames, initialize distances to Infinity, remove external link * dijkstra implementation uses adjacency list and min heap * Implement heap increasePriority and let Dijkstra use it --- data_structures/heap/heap.ts | 84 ++++++++++++++++------ data_structures/heap/test/max_heap.test.ts | 5 +- data_structures/heap/test/min_heap.test.ts | 34 +++++++-- graph/dijkstra.ts | 37 ++++++++++ graph/test/dijkstra.test.ts | 61 ++++++++++++++++ 5 files changed, 195 insertions(+), 26 deletions(-) create mode 100644 graph/dijkstra.ts create mode 100644 graph/test/dijkstra.test.ts diff --git a/data_structures/heap/heap.ts b/data_structures/heap/heap.ts index a5def710..28915849 100644 --- a/data_structures/heap/heap.ts +++ b/data_structures/heap/heap.ts @@ -12,16 +12,13 @@ */ export abstract class Heap { - private heap: T[]; + protected heap: T[]; // A comparison function. Returns true if a should be the parent of b. - private compare: (a: any, b: any) => boolean; + private compare: (a: T, b: T) => boolean; - constructor(elements: T[] = [], compare: (a: T, b: T) => boolean) { + constructor(compare: (a: T, b: T) => boolean) { this.heap = []; this.compare = compare; - for (let element of elements) { - this.insert(element); - } } /** @@ -68,17 +65,20 @@ export abstract class Heap { return this.size() === 0; } - private bubbleUp(): void { - let index = this.size() - 1; + protected swap(a: number, b: number) { + [this.heap[a], this.heap[b]] = [ + this.heap[b], + this.heap[a], + ]; + } + + protected bubbleUp(index = this.size() - 1): void { let parentIndex; while (index > 0) { parentIndex = Math.floor((index - 1) / 2); if (this.isRightlyPlaced(index, parentIndex)) break; - [this.heap[parentIndex], this.heap[index]] = [ - this.heap[index], - this.heap[parentIndex], - ]; + this.swap(parentIndex, index); index = parentIndex; } } @@ -95,10 +95,7 @@ export abstract class Heap { rightChildIndex ); if (this.isRightlyPlaced(childIndexToSwap, index)) break; - [this.heap[childIndexToSwap], this.heap[index]] = [ - this.heap[index], - this.heap[childIndexToSwap], - ]; + this.swap(childIndexToSwap, index); index = childIndexToSwap; leftChildIndex = this.getLeftChildIndex(index); rightChildIndex = this.getRightChildIndex(index); @@ -140,13 +137,60 @@ export abstract class Heap { } export class MinHeap extends Heap { - constructor(elements: T[] = [], compare = (a: T, b: T) => { return a < b }) { - super(elements, compare); + constructor(compare = (a: T, b: T) => { return a < b }) { + super(compare); } } export class MaxHeap extends Heap { - constructor(elements: T[] = [], compare = (a: T, b: T) => { return a > b }) { - super(elements, compare); + constructor(compare = (a: T, b: T) => { return a > b }) { + super(compare); + } +} + +// Priority queue that supports increasePriority() in O(log(n)). The limitation is that there can only be a single element for each key, and the max number or keys must be specified at heap construction. Most of the functions are wrappers around MinHeap functions and update the keys array. +export class PriorityQueue extends MinHeap { + // Maps from the n'th node to its index within the heap. + private keys: number[]; + // Maps from element to its index with keys. + private keys_index: (a: T) => number; + + constructor(keys_index: (a: T) => number, num_keys: number, compare = (a: T, b: T) => { return a < b }) { + super(compare); + this.keys = Array(num_keys).fill(-1); + this.keys_index = keys_index; + } + + protected swap(a: number, b: number) { + let akey = this.keys_index(this.heap[a]); + let bkey = this.keys_index(this.heap[b]); + [this.keys[akey], this.keys[bkey]] = [this.keys[bkey], this.keys[akey]]; + super.swap(a, b); + } + + public insert(value: T) { + this.keys[this.keys_index(value)] = this.size(); + super.insert(value); + } + + public extract(): T { + // Unmark the the highest priority element and set key to zero for the last element in the heap. + this.keys[this.keys_index(this.heap[0])] = -1; + if (this.size() > 1) { + this.keys[this.keys_index(this.heap[this.size() - 1])] = 0; + } + return super.extract(); + } + + public increasePriority(idx: number, value: T) { + if (this.keys[idx] == -1) { + // If the key does not exist, insert the value. + this.insert(value); + return; + } + let key = this.keys[idx]; + // Increase the priority and bubble it up the heap. + this.heap[key] = value; + this.bubbleUp(key); } } diff --git a/data_structures/heap/test/max_heap.test.ts b/data_structures/heap/test/max_heap.test.ts index 8ba7c398..a94739e6 100644 --- a/data_structures/heap/test/max_heap.test.ts +++ b/data_structures/heap/test/max_heap.test.ts @@ -7,7 +7,10 @@ describe("MaxHeap", () => { ]; beforeEach(() => { - heap = new MaxHeap(elements); + heap = new MaxHeap(); + for (let element of elements) { + heap.insert(element); + } }); it("should initialize a heap from input array", () => { diff --git a/data_structures/heap/test/min_heap.test.ts b/data_structures/heap/test/min_heap.test.ts index 4401d5c0..e7fa82ad 100644 --- a/data_structures/heap/test/min_heap.test.ts +++ b/data_structures/heap/test/min_heap.test.ts @@ -1,4 +1,4 @@ -import { MinHeap } from "../heap"; +import { MinHeap, PriorityQueue } from "../heap"; describe("MinHeap", () => { let heap: MinHeap; @@ -7,7 +7,10 @@ describe("MinHeap", () => { ]; beforeEach(() => { - heap = new MinHeap(elements); + heap = new MinHeap(); + for (let element of elements) { + heap.insert(element); + } }); it("should initialize a heap from input array", () => { @@ -27,7 +30,7 @@ describe("MinHeap", () => { heap.check(); }); - const extract_all = (heap: MinHeap) => { + const extract_all = (heap: MinHeap, elements: number[]) => { [...elements].sort((a, b) => a - b).forEach((element: number) => { expect(heap.extract()).toEqual(element); }); @@ -36,7 +39,7 @@ describe("MinHeap", () => { } it("should remove and return the min elements in order", () => { - extract_all(heap); + extract_all(heap, elements); }); it("should insert all, then remove and return the min elements in order", () => { @@ -46,6 +49,27 @@ describe("MinHeap", () => { }); heap.check(); expect(heap.size()).toEqual(elements.length); - extract_all(heap); + extract_all(heap, elements); + }); + + it("should increase priority", () => { + let heap = new PriorityQueue((a: number) => { return a; }, elements.length); + elements.forEach((element: number) => { + heap.insert(element); + }); + heap.check(); + expect(heap.size()).toEqual(elements.length); + + heap.increasePriority(55, 14); + heap.increasePriority(18, 16); + heap.increasePriority(81, 72); + heap.increasePriority(9, 0); + heap.increasePriority(43, 33); + heap.check(); + // Elements after increasing priority + const newElements: number[] = [ + 12, 4, 33, 42, 0, 7, 39, 16, 14, 1, 51, 34, 72, 16, + ]; + extract_all(heap, newElements); }); }); diff --git a/graph/dijkstra.ts b/graph/dijkstra.ts new file mode 100644 index 00000000..1d5c05ae --- /dev/null +++ b/graph/dijkstra.ts @@ -0,0 +1,37 @@ +import { MinHeap, PriorityQueue } from '../data_structures/heap/heap'; +/** + * @function dijkstra + * @description Compute the shortest path from a source node to all other nodes. The input graph is in adjacency list form. It is a multidimensional array of edges. graph[i] holds the edges for the i'th node. Each edge is a 2-tuple where the 0'th item is the destination node, and the 1'th item is the edge weight. + * @Complexity_Analysis + * Time complexity: O((V+E)*log(V)). For fully connected graphs, it is O(E*log(V)). + * Space Complexity: O(V) + * @param {[number, number][][]} graph - The graph in adjacency list form + * @param {number} start - The source node + * @return {number[]} - The shortest path to each node + * @see https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm + */ +export const dijkstra = (graph: [number, number][][], start: number): number[] => { + // We use a priority queue to make sure we always visit the closest node. The + // queue makes comparisons based on path weights. + let priorityQueue = new PriorityQueue((a: [number, number]) => { return a[0] }, graph.length, (a: [number, number], b: [number, number]) => { return a[1] < b[1] }); + priorityQueue.insert([start, 0]); + // We save the shortest distance to each node in `distances`. If a node is + // unreachable from the start node, its distance is Infinity. + let distances = Array(graph.length).fill(Infinity); + distances[start] = 0; + + while (priorityQueue.size() > 0) { + const [node, _] = priorityQueue.extract(); + graph[node].forEach(([child, weight]) => { + let new_distance = distances[node] + weight; + if (new_distance < distances[child]) { + // Found a new shortest path to child node. Record its distance and add child to the queue. + // If the child already exists in the queue, the priority will be updated. This will make sure the queue will be at most size V (number of vertices). + priorityQueue.increasePriority(child, [child, weight]); + distances[child] = new_distance; + } + }); + } + + return distances; +} diff --git a/graph/test/dijkstra.test.ts b/graph/test/dijkstra.test.ts new file mode 100644 index 00000000..eacf2e68 --- /dev/null +++ b/graph/test/dijkstra.test.ts @@ -0,0 +1,61 @@ +import { dijkstra } from "../dijkstra"; + +describe("dijkstra", () => { + + const init_graph = (N: number): [number, number][][] => { + let graph = Array(N); + for (let i = 0; i < N; ++i) { + graph[i] = []; + } + return graph; + } + + const add_edge = (graph: [number, number][][], a: number, b: number, weight: number) => { + graph[a].push([b, weight]); + graph[b].push([a, weight]); + } + + it("should return the correct value", () => { + let graph = init_graph(9); + add_edge(graph, 0, 1, 4); + add_edge(graph, 0, 7, 8); + add_edge(graph, 1, 2, 8); + add_edge(graph, 1, 7, 11); + add_edge(graph, 2, 3, 7); + add_edge(graph, 2, 5, 4); + add_edge(graph, 2, 8, 2); + add_edge(graph, 3, 4, 9); + add_edge(graph, 3, 5, 14); + add_edge(graph, 4, 5, 10); + add_edge(graph, 5, 6, 2); + add_edge(graph, 6, 7, 1); + add_edge(graph, 6, 8, 6); + add_edge(graph, 7, 8, 7); + expect(dijkstra(graph, 0)).toStrictEqual([0, 4, 12, 19, 21, 11, 9, 8, 14]); + }); + + it("should return the correct value for single element graph", () => { + expect(dijkstra([[]], 0)).toStrictEqual([0]); + }); + + let linear_graph = init_graph(4); + add_edge(linear_graph, 0, 1, 1); + add_edge(linear_graph, 1, 2, 2); + add_edge(linear_graph, 2, 3, 3); + test.each([[0, [0, 1, 3, 6]], [1, [1, 0, 2, 5]], [2, [3, 2, 0, 3]], [3, [6, 5, 3, 0]]])( + "correct result for linear graph with source node %i", + (source, result) => { + expect(dijkstra(linear_graph, source)).toStrictEqual(result); + } + ); + + let unreachable_graph = init_graph(3); + add_edge(unreachable_graph, 0, 1, 1); + test.each([[0, [0, 1, Infinity]], [1, [1, 0, Infinity]], [2, [Infinity, Infinity, 0]]])( + "correct result for graph with unreachable nodes with source node %i", + (source, result) => { + expect(dijkstra(unreachable_graph, source)).toStrictEqual(result); + } + ); +}) + From 03dc8b8c8179e13b0fc87c9fe815ab5cae7cfa8f Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Thu, 13 Jul 2023 10:53:55 -0700 Subject: [PATCH 047/107] feat: add Prim's algorithm for Minimum Spanning Tree (#142) * feat: add Prim's algorithm for Minimum Spanning Tree fix: do not decrease priority in PriorityQueue increasePriority() * clarify comment --- data_structures/heap/heap.ts | 6 +- data_structures/heap/test/min_heap.test.ts | 5 ++ graph/prim.ts | 59 +++++++++++++++ graph/test/prim.test.ts | 85 ++++++++++++++++++++++ 4 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 graph/prim.ts create mode 100644 graph/test/prim.test.ts diff --git a/data_structures/heap/heap.ts b/data_structures/heap/heap.ts index 28915849..5f8e8974 100644 --- a/data_structures/heap/heap.ts +++ b/data_structures/heap/heap.ts @@ -14,7 +14,7 @@ export abstract class Heap { protected heap: T[]; // A comparison function. Returns true if a should be the parent of b. - private compare: (a: T, b: T) => boolean; + protected compare: (a: T, b: T) => boolean; constructor(compare: (a: T, b: T) => boolean) { this.heap = []; @@ -189,6 +189,10 @@ export class PriorityQueue extends MinHeap { return; } let key = this.keys[idx]; + if (this.compare(this.heap[key], value)) { + // Do not do anything if the value in the heap already has a higher priority. + return; + } // Increase the priority and bubble it up the heap. this.heap[key] = value; this.bubbleUp(key); diff --git a/data_structures/heap/test/min_heap.test.ts b/data_structures/heap/test/min_heap.test.ts index e7fa82ad..33ac03cd 100644 --- a/data_structures/heap/test/min_heap.test.ts +++ b/data_structures/heap/test/min_heap.test.ts @@ -65,6 +65,11 @@ describe("MinHeap", () => { heap.increasePriority(81, 72); heap.increasePriority(9, 0); heap.increasePriority(43, 33); + // decreasing priority should do nothing + heap.increasePriority(72, 100); + heap.increasePriority(12, 24); + heap.increasePriority(39, 40); + heap.check(); // Elements after increasing priority const newElements: number[] = [ diff --git a/graph/prim.ts b/graph/prim.ts new file mode 100644 index 00000000..5c36479a --- /dev/null +++ b/graph/prim.ts @@ -0,0 +1,59 @@ +import { PriorityQueue } from '../data_structures/heap/heap' +/** + * @function prim + * @description Compute a minimum spanning tree(MST) of a fully connected weighted undirected graph. The input graph is in adjacency list form. It is a multidimensional array of edges. graph[i] holds the edges for the i'th node. Each edge is a 2-tuple where the 0'th item is the destination node, and the 1'th item is the edge weight. + * @Complexity_Analysis + * Time complexity: O(Elog(V)) + * Space Complexity: O(V) + * @param {[number, number][][]} graph - The graph in adjacency list form + * @return {Edge[], number} - [The edges of the minimum spanning tree, the sum of the weights of the edges in the tree] + * @see https://en.wikipedia.org/wiki/Prim%27s_algorithm + */ +export const prim = (graph: [number, number][][]): [Edge[], number] => { + if (graph.length == 0) { + return [[], 0]; + } + let minimum_spanning_tree: Edge[] = []; + let total_weight = 0; + + let priorityQueue = new PriorityQueue((e: Edge) => { return e.b }, graph.length, (a: Edge, b: Edge) => { return a.weight < b.weight }); + let visited = new Set(); + + // Start from the 0'th node. For fully connected graphs, we can start from any node and still produce the MST. + visited.add(0); + add_children(graph, priorityQueue, 0); + + while (!priorityQueue.isEmpty()) { + // We have already visited vertex `edge.a`. If we have not visited `edge.b` yet, we add its outgoing edges to the PriorityQueue. + let edge = priorityQueue.extract(); + if (visited.has(edge.b)) { + continue; + } + minimum_spanning_tree.push(edge); + total_weight += edge.weight; + visited.add(edge.b); + add_children(graph, priorityQueue, edge.b); + } + + return [minimum_spanning_tree, total_weight]; +} + +const add_children = (graph: [number, number][][], priorityQueue: PriorityQueue, node: number) => { + for (let i = 0; i < graph[node].length; ++i) { + let out_edge = graph[node][i]; + // By increasing the priority, we ensure we only add each vertex to the queue one time, and the queue will be at most size V. + priorityQueue.increasePriority(out_edge[0], new Edge(node, out_edge[0], out_edge[1])); + } +} + +export class Edge { + a: number = 0; + b: number = 0; + weight: number = 0; + constructor(a: number, b: number, weight: number) { + this.a = a; + this.b = b; + this.weight = weight; + } +} + diff --git a/graph/test/prim.test.ts b/graph/test/prim.test.ts new file mode 100644 index 00000000..763f1716 --- /dev/null +++ b/graph/test/prim.test.ts @@ -0,0 +1,85 @@ +import { Edge, prim } from "../prim"; + +let edge_equal = (x: Edge, y: Edge): boolean => { + return (x.a == y.a && x.b == y.b) || (x.a == y.b && x.b == y.a) && x.weight == y.weight; +} + +let test_graph = (expected_tree_edges: Edge[], other_edges: Edge[], num_vertices: number, expected_cost: number) => { + // First make sure the graph is undirected + let graph: [number, number][][] = []; + for (let _ = 0; _ < num_vertices; ++_) { + graph.push([]); + } + for (let edge of expected_tree_edges) { + graph[edge.a].push([edge.b, edge.weight]); + graph[edge.b].push([edge.a, edge.weight]); + } + for (let edge of other_edges) { + graph[edge.a].push([edge.b, edge.weight]); + graph[edge.b].push([edge.a, edge.weight]); + } + + let [tree_edges, cost] = prim(graph); + expect(cost).toStrictEqual(expected_cost); + for (let expected_edge of expected_tree_edges) { + expect(tree_edges.find(edge => edge_equal(edge, expected_edge))).toBeTruthy(); + } + for (let unexpected_edge of other_edges) { + expect(tree_edges.find(edge => edge_equal(edge, unexpected_edge))).toBeFalsy(); + } +}; + + +describe("prim", () => { + + it("should return empty tree for empty graph", () => { + expect(prim([])).toStrictEqual([[], 0]); + }); + + it("should return empty tree for single element graph", () => { + expect(prim([])).toStrictEqual([[], 0]); + }); + + it("should return correct value for two element graph", () => { + expect(prim([[[1, 5]], []])).toStrictEqual([[new Edge(0, 1, 5)], 5]); + }); + + it("should return the correct value", () => { + let expected_tree_edges = [ + new Edge(0, 1, 1), + new Edge(1, 3, 2), + new Edge(3, 2, 3), + ]; + + let other_edges = [ + new Edge(0, 2, 4), + new Edge(0, 3, 5), + new Edge(1, 2, 6), + ]; + + test_graph(expected_tree_edges, other_edges, 4, 6); + }); + + it("should return the correct value", () => { + let expected_tree_edges = [ + new Edge(0, 2, 2), + new Edge(1, 3, 9), + new Edge(2, 6, 74), + new Edge(2, 7, 8), + new Edge(3, 4, 3), + new Edge(4, 9, 9), + new Edge(5, 7, 5), + new Edge(7, 9, 4), + new Edge(8, 9, 2), + ] + + let other_edges = [ + new Edge(0, 1, 10), + new Edge(2, 4, 47), + new Edge(4, 5, 42), + ]; + + test_graph(expected_tree_edges, other_edges, 10, 116); + }); + +}) From e8a850c6a7a89f7c20eb5036d643fd850c64f5e2 Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Thu, 13 Jul 2023 10:55:02 -0700 Subject: [PATCH 048/107] feat: add johnson algorithm for all pairs shortest paths (#145) * feat: add johnson algorithm for all pairs shortest paths * fix initializing edges. add test case for empty graph and disjoint graph. * more detail to test description * Remove accidentally committed files --- graph/johnson.ts | 52 ++++++++++++++++++ graph/test/johnson.test.ts | 107 +++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 graph/johnson.ts create mode 100644 graph/test/johnson.test.ts diff --git a/graph/johnson.ts b/graph/johnson.ts new file mode 100644 index 00000000..7eac28ac --- /dev/null +++ b/graph/johnson.ts @@ -0,0 +1,52 @@ +import { bellmanFord } from './bellman_ford' +import { dijkstra } from './dijkstra' + +/** + * @function johnson + * @description Compute the shortest path for all pairs of nodes. The input graph is in adjacency list form. It is a multidimensional array of edges. graph[i] holds the edges for the i'th node. Each edge is a 2-tuple where the 0'th item is the destination node, and the 1'th item is the edge weight. Returned undefined if the graph has negative weighted cycles. + * @Complexity_Analysis + * Time complexity: O(VElog(V)) + * Space Complexity: O(V^2) to hold the result + * @param {[number, number][][]} graph - The graph in adjacency list form + * @return {number[][]} - A matrix holding the shortest path for each pair of nodes. matrix[i][j] holds the distance of the shortest path (i -> j). + * @see https://en.wikipedia.org/wiki/Johnson%27s_algorithm + */ +export const johnson = (graph: [number, number][][]): number[][] | undefined => { + let N = graph.length; + + // Add a new node and 0 weighted edges from the new node to all existing nodes. + let newNodeGraph = structuredClone(graph); + let newNode: [number, number][] = []; + for (let i = 0; i < N; ++i) { + newNode.push([i, 0]); + } + newNodeGraph.push(newNode); + + // Compute distances from the new node to existing nodes using the Bellman-Ford algorithm. + let adjustedGraph = bellmanFord(newNodeGraph, N); + if (adjustedGraph === undefined) { + // Found a negative weight cycle. + return undefined; + } + + for (let i = 0; i < N; ++i) { + for (let edge of graph[i]) { + // Adjust edge weights using the Bellman Ford output weights. This ensure that: + // 1. Each weight is non-negative. This is required for the Dijkstra algorithm. + // 2. The shortest path from node i to node j consists of the same nodes with or without adjustment. + edge[1] += adjustedGraph[i] - adjustedGraph[edge[0]]; + } + } + + let shortestPaths: number[][] = []; + for (let i = 0; i < N; ++i) { + // Compute Dijkstra weights for each node and re-adjust weights to their original values. + let dijkstraShorestPaths = dijkstra(graph, i); + for (let j = 0; j < N; ++j) { + dijkstraShorestPaths[j] += adjustedGraph[j] - adjustedGraph[i]; + } + shortestPaths.push(dijkstraShorestPaths); + } + return shortestPaths; +} + diff --git a/graph/test/johnson.test.ts b/graph/test/johnson.test.ts new file mode 100644 index 00000000..24600879 --- /dev/null +++ b/graph/test/johnson.test.ts @@ -0,0 +1,107 @@ +import { johnson } from "../johnson"; + +describe("johnson", () => { + + const init_graph = (N: number): [number, number][][] => { + let graph = Array(N); + for (let i = 0; i < N; ++i) { + graph[i] = []; + } + return graph; + } + + const add_edge = (graph: [number, number][][], a: number, b: number, weight: number) => { + graph[a].push([b, weight]); + graph[b].push([a, weight]); + } + + it("should return the correct value", () => { + let graph = init_graph(9); + add_edge(graph, 0, 1, 4); + add_edge(graph, 0, 7, 8); + add_edge(graph, 1, 2, 8); + add_edge(graph, 1, 7, 11); + add_edge(graph, 2, 3, 7); + add_edge(graph, 2, 5, 4); + add_edge(graph, 2, 8, 2); + add_edge(graph, 3, 4, 9); + add_edge(graph, 3, 5, 14); + add_edge(graph, 4, 5, 10); + add_edge(graph, 5, 6, 2); + add_edge(graph, 6, 7, 1); + add_edge(graph, 6, 8, 6); + add_edge(graph, 7, 8, 7); + + let expected = [ + [0, 4, 12, 19, 21, 11, 9, 8, 14], + [4, 0, 8, 15, 22, 12, 12, 11, 10], + [12, 8, 0, 7, 14, 4, 6, 7, 2], + [19, 15, 7, 0, 9, 11, 13, 14, 9], + [21, 22, 14, 9, 0, 10, 12, 13, 16], + [11, 12, 4, 11, 10, 0, 2, 3, 6], + [9, 12, 6, 13, 12, 2, 0, 1, 6], + [8, 11, 7, 14, 13, 3, 1, 0, 7], + [14, 10, 2, 9, 16, 6, 6, 7, 0] + ] + expect(johnson(graph)).toStrictEqual(expected); + }); + + it("should return the correct value for graph with negative weights", () => { + let graph = init_graph(4); + graph[0].push([1, -5]); + graph[0].push([2, 2]); + graph[0].push([3, 3]); + graph[1].push([2, 4]); + graph[2].push([3, 1]); + + let expected = [ + [ 0, -5, -1, 0 ], + [ Infinity, 0, 4, 5 ], + [ Infinity, Infinity, 0, 1 ], + [ Infinity, Infinity, Infinity, 0 ] + ] + expect(johnson(graph)).toStrictEqual(expected); + }); + + it("should return the undefined for two node graph with negative-weight cycle", () => { + let graph = init_graph(2); + add_edge(graph, 0, 1, -1); + expect(johnson(graph)).toStrictEqual(undefined); + }); + + it("should return the undefined for three node graph with negative-weight cycle", () => { + let graph = init_graph(3); + graph[0].push([1, -1]); + graph[0].push([2, 7]); + graph[1].push([2, -5]); + graph[2].push([0, 4]); + expect(johnson(graph)).toStrictEqual(undefined); + }); + + it("should return the correct value for zero element graph", () => { + expect(johnson([])).toStrictEqual([]); + }); + + it("should return the correct value for single element graph", () => { + expect(johnson([[]])).toStrictEqual([[0]]); + }); + + it("should return the correct value for a linear graph", () => { + let linear_graph = init_graph(4); + add_edge(linear_graph, 0, 1, 1); + add_edge(linear_graph, 1, 2, 2); + add_edge(linear_graph, 2, 3, 3); + + let expected = [[0, 1, 3, 6 ], [1, 0, 2, 5], [3, 2, 0, 3], [6, 5, 3, 0]]; + expect(johnson(linear_graph)).toStrictEqual(expected); + }); + + it("should return the correct value for a linear graph with unreachable node", () => { + let linear_graph = init_graph(3); + add_edge(linear_graph, 0, 1, 1); + + let expected = [[0, 1, Infinity], [1, 0, Infinity], [Infinity, Infinity, 0]]; + expect(johnson(linear_graph)).toStrictEqual(expected); + }); +}) + From 042f52c02f329a33b4d0ad81e88b63ee1e14b6e0 Mon Sep 17 00:00:00 2001 From: Noah <70114451+zFl4wless@users.noreply.github.com> Date: Thu, 13 Jul 2023 19:55:44 +0200 Subject: [PATCH 049/107] feat(maths): adds prime sieve and generator (#144) * Update DIRECTORY.md * feat(maths): adds prime sieve and generator * Update DIRECTORY.md --------- Co-authored-by: autoprettier --- DIRECTORY.md | 74 ++++++++++++++++++++++++++++--- maths/is_prime.ts | 28 ------------ maths/primes.ts | 87 +++++++++++++++++++++++++++++++++++++ maths/test/is_prime.test.ts | 19 -------- maths/test/primes.test.ts | 59 +++++++++++++++++++++++++ 5 files changed, 215 insertions(+), 52 deletions(-) delete mode 100644 maths/is_prime.ts create mode 100644 maths/primes.ts delete mode 100644 maths/test/is_prime.test.ts create mode 100644 maths/test/primes.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 88c729ed..ce0e7c51 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -3,24 +3,79 @@ * [Xor Cipher](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/ciphers/xor_cipher.ts) ## Data Structures - * [Array Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/array_queue.ts) - * [Linked Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/linked_queue.ts) - * [Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue.ts) - * [Stack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack.ts) - * [Stack Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack_queue.ts) + * Disjoint Set + * [Disjoint Set](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/disjoint_set/disjoint_set.ts) + * Test + * [Disjoint Set.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/disjoint_set/test/disjoint_set.test.ts) + * Heap + * [Heap](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/heap/heap.ts) + * Test + * [Max Heap.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/heap/test/max_heap.test.ts) + * [Min Heap.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/heap/test/min_heap.test.ts) + * List + * [Doubly Linked List](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/list/doubly_linked_list.ts) + * [Linked List](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/list/linked_list.ts) + * [Singly Linked List](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/list/singly_linked_list.ts) + * Test + * [Doubly Linked List.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/list/test/doubly_linked_list.test.ts) + * [Linked List](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/list/test/linked_list.ts) + * [Singly Linked List.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/list/test/singly_linked_list.test.ts) + * Map + * [Hash Map](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/map/hash_map.ts) + * [Map](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/map/map.ts) + * Test + * [Hash Map.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/map/test/hash_map.test.ts) + * Queue + * [Array Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue/array_queue.ts) + * [Circular Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue/circular_queue.ts) + * [Linked Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue/linked_queue.ts) + * [Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue/queue.ts) + * [Stack Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue/stack_queue.ts) + * Test + * [Array Queue.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue/test/array_queue.test.ts) + * [Circular Queue.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue/test/circular_queue.test.ts) + * [Linked Queue.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue/test/linked_queue.test.ts) + * [Queue](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue/test/queue.ts) + * [Stack Queue.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/queue/test/stack_queue.test.ts) + * Set + * [Hash Map Set](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/set/hash_map_set.ts) + * [Map Set](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/set/map_set.ts) + * [Set](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/set/set.ts) + * Stack + * [Linked List Stack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack/linked_list_stack.ts) + * [Stack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack/stack.ts) + * Test + * [Linked List Stack.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack/test/linked_list_stack.test.ts) + * [Stack.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/stack/test/stack.test.ts) + * Tree + * [Binary Search Tree](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/tree/binary_search_tree.ts) + * Test + * [Binary Search Tree.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/tree/test/binary_search_tree.test.ts) ## Dynamic Programming * [Knapsack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/knapsack.ts) +## Graph + * [Bellman Ford](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/bellman_ford.ts) + * [Dijkstra](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/dijkstra.ts) + * [Kruskal](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/kruskal.ts) + * Test + * [Bellman Ford.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/bellman_ford.test.ts) + * [Dijkstra.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/dijkstra.test.ts) + * [Kruskal.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/kruskal.test.ts) + ## Maths * [Absolute Value](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/absolute_value.ts) * [Aliquot Sum](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/aliquot_sum.ts) * [Armstrong Number](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/armstrong_number.ts) * [Binary Convert](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/binary_convert.ts) + * [Binomial Coefficient](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/binomial_coefficient.ts) * [Calculate Mean](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/calculate_mean.ts) + * [Calculate Median](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/calculate_median.ts) * [Degrees To Radians](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/degrees_to_radians.ts) * [Digit Sum](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/digit_sum.ts) * [Factorial](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/factorial.ts) + * [Factors](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/factors.ts) * [Fibonacci](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/fibonacci.ts) * [Find Min](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/find_min.ts) * [Greatest Common Factor](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/greatest_common_factor.ts) @@ -31,8 +86,13 @@ * [Is Odd](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_odd.ts) * [Is Palindrome](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_palindrome.ts) * [Is Square Free](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_square_free.ts) + * [Juggler Sequence](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/juggler_sequence.ts) * [Lowest Common Multiple](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/lowest_common_multiple.ts) + * [Number Of Digits](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/number_of_digits.ts) + * [Pascals Triangle](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/pascals_triangle.ts) + * [Perfect Cube](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_cube.ts) * [Perfect Square](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_square.ts) + * [Primes](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/primes.ts) * [Pronic Number](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/pronic_number.ts) * [Radians To Degrees](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/radians_to_degrees.ts) * Series @@ -41,6 +101,7 @@ * [Hexagonal Numbers.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/series/test/hexagonal_numbers.test.ts) * [Sieve Of Eratosthenes](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/sieve_of_eratosthenes.ts) * [Signum](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/signum.ts) + * [Zellers Congruence](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/zellers_congruence.ts) ## Other * [Parse Nested Brackets](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/other/parse_nested_brackets.ts) @@ -58,4 +119,7 @@ * [Gnome Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/gnome_sort.ts) * [Insertion Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/insertion_sort.ts) * [Merge Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/merge_sort.ts) + * [Quick Select](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/quick_select.ts) * [Quick Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/quick_sort.ts) + * [Selection Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/selection_sort.ts) + * [Shell Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/shell_sort.ts) diff --git a/maths/is_prime.ts b/maths/is_prime.ts deleted file mode 100644 index 2835091a..00000000 --- a/maths/is_prime.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @function IsPrime - * @description Determine if given number is prime. - * @param {number} num - A natural number. - * @return {boolean} - Whether the given number is prime. - * @see https://en.wikipedia.org/wiki/Prime_number - * @example IsPrime(2) = false - * @example IsPrime(3) = true - */ - -export const IsPrime = (num: number): boolean => { - // raise corresponding errors upon invalid inputs - if (num <= 0 || !Number.isInteger(num)) { - throw new Error("only natural numbers are supported"); - } - - // handle input being 1 - if (num === 1) return false; - - // iterate from 2 to the square root of num to find a factor - // return false upon finding a factor - for (let i = 2; i <= Math.sqrt(num); i++) { - if (num % i === 0) return false; - } - - // if the entire loop runs without finding a factor, return true - return true; -}; diff --git a/maths/primes.ts b/maths/primes.ts new file mode 100644 index 00000000..e6deab08 --- /dev/null +++ b/maths/primes.ts @@ -0,0 +1,87 @@ +/** + * Implementation of the Sieve of Eratosthenes algorithm. + * + * @param limit An integer _n_ > 1 + * @returns All prime numbers from 2 through {@link limit} + * + * @see https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes + */ +export function sieveOfEratosthenes(limit: number): number[] { + if (!Number.isInteger(limit) || limit <= 1) { + throw new Error("limit should be an integer greater than 1"); + } + + const maybePrime: boolean[] = new Array(limit + 1).fill(true); + for (let i = 2; i * i <= limit; i++) { + if (!maybePrime[i]) continue; + for (let j = i * i; j <= limit; j += i) { + maybePrime[j] = false; + } + } + + const primes: number[] = []; + for (let i = 2; i < maybePrime.length; i++) { + if (maybePrime[i]) { + primes.push(i); + } + } + + return primes; +} + +/** + * Generator that yields primes. + * + * Inspired by https://gist.github.com/e-nikolov/cd94db0de2a6b70da144124ae93a6458 + */ +export function* primeGenerator() { + type NumberGen = Generator; + + function* filter(input: NumberGen, prime: number): NumberGen { + while (true) { + const {done, value} = input.next(); + if (done) break; + if (value % prime !== 0) yield value; + } + } + + let chain: NumberGen = (function* () { + let i = 2; + while (true) yield i++; + })(); + + while (true) { + const {done, value} = chain.next(); + if (done) break; + yield value; + chain = filter(chain, value); + } +} + +/** + * @function isPrime + * @description Determine if given number is prime. + * @param {number} num - A natural number. + * @return {boolean} - Whether the given number is prime. + * @see https://en.wikipedia.org/wiki/Prime_number + * @example isPrime(2) = false + * @example isPrime(3) = true + */ +export const isPrime = (num: number): boolean => { + // raise corresponding errors upon invalid inputs + if (num <= 0 || !Number.isInteger(num)) { + throw new Error("only natural numbers are supported"); + } + + // handle input being 1 + if (num === 1) return false; + + // iterate from 2 to the square root of num to find a factor + // return false upon finding a factor + for (let i = 2; i <= Math.sqrt(num); i++) { + if (num % i === 0) return false; + } + + // if the entire loop runs without finding a factor, return true + return true; +}; diff --git a/maths/test/is_prime.test.ts b/maths/test/is_prime.test.ts deleted file mode 100644 index 2a2c7ca6..00000000 --- a/maths/test/is_prime.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { IsPrime } from "../is_prime"; - -describe("IsPrime", () => { - test.each([[1, false], [2, true], [3, true], [3*3, false], [13, true], [24, false]])( - "correct output for %i", - (nums, expected) => { - expect(IsPrime(nums)).toBe(expected); - }, - ); - - test.each([-890, -5.56, -7, 0.73, 4.2, NaN, -Infinity, Infinity])( - "should throw an error for non natural number %d", - (num) => { - expect(() => IsPrime(num)).toThrowError( - "only natural numbers are supported", - ); - }, - ); -}); diff --git a/maths/test/primes.test.ts b/maths/test/primes.test.ts new file mode 100644 index 00000000..c67a2fd8 --- /dev/null +++ b/maths/test/primes.test.ts @@ -0,0 +1,59 @@ +import {isPrime, primeGenerator, sieveOfEratosthenes} from "../primes"; + + +describe(sieveOfEratosthenes, () => { + test.each([-1, 0, 1, 2.123, 1337.80085])( + "should throw an error when given an invalid limit=%d", + (invalidLimit) => { + expect(() => sieveOfEratosthenes(invalidLimit)).toThrow(); + } + ); + test.each([ + [2, [2]], + [3, [2, 3]], + [4, [2, 3]], + [5, [2, 3, 5]], + [6, [2, 3, 5]], + [7, [2, 3, 5, 7]], + [8, [2, 3, 5, 7]], + [9, [2, 3, 5, 7]], + ])( + "should return the expected list of primes for limit=%i", + (limit, expected) => { + expect(sieveOfEratosthenes(limit)).toEqual(expected); + } + ); +}); + +describe(primeGenerator, () => { + it("should generate prime numbers", () => { + const primeGen = primeGenerator(); + for (let i = 0; i < 100; i++) { + const prime = primeGen.next().value; + + if (prime === undefined) { + throw new Error("prime generator returned undefined"); + } + + expect(isPrime(prime)).toBe(true); + } + }); +}); + +describe("IsPrime", () => { + test.each([[1, false], [2, true], [3, true], [3 * 3, false], [13, true], [24, false]])( + "correct output for %i", + (nums, expected) => { + expect(isPrime(nums)).toBe(expected); + }, + ); + + test.each([-890, -5.56, -7, 0.73, 4.2, NaN, -Infinity, Infinity])( + "should throw an error for non natural number %d", + (num) => { + expect(() => isPrime(num)).toThrowError( + "only natural numbers are supported", + ); + }, + ); +}); From 79887130110b166297ed02fc66f5be4b41d1bfca Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Thu, 13 Jul 2023 10:56:12 -0700 Subject: [PATCH 050/107] feat: floyd-warshall for all pairs shortest path (#143) * feat: floyd-warshall for all pairs shortest path * rewrite incorrect comments --- graph/floyd_warshall.ts | 37 ++++++++++++++++++ graph/test/floyd_warshall.test.ts | 63 +++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 graph/floyd_warshall.ts create mode 100644 graph/test/floyd_warshall.test.ts diff --git a/graph/floyd_warshall.ts b/graph/floyd_warshall.ts new file mode 100644 index 00000000..c8addc46 --- /dev/null +++ b/graph/floyd_warshall.ts @@ -0,0 +1,37 @@ +/** + * @function floydWarshall + * @description Compute the shortest path for all pairs of nodes for a graph without negative weight edges. The input graph is a adjacency matrix, where graph[i][j] holds the weight of edges a->b. If the edge does not exist, the value in the matrix is Infinity. + * @Complexity_Analysis + * Time complexity: O(V^3) + * Space Complexity: O(V^2). This space is required to hold the result + * @param {number[][]} graph - The graph in adjacency matrix form + * @return {number[][]} - A matrix holding the shortest path for each pair of nodes. matrix[i][j] holds the distance of the shortest path (i -> j). + * @see https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm + */ +export const floydWarshall = (graph: number[][]): number[][] => { + let distances = structuredClone(graph); + let N = graph.length; + + // We begin by setting the weighted adjacency matrix as the shortest paths. + // For the k'th iteration, we try to relax the shortest paths by including node k in the path. + for (let k = 0; k < N; ++k) { + let newDistances = []; + for (let i = 0; i < N; ++i) { + newDistances.push(Array(N).fill(Infinity)); + } + + for (let i = 0; i < N; ++i) { + for (let j = 0; j < N; ++j) { + // The shortest path from node i to j is the minimum of: + // 1. the shortest path (i -> j) without node k + // 2. the sum of the shortest path (i -> k) and (k -> j) + newDistances[i][j] = Math.min(distances[i][j], distances[i][k] + distances[k][j]); + } + } + distances = newDistances; + } + + return distances; +} + + diff --git a/graph/test/floyd_warshall.test.ts b/graph/test/floyd_warshall.test.ts new file mode 100644 index 00000000..33cc67dc --- /dev/null +++ b/graph/test/floyd_warshall.test.ts @@ -0,0 +1,63 @@ +import { floydWarshall } from "../floyd_warshall"; + +describe("floydWarshall", () => { + it("should return the correct value for zero element graph", () => { + expect(floydWarshall([])).toEqual([]); + }); + + it("should return the correct value for one element graph", () => { + expect(floydWarshall([[1]])).toStrictEqual([[1]]); + }); + + it("should return the correct value for two element graph", () => { + expect(floydWarshall([[10, 4], [3, 6]])).toStrictEqual([[7, 4], [3, 6]]); + }); + + it("should return the correct value", () => { + let graph = []; + for (let i = 1; i <= 5; ++i) { + let arr = []; + for (let j = 1; j <= 5; ++j) { + arr.push(i * j); + } + graph.push(arr); + } + + let expected = [ + [ 1, 2, 3, 4, 5 ], + [ 2, 4, 5, 6, 7 ], + [ 3, 5, 6, 7, 8 ], + [ 4, 6, 7, 8, 9 ], + [ 5, 7, 8, 9, 10 ] + ]; + expect(floydWarshall(graph)).toStrictEqual(expected); + }); + + it("should return the correct value", () => { + let graph = [ + [0, 4, Infinity, Infinity, Infinity, Infinity, Infinity, 8, Infinity], + [4, 0, 8, Infinity, Infinity, Infinity, Infinity, 11, Infinity], + [Infinity, 8, 0, 7, Infinity, 4, Infinity, Infinity, 2], + [Infinity, Infinity, 7, 0, 9, 14, Infinity, Infinity, Infinity], + [Infinity, Infinity, Infinity, 9, 0, 10, Infinity, Infinity, Infinity], + [Infinity, Infinity, 4, 14, 10, 0, 2, Infinity, Infinity], + [Infinity, Infinity, Infinity, Infinity, Infinity, 2, 0, 1, 6], + [8, 11, Infinity, Infinity, Infinity, Infinity, 1, 0, 7], + [Infinity, Infinity, 2, Infinity, Infinity, Infinity, 6, 7, 0] + ]; + + let expected = [ + [0, 4, 12, 19, 21, 11, 9, 8, 14], + [4, 0, 8, 15, 22, 12, 12, 11, 10], + [12, 8, 0, 7, 14, 4, 6, 7, 2], + [19, 15, 7, 0, 9, 11, 13, 14, 9], + [21, 22, 14, 9, 0, 10, 12, 13, 16], + [11, 12, 4, 11, 10, 0, 2, 3, 6], + [9, 12, 6, 13, 12, 2, 0, 1, 6], + [8, 11, 7, 14, 13, 3, 1, 0, 7], + [14, 10, 2, 9, 16, 6, 6, 7, 0] + ] + + expect(floydWarshall(graph)).toStrictEqual(expected); + }); +}); From a4c8d373a3168e13988fca770290bbee0e90f9d1 Mon Sep 17 00:00:00 2001 From: Omer M <125453822+mendlero@users.noreply.github.com> Date: Wed, 9 Aug 2023 22:05:27 +0300 Subject: [PATCH 051/107] added bogosort algorithem (#147) * added bogo sort algorithem * Revert "added bogo sort algorithem" This reverts commit 5a512df0cc7e726834d769ed347f4ade14a018a9. * feat: added bogosort algorithem * refactor: split bogosort into 2 seperate algorithems * test: added tests to shuffle_array and is_sorted_array * test: added test for bogo sort algorithem * refactor: changed the complexity analysis of the bogosort algorithem * test: updated the test to use test.each * refactor: removed the description of shuffleArray --- other/is_sorted_array.ts | 16 ++++++++++++++++ other/shuffle_array.ts | 8 ++++++++ other/test/is_sorted_array.test.ts | 11 +++++++++++ other/test/shuffle_array.test.ts | 25 +++++++++++++++++++++++++ sorts/bogo_sort.ts | 29 +++++++++++++++++++++++++++++ sorts/test/bogo_sort.test.ts | 15 +++++++++++++++ 6 files changed, 104 insertions(+) create mode 100644 other/is_sorted_array.ts create mode 100644 other/shuffle_array.ts create mode 100644 other/test/is_sorted_array.test.ts create mode 100644 other/test/shuffle_array.test.ts create mode 100644 sorts/bogo_sort.ts create mode 100644 sorts/test/bogo_sort.test.ts diff --git a/other/is_sorted_array.ts b/other/is_sorted_array.ts new file mode 100644 index 00000000..e35ff2ef --- /dev/null +++ b/other/is_sorted_array.ts @@ -0,0 +1,16 @@ +/** + * @function isSortedArray + * @description Checks if the array is sorted. + * @param {number[]} arr - array to check if it is sorted + * @returns {boolean} - true if the array is sorted and false if it's not sorted + * @example isSortedArray([1,2,3]) => true + * @example isSortedArray([9,2,3]) => false +*/ +export function isSortedArray(arr: number[]): boolean { + for (let i = 0; i < arr.length - 1; i++) { + if (arr[i] >= arr[i + 1]) { + return false; + } + } + return true; +} diff --git a/other/shuffle_array.ts b/other/shuffle_array.ts new file mode 100644 index 00000000..04a5b701 --- /dev/null +++ b/other/shuffle_array.ts @@ -0,0 +1,8 @@ +export function shuffleArray(arr: number[]) { + for (let i = arr.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + const temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } +} diff --git a/other/test/is_sorted_array.test.ts b/other/test/is_sorted_array.test.ts new file mode 100644 index 00000000..58a223b4 --- /dev/null +++ b/other/test/is_sorted_array.test.ts @@ -0,0 +1,11 @@ +import { isSortedArray } from '../is_sorted_array'; + +describe('isSortedArray', () => { + test.each([ + { arr: [100], expected: true }, + { arr: [9, 2, 3], expected: false }, + { arr: [1, 2, 3], expected: true }, + ])('The return value of ($arr) should be $expected', ({ arr, expected }) => { + expect(isSortedArray(arr)).toEqual(expected); + }); +}); diff --git a/other/test/shuffle_array.test.ts b/other/test/shuffle_array.test.ts new file mode 100644 index 00000000..a5ac836d --- /dev/null +++ b/other/test/shuffle_array.test.ts @@ -0,0 +1,25 @@ +import { shuffleArray } from '../shuffle_array'; + +describe('shuffleArray', () => { + test.each([{ arr: [1, 2, 3] }, { arr: [1, 2, 3, 6, 78, 2] }])( + "The length of the array $arr does'nt change after shuffling the array", + ({ arr }) => { + const originalLength = arr.length; + shuffleArray(arr); + expect(arr.length).toEqual(originalLength); + } + ); + + test.each([{ arr: [1, 2, 3] }, { arr: [1, 2, 3, 6, 78, 2] }])( + 'The elements of the array $arr remain the same (possibly with different order) after shuffling the array', + ({ arr }) => { + const copyArray = Array.from(arr); + shuffleArray(arr); + expect( + arr.every((elem) => { + return copyArray.includes(elem); + }) + ).toEqual(true); + } + ); +}); diff --git a/sorts/bogo_sort.ts b/sorts/bogo_sort.ts new file mode 100644 index 00000000..b2231d28 --- /dev/null +++ b/sorts/bogo_sort.ts @@ -0,0 +1,29 @@ +import { isSortedArray } from '../other/is_sorted_array'; +import { shuffleArray } from '../other/shuffle_array'; + +/** + * @function bogoSort + * @description bogo sort is very simple to understand, it randomly shuffeles the input array until it is sorted + * @Complexity_Analysis + * Space complexity - O(1) + * Time complexity + *      Best case   -   O(n) + * The best case occurs when the array is already sorted. + *      Worst case  -   unbounded + * The worst case occurs when the shuffles never make the array sorted. + *      Average case -  O(n!n) + * The average case occurs when the shuffles sort the array after + * n! iterations (every iteration has a probability of 1/n! to sort the array), + * each iteration takes O(n) time. + * + * @param {number[]} arr - The input array + * @return {number[]} - The sorted array. + * @see [Bogo Sort](https://en.wikipedia.org/wiki/Bogosort) + * @example bogoSort([8, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 8] + */ +export function bogoSort(arr: number[]): number[] { + while (!isSortedArray(arr)) { + shuffleArray(arr); + } + return arr; +} diff --git a/sorts/test/bogo_sort.test.ts b/sorts/test/bogo_sort.test.ts new file mode 100644 index 00000000..81e11ae9 --- /dev/null +++ b/sorts/test/bogo_sort.test.ts @@ -0,0 +1,15 @@ +import { bogoSort } from '../bogo_sort'; + +describe('BogoSort', () => { + test.each([ + { arr: [1], expectedResult: [1] }, + { arr: [2, 1], expectedResult: [1, 2] }, + { arr: [3, 1, 2], expectedResult: [1, 2, 3] }, + { arr: [3, 4, 1, 2], expectedResult: [1, 2, 3, 4] }, + ])( + 'The return value of $arr should be $expectedResult', + ({ arr, expectedResult }) => { + expect(bogoSort(arr)).toStrictEqual(expectedResult); + } + ); +}); From 5f5352daeef4f3a289086b30e59f9fe286bcb015 Mon Sep 17 00:00:00 2001 From: Francesco Benedetto Date: Tue, 29 Aug 2023 09:00:56 +0200 Subject: [PATCH 052/107] feat(backtracking): all combinations of k numbers out of 1...n (#148) * feat(backtracking): all combinations of k numbers out of 1...n * refactor(backtracking): remove default of 'startCursor' param * docs(backtracking): add docs * refactor(backtracking): move recursive routine in closure --- backtracking/all-combinations-of-size-k.ts | 38 +++++++++++++++++++ .../test/all-combinations-of-size-k.test.ts | 26 +++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 backtracking/all-combinations-of-size-k.ts create mode 100644 backtracking/test/all-combinations-of-size-k.test.ts diff --git a/backtracking/all-combinations-of-size-k.ts b/backtracking/all-combinations-of-size-k.ts new file mode 100644 index 00000000..c2316982 --- /dev/null +++ b/backtracking/all-combinations-of-size-k.ts @@ -0,0 +1,38 @@ +/** + * This generates an array of unique sub"sets" (represented by ascendingly sorted subarrays) + * of size k out of n+1 numbers from 1 to n. + * + * By using a backtracking algorithm we can incrementally build sub"sets" while dropping candidates + * that cannot contribute anymore to a valid solution. + * Steps: + * - From the starting number (i.e. "1") generate all combinations of k numbers. + * - Once we got all combinations for the given number we can discard it (“backtracks”) + * and repeat the same process for the next number. + */ +export function generateCombinations(n: number, k: number): number[][] { + let combinationsAcc: number[][] = []; + let currentCombination: number[] = []; + + function generateAllCombos( + n: number, + k: number, + startCursor: number + ): number[][] { + if (k === 0) { + if (currentCombination.length > 0) { + combinationsAcc.push(currentCombination.slice()); + } + return combinationsAcc; + } + + const endCursor = n - k + 2; + for (let i = startCursor; i < endCursor; i++) { + currentCombination.push(i); + generateAllCombos(n, k - 1, i + 1); + currentCombination.pop(); + } + return combinationsAcc; + } + + return generateAllCombos(n, k, 1); +} diff --git a/backtracking/test/all-combinations-of-size-k.test.ts b/backtracking/test/all-combinations-of-size-k.test.ts new file mode 100644 index 00000000..8fd440d1 --- /dev/null +++ b/backtracking/test/all-combinations-of-size-k.test.ts @@ -0,0 +1,26 @@ +import { generateCombinations } from "../all-combinations-of-size-k"; + +const cases = [ + [ + 3, + 2, + [ + [1, 2], + [1, 3], + [2, 3], + ], + ], + [4, 2, [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]], + [0, 0, []], + [2, 3, []], +] as const; + +describe("AllCombinationsOfSizeK", () => { + it.each(cases)( + "create all combinations given n=%p and k=%p", + (n, k, expectedCombos) => { + const combinations = generateCombinations(n, k); + expect(combinations).toEqual(expectedCombos); + } + ); +}); From 24b02c11a238bd3535363cd9b4e419bda8e3968d Mon Sep 17 00:00:00 2001 From: Surya Prakash Chaudhary <67498076+Suryac72@users.noreply.github.com> Date: Fri, 29 Sep 2023 18:01:55 +0530 Subject: [PATCH 053/107] feat: added tries implementation using typescript (#150) --- data_structures/tries/test/tries.test.ts | 40 +++++++++++ data_structures/tries/tries.ts | 91 ++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 data_structures/tries/test/tries.test.ts create mode 100644 data_structures/tries/tries.ts diff --git a/data_structures/tries/test/tries.test.ts b/data_structures/tries/test/tries.test.ts new file mode 100644 index 00000000..89319c6d --- /dev/null +++ b/data_structures/tries/test/tries.test.ts @@ -0,0 +1,40 @@ +import { Trie } from "../tries"; + +describe('Trie', () => { + let trie: Trie; + + beforeEach(() => { + trie = new Trie(); + }); + + it('should add and find a word', () => { + trie.add('apple'); + expect(trie.find('apple')).toBe(true); + }); + + it('should not find a word that was not added', () => { + trie.add('apple'); + expect(trie.find('banana')).toBe(false); + }); + + it('should not find a partial word', () => { + trie.add('apple'); + expect(trie.find('app')).toBe(false); + }); + + it('should add and find multiple words', () => { + trie.add('apple'); + trie.add('banana'); + trie.add('cherry'); + expect(trie.find('apple')).toBe(true); + expect(trie.find('banana')).toBe(true); + expect(trie.find('cherry')).toBe(true); + }); + + it('should find words with a common prefix', () => { + trie.add('apple'); + trie.add('appetizer'); + expect(trie.find('app', true)).toBe(true); + expect(trie.find('app', false)).toBe(false); + }); +}); diff --git a/data_structures/tries/tries.ts b/data_structures/tries/tries.ts new file mode 100644 index 00000000..1bf6ac27 --- /dev/null +++ b/data_structures/tries/tries.ts @@ -0,0 +1,91 @@ +/** + * Represents a node in a Trie data structure. + */ +class TrieNode { + /** + * An object that stores child nodes for each character in the alphabet. + */ + children: { [key: string]: TrieNode } = {}; + + /** + * Indicates whether the node represents the end of a word. + */ + isWord: boolean = false; +} + +/** + * Trie Data structure for storing and searching words. + */ +export class Trie { + /** + * The root node of the Trie. + */ + root: TrieNode = new TrieNode(); + + /** + * Creates a new Trie instance. + */ + constructor() {} + + /** + * Inserts a word into the Trie. + * + * @param word - The word to insert into the Trie. + */ + private insertNode(node: TrieNode, word: string): void { + for (const char of word) { + if (!node.children[char]) { + node.children[char] = new TrieNode(); + } + node = node.children[char]; + } + node.isWord = true; + } + + /** + * Searches for a word in the Trie. + * + * @param word - The word to search for. + * @param isPrefixMatch - Indicates whether to perform a prefix match (default: false). + * If true, the method returns true if the Trie contains words with the specified prefix. + * If false, the method returns true only if an exact match is found. + * @returns True if the word (or prefix) is found in the Trie; otherwise, false. + */ + public find(word: string, isPrefixMatch: boolean = false): boolean { + return this.searchNode(this.root, word, isPrefixMatch); + } + + /** + * Adds a word to the Trie. + * + * @param word - The word to add to the Trie. + * @returns The Trie instance, allowing for method chaining. + */ + public add(word: string): this { + this.insertNode(this.root, word); + return this; + } + + /** + * Searches for a word in the Trie. + * + * @param node - The current Trie node being examined. + * @param word - The word to search for. + * @param prefixMatch - Indicates whether to perform a prefix match. + * @returns True if the word (or prefix) is found in the Trie; otherwise, false. + * @private + */ + private searchNode( + node: TrieNode, + word: string, + prefixMatch: boolean + ): boolean { + for (const char of word) { + if (!node.children[char]) { + return false; + } + node = node.children[char]; + } + return prefixMatch || node.isWord; + } +} From 4db32785a0ccd2f34950f12f3c1d20b065f73e03 Mon Sep 17 00:00:00 2001 From: Ansh Tyagi <53685410+anshvert@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:40:24 +0530 Subject: [PATCH 054/107] Switch quicksort pivot selection strategy to random (#156) * feat: add Random Pivot Quick Sort * feat: add Random Pivot for Quick Sort * removed redundant export --- sorts/quick_sort.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/sorts/quick_sort.ts b/sorts/quick_sort.ts index c0fd192e..a1abd5e8 100644 --- a/sorts/quick_sort.ts +++ b/sorts/quick_sort.ts @@ -10,7 +10,7 @@ export const partition = ( left: number = 0, right: number = array.length - 1 ) => { - const pivot = array[Math.floor((right + left) / 2)]; + const pivot = array[choosePivot(left,right)]; let i = left; let j = right; @@ -33,6 +33,20 @@ export const partition = ( return i; }; +/** + * @function choosePivot + * @description Chooses a pivot element randomly within the subarray. + * @param {number} left - The left index of the subarray. + * @param {number} right - The right index of the subarray. + * @returns {number} - The index of the chosen pivot element. + */ +const choosePivot = ( + left: number, + right: number +): number => { + return Math.floor(Math.random() * (right - left + 1)) + left +}; + /** * Quicksort implementation * @@ -55,7 +69,7 @@ export const QuickSort = ( array: number[], left: number = 0, right: number = array.length - 1 -) => { +): number[] => { let index; if (array.length > 1) { From a710e646daaf59cede6dbec9be69beead4385838 Mon Sep 17 00:00:00 2001 From: Madhurendra Nath Tiwari <68775519+dev-madhurendra@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:11:39 +0530 Subject: [PATCH 055/107] feat : added fibonacci method using formula (#151) * feat : added fibonacci method using formula * fix : test cases --------- Co-authored-by: madhuredra --- maths/fibonacci.ts | 15 +++++++++++++++ maths/test/fibonacci.test.ts | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/maths/fibonacci.ts b/maths/fibonacci.ts index 33013d68..3d4cb118 100644 --- a/maths/fibonacci.ts +++ b/maths/fibonacci.ts @@ -56,3 +56,18 @@ export const nthFibonacciRecursively = (number: number): number => { nthFibonacciRecursively(number - 1) + nthFibonacciRecursively(number - 2) ); }; + + +/** + * @param number The index of the number in the Fibonacci sequence. + * @return The Fibonacci number on the nth index in the sequence. + * @example nthFibonacci(4) => 3 | nthFibonacci(6) => 8 + * @see : https://math.hmc.edu/funfacts/fibonacci-number-formula/ + * @author : dev-madhurendra + */ + +const sqrt5 = Math.sqrt(5) +const phi = (1 + sqrt5) / 2 +const psi = (1 - sqrt5) / 2 + +export const nthFibonacciUsingFormula = (n : number) => Math.round((phi ** n - psi ** n) / sqrt5) diff --git a/maths/test/fibonacci.test.ts b/maths/test/fibonacci.test.ts index e0a8d14b..9d48d2a4 100644 --- a/maths/test/fibonacci.test.ts +++ b/maths/test/fibonacci.test.ts @@ -1,4 +1,4 @@ -import { nthFibonacci, nthFibonacciRecursively } from '../fibonacci'; +import { nthFibonacciUsingFormula, nthFibonacci, nthFibonacciRecursively } from '../fibonacci'; const test = (func: (n: number) => number) => it.each([ @@ -11,3 +11,4 @@ const test = (func: (n: number) => number) => ])('fib(%i) = %i', (n, expected) => expect(func(n)).toBe(expected)); describe('Fibonacci iterative', () => test(nthFibonacci)); describe('Fibonacci recursive', () => test(nthFibonacciRecursively)); +describe('Fibonacci Using formula', () => test(nthFibonacciUsingFormula)); From f14c93017b2ae8d464a6710071ff40d2844ca5fa Mon Sep 17 00:00:00 2001 From: Madhurendra Nath Tiwari <68775519+dev-madhurendra@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:12:05 +0530 Subject: [PATCH 056/107] feat: added is power of 4 method (#158) Co-authored-by: madhuredra --- bit_manipulation/is_power_of_4.ts | 15 +++++++++++++++ bit_manipulation/test/is_power_of_4.test.ts | 14 ++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 bit_manipulation/is_power_of_4.ts create mode 100644 bit_manipulation/test/is_power_of_4.test.ts diff --git a/bit_manipulation/is_power_of_4.ts b/bit_manipulation/is_power_of_4.ts new file mode 100644 index 00000000..e7a57bc5 --- /dev/null +++ b/bit_manipulation/is_power_of_4.ts @@ -0,0 +1,15 @@ +/** + * @author : dev-madhurendra + * Checks whether the given number is a power of four or not. + * + * A number is considered a power of four if and only if there is a single '1' bit in its binary representation, + * and that '1' bit is at the first position, followed by an even number of '0' bits. + * + * @param {number} n - The input number to check. + * @returns {boolean} True if the number is a power of four, false otherwise. + * + * @example + * const result = isPowerOfFour(16); // Returns true (16 is 4^2) + * const result2 = isPowerOfFour(5); // Returns false (5 is not a power of four) + */ +export const isPowerOfFour = (n: number): boolean => ((n > 0) && ((n & n - 1) === 0) && (n % 3 === 1)) diff --git a/bit_manipulation/test/is_power_of_4.test.ts b/bit_manipulation/test/is_power_of_4.test.ts new file mode 100644 index 00000000..a9b31c47 --- /dev/null +++ b/bit_manipulation/test/is_power_of_4.test.ts @@ -0,0 +1,14 @@ +import { isPowerOfFour } from "../is_power_of_4" + +describe('IsPowerOfFour', () => { + it.each([ + [0, false], + [4, true], + [16, true], + [12, false], + [64, true], + [-64, false] + ])('should return the number %i is power of four or not', (n, expected) => { + expect(isPowerOfFour(n)).toBe(expected) + }) +}) \ No newline at end of file From d8fc33aaab64a00a13c1ea15d8059da30b962bce Mon Sep 17 00:00:00 2001 From: Madhurendra Nath Tiwari <68775519+dev-madhurendra@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:12:48 +0530 Subject: [PATCH 057/107] feat: added is power of two in bit manipulation (#157) * feat : added is power of two in bit manipulation * fix : file name fixed --------- Co-authored-by: madhuredra --- bit_manipulation/is_power_of_2.ts | 25 +++++++++++++++++++++ bit_manipulation/test/is_power_of_2.test.ts | 14 ++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 bit_manipulation/is_power_of_2.ts create mode 100644 bit_manipulation/test/is_power_of_2.test.ts diff --git a/bit_manipulation/is_power_of_2.ts b/bit_manipulation/is_power_of_2.ts new file mode 100644 index 00000000..487c1a8c --- /dev/null +++ b/bit_manipulation/is_power_of_2.ts @@ -0,0 +1,25 @@ +/** + * This code will check whether the given number is a power of two or not. + * @author dev-madhurendra + * @explanation + + A number will be a power of two if only one bit is set and rest are unset. + This is true for all the cases except 01 because (2^0 = 1) which is not a power of 2. + For eg: 10 (2^1 = 2), 100 (2^2 = 4), 10000 (2^4 = 16) + + @see: https://www.hackerearth.com/practice/notes/round-a-number-to-the-next-power-of-2/ + + If we will subtract 1 from a number that is a power of 2 we will get it's + 1's complement.And we know that 1's complement is just opp. of that number. + So, (n & (n-1)) will be 0. + + For eg: (1000 & (1000-1)) + 1 0 0 0 // Original Number (8) + 0 1 1 1 // After Subtracting 1 (8-1 = 7) + _______ + 0 0 0 0 // will become 0 + * @param {number} + * @returns {boolean} + */ + +export const isPowerOfTwo = (n: number): boolean => n > 0 && (n & (n - 1)) === 0 \ No newline at end of file diff --git a/bit_manipulation/test/is_power_of_2.test.ts b/bit_manipulation/test/is_power_of_2.test.ts new file mode 100644 index 00000000..1276e6d1 --- /dev/null +++ b/bit_manipulation/test/is_power_of_2.test.ts @@ -0,0 +1,14 @@ +import { isPowerOfTwo } from "../is_power_of_2" + + +describe('IsPowerOfTwo' , () => { + it.each([ + [0, false], + [1, true], + [4, true], + [1024, true], + [1025, false], + ])('Check if %i is a power of 2 or not', (number, expected) => { + expect(isPowerOfTwo(number)).toBe(expected); + }); +}) \ No newline at end of file From 6fc7f3f62806946ec781803cac0710142b3a780b Mon Sep 17 00:00:00 2001 From: Ansh Tyagi <53685410+anshvert@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:44:29 +0530 Subject: [PATCH 058/107] feat: Added Sentinel Search (#163) * feat: added Sentinel Search * return type to null if element not found --- search/sentinel_search.ts | 42 +++++++++++++++++++++++++++++ search/test/sentinel_search.test.ts | 16 +++++++++++ 2 files changed, 58 insertions(+) create mode 100644 search/sentinel_search.ts create mode 100644 search/test/sentinel_search.test.ts diff --git a/search/sentinel_search.ts b/search/sentinel_search.ts new file mode 100644 index 00000000..3a9052a2 --- /dev/null +++ b/search/sentinel_search.ts @@ -0,0 +1,42 @@ +/** + * @function sentinelSearch + * @description Sentinel search algorithm for array. + * + * Sentinel linear search is a variation of the standard linear search algorithm used to + * find a target value in an array or list. The basic idea behind this algorithm is to add a + * sentinel value at the end of the array which is equal to the target value we are looking for. + * This helps to avoid checking the array boundary condition during each iteration of the loop, + * as the sentinel value acts as a stopper for the loop. + * + * @param {number[]} array - sorted list of numbers + * @param {number} target - target number to search for + * @return {number|null} - index of the target number in the list, or null if not found + * @see [SentinelSearch](https://www.geeksforgeeks.org/sentinel-linear-search/) + * @example sentinelSearch([1,2,3], 2) => 1 + * @example sentinelSearch([4,5,6], 2) => null + * @complexity_analysis + * Time Complexity : + * Worst Case -> The time complexity of the Sentinel Linear Search algorithm is O(n) in the worst case. + * Best Case -> In the best case, when the key is found in the first iteration, the time complexity will be O(1). + * Average Case -> However, the average time complexity is still O(n). + * Auxiliary Space: O(1) + */ + +export const sentinelSearch = (array: number[], target: number): number|null => { + const arrayLength = array.length + if (arrayLength === 0) return null; + + // Element to be searched is placed at the last index + const last = array[arrayLength-1] + array[arrayLength-1] = target + + let index: number = 0 + while (array[index] !== target) index += 1 + + // Put the last element back + array[arrayLength-1] = last + + if ((index < arrayLength - 1) || (array[arrayLength - 1] === target)) + return index + return null +} \ No newline at end of file diff --git a/search/test/sentinel_search.test.ts b/search/test/sentinel_search.test.ts new file mode 100644 index 00000000..910aa254 --- /dev/null +++ b/search/test/sentinel_search.test.ts @@ -0,0 +1,16 @@ +import { sentinelSearch } from "../sentinel_search"; + +describe("Sentinel search", () => { + test.each([ + [['o', 'b', 'c'], 'c', 2], + [[1, 2, 3, 4, 5], 4, 3], + [['s', 't', 'r', 'i', 'n', 'g'], 'a', null], + [['1','2','3'],'1',0], + [['4','e','6','10'],4,null] + ])( + "of %o , searching for %o, expected %i", + (array: any[], target: any, index: number|null) => { + expect(sentinelSearch(array, target)).toStrictEqual(index) + }, + ); +}); \ No newline at end of file From 269cfc8d54bda07eda7739e58b6d4dc3963818a8 Mon Sep 17 00:00:00 2001 From: Omar Ferreiro <27824673+IcarusTheFly@users.noreply.github.com> Date: Mon, 2 Oct 2023 18:48:49 +0200 Subject: [PATCH 059/107] Add Generate Parentheses algorithm in TypeScript (#166) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Generate Parentheses algorithm in TypeScript * Fix typo --------- Co-authored-by: IcarusTheFly Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- backtracking/generateParentheses.ts | 31 +++++++ backtracking/test/generateParentheses.test.ts | 83 +++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 backtracking/generateParentheses.ts create mode 100644 backtracking/test/generateParentheses.test.ts diff --git a/backtracking/generateParentheses.ts b/backtracking/generateParentheses.ts new file mode 100644 index 00000000..e2c93662 --- /dev/null +++ b/backtracking/generateParentheses.ts @@ -0,0 +1,31 @@ +/** + * Given a number n pairs of parentheses, generate all combinations of valid parentheses + * @param {number} n: Number of given parentheses + * @return {string[]} result: Array that contains all valid parentheses + * @see https://leetcode.com/problems/generate-parentheses/ + */ + +const generateParentheses = (n: number): string[] => { + const result: string[] = []; + + const solve = (chars: string, openParentheses: number, closedParentheses: number) => { + if (openParentheses === n && closedParentheses === n) { + result.push(chars); + return; + } + + if (openParentheses <= n) { + solve(chars + "(", openParentheses + 1, closedParentheses); + } + + if (closedParentheses < openParentheses) { + solve(chars + ")", openParentheses, closedParentheses + 1); + } + }; + + solve("", 0, 0); + + return result; +}; + +export { generateParentheses }; diff --git a/backtracking/test/generateParentheses.test.ts b/backtracking/test/generateParentheses.test.ts new file mode 100644 index 00000000..6df3373a --- /dev/null +++ b/backtracking/test/generateParentheses.test.ts @@ -0,0 +1,83 @@ +import { generateParentheses } from "../generateParentheses"; + +const cases: [number, string[]][] = [ + [0, [""]], + [1, ["()"]], + [2, ["(())", "()()"]], + [3, ["((()))", "(()())", "(())()", "()(())", "()()()"]], + [ + 4, + [ + "(((())))", + "((()()))", + "((())())", + "((()))()", + "(()(()))", + "(()()())", + "(()())()", + "(())(())", + "(())()()", + "()((()))", + "()(()())", + "()(())()", + "()()(())", + "()()()()", + ], + ], + [ + 5, + [ + "((((()))))", + "(((()())))", + "(((())()))", + "(((()))())", + "(((())))()", + "((()(())))", + "((()()()))", + "((()())())", + "((()()))()", + "((())(()))", + "((())()())", + "((())())()", + "((()))(())", + "((()))()()", + "(()((())))", + "(()(()()))", + "(()(())())", + "(()(()))()", + "(()()(()))", + "(()()()())", + "(()()())()", + "(()())(())", + "(()())()()", + "(())((()))", + "(())(()())", + "(())(())()", + "(())()(())", + "(())()()()", + "()(((())))", + "()((()()))", + "()((())())", + "()((()))()", + "()(()(()))", + "()(()()())", + "()(()())()", + "()(())(())", + "()(())()()", + "()()((()))", + "()()(()())", + "()()(())()", + "()()()(())", + "()()()()()", + ], + ], +]; + +describe("Generate Parentheses", () => { + test.each(cases)( + "generate all valid parentheses of input %n", + (n: number, expected: string[]) => { + expect(generateParentheses(n)).toStrictEqual(expected); + } + ); +}); From db5510d42df5904b35a590a859cf7006567031ba Mon Sep 17 00:00:00 2001 From: Madhurendra Nath Tiwari <68775519+dev-madhurendra@users.noreply.github.com> Date: Mon, 2 Oct 2023 23:21:39 +0530 Subject: [PATCH 060/107] feat : added counting sort method (#170) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat : added counting sort method * Remove some unnecessary colons --------- Co-authored-by: madhuredra Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- sorts/counting_sort.ts | 30 ++++++++++++++++++++++++++++++ sorts/test/counting_sort.test.ts | 28 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 sorts/counting_sort.ts create mode 100644 sorts/test/counting_sort.test.ts diff --git a/sorts/counting_sort.ts b/sorts/counting_sort.ts new file mode 100644 index 00000000..61ecbfbd --- /dev/null +++ b/sorts/counting_sort.ts @@ -0,0 +1,30 @@ +/** + * @author dev-madhurendra + * Counting sort is an algorithm for sorting a collection + * of objects according to keys that are small integers. + * @see https://en.wikipedia.org/wiki/Counting_sort + * @example + * const array = [3, 0, 2, 5, 4, 1] + * countingSort(array, 0, 5) + */ + +export const countingSort = (inputArr: number[], min: number, max: number) => { + const sortedArr = [] + + const count = new Array(max - min + 1).fill(0) + + for (let i = 0; i < inputArr.length; i++) + count[inputArr[i] - min]++ + + count[0] -= 1 + + for (let i = 1; i < count.length; i++) + count[i] += count[i - 1] + + for (let i = inputArr.length - 1; i >= 0; i--) { + sortedArr[count[inputArr[i] - min]] = inputArr[i] + count[inputArr[i] - min]-- + } + + return sortedArr + } diff --git a/sorts/test/counting_sort.test.ts b/sorts/test/counting_sort.test.ts new file mode 100644 index 00000000..1f8d409f --- /dev/null +++ b/sorts/test/counting_sort.test.ts @@ -0,0 +1,28 @@ +import { countingSort } from "../counting_sort"; + +const testCases = [ + [ + [3, 0, 2, 5, 4, 1], + [0, 1, 2, 3, 4, 5], + ], + [ + [6, 4, 2, 1, 3, 5], + [1, 2, 3, 4, 5, 6], + ], + [ + [11, 14, 12, 15, 16, 13], + [11, 12, 13, 14, 15, 16], + ], + [ + [13, 18, 2, 15, 43, 11], + [2, 11, 13, 15, 18, 43], + ], +]; + +it.each(testCases)( + 'The countingSort of the array %p is %p', + (input, expected) => { + const res = countingSort(input, Math.min(...input), Math.max(...input)); + expect(res).toEqual(expected); + } +); From be813fbab720fa7efadbb7202c7aefbb14174886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Wed, 4 Oct 2023 06:20:59 +0200 Subject: [PATCH 061/107] revert: "Switch quicksort pivot selection strategy to random (#172) * Revert "Switch quicksort pivot selection strategy to random (#156)" This reverts commit 4db32785a0ccd2f34950f12f3c1d20b065f73e03. * Formatting filenames 73378538 * Update DIRECTORY.md --------- Co-authored-by: autoprettier --- DIRECTORY.md | 30 +++++++++++++++++++ ...ize-k.ts => all_combinations_of_size_k.ts} | 0 ...eParentheses.ts => generateparentheses.ts} | 0 ....ts => all_combinations_of_size_k.test.ts} | 0 ...es.test.ts => generateparentheses.test.ts} | 0 sorts/quick_sort.ts | 18 ++--------- 6 files changed, 32 insertions(+), 16 deletions(-) rename backtracking/{all-combinations-of-size-k.ts => all_combinations_of_size_k.ts} (100%) rename backtracking/{generateParentheses.ts => generateparentheses.ts} (100%) rename backtracking/test/{all-combinations-of-size-k.test.ts => all_combinations_of_size_k.test.ts} (100%) rename backtracking/test/{generateParentheses.test.ts => generateparentheses.test.ts} (100%) diff --git a/DIRECTORY.md b/DIRECTORY.md index ce0e7c51..6d5326b1 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -1,4 +1,18 @@ +## Backtracking + * [All Combinations Of Size K](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/backtracking/all_combinations_of_size_k.ts) + * [Generateparentheses](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/backtracking/generateparentheses.ts) + * Test + * [All Combinations Of Size K.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/backtracking/test/all_combinations_of_size_k.test.ts) + * [Generateparentheses.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/backtracking/test/generateparentheses.test.ts) + +## Bit Manipulation + * [Is Power Of 2](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/is_power_of_2.ts) + * [Is Power Of 4](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/is_power_of_4.ts) + * Test + * [Is Power Of 2.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/test/is_power_of_2.test.ts) + * [Is Power Of 4.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/test/is_power_of_4.test.ts) + ## Ciphers * [Xor Cipher](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/ciphers/xor_cipher.ts) @@ -51,6 +65,9 @@ * [Binary Search Tree](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/tree/binary_search_tree.ts) * Test * [Binary Search Tree.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/tree/test/binary_search_tree.test.ts) + * Tries + * [Tries.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/tries/test/tries.test.ts) + * [Tries](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/tries/tries.ts) ## Dynamic Programming * [Knapsack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/knapsack.ts) @@ -58,11 +75,17 @@ ## Graph * [Bellman Ford](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/bellman_ford.ts) * [Dijkstra](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/dijkstra.ts) + * [Floyd Warshall](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/floyd_warshall.ts) + * [Johnson](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/johnson.ts) * [Kruskal](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/kruskal.ts) + * [Prim](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/prim.ts) * Test * [Bellman Ford.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/bellman_ford.test.ts) * [Dijkstra.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/dijkstra.test.ts) + * [Floyd Warshall.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/floyd_warshall.test.ts) + * [Johnson.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/johnson.test.ts) * [Kruskal.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/kruskal.test.ts) + * [Prim.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/prim.test.ts) ## Maths * [Absolute Value](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/absolute_value.ts) @@ -104,17 +127,24 @@ * [Zellers Congruence](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/zellers_congruence.ts) ## Other + * [Is Sorted Array](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/other/is_sorted_array.ts) * [Parse Nested Brackets](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/other/parse_nested_brackets.ts) + * [Shuffle Array](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/other/shuffle_array.ts) * Test + * [Is Sorted Array.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/other/test/is_sorted_array.test.ts) * [Parse Nested Brackets.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/other/test/parse_nested_brackets.test.ts) + * [Shuffle Array.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/other/test/shuffle_array.test.ts) ## Search * [Binary Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/binary_search.ts) * [Jump Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/jump_search.ts) * [Linear Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/linear_search.ts) + * [Sentinel Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/sentinel_search.ts) ## Sorts + * [Bogo Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/bogo_sort.ts) * [Bubble Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/bubble_sort.ts) + * [Counting Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/counting_sort.ts) * [Cycle Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/cycle_sort.ts) * [Gnome Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/gnome_sort.ts) * [Insertion Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/insertion_sort.ts) diff --git a/backtracking/all-combinations-of-size-k.ts b/backtracking/all_combinations_of_size_k.ts similarity index 100% rename from backtracking/all-combinations-of-size-k.ts rename to backtracking/all_combinations_of_size_k.ts diff --git a/backtracking/generateParentheses.ts b/backtracking/generateparentheses.ts similarity index 100% rename from backtracking/generateParentheses.ts rename to backtracking/generateparentheses.ts diff --git a/backtracking/test/all-combinations-of-size-k.test.ts b/backtracking/test/all_combinations_of_size_k.test.ts similarity index 100% rename from backtracking/test/all-combinations-of-size-k.test.ts rename to backtracking/test/all_combinations_of_size_k.test.ts diff --git a/backtracking/test/generateParentheses.test.ts b/backtracking/test/generateparentheses.test.ts similarity index 100% rename from backtracking/test/generateParentheses.test.ts rename to backtracking/test/generateparentheses.test.ts diff --git a/sorts/quick_sort.ts b/sorts/quick_sort.ts index a1abd5e8..c0fd192e 100644 --- a/sorts/quick_sort.ts +++ b/sorts/quick_sort.ts @@ -10,7 +10,7 @@ export const partition = ( left: number = 0, right: number = array.length - 1 ) => { - const pivot = array[choosePivot(left,right)]; + const pivot = array[Math.floor((right + left) / 2)]; let i = left; let j = right; @@ -33,20 +33,6 @@ export const partition = ( return i; }; -/** - * @function choosePivot - * @description Chooses a pivot element randomly within the subarray. - * @param {number} left - The left index of the subarray. - * @param {number} right - The right index of the subarray. - * @returns {number} - The index of the chosen pivot element. - */ -const choosePivot = ( - left: number, - right: number -): number => { - return Math.floor(Math.random() * (right - left + 1)) + left -}; - /** * Quicksort implementation * @@ -69,7 +55,7 @@ export const QuickSort = ( array: number[], left: number = 0, right: number = array.length - 1 -): number[] => { +) => { let index; if (array.length > 1) { From 6be6a4bcb289c8d63db0db43f27c4151611c70f8 Mon Sep 17 00:00:00 2001 From: The Defective Detective <71999854+SpiderMath@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:00:48 +0530 Subject: [PATCH 062/107] feat: Added implementation for ugly numbers (#146) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update DIRECTORY.md * Added ugly numbers 🧟 * Update DIRECTORY.md * 🚀 feat: use generator for ugly nums * Formatting filenames ad9848e0 * Update DIRECTORY.md * Test first 11 ugly numbers * fix oopsie --------- Co-authored-by: autoprettier Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- DIRECTORY.md | 1 + maths/test/ugly_numbers.test.ts | 6 ++++++ maths/ugly_numbers.ts | 36 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 maths/test/ugly_numbers.test.ts create mode 100644 maths/ugly_numbers.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 6d5326b1..3237c4e5 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -124,6 +124,7 @@ * [Hexagonal Numbers.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/series/test/hexagonal_numbers.test.ts) * [Sieve Of Eratosthenes](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/sieve_of_eratosthenes.ts) * [Signum](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/signum.ts) + * [Ugly Numbers](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/ugly_numbers.ts) * [Zellers Congruence](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/zellers_congruence.ts) ## Other diff --git a/maths/test/ugly_numbers.test.ts b/maths/test/ugly_numbers.test.ts new file mode 100644 index 00000000..d25633dc --- /dev/null +++ b/maths/test/ugly_numbers.test.ts @@ -0,0 +1,6 @@ +import { UglyNumbers } from '../ugly_numbers'; + +test('Ugly Numbers', () => { + const uglyNumbers = UglyNumbers(); + expect(Array(11).fill(undefined).map(() => uglyNumbers.next())).toEqual([1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15]); +}) diff --git a/maths/ugly_numbers.ts b/maths/ugly_numbers.ts new file mode 100644 index 00000000..5b7f60af --- /dev/null +++ b/maths/ugly_numbers.ts @@ -0,0 +1,36 @@ +/** + * @generator + * @description Generates ugly numbers + * @summary Ugly numbers are natural numbers whose only prime factors are 2, 3 and 5. + * They can be represented in the form 2^a * 3^b * 5*c. By convention, 1 is also considered to be + * an ugly number. + * The first few terms of the sequence are: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20... + * + * For the provided n, the nth ugly number shall be computed. + * @see [GeeksForGeeks](https://www.geeksforgeeks.org/ugly-numbers/) + */ +function* UglyNumbers() { + yield 1 + + let idx2 = 0, idx3 = 0, idx5 = 0 + const uglyNumbers = [1] + + let nextx2: number, nextx3: number, nextx5: number, nextUglyNum: number + + while(true) { + nextx2 = uglyNumbers[idx2] * 2 + nextx3 = uglyNumbers[idx3] * 3 + nextx5 = uglyNumbers[idx5] * 5 + + nextUglyNum = Math.min(nextx2, nextx3, nextx5) + yield nextUglyNum + + if(nextx2 === nextUglyNum) idx2++ + if(nextx3 === nextUglyNum) idx3++ + if(nextx5 === nextUglyNum) idx5++ + + uglyNumbers.push(nextUglyNum) + } +} + +export { UglyNumbers } From 7dda0e754231bbb2fdb6bb147d8d0ca7290b7bc5 Mon Sep 17 00:00:00 2001 From: Madhurendra Nath Tiwari <68775519+dev-madhurendra@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:39:08 +0530 Subject: [PATCH 063/107] feat: swap sort (#171) --------- Co-authored-by: madhuredra Co-authored-by: Rak Laptudirm --- sorts/swap_sort.ts | 33 +++++++++++++++++++++++++++++++++ sorts/test/swap_sort.test.ts | 15 +++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 sorts/swap_sort.ts create mode 100644 sorts/test/swap_sort.test.ts diff --git a/sorts/swap_sort.ts b/sorts/swap_sort.ts new file mode 100644 index 00000000..68a83ced --- /dev/null +++ b/sorts/swap_sort.ts @@ -0,0 +1,33 @@ +/** + * @author : dev-madhurendra + * @description + * Swap Sort is an algorithm to find the number of swaps required to sort an array. + * @param {number[]} inputArr - Array of numbers + * @return {number} - Number of swaps required to sort the array. + * @see + */ + +export const minSwapsToSort = (inputArr: number[]): number => { + const sortedArray = inputArr.slice() + + sortedArray.sort() + + let indexMap = new Map(); + + for (let i = 0; i < inputArr.length; i++) + indexMap.set(inputArr[i],i); + + let swaps = 0 + for (let i = 0; i < inputArr.length; i++) { + if (inputArr[i] !== sortedArray[i]) { + const temp = inputArr[i] + inputArr[i] = inputArr[indexMap.get(sortedArray[i])] + inputArr[indexMap.get(sortedArray[i])] = temp + indexMap.set(temp,indexMap.get(sortedArray[i])) + indexMap.set(sortedArray[i],1) + swaps++ + } + } + + return swaps +} diff --git a/sorts/test/swap_sort.test.ts b/sorts/test/swap_sort.test.ts new file mode 100644 index 00000000..5221f57b --- /dev/null +++ b/sorts/test/swap_sort.test.ts @@ -0,0 +1,15 @@ +import { minSwapsToSort } from "../swap_sort"; + +describe('SwapSort', () => { + it.each([ + { input: [], expected: 0 }, + { input: [1, 2, 3, 4, 5, 6], expected: 0 }, + { input: [7, 6, 2, 5, 11, 0], expected: 2 }, + { input: [3, 3, 2, 1, 0], expected: 2 }, + { input: [3, 0, 2, 1, 9, 8, 7, 6], expected: 4 }, + { input: [1, 0, 14, 0, 8, 6, 8], expected: 3 }, + ])('should work for given input', ({ input, expected }) => { + expect(minSwapsToSort(input)).toEqual(expected); + }); + }); + \ No newline at end of file From 9843df6bbfe79986b91b9eff180b2f1e38b01888 Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Wed, 4 Oct 2023 23:41:37 +0530 Subject: [PATCH 064/107] fix: failing tests (#174) * chore: fix import after CI name change * chore: fix import after CI name change 2 * chore: fix name after CI name change 3 * fix: ugly numbers test Extract value from iterator object instead of directly using the object. --- backtracking/test/all_combinations_of_size_k.test.ts | 2 +- backtracking/test/generateparentheses.test.ts | 2 +- maths/test/ugly_numbers.test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backtracking/test/all_combinations_of_size_k.test.ts b/backtracking/test/all_combinations_of_size_k.test.ts index 8fd440d1..09639406 100644 --- a/backtracking/test/all_combinations_of_size_k.test.ts +++ b/backtracking/test/all_combinations_of_size_k.test.ts @@ -1,4 +1,4 @@ -import { generateCombinations } from "../all-combinations-of-size-k"; +import { generateCombinations } from "../all_combinations_of_size_k"; const cases = [ [ diff --git a/backtracking/test/generateparentheses.test.ts b/backtracking/test/generateparentheses.test.ts index 6df3373a..c3752d34 100644 --- a/backtracking/test/generateparentheses.test.ts +++ b/backtracking/test/generateparentheses.test.ts @@ -1,4 +1,4 @@ -import { generateParentheses } from "../generateParentheses"; +import { generateParentheses } from "../generateparentheses"; const cases: [number, string[]][] = [ [0, [""]], diff --git a/maths/test/ugly_numbers.test.ts b/maths/test/ugly_numbers.test.ts index d25633dc..f55cd78c 100644 --- a/maths/test/ugly_numbers.test.ts +++ b/maths/test/ugly_numbers.test.ts @@ -2,5 +2,5 @@ import { UglyNumbers } from '../ugly_numbers'; test('Ugly Numbers', () => { const uglyNumbers = UglyNumbers(); - expect(Array(11).fill(undefined).map(() => uglyNumbers.next())).toEqual([1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15]); + expect(Array(11).fill(undefined).map(() => uglyNumbers.next().value)).toEqual([1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15]); }) From d64e4fb7a11201d0930073b4991be95740c7087b Mon Sep 17 00:00:00 2001 From: Madhurendra Nath Tiwari <68775519+dev-madhurendra@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:29:43 +0530 Subject: [PATCH 065/107] feat: added log2 method implementation (#175) Co-authored-by: madhuredra --- bit_manipulation/log_two.ts | 15 +++++++++++++++ bit_manipulation/test/log_two.test.ts | 10 ++++++++++ 2 files changed, 25 insertions(+) create mode 100644 bit_manipulation/log_two.ts create mode 100644 bit_manipulation/test/log_two.test.ts diff --git a/bit_manipulation/log_two.ts b/bit_manipulation/log_two.ts new file mode 100644 index 00000000..6fb40f2d --- /dev/null +++ b/bit_manipulation/log_two.ts @@ -0,0 +1,15 @@ +/** + * @author dev-madhurendra + * @see https://handwiki.org/wiki/Binary_logarithm + * Approximate log2 using bitwise operators + * @param {number} n + * @returns {number} Log2 approximation equal to floor(log2(n)) + */ +export const logTwo = (n: number): number => { + let result = 0 + while (n >> 1) { + n >>= 1 + result++ + } + return result +} \ No newline at end of file diff --git a/bit_manipulation/test/log_two.test.ts b/bit_manipulation/test/log_two.test.ts new file mode 100644 index 00000000..ff168ad3 --- /dev/null +++ b/bit_manipulation/test/log_two.test.ts @@ -0,0 +1,10 @@ +import { logTwo } from "../log_two" + +describe('LogTwoTests' , () => { + test.each([...Array(100).keys()].map(i => [i + 1]))( + 'log2(%i)', + (input) => { + expect(logTwo(input)).toBe(Math.floor(Math.log2(input))); + } + ); +}) \ No newline at end of file From b1094362e92ec1ef40b925efcf099069526b6bf1 Mon Sep 17 00:00:00 2001 From: Surya Prakash Chaudhary <67498076+Suryac72@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:33:31 +0530 Subject: [PATCH 066/107] feat: Added Longest Common Subsequence (#173) --- dynamic_programming/lcs.ts | 46 ++++++++++++++++++++++++++++ dynamic_programming/test/lcs.test.ts | 28 +++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 dynamic_programming/lcs.ts create mode 100644 dynamic_programming/test/lcs.test.ts diff --git a/dynamic_programming/lcs.ts b/dynamic_programming/lcs.ts new file mode 100644 index 00000000..654d3934 --- /dev/null +++ b/dynamic_programming/lcs.ts @@ -0,0 +1,46 @@ +/** + * Find the Longest Common Subsequence (LCS) of two strings. + * @param text1 - The first input string. + * @param text2 - The second input string. + * @returns The longest common subsequence as a string. + */ + +export const longestCommonSubsequence = (text1: string, text2: string): string => { + const m = text1.length; + const n = text2.length; + + // Create a 2D array to store the lengths of LCS + const dp: number[][] = Array.from({ length: m + 1 }, () => + Array(n + 1).fill(0) + ); + + // Fill in the DP table + for (let i = 1; i <= m; i++) { + for (let j = 1; j <= n; j++) { + if (text1[i - 1] === text2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + + // Reconstruct the LCS from the DP table + let i = m; + let j = n; + const lcs: string[] = []; + while (i > 0 && j > 0) { + if (text1[i - 1] === text2[j - 1]) { + lcs.unshift(text1[i - 1]); + i--; + j--; + } else if (dp[i - 1][j] > dp[i][j - 1]) { + i--; + } else { + j--; + } + } + + return lcs.join(''); + } + \ No newline at end of file diff --git a/dynamic_programming/test/lcs.test.ts b/dynamic_programming/test/lcs.test.ts new file mode 100644 index 00000000..c1374b07 --- /dev/null +++ b/dynamic_programming/test/lcs.test.ts @@ -0,0 +1,28 @@ +import { longestCommonSubsequence } from "../lcs"; + +describe("longestCommonSubsequence", () => { + it("should return the longest common subsequence", () => { + expect(longestCommonSubsequence("ABCD", "ACDF")).toBe("ACD"); + + expect(longestCommonSubsequence("AGGTAB", "GXTXAYB")).toBe("GTAB"); + + expect(longestCommonSubsequence("abcdef", "xyz")).toBe(""); + + expect(longestCommonSubsequence("", "")).toBe(""); + }); + + it("should handle cases with spaces and special characters", () => { + expect(longestCommonSubsequence("A B C D", "A C D E")).toBe("A C D"); + + expect(longestCommonSubsequence("1234$%^", "!@#$%^")).toBe("$%^"); + }); + + it("should handle cases with longer input strings", () => { + expect( + longestCommonSubsequence( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + ) + ).toBe("e iumoor it t oeetr ag li."); + }); +}); From b15cb5d1c639d4cc97dc6b6e1b7512e157830ea1 Mon Sep 17 00:00:00 2001 From: James Titus Date: Tue, 10 Oct 2023 12:52:33 +0530 Subject: [PATCH 067/107] feat: Heap Sort (#182) --- sorts/heap_sort.ts | 61 ++++++++++++++++++++++++++++++++++++ sorts/test/heap_sort.test.ts | 15 +++++++++ 2 files changed, 76 insertions(+) create mode 100644 sorts/heap_sort.ts create mode 100644 sorts/test/heap_sort.test.ts diff --git a/sorts/heap_sort.ts b/sorts/heap_sort.ts new file mode 100644 index 00000000..ecc42995 --- /dev/null +++ b/sorts/heap_sort.ts @@ -0,0 +1,61 @@ +/** + * @function heapsort + * @description is a comparison-based sorting algorithm that uses a binary heap data structure to repeatedly select and remove the maximum (for max-heap) or minimum (for min-heap) element and place it at the end of the sorted array. + * @see [Heap Sort](https://www.geeksforgeeks.org/heap-sort/) + * @example MergeSort([7, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 7] + * @Complexity_Analysis + * Space complexity - O(n) + * Time complexity + * Best case - O(nlogn) + * Worst case - O(nlogn) + * Average case - O(nlogn) + */ + +// Function to perform the Heap Sort +export const HeapSort = (arr: number[]): number[] => { + + buildMaxHeap(arr); + + for (let i = arr.length - 1; i > 0; i--) { + swap(arr, 0, i); + heapify(arr, 0, i); + } + + return arr; +}; + +// Function to build a max-heap from an array +function buildMaxHeap(arr: number[]): void { + const n = arr.length; + + for (let i = Math.floor(n / 2) - 1; i >= 0; i--) { + heapify(arr, i, n); + } +} + +// Function to heapify a subtree rooted at a given index +function heapify(arr: number[], index: number, size: number): void { + let largest = index; + const left = 2 * index + 1; + const right = 2 * index + 2; + + if (left < size && arr[left] > arr[largest]) { + largest = left; + } + + if (right < size && arr[right] > arr[largest]) { + largest = right; + } + + if (largest !== index) { + swap(arr, index, largest); + heapify(arr, largest, size); + } +} + +// Function to swap two elements in an array +function swap(arr: number[], i: number, j: number): void { + const temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; +} diff --git a/sorts/test/heap_sort.test.ts b/sorts/test/heap_sort.test.ts new file mode 100644 index 00000000..3463a91d --- /dev/null +++ b/sorts/test/heap_sort.test.ts @@ -0,0 +1,15 @@ +import { HeapSort } from "../heap_sort"; + +describe("Heap Sort", () => { + it("should return the correct value for average case", () => { + expect(HeapSort([1, 4, 2, 5, 9, 6, 3, 8, 10, 7])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); + + it("should return the correct value for worst case", () => { + expect(HeapSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); + + it("should return the correct value for best case", () => { + expect(HeapSort([1, 4, 2, 9, 5, 7, 3, 8, 10, 6])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + }); + }); \ No newline at end of file From 362f503afcbac48b90d8efcb770ec3caddf4447f Mon Sep 17 00:00:00 2001 From: Surya Prakash Chaudhary <67498076+Suryac72@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:42:32 +0530 Subject: [PATCH 068/107] feat: Gaussian Elimination Method (#184) * feat(gaussian_elimination) * fix(gaussian-elimination) --- maths/gaussian_elimination.ts | 52 +++++++++++++++++++++++++ maths/test/gaussian_elimination.test.ts | 41 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 maths/gaussian_elimination.ts create mode 100644 maths/test/gaussian_elimination.test.ts diff --git a/maths/gaussian_elimination.ts b/maths/gaussian_elimination.ts new file mode 100644 index 00000000..660d4fbe --- /dev/null +++ b/maths/gaussian_elimination.ts @@ -0,0 +1,52 @@ +/** + * Solves a system of linear equations using Gaussian Elimination with partial pivoting. + * + * @param {number[][]} matrix - The augmented matrix representing the system of equations. + * @returns {number[]} An array representing the solutions to the equations. + */ +export function gaussianElimination(matrix: number[][]): number[] { + const result: number[] = new Array(matrix.length); + + function partialPivot(): void { + for (let row = 0; row < matrix.length; row++) { + let pivotRow = row; + + for (let column = row + 1; column < matrix.length; column++) { + if (Math.abs(matrix[column][row]) > Math.abs(matrix[pivotRow][row])) { + pivotRow = column; + } + } + + if (pivotRow !== row) { + for (let column = row; column <= matrix.length; column++) { + [matrix[row][column], matrix[pivotRow][column]] = [ + matrix[pivotRow][column], + matrix[row][column], + ]; + } + } + + for (let column = row + 1; column < matrix.length; column++) { + const factor = matrix[column][row] / matrix[row][row]; + for (let k = row; k <= matrix.length; k++) { + matrix[column][k] -= factor * matrix[row][k]; + } + } + } + } + + function backSubstitute(): void { + for (let row = matrix.length - 1; row >= 0; row--) { + let sum = 0; + for (let column = row + 1; column < matrix.length; column++) { + sum += matrix[row][column] * result[column]; + } + result[row] = (matrix[row][matrix.length] - sum) / matrix[row][row]; + } + } + + partialPivot(); + backSubstitute(); + + return result; +} diff --git a/maths/test/gaussian_elimination.test.ts b/maths/test/gaussian_elimination.test.ts new file mode 100644 index 00000000..b428d196 --- /dev/null +++ b/maths/test/gaussian_elimination.test.ts @@ -0,0 +1,41 @@ +import { gaussianElimination } from "../gaussian_elimination"; + +describe("gaussianElimination", () => { + it("should solve system of linear equations", () => { + const A: number[][] = [ + [3.0, 2.0, -4.0, 3.0], + [2.0, 3.0, 3.0, 15.0], + [5.0, -3, 1.0, 14.0], + ]; + + let solution: number[] = gaussianElimination(A); + solution = solution.map((x) => Math.round(x)); + + expect(solution.map((x) => Math.round(x))).toEqual([3, 1, 2]); + }); + + it("should solve a 2x2 system of linear equations", () => { + const A: number[][] = [ + [2.0, 1.0, 5.0], + [1.0, -3.0, 6.0], + ]; + + let solution: number[] = gaussianElimination(A); + solution = solution.map((x) => Math.round(x)); + + expect(solution.map((x) => Math.round(x))).toEqual([3, -1]); + }); + + it("should handle a system with no solution", () => { + const A: number[][] = [ + [1.0, 2.0, 3.0, 4.0], + [2.0, 4.0, 6.0, 7.0], + [3.0, 6.0, 9.0, 10.0], + ]; + + let solution: number[] = gaussianElimination(A); + solution = solution.filter((value) => !isNaN(value)); + + expect(solution).toEqual([]); + }); +}); From d2d28f03ca39170e7c5d194d939d5e9e2336e9ff Mon Sep 17 00:00:00 2001 From: Surya Prakash Chaudhary <67498076+Suryac72@users.noreply.github.com> Date: Thu, 12 Oct 2023 12:01:06 +0530 Subject: [PATCH 069/107] feat: bipartite graph (#190) --- graph/bipartite_graph.ts | 46 ++++++++++++++++++++++++++++++ graph/test/bipartite_graph.test.ts | 33 +++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 graph/bipartite_graph.ts create mode 100644 graph/test/bipartite_graph.test.ts diff --git a/graph/bipartite_graph.ts b/graph/bipartite_graph.ts new file mode 100644 index 00000000..ffcefff8 --- /dev/null +++ b/graph/bipartite_graph.ts @@ -0,0 +1,46 @@ +const dfs = ( + graph: number[][], + colors: number[], + node: number, + color: number +): boolean => { + if (colors[node] !== 0) { + return colors[node] === color; + } + + colors[node] = color; + + for (const neighbor of graph[node]) { + if (!dfs(graph, colors, neighbor, -color)) { + return false; + } + } + + return true; +}; + + +/** + * Determines if a given graph is bipartite. + * + * A Bipartite Graph is a graph whose vertices can be divided into two independent sets, + * U and V such that every edge (u, v) either connects a vertex from U to V or a vertex from + * V to U + * + * @param {number[][]} graph - The graph represented as an adjacency list. + * @returns {boolean} - `true` if the graph is bipartite, `false` otherwise. + */ + + +export const isBipartite = (graph: number[][]): boolean => { + const n: number = graph.length; + const colors: number[] = new Array(n).fill(0); + + for (let i = 0; i < n; i++) { + if (colors[i] === 0 && !dfs(graph, colors, i, 1)) { + return false; + } + } + + return true; +}; diff --git a/graph/test/bipartite_graph.test.ts b/graph/test/bipartite_graph.test.ts new file mode 100644 index 00000000..050060ba --- /dev/null +++ b/graph/test/bipartite_graph.test.ts @@ -0,0 +1,33 @@ +import { isBipartite } from "../bipartite_graph"; + +describe('isBipartite', () => { + it('should return true for a bipartite graph', () => { + const graph = [[1, 3], [0, 2], [1, 3], [0, 2]]; + const result = isBipartite(graph); + expect(result).toBe(true); + }); + + it('should return true for an empty graph', () => { + const graph: number[][] = []; + const result = isBipartite(graph); + expect(result).toBe(true); + }); + + it('should return true for a single node graph', () => { + const graph = [[]]; + const result = isBipartite(graph); + expect(result).toBe(true); + }); + + it('should return false for a non-bipartite graph', () => { + const graph = [[1, 2, 3], [0, 2], [0, 1, 3], [0, 2]]; + const result = isBipartite(graph); + expect(result).toBe(false); + }); + + it('should return true for a disconnected bipartite graph', () => { + const graph = [[1, 2], [0], [0], [4], [3]]; + const result = isBipartite(graph); + expect(result).toBe(true); + }); + }); \ No newline at end of file From 9b286246819de0af56cb6004e36d09ac3790dc10 Mon Sep 17 00:00:00 2001 From: Surya Prakash Chaudhary <67498076+Suryac72@users.noreply.github.com> Date: Sat, 14 Oct 2023 22:26:16 +0530 Subject: [PATCH 070/107] chore: find the binary sum of numbers (#191) --- bit_manipulation/add_binary.ts | 27 +++++++++++++++++++ bit_manipulation/test/add_binary.test.ts | 33 ++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 bit_manipulation/add_binary.ts create mode 100644 bit_manipulation/test/add_binary.test.ts diff --git a/bit_manipulation/add_binary.ts b/bit_manipulation/add_binary.ts new file mode 100644 index 00000000..ebc05440 --- /dev/null +++ b/bit_manipulation/add_binary.ts @@ -0,0 +1,27 @@ +/** + * Adds two binary strings and returns the result as a binary string. + * + * @param firstBinaryNo - The first binary string. + * @param secondBinaryNo - The second binary string. + * @returns The binary sum of the input strings. + */ +export function addBinary(firstBinaryNo: string, secondBinaryNo: string): string { + let lengthOfFirstNumber: number = firstBinaryNo.length - 1; + let lengthOfSecondNumber: number = secondBinaryNo.length - 1; + let solution: string[] = []; + let carry: number = 0; + + while ( lengthOfFirstNumber >= 0 || lengthOfSecondNumber >= 0) { + let sum: number = carry; + if (lengthOfFirstNumber >= 0) sum += parseInt(firstBinaryNo.charAt(lengthOfFirstNumber)); + if (lengthOfSecondNumber >= 0) sum += parseInt(secondBinaryNo.charAt(lengthOfSecondNumber)); + solution.push((sum % 2).toString()); + carry = Math.floor(sum / 2); + lengthOfFirstNumber--; + lengthOfSecondNumber--; + } + + if (carry !== 0) solution.push(carry.toString()); + + return solution.reverse().join(''); +} diff --git a/bit_manipulation/test/add_binary.test.ts b/bit_manipulation/test/add_binary.test.ts new file mode 100644 index 00000000..e8ce1776 --- /dev/null +++ b/bit_manipulation/test/add_binary.test.ts @@ -0,0 +1,33 @@ +import { addBinary } from "../add_binary"; + +describe('Add Binary Number', () => { + it('should add two binary numbers with no carry', () => { + const result = addBinary('1101', '1011'); + expect(result).toBe('11000'); + }); + + it('should add two binary numbers with carry', () => { + const result = addBinary('1111', '1111'); + expect(result).toBe('11110'); + }); + + it('should add two different-length binary numbers', () => { + const result = addBinary('1101', '111'); + expect(result).toBe('10100'); + }); + + it('should add two empty binary numbers', () => { + const result = addBinary('', ''); + expect(result).toBe(''); + }); + + it('should add one empty binary number to a non-empty number', () => { + const result = addBinary('1010', ''); + expect(result).toBe('1010'); + }); + + it('should add one non-empty binary number to an empty number', () => { + const result = addBinary('', '1101'); + expect(result).toBe('1101'); + }); +}); \ No newline at end of file From 4fde4fe94679bdc1806bc4e9fab191fac04ff7b5 Mon Sep 17 00:00:00 2001 From: Omar Ferreiro <27824673+IcarusTheFly@users.noreply.github.com> Date: Fri, 20 Oct 2023 19:25:22 +0200 Subject: [PATCH 071/107] chore: Change to MapEntry (#206) Co-authored-by: IcarusTheFly --- data_structures/map/hash_map.ts | 12 ++++++------ data_structures/map/map.ts | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/data_structures/map/hash_map.ts b/data_structures/map/hash_map.ts index 3a57d759..900848a5 100644 --- a/data_structures/map/hash_map.ts +++ b/data_structures/map/hash_map.ts @@ -15,7 +15,7 @@ import { Map } from "./map"; */ export class HashMap implements Map { private size!: number; - private buckets!: HashMapEntry[][]; + private buckets!: MapEntry[][]; private readonly loadFactor = 0.75; constructor() { @@ -47,7 +47,7 @@ export class HashMap implements Map { const bucket = this.buckets[index]; if (bucket.length === 0) { - bucket.push(new HashMapEntry(key, value)); + bucket.push(new MapEntry(key, value)); this.size++; return; } @@ -59,7 +59,7 @@ export class HashMap implements Map { } } - bucket.push(new HashMapEntry(key, value)); + bucket.push(new MapEntry(key, value)); this.size++; } @@ -164,8 +164,8 @@ export class HashMap implements Map { * * @returns The entries. */ - entries(): HashMapEntry[] { - const entries: HashMapEntry[] = []; + entries(): MapEntry[] { + const entries: MapEntry[] = []; for (const bucket of this.buckets) { for (const entry of bucket) { entries.push(entry); @@ -228,7 +228,7 @@ export class HashMap implements Map { * @param key The key. * @param value The value. */ -export class HashMapEntry { +export class MapEntry { key: K; value: V; diff --git a/data_structures/map/map.ts b/data_structures/map/map.ts index 1e15c893..ff2a9fc3 100644 --- a/data_structures/map/map.ts +++ b/data_structures/map/map.ts @@ -1,4 +1,4 @@ -import { HashMapEntry } from "./hash_map"; +import { MapEntry } from "./hash_map"; /** * This interface is a representation of the Map data structure. @@ -12,5 +12,5 @@ export interface Map { clear(): void; keys(): K[]; values(): V[]; - entries(): HashMapEntry[]; + entries(): MapEntry[]; } From 2e4d8062a715a78e7aa7883b99a9d02b084a8660 Mon Sep 17 00:00:00 2001 From: Britney <62298176+britneywwc@users.noreply.github.com> Date: Sat, 21 Oct 2023 04:30:36 +1100 Subject: [PATCH 072/107] feat: add square root (#208) * feat: add maths square root * test: add test for maths square root * docs: add square root to DIRECTORY.md * test: fixed test suites PR comments * fix: removed unused code and fixed function naming * chore: fix camelcasing and linting * chore: updated function docs * fix: removed ugly numbers changes * fix: remove ugly numbers changes --- DIRECTORY.md | 1 + maths/square_root.ts | 26 ++++++++++++++++++++++++++ maths/test/square_root.test.ts | 28 ++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 maths/square_root.ts create mode 100644 maths/test/square_root.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 3237c4e5..8934c233 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -124,6 +124,7 @@ * [Hexagonal Numbers.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/series/test/hexagonal_numbers.test.ts) * [Sieve Of Eratosthenes](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/sieve_of_eratosthenes.ts) * [Signum](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/signum.ts) + * [Square Root](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/square_root.ts) * [Ugly Numbers](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/ugly_numbers.ts) * [Zellers Congruence](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/zellers_congruence.ts) diff --git a/maths/square_root.ts b/maths/square_root.ts new file mode 100644 index 00000000..04a8eda0 --- /dev/null +++ b/maths/square_root.ts @@ -0,0 +1,26 @@ +/** + * @function squareRoot + * @description Finding the square root of a number using Newton's method. + * @param {number} num - A number. + * @param {number} precision - Precision of square root, 1e-15 by default. + * @returns {number} - Square root of the given number. + * @see https://www.geeksforgeeks.org/find-root-of-a-number-using-newtons-method/ + * @example SquareRoot(36) = 6 + * @example SquareRoot(50) = 7.0710678118654755 + */ + +export const squareRoot = (num: number, precision: number = 1e-15): number => { + if (num < 0) throw new Error("number must be non-negative number"); + if (num === 0) return 0; + + let sqrt: number = num; + let curr: number; + + while (true) { + curr = 0.5 * (sqrt + num / sqrt); + if (Math.abs(curr - sqrt) < precision) { + return sqrt; + } + sqrt = curr; + } +}; diff --git a/maths/test/square_root.test.ts b/maths/test/square_root.test.ts new file mode 100644 index 00000000..3dbd8658 --- /dev/null +++ b/maths/test/square_root.test.ts @@ -0,0 +1,28 @@ +import { squareRoot } from "../square_root"; + +describe("squareRoot", () => { + test.each([-1, -10, -2.4])( + "should throw an error for negative numbers", + (n: number) => { + expect(() => squareRoot(n)).toThrow("number must be non-negative number"); + } + ); + + test.each([0, 1, 4, 9, 16, 25])( + "should return correct rational square root value", + () => { + (n: number) => { + expect(() => squareRoot(n)).toBeCloseTo(Math.sqrt(n)); + }; + } + ); + + test.each([2, 15, 20, 40, 99, 10032])( + "should return correct irrational square root value", + () => { + (n: number) => { + expect(() => squareRoot(n)).toBeCloseTo(Math.sqrt(n)); + }; + } + ); +}); From c9b3d38bcb8fedc91becf733c1bdf4268b4b325d Mon Sep 17 00:00:00 2001 From: Britney <62298176+britneywwc@users.noreply.github.com> Date: Sat, 21 Oct 2023 04:33:14 +1100 Subject: [PATCH 073/107] chore: fix naming convention for maths functions (#209) * chore: added function return type * chore: fix naming conventions for maths functions --- maths/absolute_value.ts | 10 +++++----- maths/aliquot_sum.ts | 8 ++++---- maths/armstrong_number.ts | 8 ++++---- maths/binary_convert.ts | 8 ++++---- maths/binomial_coefficient.ts | 16 ++++++++-------- maths/digit_sum.ts | 8 ++++---- maths/factorial.ts | 12 ++++++------ maths/factors.ts | 10 +++++----- maths/find_min.ts | 12 ++++++------ maths/greatest_common_factor.ts | 2 +- maths/hamming_distance.ts | 8 ++++---- maths/is_divisible.ts | 8 ++++---- maths/is_even.ts | 8 ++++---- maths/is_leap_year.ts | 8 ++++---- maths/is_odd.ts | 8 ++++---- maths/is_palindrome.ts | 2 +- maths/lowest_common_multiple.ts | 2 +- maths/number_of_digits.ts | 10 +++++----- maths/perfect_square.ts | 2 +- maths/pronic_number.ts | 12 ++++++------ maths/sieve_of_eratosthenes.ts | 8 ++++---- maths/signum.ts | 12 ++++++------ maths/test/absolute_value.test.ts | 14 +++++++------- maths/test/aliquot_sum.test.ts | 4 ++-- maths/test/armstrong_number.test.ts | 4 ++-- maths/test/binary_convert.test.ts | 16 ++++++++-------- maths/test/binomial_coefficient.test.ts | 8 ++++---- maths/test/digit_sum.test.ts | 8 ++++---- maths/test/factorial.test.ts | 10 +++++----- maths/test/factors.test.ts | 8 ++++---- maths/test/find_min.test.ts | 8 ++++---- maths/test/hamming_distance.test.ts | 4 ++-- maths/test/is_divisible.test.ts | 10 +++++----- maths/test/is_even.test.ts | 8 ++++---- maths/test/is_leap_year.test.ts | 20 ++++++++++---------- maths/test/is_odd.test.ts | 8 ++++---- maths/test/is_palindrome.test.ts | 6 +++--- maths/test/number_of_digits.test.ts | 8 ++++---- maths/test/perfect_square.test.ts | 12 ++++++------ maths/test/pronic_number.test.ts | 4 ++-- maths/test/radians_to_degrees.test.ts | 2 +- maths/test/sieve_of_eratosthenes.test.ts | 6 +++--- maths/test/signum.test.ts | 4 ++-- maths/test/ugly_numbers.test.ts | 6 +++--- maths/test/zellers_congruence.test.ts | 16 ++++++++-------- maths/ugly_numbers.ts | 14 +++++++------- maths/zellers_congruence.ts | 8 ++++---- 47 files changed, 199 insertions(+), 199 deletions(-) diff --git a/maths/absolute_value.ts b/maths/absolute_value.ts index 9451887a..a9c7f88f 100644 --- a/maths/absolute_value.ts +++ b/maths/absolute_value.ts @@ -1,15 +1,15 @@ /** - * @function AbsoluteValue + * @function absoluteValue * @description Calculate the absolute value of an input number. * @param {number} number - a numeric input value * @return {number} - Absolute number of input number * @see https://en.wikipedia.org/wiki/Absolute_value - * @example AbsoluteValue(-10) = 10 - * @example AbsoluteValue(50) = 50 - * @example AbsoluteValue(0) = 0 + * @example absoluteValue(-10) = 10 + * @example absoluteValue(50) = 50 + * @example absoluteValue(0) = 0 */ -export const AbsoluteValue = (number: number): number => { +export const absoluteValue = (number: number): number => { // if input number is less than 0, convert it to positive via double negation // e.g. if n = -2, then return -(-2) = 2 return number < 0 ? -number : number; diff --git a/maths/aliquot_sum.ts b/maths/aliquot_sum.ts index be7d44de..aac91846 100644 --- a/maths/aliquot_sum.ts +++ b/maths/aliquot_sum.ts @@ -1,5 +1,5 @@ /** - * @function AliquotSum + * @function aliquotSum * @description Returns the aliquot sum of the provided number * @summary The aliquot sum of a number n is the sum of all the proper divisors * of n apart from n itself. @@ -9,10 +9,10 @@ * @param {number} num The input number * @return {number} The aliquot sum of the number * @see [Wikipedia](https://en.wikipedia.org/wiki/Aliquot_sum) - * @example AliquotSum(18) = 21 - * @example AliquotSum(15) = 9 + * @example aliquotSum(18) = 21 + * @example aliquotSum(15) = 9 */ -export const AliquotSum = (num: number): number => { +export const aliquotSum = (num: number): number => { if (typeof num !== 'number') throw new TypeError('Input needs to be a number') if (num < 0) throw new TypeError('Input cannot be negative') if (!Number.isInteger(num)) throw new TypeError('Input cannot be a decimal') diff --git a/maths/armstrong_number.ts b/maths/armstrong_number.ts index 78776127..d8452ed6 100644 --- a/maths/armstrong_number.ts +++ b/maths/armstrong_number.ts @@ -1,5 +1,5 @@ /** - * @function ArmstrongNumber + * @function armstrongNumber * @description Check if the provided number is an Armstrong number or not. * @summary Armstrong numbers are numbers, the sum of whose digits each raised * to the power of the number of digits is equal to the number itself. @@ -10,10 +10,10 @@ * @return {boolean} Whether the input number is an Armstrong number * @see [Wikipedia](https://en.wikipedia.org/wiki/Armstrong_number) * @see [OEIS](https://oeis.org/A005188) - * @example ArmstrongNumber(370) = true - * @example ArmstrongNumber(10) = false + * @example armstrongNumber(370) = true + * @example armstrongNumber(10) = false */ -export const ArmstrongNumber = (num: number): boolean => { +export const armstrongNumber = (num: number): boolean => { if (typeof num !== 'number' || num <= 0) return false; let compNum = 0 diff --git a/maths/binary_convert.ts b/maths/binary_convert.ts index 824d80b4..ba4bc49b 100644 --- a/maths/binary_convert.ts +++ b/maths/binary_convert.ts @@ -1,14 +1,14 @@ /** - * @function BinaryConvert + * @function binaryConvert * @description Convert the decimal to binary. * @param {number} num - The input integer * @return {string} - Binary of num. * @see [BinaryConvert](https://www.programiz.com/javascript/examples/decimal-binary) - * @example BinaryConvert(12) = 1100 - * @example BinaryConvert(12 + 2) = 1110 + * @example binaryConvert(12) = 1100 + * @example binaryConvert(12 + 2) = 1110 */ -export const BinaryConvert = (num: number): string => { +export const binaryConvert = (num: number): string => { let binary = '' while (num !== 0) { diff --git a/maths/binomial_coefficient.ts b/maths/binomial_coefficient.ts index cc522c3b..9ba1572a 100644 --- a/maths/binomial_coefficient.ts +++ b/maths/binomial_coefficient.ts @@ -1,24 +1,24 @@ -import { Factorial } from "./factorial"; +import { factorial } from "./factorial"; /** - * @function BinomialCoefficient + * @function binomialCoefficient * @description Calculate the binomial coefficient (n choose k) of two input numbers. * @param {number} n - the total number of items * @param {number} k - the number of items to be chosen * @return {number} - Binomial coefficient (n choose k) * @see https://en.wikipedia.org/wiki/Binomial_coefficient - * @example BinomialCoefficient(5, 2) = 10 - * @example BinomialCoefficient(10, 3) = 120 - * @example BinomialCoefficient(6, 0) = 1 + * @example binomialCoefficient(5, 2) = 10 + * @example binomialCoefficient(10, 3) = 120 + * @example binomialCoefficient(6, 0) = 1 */ -export const BinomialCoefficient = (n: number, k: number): number => { +export const binomialCoefficient = (n: number, k: number): number => { // Check if k is larger than n or negative if (k > n || k < 0) { return 0; } // Calculate the binomial coefficient using the implemented factorial - const numerator = Factorial(n); - const denominator = Factorial(k) * Factorial(n - k); + const numerator = factorial(n); + const denominator = factorial(k) * factorial(n - k); return numerator / denominator; }; diff --git a/maths/digit_sum.ts b/maths/digit_sum.ts index 65a0f3f0..58a9f677 100644 --- a/maths/digit_sum.ts +++ b/maths/digit_sum.ts @@ -1,14 +1,14 @@ /** - * @function DigitSum + * @function digitSum * @description Calculate the sum of all digits of a natural number (number base 10). * @param {number} num - A natural number. * @return {number} - Sum of all digits of given natural number. * @see https://en.wikipedia.org/wiki/Digit_sum - * @example DigitSum(12) = 3 - * @example DigitSum(9045) = 18 + * @example digitSum(12) = 3 + * @example digitSum(9045) = 18 */ -export const DigitSum = (num: number): number => { +export const digitSum = (num: number): number => { if (num < 0 || !Number.isInteger(num)) { throw new Error("only natural numbers are supported"); } diff --git a/maths/factorial.ts b/maths/factorial.ts index 1783383b..0eb3e744 100644 --- a/maths/factorial.ts +++ b/maths/factorial.ts @@ -1,16 +1,16 @@ /** - * @function Factorial + * @function factorial * @description Calculate the factorial of a natural number. * @param {number} num - A natural number. * @return {number} - The factorial. - * @see https://en.wikipedia.org/wiki/Factorial - * @example Factorial(0) = 1 - * @example Factorial(3) = 6 + * @see https://en.wikipedia.org/wiki/factorial + * @example factorial(0) = 1 + * @example factorial(3) = 6 */ -export const Factorial = (num: number): number => { +export const factorial = (num: number): number => { if (num < 0 || !Number.isInteger(num)) { throw new Error("only natural numbers are supported"); } - return num === 0 ? 1 : num * Factorial(num - 1); + return num === 0 ? 1 : num * factorial(num - 1); }; diff --git a/maths/factors.ts b/maths/factors.ts index b9177684..f592ae2b 100644 --- a/maths/factors.ts +++ b/maths/factors.ts @@ -1,14 +1,14 @@ /** - * @function FindFactors + * @function findFactors * @description Find all the factors of a natural number. * @param {number} num - A natural number. * @return {Set} - A set of all the factors of given natural number. * @see https://en.wikipedia.org/wiki/Divisor - * @example FindFactors(1) = [1] - * @example FindFactors(4) = [1,2,4] - * @example FindFactors(16) = [1,3,5,15] + * @example findFactors(1) = [1] + * @example findFactors(4) = [1,2,4] + * @example findFactors(16) = [1,3,5,15] */ -export const FindFactors = (num: number): Set => { +export const findFactors = (num: number): Set => { if (num <= 0 || !Number.isInteger(num)) { throw new Error("Only natural numbers are supported."); } diff --git a/maths/find_min.ts b/maths/find_min.ts index 502a79e3..26ea663a 100644 --- a/maths/find_min.ts +++ b/maths/find_min.ts @@ -1,15 +1,15 @@ /** - * @function FindMin + * @function findMin * @description Find the minimum in an array of numbers. * @param {Number[]} nums - An array of numbers. * @return {Number} - The minimum. * @see https://infinitbility.com/how-to-find-minimum-value-in-array-in-typescript/ - * @example FindMin([1,2,3,4,5]) = 1 - * @example FindMin([87,6,13,999]) = 6 - * @example FindMin([0.8,0.2,0.3,0.5]) = 0.2 - * @example FindMin([1,0.1,-1]) = -1 + * @example findMin([1,2,3,4,5]) = 1 + * @example findMin([87,6,13,999]) = 6 + * @example findMin([0.8,0.2,0.3,0.5]) = 0.2 + * @example findMin([1,0.1,-1]) = -1 */ - export const FindMin = (nums: number[]): number => { + export const findMin = (nums: number[]): number => { if (nums.length === 0) { throw new Error("array must have length of 1 or greater"); } diff --git a/maths/greatest_common_factor.ts b/maths/greatest_common_factor.ts index 15383e62..48afa1f3 100644 --- a/maths/greatest_common_factor.ts +++ b/maths/greatest_common_factor.ts @@ -1,5 +1,5 @@ /** - * @function GreatestCommonFactor + * @function greatestCommonFactor * @description Determine the greatest common factor of a group of numbers. * @param {Number[]} nums - An array of numbers. * @return {Number} - The greatest common factor. diff --git a/maths/hamming_distance.ts b/maths/hamming_distance.ts index a7eac5be..2828dc52 100644 --- a/maths/hamming_distance.ts +++ b/maths/hamming_distance.ts @@ -1,5 +1,5 @@ /** - * @function HammingDistance + * @function hammingDistance * @description Returns the Hamming distance between two strings of equal length * @summary The Hamming distance between two strings of equal length is the * number of positions at which the corresponding symbols are different. In other words, @@ -10,9 +10,9 @@ * @param str2 One of the strings to compare to the other * @returns {number} * @see [Wikipedia](https://en.wikipedia.org/wiki/Hamming_distance) - * @example HammingDistance('happy', 'homie') + * @example hammingDistance('happy', 'homie') */ -const HammingDistance = (str1: string, str2: string) => { +const hammingDistance = (str1: string, str2: string) => { if (str1.length !== str2.length) throw new Error('Strings must of the same length.') let dist = 0 @@ -22,4 +22,4 @@ const HammingDistance = (str1: string, str2: string) => { return dist } -export { HammingDistance } +export { hammingDistance } diff --git a/maths/is_divisible.ts b/maths/is_divisible.ts index bed87628..57f0bbe2 100644 --- a/maths/is_divisible.ts +++ b/maths/is_divisible.ts @@ -1,14 +1,14 @@ /** - * @function IsDivisible + * @function isDivisible * @description Checks is number is divisible by another number without remainder. * @param {number} num1 - first number, a dividend. * @param {number} num2 - second number, a divisor. * @return {boolean} - true if first number can be divided by second number without a remainder. - * @example IsDivisible(10, 2) = true - * @example IsDivisible(11, 3) = false + * @example isDivisible(10, 2) = true + * @example isDivisible(11, 3) = false */ -export const IsDivisible = (num1: number, num2: number): boolean => { +export const isDivisible = (num1: number, num2: number): boolean => { if (num2 === 0) { throw new Error('Cannot divide by 0'); } diff --git a/maths/is_even.ts b/maths/is_even.ts index 52154a99..df8fbdd5 100644 --- a/maths/is_even.ts +++ b/maths/is_even.ts @@ -1,13 +1,13 @@ /** - * @function IsEven + * @function isEven * @description Determine whether a number is even. * @param {Number} num - A number. * @return {Boolean} - Whether the given number is even. * @see https://en.wikipedia.org/wiki/Parity_(mathematics) - * @example IsEven(1) = false - * @example IsEven(2) = true + * @example isEven(1) = false + * @example isEven(2) = true */ - export const IsEven = (num: number): boolean => { + export const isEven = (num: number): boolean => { if (!Number.isInteger(num)) { throw new Error("only integers can be even or odd"); } diff --git a/maths/is_leap_year.ts b/maths/is_leap_year.ts index 0d607bb5..3aafbf04 100644 --- a/maths/is_leap_year.ts +++ b/maths/is_leap_year.ts @@ -1,15 +1,15 @@ /** - * @function IsLeapYear + * @function isLeapYear * @description Checks if a year is a leap year (Gregorian calendar). * A year is a leap year if it is divisible by 4 but not by 400 or if it is divisible by 400. * @param {number} year - A year, natural number > 0. * @return {boolean} - True if given year is a leap year. * @see https://en.wikipedia.org/wiki/Leap_year#Gregorian_calendar - * @example IsLeapYear(2000) = true - * @example IsLeapYear(2001) = false + * @example isLeapYear(2000) = true + * @example isLeapYear(2001) = false */ -export const IsLeapYear = (year: number): boolean => { +export const isLeapYear = (year: number): boolean => { if (year <= 0 || !Number.isInteger(year)) { throw new Error("year must be a natural number > 0"); } diff --git a/maths/is_odd.ts b/maths/is_odd.ts index f2ed46f9..529c7f5b 100644 --- a/maths/is_odd.ts +++ b/maths/is_odd.ts @@ -1,13 +1,13 @@ /** - * @function IsOdd + * @function isOdd * @description Determine whether a number is odd. * @param {Number} num - A number. * @return {Boolean} - Whether the given number is odd. * @see https://en.wikipedia.org/wiki/Parity_(mathematics) - * @example IsOdd(1) = true - * @example IsOdd(2) = false + * @example isOdd(1) = true + * @example isOdd(2) = false */ - export const IsOdd = (num: number): boolean => { + export const isOdd = (num: number): boolean => { if (!Number.isInteger(num)) { throw new Error("only integers can be even or odd"); } diff --git a/maths/is_palindrome.ts b/maths/is_palindrome.ts index f093d9be..c5ed9f07 100644 --- a/maths/is_palindrome.ts +++ b/maths/is_palindrome.ts @@ -6,7 +6,7 @@ * @param number The input number. * @return {boolean} Wether the number is a Palindrome or not. */ -export const IsPalindrome = (number: number): boolean => { +export const isPalindrome = (number: number): boolean => { if (number < 0 || (number % 10 === 0 && number !== 0)) { return false; } diff --git a/maths/lowest_common_multiple.ts b/maths/lowest_common_multiple.ts index c690ae05..ec852425 100644 --- a/maths/lowest_common_multiple.ts +++ b/maths/lowest_common_multiple.ts @@ -1,5 +1,5 @@ /** - * @function LowestCommonMultiple + * @function lowestCommonMultiple * @description Determine the lowest common multiple of a group of numbers. * @param {Number[]} nums - An array of numbers. * @return {Number} - The lowest common multiple. diff --git a/maths/number_of_digits.ts b/maths/number_of_digits.ts index 0a21aa52..e517cfda 100644 --- a/maths/number_of_digits.ts +++ b/maths/number_of_digits.ts @@ -1,15 +1,15 @@ /** - * @function NumberOfDigits + * @function numberOfDigits * @description Calculate the number of digits of a natural number. * @param {number} num - A natural number. * @return {number} - Number of digits of given natural number. * @see https://math.stackexchange.com/a/231745/518862 - * @example NumberOfDigits(18) = 2 - * @example NumberOfDigits(294568) = 6 - * @example NumberOfDigits(128798319794) = 12 + * @example numberOfDigits(18) = 2 + * @example numberOfDigits(294568) = 6 + * @example numberOfDigits(128798319794) = 12 */ -export const NumberOfDigits = (num: number): number => { +export const numberOfDigits = (num: number): number => { if (num <= 0 || !Number.isInteger(num)) { throw new Error("only natural numbers are supported"); } diff --git a/maths/perfect_square.ts b/maths/perfect_square.ts index d66d4a90..c7f6c279 100644 --- a/maths/perfect_square.ts +++ b/maths/perfect_square.ts @@ -6,6 +6,6 @@ * @param {num} number */ -export const PerfectSquare = (num: number) => { +export const perfectSquare = (num: number) => { return Number.isInteger(Math.sqrt(num)); }; diff --git a/maths/pronic_number.ts b/maths/pronic_number.ts index 3709c6b5..d3aa607d 100644 --- a/maths/pronic_number.ts +++ b/maths/pronic_number.ts @@ -1,5 +1,5 @@ /** - * @function PronicNumber + * @function pronicNumber * @description Checks whether a given number is a pronic number or not * @summary Pronic numbers, or oblong numbers as they are often referred to as, * are numbers which are the product of two consecutive integers. That is, @@ -9,11 +9,11 @@ * @param num The number to check for being pronic * @returns {boolean} Whether the number is pronic or not * @see [Wikipedia](https://en.wikipedia.org/wiki/Pronic_number) - * @example PronicNumber(20) = true - * @example PronicNumber(30) = true - * @example PronicNumber(49) = false + * @example pronicNumber(20) = true + * @example pronicNumber(30) = true + * @example pronicNumber(49) = false */ -const PronicNumber = (n: number) => { +const pronicNumber = (n: number) => { if (isNaN(n)) throw new Error('The input needs to be a number') if (!Number.isInteger(n) || n < 0) throw new Error('The input needs to be a non-negative integer') if (n === 0) return true @@ -21,4 +21,4 @@ const PronicNumber = (n: number) => { return !Number.isInteger(Math.sqrt(n)) && Math.floor(Math.sqrt(n)) * Math.ceil(Math.sqrt(n)) === n } -export { PronicNumber } +export { pronicNumber } diff --git a/maths/sieve_of_eratosthenes.ts b/maths/sieve_of_eratosthenes.ts index 29f29707..d7fe21db 100644 --- a/maths/sieve_of_eratosthenes.ts +++ b/maths/sieve_of_eratosthenes.ts @@ -1,14 +1,14 @@ /** - * @function SieveOfEratosthenes + * @function sieveOfEratosthenes * @description Find the prime numbers between 2 and n * @param {number} n - numbers set the limit that the algorithm needs to look to find the primes * @return {number[]} - List of prime numbers * @see https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes\ - * @example SieveOfErastosthenes(5) = [2,3,5] - * @example SieveOfErastosthenes(10) = [2,3,5,7] + * @example sieveOfEratosthenes(5) = [2,3,5] + * @example sieveOfEratosthenes(10) = [2,3,5,7] */ -export function SieveOfEratosthenes(n: number): number[] { +export function sieveOfEratosthenes(n: number): number[] { if (n < 0 || !Number.isInteger(n)) { throw new Error("Only natural numbers are supported"); } diff --git a/maths/signum.ts b/maths/signum.ts index d712c149..259a61ba 100644 --- a/maths/signum.ts +++ b/maths/signum.ts @@ -1,5 +1,5 @@ /** - * @function Signum + * @function signum * @description Returns the sign of a number * @summary The signum function is an odd mathematical function, which returns the * sign of the provided real number. @@ -8,12 +8,12 @@ * @param {Number} input * @returns {-1 | 0 | 1 | NaN} sign of input (and NaN if the input is not a number) * @see [Wikipedia](https://en.wikipedia.org/wiki/Sign_function) - * @example Signum(10) = 1 - * @example Signum(0) = 0 - * @example Signum(-69) = -1 - * @example Signum("hello world") = NaN + * @example signum(10) = 1 + * @example signum(0) = 0 + * @example signum(-69) = -1 + * @example signum("hello world") = NaN */ -export const Signum = (num: number) => { +export const signum = (num: number) => { if (num === 0) return 0 if (num > 0) return 1 if (num < 0) return -1 diff --git a/maths/test/absolute_value.test.ts b/maths/test/absolute_value.test.ts index 6ed93099..534c0983 100644 --- a/maths/test/absolute_value.test.ts +++ b/maths/test/absolute_value.test.ts @@ -1,28 +1,28 @@ -import { AbsoluteValue } from "../absolute_value"; +import { absoluteValue } from "../absolute_value"; -describe("AbsoluteValue", () => { +describe("absoluteValue", () => { it("should return the absolute value of zero", () => { - const absoluteValueOfZero = AbsoluteValue(0); + const absoluteValueOfZero = absoluteValue(0); expect(absoluteValueOfZero).toBe(0); }); it("should return the absolute value of a negative integer", () => { - const absoluteValueOfNegativeInteger = AbsoluteValue(-34); + const absoluteValueOfNegativeInteger = absoluteValue(-34); expect(absoluteValueOfNegativeInteger).toBe(34); }); it("should return the absolute value of a positive integer", () => { - const absoluteValueOfPositiveInteger = AbsoluteValue(50); + const absoluteValueOfPositiveInteger = absoluteValue(50); expect(absoluteValueOfPositiveInteger).toBe(50); }); it("should return the absolute value of a positive floating number", () => { - const absoluteValueOfPositiveFloating = AbsoluteValue(20.2034); + const absoluteValueOfPositiveFloating = absoluteValue(20.2034); expect(absoluteValueOfPositiveFloating).toBe(20.2034); }); it("should return the absolute value of a negative floating number", () => { - const absoluteValueOfNegativeFloating = AbsoluteValue(-20.2034); + const absoluteValueOfNegativeFloating = absoluteValue(-20.2034); expect(absoluteValueOfNegativeFloating).toBe(20.2034); }); }); diff --git a/maths/test/aliquot_sum.test.ts b/maths/test/aliquot_sum.test.ts index 48838589..b575cdc1 100644 --- a/maths/test/aliquot_sum.test.ts +++ b/maths/test/aliquot_sum.test.ts @@ -1,5 +1,5 @@ -import { AliquotSum } from "../aliquot_sum"; +import { aliquotSum } from "../aliquot_sum"; test.each([[15, 9], [18, 21], [28, 28], [100, 117], [169, 14], [1729, 511], [15625, 3906]])("Aliquot Sum of %i is %i", (num, expected) => { - expect(AliquotSum(num)).toBe(expected) + expect(aliquotSum(num)).toBe(expected) }) \ No newline at end of file diff --git a/maths/test/armstrong_number.test.ts b/maths/test/armstrong_number.test.ts index fab10e58..d35f28c3 100644 --- a/maths/test/armstrong_number.test.ts +++ b/maths/test/armstrong_number.test.ts @@ -1,5 +1,5 @@ -import { ArmstrongNumber } from "../armstrong_number" +import { armstrongNumber } from "../armstrong_number" test.each([[9, true], [-310, false], [0, false], [407, true], [420, false], [92727, true], [13579, false]])('i is an Armstrong number or not', (num, expected) => { - expect(ArmstrongNumber(num)).toBe(expected) + expect(armstrongNumber(num)).toBe(expected) }) diff --git a/maths/test/binary_convert.test.ts b/maths/test/binary_convert.test.ts index 73051a02..2e8a4eb3 100644 --- a/maths/test/binary_convert.test.ts +++ b/maths/test/binary_convert.test.ts @@ -1,22 +1,22 @@ -import { BinaryConvert } from '../binary_convert' +import { binaryConvert } from '../binary_convert' -describe('BinaryConvert', () => { +describe('binaryConvert', () => { it('should return the correct value', () => { - expect(BinaryConvert(4)).toBe('100') + expect(binaryConvert(4)).toBe('100') }) it('should return the correct value', () => { - expect(BinaryConvert(12)).toBe('1100') + expect(binaryConvert(12)).toBe('1100') }) it('should return the correct value of the sum from two number', () => { - expect(BinaryConvert(12 + 2)).toBe('1110') + expect(binaryConvert(12 + 2)).toBe('1110') }) it('should return the correct value of the subtract from two number', () => { - expect(BinaryConvert(245 - 56)).toBe('10111101') + expect(binaryConvert(245 - 56)).toBe('10111101') }) it('should return the correct value', () => { - expect(BinaryConvert(254)).toBe('11111110') + expect(binaryConvert(254)).toBe('11111110') }) it('should return the correct value', () => { - expect(BinaryConvert(63483)).toBe('1111011111111011') + expect(binaryConvert(63483)).toBe('1111011111111011') }) }) diff --git a/maths/test/binomial_coefficient.test.ts b/maths/test/binomial_coefficient.test.ts index ca677264..661566ff 100644 --- a/maths/test/binomial_coefficient.test.ts +++ b/maths/test/binomial_coefficient.test.ts @@ -1,6 +1,6 @@ -import { BinomialCoefficient } from '../binomial_coefficient'; +import { binomialCoefficient } from '../binomial_coefficient'; -describe('BinomialCoefficient', () => { +describe('binomialCoefficient', () => { it('should calculate the correct binomial coefficient', () => { // Test cases with expected results const testCases: [number, number, number][] = [ @@ -14,7 +14,7 @@ describe('BinomialCoefficient', () => { // Iterate through each test case and verify the result testCases.forEach(([n, k, expected]) => { - const result = BinomialCoefficient(n, k); + const result = binomialCoefficient(n, k); expect(result).toEqual(expected); }); }); @@ -27,7 +27,7 @@ describe('BinomialCoefficient', () => { ]; invalidCases.forEach(([n, k]) => { - const result = BinomialCoefficient(n, k); + const result = binomialCoefficient(n, k); expect(result).toEqual(0); }); }); diff --git a/maths/test/digit_sum.test.ts b/maths/test/digit_sum.test.ts index 5430f90b..efb4a207 100644 --- a/maths/test/digit_sum.test.ts +++ b/maths/test/digit_sum.test.ts @@ -1,10 +1,10 @@ -import { DigitSum } from "../digit_sum"; +import { digitSum } from "../digit_sum"; -describe("DigitSum", () => { +describe("digitSum", () => { test.each([-42, -0.1, -1, 0.2, 3.3, NaN, -Infinity, Infinity])( "should throw an error for non natural number %d", (num) => { - expect(() => DigitSum(num)).toThrowError( + expect(() => digitSum(num)).toThrowError( "only natural numbers are supported", ); }, @@ -13,7 +13,7 @@ describe("DigitSum", () => { test.each([[0,0], [1, 1], [12, 3], [123, 6], [9045, 18], [1234567890, 45]])( "of %i should be %i", (num, expected) => { - expect(DigitSum(num)).toBe(expected); + expect(digitSum(num)).toBe(expected); }, ); }); diff --git a/maths/test/factorial.test.ts b/maths/test/factorial.test.ts index ecd26258..f53b415c 100644 --- a/maths/test/factorial.test.ts +++ b/maths/test/factorial.test.ts @@ -1,10 +1,10 @@ -import { Factorial } from "../factorial"; +import { factorial } from "../factorial"; -describe("Factorial", () => { +describe("factorial", () => { test.each([-0.1, -1, -2, -42, 0.01, 0.42, 0.5, 1.337])( "should throw an error for non natural number %d", (num) => { - expect(() => Factorial(num)).toThrowError( + expect(() => factorial(num)).toThrowError( "only natural numbers are supported", ); }, @@ -13,11 +13,11 @@ describe("Factorial", () => { test.each([[1, 1], [3, 6], [5, 120], [10, 3628800]])( "of %i should be %i", (num, expected) => { - expect(Factorial(num)).toBe(expected); + expect(factorial(num)).toBe(expected); }, ); test("of 1 should be 0 by definition", () => { - expect(Factorial(0)).toBe(1); + expect(factorial(0)).toBe(1); }); }); diff --git a/maths/test/factors.test.ts b/maths/test/factors.test.ts index 7bcc4c46..3d560851 100644 --- a/maths/test/factors.test.ts +++ b/maths/test/factors.test.ts @@ -1,10 +1,10 @@ -import { FindFactors } from "../factors"; +import { findFactors } from "../factors"; -describe("FindFactors", () => { +describe("findFactors", () => { test.each([-890, -5.56, -7, 0, 0.73, 4.2, NaN, -Infinity, Infinity])( "should throw an error for non natural number %d", (num) => { - expect(() => FindFactors(num)).toThrowError( + expect(() => findFactors(num)).toThrowError( "Only natural numbers are supported." ); } @@ -19,7 +19,7 @@ describe("FindFactors", () => { ])( "of %i should return the correct set of its factors", (num, expected) => { - expect(FindFactors(num)).toStrictEqual(expected); + expect(findFactors(num)).toStrictEqual(expected); } ); }); diff --git a/maths/test/find_min.test.ts b/maths/test/find_min.test.ts index ec19c841..e7b1d32d 100644 --- a/maths/test/find_min.test.ts +++ b/maths/test/find_min.test.ts @@ -1,15 +1,15 @@ -import { FindMin } from "../find_min"; +import { findMin } from "../find_min"; -describe("FindMin", () => { +describe("findMin", () => { test.each([[[1,2,3,4,5,6], 1], [[87,6,13,999], 6], [[0.8,0.2,0.3,0.5], 0.2], [[1,0.1,-1], -1]])( "of this array should be %i", (nums, expected) => { - expect(FindMin(nums)).toBe(expected); + expect(findMin(nums)).toBe(expected); }, ); test("of arrays with length 0 should error", () => { - expect(() => FindMin([])).toThrowError( + expect(() => findMin([])).toThrowError( "array must have length of 1 or greater", ); }); diff --git a/maths/test/hamming_distance.test.ts b/maths/test/hamming_distance.test.ts index 64641172..c14df646 100644 --- a/maths/test/hamming_distance.test.ts +++ b/maths/test/hamming_distance.test.ts @@ -1,5 +1,5 @@ -import { HammingDistance } from "../hamming_distance" +import { hammingDistance } from "../hamming_distance" test.each([['happy', 'homie', 4], ['hole', 'home', 1], ['cathrine', 'caroline', 3], ['happiness', 'dizziness', 4]])('Hamming Distance', (str1, str2, result) => { - expect(HammingDistance(str1, str2)).toBe(result) + expect(hammingDistance(str1, str2)).toBe(result) }) diff --git a/maths/test/is_divisible.test.ts b/maths/test/is_divisible.test.ts index 93330674..7952903c 100644 --- a/maths/test/is_divisible.test.ts +++ b/maths/test/is_divisible.test.ts @@ -1,6 +1,6 @@ -import { IsDivisible } from "../is_divisible"; +import { isDivisible } from "../is_divisible"; -describe("IsDivisible", () => { +describe("isDivisible", () => { test.each([ [1, 1], [6, 3], @@ -14,7 +14,7 @@ describe("IsDivisible", () => { ])( "%f is divisible by %f", (num1, num2) => { - expect(IsDivisible(num1, num2)).toBe(true); + expect(isDivisible(num1, num2)).toBe(true); }, ); @@ -31,11 +31,11 @@ describe("IsDivisible", () => { ])( "%f is not divisible by %f", (num1, num2) => { - expect(IsDivisible(num1, num2)).toBe(false); + expect(isDivisible(num1, num2)).toBe(false); }, ); test("should not divide by 0", () => { - expect(() => IsDivisible(10, 0)).toThrow(); + expect(() => isDivisible(10, 0)).toThrow(); }); }); \ No newline at end of file diff --git a/maths/test/is_even.test.ts b/maths/test/is_even.test.ts index d07aef02..571211f7 100644 --- a/maths/test/is_even.test.ts +++ b/maths/test/is_even.test.ts @@ -1,15 +1,15 @@ -import { IsEven } from "../is_even"; +import { isEven } from "../is_even"; -describe("IsEven", () => { +describe("isEven", () => { test.each([[2, true], [1, false], [0, true], [-1, false], [-2, true]])( "correct output for for %i", (nums, expected) => { - expect(IsEven(nums)).toBe(expected); + expect(isEven(nums)).toBe(expected); }, ); test("only whole numbers should be accepted", () => { - expect(() => IsEven(0.5)).toThrowError( + expect(() => isEven(0.5)).toThrowError( "only integers can be even or odd", ); }); diff --git a/maths/test/is_leap_year.test.ts b/maths/test/is_leap_year.test.ts index 184f366d..05d3d25c 100644 --- a/maths/test/is_leap_year.test.ts +++ b/maths/test/is_leap_year.test.ts @@ -1,12 +1,12 @@ -import { IsLeapYear } from "../is_leap_year"; +import { isLeapYear } from "../is_leap_year"; -describe("IsLeapYear", () => { +describe("isLeapYear", () => { test.each([4, 8, 12, 2004])( "a year is a leap year it is divisible by 4 but not by 400 like %i", (year) => { expect(year % 4 === 0).toBe(true); expect(year % 400 === 0).toBe(false); - expect(IsLeapYear(year)).toBe(true); + expect(isLeapYear(year)).toBe(true); }, ); @@ -14,7 +14,7 @@ describe("IsLeapYear", () => { "a year is a leap year it is divisible by 400 like %i", (year) => { expect(year % 400 === 0).toBe(true); - expect(IsLeapYear(year)).toBe(true); + expect(isLeapYear(year)).toBe(true); }, ); @@ -22,7 +22,7 @@ describe("IsLeapYear", () => { "a year is not a leap year if it is not divisible by 4 like %i", (year) => { expect(year % 4 === 0).toBe(false); - expect(IsLeapYear(year)).toBe(false); + expect(isLeapYear(year)).toBe(false); }, ); @@ -31,7 +31,7 @@ describe("IsLeapYear", () => { (year) => { expect(year % 100 === 0).toBe(true); expect(year % 400 === 0).toBe(false); - expect(IsLeapYear(year)).toBe(false); + expect(isLeapYear(year)).toBe(false); }, ); @@ -40,7 +40,7 @@ describe("IsLeapYear", () => { (year) => { expect(year > 0).toBe(true); expect(Number.isInteger(year)).toBe(true); - expect(() => IsLeapYear(year)).not.toThrow(); + expect(() => isLeapYear(year)).not.toThrow(); }, ); @@ -48,7 +48,7 @@ describe("IsLeapYear", () => { "a year is not supported if it is negative like %i", (year) => { expect(year < 0).toBe(true); - expect(() => IsLeapYear(year)).toThrow("year must be a natural number > 0"); + expect(() => isLeapYear(year)).toThrow("year must be a natural number > 0"); }, ); @@ -56,11 +56,11 @@ describe("IsLeapYear", () => { "a year is not supported if it is not an integer %d", (year) => { expect(Number.isInteger(year)).toBe(false); - expect(() => IsLeapYear(year)).toThrow("year must be a natural number > 0"); + expect(() => isLeapYear(year)).toThrow("year must be a natural number > 0"); }, ); test("a year is not supported if it is 0", () => { - expect(() => IsLeapYear(0)).toThrow("year must be a natural number > 0"); + expect(() => isLeapYear(0)).toThrow("year must be a natural number > 0"); }) }); diff --git a/maths/test/is_odd.test.ts b/maths/test/is_odd.test.ts index d4c105d1..2d305cf8 100644 --- a/maths/test/is_odd.test.ts +++ b/maths/test/is_odd.test.ts @@ -1,15 +1,15 @@ -import { IsOdd } from "../is_odd"; +import { isOdd } from "../is_odd"; -describe("IsOdd", () => { +describe("isOdd", () => { test.each([[2, false], [1, true], [0, false], [-1, true], [-2, false]])( "correct output for for %i", (nums, expected) => { - expect(IsOdd(nums)).toBe(expected); + expect(isOdd(nums)).toBe(expected); }, ); test("only whole numbers should be accepted", () => { - expect(() => IsOdd(0.5)).toThrowError( + expect(() => isOdd(0.5)).toThrowError( "only integers can be even or odd", ); }); diff --git a/maths/test/is_palindrome.test.ts b/maths/test/is_palindrome.test.ts index fa375f73..23911cbf 100644 --- a/maths/test/is_palindrome.test.ts +++ b/maths/test/is_palindrome.test.ts @@ -1,10 +1,10 @@ -import { IsPalindrome } from "../is_palindrome"; +import { isPalindrome } from "../is_palindrome"; -describe("IsPalindrome", () => { +describe("isPalindrome", () => { test.each([[5, true], [1234, false], [12321, true], [31343, false]])( "correct output for %i", (nums, expected) => { - expect(IsPalindrome(nums)).toBe(expected); + expect(isPalindrome(nums)).toBe(expected); }, ); }); \ No newline at end of file diff --git a/maths/test/number_of_digits.test.ts b/maths/test/number_of_digits.test.ts index 58d9b2ba..7dcd4254 100644 --- a/maths/test/number_of_digits.test.ts +++ b/maths/test/number_of_digits.test.ts @@ -1,10 +1,10 @@ -import { NumberOfDigits } from "../number_of_digits"; +import { numberOfDigits } from "../number_of_digits"; -describe("NumberOfDigits", () => { +describe("numberOfDigits", () => { test.each([-890, -5.56, -7, 0, 0.73, 4.2, NaN, -Infinity, Infinity])( "should throw an error for non natural number %d", (num) => { - expect(() => NumberOfDigits(num)).toThrowError( + expect(() => numberOfDigits(num)).toThrowError( "only natural numbers are supported", ); }, @@ -13,7 +13,7 @@ describe("NumberOfDigits", () => { test.each([[1, 1], [18, 2], [549, 3], [7293, 4], [1234567890, 10]])( "of %i should be %i", (num, expected) => { - expect(NumberOfDigits(num)).toBe(expected); + expect(numberOfDigits(num)).toBe(expected); }, ); }); diff --git a/maths/test/perfect_square.test.ts b/maths/test/perfect_square.test.ts index 28020020..e0612c6d 100644 --- a/maths/test/perfect_square.test.ts +++ b/maths/test/perfect_square.test.ts @@ -1,9 +1,9 @@ -import { PerfectSquare } from "../perfect_square"; +import { perfectSquare } from "../perfect_square"; test("Check perfect square", () => { - expect(PerfectSquare(16)).toBe(true); - expect(PerfectSquare(12)).toBe(false); - expect(PerfectSquare(19)).toBe(false); - expect(PerfectSquare(25)).toBe(true); - expect(PerfectSquare(42)).toBe(false); + expect(perfectSquare(16)).toBe(true); + expect(perfectSquare(12)).toBe(false); + expect(perfectSquare(19)).toBe(false); + expect(perfectSquare(25)).toBe(true); + expect(perfectSquare(42)).toBe(false); }); diff --git a/maths/test/pronic_number.test.ts b/maths/test/pronic_number.test.ts index 80b5a1fc..9817eaa9 100644 --- a/maths/test/pronic_number.test.ts +++ b/maths/test/pronic_number.test.ts @@ -1,5 +1,5 @@ -import { PronicNumber } from '../pronic_number' +import { pronicNumber } from '../pronic_number' test.each([[0, true], [10, false], [30, true], [69, false], [420, true]])('Pronic Number', (number, result) => { - expect(PronicNumber(number)).toBe(result) + expect(pronicNumber(number)).toBe(result) }) diff --git a/maths/test/radians_to_degrees.test.ts b/maths/test/radians_to_degrees.test.ts index 9f61994f..9ff8868f 100644 --- a/maths/test/radians_to_degrees.test.ts +++ b/maths/test/radians_to_degrees.test.ts @@ -1,4 +1,4 @@ -import {radiansToDegrees} from '../radians_to_degrees'; +import { radiansToDegrees } from '../radians_to_degrees'; test("RadiansToDegrees", () => { expect(radiansToDegrees(0)).toBe(0); diff --git a/maths/test/sieve_of_eratosthenes.test.ts b/maths/test/sieve_of_eratosthenes.test.ts index 3e7fd866..9670e063 100644 --- a/maths/test/sieve_of_eratosthenes.test.ts +++ b/maths/test/sieve_of_eratosthenes.test.ts @@ -1,11 +1,11 @@ -import { SieveOfEratosthenes } from "../sieve_of_eratosthenes"; +import { sieveOfEratosthenes } from "../sieve_of_eratosthenes"; describe("Sieve of Eratosthenes", () => { test.each([-2, 0.1, -0.01, 2.2])( "should throw a error for non natural number", (n) => { - expect(() => SieveOfEratosthenes(n)).toThrow( + expect(() => sieveOfEratosthenes(n)).toThrow( "Only natural numbers are supported" ); }, @@ -14,7 +14,7 @@ describe("Sieve of Eratosthenes", () => { test.each([[5, [2, 3, 5]], [11, [2, 3, 5, 7, 11]], [30, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]]])( "of %i should be %o", (num, expected) => { - expect(SieveOfEratosthenes(num)).toStrictEqual(expected); + expect(sieveOfEratosthenes(num)).toStrictEqual(expected); }, ); }); diff --git a/maths/test/signum.test.ts b/maths/test/signum.test.ts index 2764ca9c..93c8ff68 100644 --- a/maths/test/signum.test.ts +++ b/maths/test/signum.test.ts @@ -1,5 +1,5 @@ -import { Signum } from "../signum"; +import { signum } from "../signum"; test.each([[10, 1], [0, 0], [-69, -1], [NaN, NaN]])("The sign of %i is %i", (num, expected) => { - expect(Signum(num)).toBe(expected) + expect(signum(num)).toBe(expected) }) diff --git a/maths/test/ugly_numbers.test.ts b/maths/test/ugly_numbers.test.ts index f55cd78c..41f22cb5 100644 --- a/maths/test/ugly_numbers.test.ts +++ b/maths/test/ugly_numbers.test.ts @@ -1,6 +1,6 @@ -import { UglyNumbers } from '../ugly_numbers'; +import { uglyNumbers } from '../ugly_numbers'; test('Ugly Numbers', () => { - const uglyNumbers = UglyNumbers(); - expect(Array(11).fill(undefined).map(() => uglyNumbers.next().value)).toEqual([1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15]); + const uglyNums = uglyNumbers(); + expect(Array(11).fill(undefined).map(() => uglyNums.next().value)).toEqual([1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15]); }) diff --git a/maths/test/zellers_congruence.test.ts b/maths/test/zellers_congruence.test.ts index 19432a10..719969e0 100644 --- a/maths/test/zellers_congruence.test.ts +++ b/maths/test/zellers_congruence.test.ts @@ -1,4 +1,4 @@ -import { Calendar, GetWeekday } from "../zellers_congruence"; +import { Calendar, getWeekday } from "../zellers_congruence"; describe("Zeller's congruence", () => { test.each([ @@ -23,7 +23,7 @@ describe("Zeller's congruence", () => { ])( `The weekday of $year-$month-$day in the default calendar is $expected`, ({ year, month, day, expected }) => { - expect(GetWeekday(year, month, day)).toEqual(expected); + expect(getWeekday(year, month, day)).toEqual(expected); } ); @@ -47,12 +47,12 @@ describe("Zeller's congruence", () => { ])( `The weekday of $year-$month-$day in the Julian calendar is $expected`, ({ year, month, day, expected }) => { - expect(GetWeekday(year, month, day, Calendar.Julian)).toEqual(expected); + expect(getWeekday(year, month, day, Calendar.Julian)).toEqual(expected); } ); test(`The default calendar is Gregorian`, () => { - expect(GetWeekday(1, 1, 1)).toEqual(1); + expect(getWeekday(1, 1, 1)).toEqual(1); }); test.each([ @@ -70,7 +70,7 @@ describe("Zeller's congruence", () => { const dateString = `${year.toString().padStart(4, "0")}-${month .toString() .padStart(2, "0")}-${day.toString().padStart(2, "0")}`; - expect(GetWeekday(year, month, day)).toEqual( + expect(getWeekday(year, month, day)).toEqual( new Date(dateString).getUTCDay() ); } @@ -81,7 +81,7 @@ describe("Zeller's congruence", () => { { year: -5, month: 1, day: 1 }, { year: 12.2, month: 1, day: 1 }, ])(`Should throw an error for invalid year $year`, ({ year, month, day }) => { - expect(() => GetWeekday(year, month, day)).toThrow( + expect(() => getWeekday(year, month, day)).toThrow( "Year must be an integer greater than 0" ); }); @@ -94,7 +94,7 @@ describe("Zeller's congruence", () => { ])( `Should throw an error for invalid month $month`, ({ year, month, day }) => { - expect(() => GetWeekday(year, month, day)).toThrow( + expect(() => getWeekday(year, month, day)).toThrow( "Month must be an integer between 1 and 12" ); } @@ -105,7 +105,7 @@ describe("Zeller's congruence", () => { { year: 2001, month: 1, day: 0 }, { year: 2001, month: 1, day: 32 }, ])(`Should throw an error for invalid day $day`, ({ year, month, day }) => { - expect(() => GetWeekday(year, month, day)).toThrow( + expect(() => getWeekday(year, month, day)).toThrow( "Day must be an integer between 1 and 31" ); }); diff --git a/maths/ugly_numbers.ts b/maths/ugly_numbers.ts index 5b7f60af..81414d84 100644 --- a/maths/ugly_numbers.ts +++ b/maths/ugly_numbers.ts @@ -9,18 +9,18 @@ * For the provided n, the nth ugly number shall be computed. * @see [GeeksForGeeks](https://www.geeksforgeeks.org/ugly-numbers/) */ -function* UglyNumbers() { +function* uglyNumbers(): Generator { yield 1 let idx2 = 0, idx3 = 0, idx5 = 0 - const uglyNumbers = [1] + const uglyNums = [1] let nextx2: number, nextx3: number, nextx5: number, nextUglyNum: number while(true) { - nextx2 = uglyNumbers[idx2] * 2 - nextx3 = uglyNumbers[idx3] * 3 - nextx5 = uglyNumbers[idx5] * 5 + nextx2 = uglyNums[idx2] * 2 + nextx3 = uglyNums[idx3] * 3 + nextx5 = uglyNums[idx5] * 5 nextUglyNum = Math.min(nextx2, nextx3, nextx5) yield nextUglyNum @@ -29,8 +29,8 @@ function* UglyNumbers() { if(nextx3 === nextUglyNum) idx3++ if(nextx5 === nextUglyNum) idx5++ - uglyNumbers.push(nextUglyNum) + uglyNums.push(nextUglyNum) } } -export { UglyNumbers } +export { uglyNumbers } diff --git a/maths/zellers_congruence.ts b/maths/zellers_congruence.ts index bda69700..76315eb2 100644 --- a/maths/zellers_congruence.ts +++ b/maths/zellers_congruence.ts @@ -4,17 +4,17 @@ export enum Calendar { } /** - * @function GetWeekday + * @function getWeekday * @description Calculate the day of the week for any Julian or Gregorian calendar date. * @param {number} year - Year with century. * @param {number} month - Month of the year (1-12). * @param {number} day - Day of the month (1-31). * @return {number} Day of the week, where 0 represents Sunday. * @see https://en.wikipedia.org/wiki/Zeller's_congruence - * @example GetWeekday(2000, 1, 1) = 6 - * @example GetWeekday(1500, 1, 1, Calendar.Julian) = 3 + * @example getWeekday(2000, 1, 1) = 6 + * @example getWeekday(1500, 1, 1, Calendar.Julian) = 3 */ -export const GetWeekday = ( +export const getWeekday = ( year: number, month: number, day: number, From c7a13e70fe4a2b2f05d3e8f96deaf7b831cd3951 Mon Sep 17 00:00:00 2001 From: Omar Ferreiro <27824673+IcarusTheFly@users.noreply.github.com> Date: Fri, 20 Oct 2023 19:33:59 +0200 Subject: [PATCH 074/107] Add Interpolation search (#199) * Add Interpolation search * Add new algorithm to directory --------- Co-authored-by: IcarusTheFly --- DIRECTORY.md | 1 + search/interpolation_search.ts | 49 ++++++++++++++++++++++++ search/test/interpolation_search.test.ts | 15 ++++++++ 3 files changed, 65 insertions(+) create mode 100644 search/interpolation_search.ts create mode 100644 search/test/interpolation_search.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 8934c233..f350203e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -139,6 +139,7 @@ ## Search * [Binary Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/binary_search.ts) + * [Interpolation Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/interpolation_search.ts) * [Jump Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/jump_search.ts) * [Linear Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/linear_search.ts) * [Sentinel Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/sentinel_search.ts) diff --git a/search/interpolation_search.ts b/search/interpolation_search.ts new file mode 100644 index 00000000..61942782 --- /dev/null +++ b/search/interpolation_search.ts @@ -0,0 +1,49 @@ +/** + * @function interpolationSearch + * @description Interpolation search is an algorithm for searching for a + * key in an array that has been ordered by numerical values assigned + * to the keys (key values) + * @param {number[]} array - list of numbers + * @param {number} target - target number to search for + * @return {number} - index of the target number in the list, or -1 if not found + * @see https://en.wikipedia.org/wiki/Interpolation_search + * @example interpolationSearch([1, 3, 5, 7, 9, 11], 1) => 0 + */ +export const interpolationSearch = (array: number[], target: number): number => { + let lowIndex: number = 0; + let highIndex: number = array.length - 1; + let currentValue: number = array[lowIndex]; + let pos: number = 0; + + while (lowIndex <= highIndex) { + const lowValue: number = array[lowIndex]; + const highValue: number = array[highIndex]; + + if (lowValue === highValue) { + if (array[lowIndex] === target) { + return lowIndex; + } + break; + } + + pos = Math.round(lowIndex + (target-lowValue)*(highIndex-lowIndex) / (highValue-lowValue)); + + if (pos < 0 || pos >= array.length) { + break; + } + + currentValue = array[pos]; + + if (target === currentValue) { + return pos; + } + + if (target > currentValue) { + lowIndex = pos + 1; + } else { + highIndex = pos - 1; + } + } + + return -1; +} \ No newline at end of file diff --git a/search/test/interpolation_search.test.ts b/search/test/interpolation_search.test.ts new file mode 100644 index 00000000..6cc6e4e2 --- /dev/null +++ b/search/test/interpolation_search.test.ts @@ -0,0 +1,15 @@ +import { interpolationSearch } from "../interpolation_search"; + +describe("Interpolation search", () => { + test.each([ + [[1, 3, 5, 7, 9, 11], 1, 0], + [[1, 3, 7, 10, 14, 15, 16, 18, 20, 21, 22, 23, 25, 33, 35, 42, 45, 47, 50, 52], 33, 13], + [[0, 45, 67, 70, 89, 129, 150, 308], 308, 7], + [[0, 45, 67, 70, 89, 129, 150, 308], 190, -1] + ])( + "of %o, searching for %o, expected %i", + (array: any[], target: any, index: number) => { + expect(interpolationSearch(array, target)).toStrictEqual(index) + }, + ); +}); From bb7afaa8ce849abd6c6a1f9cddea34ed9ce63a30 Mon Sep 17 00:00:00 2001 From: Adam Ross <14985050+R055A@users.noreply.github.com> Date: Fri, 20 Oct 2023 19:35:13 +0200 Subject: [PATCH 075/107] Feat(maths): add matrix multiplication (#211) * Feat(maths): add matrix multiplication * Refactor maths/matrix_multiplication tabbing --- DIRECTORY.md | 1 + maths/matrix_multiplication.ts | 44 ++++++ maths/test/matrix_multiplication.test.ts | 170 +++++++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 maths/matrix_multiplication.ts create mode 100644 maths/test/matrix_multiplication.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index f350203e..d36d53b5 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -111,6 +111,7 @@ * [Is Square Free](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_square_free.ts) * [Juggler Sequence](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/juggler_sequence.ts) * [Lowest Common Multiple](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/lowest_common_multiple.ts) + * [Matrix Multiplication](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/matrix_multiplication.ts) * [Number Of Digits](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/number_of_digits.ts) * [Pascals Triangle](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/pascals_triangle.ts) * [Perfect Cube](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_cube.ts) diff --git a/maths/matrix_multiplication.ts b/maths/matrix_multiplication.ts new file mode 100644 index 00000000..78b861aa --- /dev/null +++ b/maths/matrix_multiplication.ts @@ -0,0 +1,44 @@ +/** + * @function matrixMultiplication + * @description Multiply a matrix with either another matrix, a vector or a scalar + * @param {Number[][]} matA - An array of an array of numbers + * @param {Number[][] | Number[] | Number} b - Either an array of an array of numbers, an array of numbers, or a number + * @return {Number[][] | Number[]} - Either an array of an array of numbers, or an array of numbers + * @example matrixMultiplication([[1, 2], [3, 4]], [[1, 2], [3, 4]]) = [[7, 10], [15, 22]] + * @example GreatestCommonFactor([[1, 2], [3, 4]], 2) = [[2, 4], [6, 8]] + * @example GreatestCommonFactor([[1, 2], [3, 4]], [1, 2]) = [5, 11] + */ + +function matrixMultiplication(matA: number[][], b: number[][]): number[][]; +function matrixMultiplication(matA: number[][], b: number): number[][]; +function matrixMultiplication(matA: number[][], b: number[]): number[]; + +function matrixMultiplication(matA: number[][], b: any): Number[][] | Number[] | null { + let matC: any = null; + + if (typeof b === 'number') { + matC = matA.map(row => row.map(colVal => colVal * b)); + } else { + if (matA[0].length !== b.length) { + return null; + } + + if (typeof b[0] === 'number') { + matC = matA.map(row => row.reduce((sum, colVal, i) => sum + colVal * b[i], 0)); + } else { + matC = new Array(matA.length).fill(null).map(() => new Array(b[0].length).fill(0)); + let i: number, j: number, k: number; + + for (i = 0; i < matA.length; i++) { + for (j = 0; j < b[0].length; j++) { + for (k = 0; k < matA[0].length; k++) { + matC[i][j] += matA[i][k] * b[k][j]; + } + } + } + } + } + return matC; +} + +export { matrixMultiplication }; diff --git a/maths/test/matrix_multiplication.test.ts b/maths/test/matrix_multiplication.test.ts new file mode 100644 index 00000000..4c869f2a --- /dev/null +++ b/maths/test/matrix_multiplication.test.ts @@ -0,0 +1,170 @@ +import { matrixMultiplication } from '../matrix_multiplication'; + +describe('Matrix-matrix multiplication', () => { + it.each([ + [ + [ + [1, 2], + [3, 4] + ], + [ + [1, 2], + [3, 4] + ], + [ + [7, 10], + [15, 22] + ] + ], + [ + [ + [1, 2], + [3, 4] + ], + [ + [4, 3], + [2, 1] + ], + [ + [8, 5], + [20, 13] + ] + ], + [ + [ + [1, 2], + [3, 4] + ], + [ + [-1, 3], + [2, -4] + ], + [ + [3, -5], + [5, -7] + ] + ], + [ + [ + [1, 2], + [3, 4] + ], + [ + [1, 2] + ], + null + ], + [ + [ + [1, 2], + [3, 4] + ], + [ + [1, 2], + [3, 4], + [5, 6] + ], + null + ], + ])('Multiplying %j with %j should return %j', (matA, matB, expected) => { + expect(matrixMultiplication(matA, matB)).toEqual(expected); + }); +}); + +describe('Matrix-scalar multiplication', () => { + it.each([ + [ + [ + [1, 2], + [3, 4] + ], + 0, + [ + [0, 0], + [0, 0] + ] + ], + [ + [ + [1, 2], + [3, 4] + ], + 1, + [ + [1, 2], + [3, 4] + ] + ], + [ + [ + [1, 2], + [3, 4] + ], + 2, + [ + [2, 4], + [6, 8] + ] + ], + [ + [ + [1, 2], + [3, 4] + ], + -3, + [ + [-3, -6], + [-9, -12] + ] + ], + ])('Multiplying %j with %i should return %j', (matA, scalar, expected) => { + expect(matrixMultiplication(matA, scalar)).toEqual(expected); + }); +}); + +describe('Matrix-vector multiplication', () => { + it.each([ + [ + [ + [1, 2], + [3, 4] + ], + [1, 2], + [5, 11] + ], + [ + [ + [1, 2], + [3, 4] + ], + [3, 4], + [11, 25] + ], + [ + [ + [1, 2], + [3, 4] + ], + [-1, 0], + [-1, -3] + ], + [ + [ + [1, 2], + [3, 4] + ], + [1], + null + ], + [ + [ + [1, 2], + [3, 4] + ], + [1, 2, 3], + null + ], + ])('Multiplying %j with %j should return %j', (matA, vector, expected) => { + expect(matrixMultiplication(matA, vector)).toEqual(expected); + }); +}); From 2716e217b5cbbdab57dba3dbbfade8f1e9ac7942 Mon Sep 17 00:00:00 2001 From: Omar Ferreiro <27824673+IcarusTheFly@users.noreply.github.com> Date: Sun, 22 Oct 2023 19:15:25 +0200 Subject: [PATCH 076/107] test: Put tests together in one file (#198) * test: Put tests together in one file * docs: Remove file from list --------- Co-authored-by: IcarusTheFly --- DIRECTORY.md | 3 +- .../test/{min_heap.test.ts => heap.test.ts} | 55 ++++++++++++++++++- data_structures/heap/test/max_heap.test.ts | 54 ------------------ 3 files changed, 55 insertions(+), 57 deletions(-) rename data_structures/heap/test/{min_heap.test.ts => heap.test.ts} (60%) delete mode 100644 data_structures/heap/test/max_heap.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index d36d53b5..2b94d207 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -24,8 +24,7 @@ * Heap * [Heap](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/heap/heap.ts) * Test - * [Max Heap.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/heap/test/max_heap.test.ts) - * [Min Heap.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/heap/test/min_heap.test.ts) + * [Heap.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/heap/test/heap.test.ts) * List * [Doubly Linked List](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/list/doubly_linked_list.ts) * [Linked List](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/list/linked_list.ts) diff --git a/data_structures/heap/test/min_heap.test.ts b/data_structures/heap/test/heap.test.ts similarity index 60% rename from data_structures/heap/test/min_heap.test.ts rename to data_structures/heap/test/heap.test.ts index 33ac03cd..9dc8f041 100644 --- a/data_structures/heap/test/min_heap.test.ts +++ b/data_structures/heap/test/heap.test.ts @@ -1,4 +1,57 @@ -import { MinHeap, PriorityQueue } from "../heap"; +import { MaxHeap, MinHeap, PriorityQueue } from "../heap"; + +describe("MaxHeap", () => { + let heap: MaxHeap; + const elements: number[] = [ + 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18, + ]; + + beforeEach(() => { + heap = new MaxHeap(); + for (let element of elements) { + heap.insert(element); + } + }); + + it("should initialize a heap from input array", () => { + expect(heap.isEmpty()).toEqual(false); + heap.check(); + }); + + it("should remove and return the max element in the heap", () => { + const maxValue = heap.extract(); + + expect(maxValue).toEqual(81); + heap.check(); + }); + + it("should insert a new element and bubble Up the element to it correct index in the heap", () => { + heap.insert(61); + heap.check(); + }); + + const extract_all = (heap: MaxHeap) => { + [...elements].sort((a, b) => b - a).forEach((element: number) => { + expect(heap.extract()).toEqual(element); + }); + heap.check(); + expect(heap.size()).toEqual(0); + } + + it("should remove and return the max elements in order", () => { + extract_all(heap); + }); + + it("should insert all, then remove and return the max elements in order", () => { + heap = new MaxHeap(); + elements.forEach((element: number) => { + heap.insert(element); + }); + heap.check(); + expect(heap.size()).toEqual(elements.length); + extract_all(heap); + }); +}); describe("MinHeap", () => { let heap: MinHeap; diff --git a/data_structures/heap/test/max_heap.test.ts b/data_structures/heap/test/max_heap.test.ts deleted file mode 100644 index a94739e6..00000000 --- a/data_structures/heap/test/max_heap.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { MaxHeap } from "../heap"; - -describe("MaxHeap", () => { - let heap: MaxHeap; - const elements: number[] = [ - 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18, - ]; - - beforeEach(() => { - heap = new MaxHeap(); - for (let element of elements) { - heap.insert(element); - } - }); - - it("should initialize a heap from input array", () => { - expect(heap.isEmpty()).toEqual(false); - heap.check(); - }); - - it("should remove and return the max element in the heap", () => { - const maxValue = heap.extract(); - - expect(maxValue).toEqual(81); - heap.check(); - }); - - it("should insert a new element and bubble Up the element to it correct index in the heap", () => { - heap.insert(61); - heap.check(); - }); - - const extract_all = (heap: MaxHeap) => { - [...elements].sort((a, b) => b - a).forEach((element: number) => { - expect(heap.extract()).toEqual(element); - }); - heap.check(); - expect(heap.size()).toEqual(0); - } - - it("should remove and return the max elements in order", () => { - extract_all(heap); - }); - - it("should insert all, then remove and return the max elements in order", () => { - heap = new MaxHeap(); - elements.forEach((element: number) => { - heap.insert(element); - }); - heap.check(); - expect(heap.size()).toEqual(elements.length); - extract_all(heap); - }); -}); From deaa0af5b9c3f0d6d037d4484257e148608fb023 Mon Sep 17 00:00:00 2001 From: Mohd Faisal Date: Sun, 22 Oct 2023 22:51:42 +0530 Subject: [PATCH 077/107] feat: Fibonacci Series (#205) * Feat: Fibonacci Series * Update DIRECTORY.md * feat: generator for fibonacci function * Update DIRECTORY.md * Update DIRECTORY.md --------- Co-authored-by: autoprettier --- DIRECTORY.md | 10 ++++++++++ maths/fibonacci.ts | 34 ++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 2b94d207..92c92ff3 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -7,11 +7,15 @@ * [Generateparentheses.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/backtracking/test/generateparentheses.test.ts) ## Bit Manipulation + * [Add Binary](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/add_binary.ts) * [Is Power Of 2](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/is_power_of_2.ts) * [Is Power Of 4](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/is_power_of_4.ts) + * [Log Two](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/log_two.ts) * Test + * [Add Binary.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/test/add_binary.test.ts) * [Is Power Of 2.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/test/is_power_of_2.test.ts) * [Is Power Of 4.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/test/is_power_of_4.test.ts) + * [Log Two.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/bit_manipulation/test/log_two.test.ts) ## Ciphers * [Xor Cipher](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/ciphers/xor_cipher.ts) @@ -70,9 +74,11 @@ ## Dynamic Programming * [Knapsack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/knapsack.ts) + * [Lcs](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/lcs.ts) ## Graph * [Bellman Ford](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/bellman_ford.ts) + * [Bipartite Graph](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/bipartite_graph.ts) * [Dijkstra](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/dijkstra.ts) * [Floyd Warshall](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/floyd_warshall.ts) * [Johnson](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/johnson.ts) @@ -80,6 +86,7 @@ * [Prim](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/prim.ts) * Test * [Bellman Ford.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/bellman_ford.test.ts) + * [Bipartite Graph.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/bipartite_graph.test.ts) * [Dijkstra.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/dijkstra.test.ts) * [Floyd Warshall.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/floyd_warshall.test.ts) * [Johnson.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/johnson.test.ts) @@ -100,6 +107,7 @@ * [Factors](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/factors.ts) * [Fibonacci](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/fibonacci.ts) * [Find Min](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/find_min.ts) + * [Gaussian Elimination](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/gaussian_elimination.ts) * [Greatest Common Factor](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/greatest_common_factor.ts) * [Hamming Distance](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/hamming_distance.ts) * [Is Divisible](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/is_divisible.ts) @@ -150,9 +158,11 @@ * [Counting Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/counting_sort.ts) * [Cycle Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/cycle_sort.ts) * [Gnome Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/gnome_sort.ts) + * [Heap Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/heap_sort.ts) * [Insertion Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/insertion_sort.ts) * [Merge Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/merge_sort.ts) * [Quick Select](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/quick_select.ts) * [Quick Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/quick_sort.ts) * [Selection Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/selection_sort.ts) * [Shell Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/shell_sort.ts) + * [Swap Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/swap_sort.ts) diff --git a/maths/fibonacci.ts b/maths/fibonacci.ts index 3d4cb118..4280a083 100644 --- a/maths/fibonacci.ts +++ b/maths/fibonacci.ts @@ -10,25 +10,31 @@ * @see https://en.m.wikipedia.org/wiki/Fibonacci_number * @author MohdFaisalBidda */ -export const nthFibonacci = (number: number): number => { - if (number < 0) { - throw 'Number should be greater than 0'; +function* generateFibonacci(): Generator { + let a = 0; + let b = 1; + while (true) { + yield a; + const c = a + b; + a = b; + b = c; } +} + +export const nthFibonacci = (number: number): number => { + if (isNaN(number)) throw new Error('The input needs to be a number'); + if (!Number.isInteger(number) || number < 0) throw new Error('The input needs to be a non-negative integer'); if (number === 0) { return 0; } - - let a = 0, - b = 1; - for (let i = 1; i < number; ++i) { - const c = a + b; - - a = b; - b = c; + + const fibonacciGenerator = generateFibonacci(); + let result = 0; + for (let i = 0; i <= number; ++i) { + result = fibonacciGenerator.next().value; } - - return b; + return result; }; /** @@ -70,4 +76,4 @@ const sqrt5 = Math.sqrt(5) const phi = (1 + sqrt5) / 2 const psi = (1 - sqrt5) / 2 -export const nthFibonacciUsingFormula = (n : number) => Math.round((phi ** n - psi ** n) / sqrt5) +export const nthFibonacciUsingFormula = (n : number) => Math.round((phi ** n - psi ** n) / sqrt5) \ No newline at end of file From b72e357c244ed059e0c71c6372e33c9e08f54906 Mon Sep 17 00:00:00 2001 From: Ayoub Chegraoui Date: Thu, 26 Oct 2023 14:36:30 +0100 Subject: [PATCH 078/107] feat: add prime factorization algorithm (#214) --- maths/prime_factorization.ts | 27 ++++++++++++++++++++++++++ maths/test/prime_factorization.test.ts | 26 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 maths/prime_factorization.ts create mode 100644 maths/test/prime_factorization.test.ts diff --git a/maths/prime_factorization.ts b/maths/prime_factorization.ts new file mode 100644 index 00000000..19032730 --- /dev/null +++ b/maths/prime_factorization.ts @@ -0,0 +1,27 @@ +/** + * @description Get exponenets of each prime number in factorization of a number n + * @param {number} n - A natural number. + * @return {Map} - factorization of number n. + * @see https://en.wikipedia.org/wiki/Integer_factorization + * @example factorize(4) = Map {2 => 2} + * @example factorize(5) = Map {5 => 1} + */ +export const factorize = (n: number): Map => { + let result: Map = new Map(); + + for (let i = 2; i * i <= n; i++) { + while (n % i == 0) { + let occurence = result.get(i); + if (!occurence) occurence = 0; + result.set(i, occurence + 1); + n = n / i; + } + } + if (n > 1) { + let occurence = result.get(n); + if (!occurence) occurence = 0; + result.set(n, occurence + 1); + } + + return result; +}; diff --git a/maths/test/prime_factorization.test.ts b/maths/test/prime_factorization.test.ts new file mode 100644 index 00000000..23eaff0b --- /dev/null +++ b/maths/test/prime_factorization.test.ts @@ -0,0 +1,26 @@ +import { factorize } from "../prime_factorization"; + + +interface TestCase { + n: number; + expected: Map +} + +const cases: TestCase[] = [ + {n: 4, expected: new Map([[2, 2]])}, + {n: 5, expected: new Map([[5, 1]])}, + {n: 7, expected: new Map([[7, 1]])}, + {n: 10, expected: new Map([[2, 1], [5, 1]])}, + {n: 999, expected: new Map([[3, 3], [37, 1]])}, + {n: 999999999999878, expected: new Map([[2, 1], [19, 1], [26315789473681, 1]])}, +]; + +describe("factorize", () => { + + test.each(cases)( + "prime factorization of $n should be $expected", + ({n, expected}) => { + expect(factorize(n)).toEqual(expected); + }, + ); +}); From f7a4b7d11886ab0e7f7b3ff67cab1f1b3edfd6a9 Mon Sep 17 00:00:00 2001 From: Vladimir Cucu <108150922+vladimir-cucu@users.noreply.github.com> Date: Fri, 27 Oct 2023 19:08:42 +0300 Subject: [PATCH 079/107] fix: Fix QuickSort (#207) --- sorts/quick_sort.ts | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/sorts/quick_sort.ts b/sorts/quick_sort.ts index c0fd192e..90d03266 100644 --- a/sorts/quick_sort.ts +++ b/sorts/quick_sort.ts @@ -10,29 +10,39 @@ export const partition = ( left: number = 0, right: number = array.length - 1 ) => { - const pivot = array[Math.floor((right + left) / 2)]; - let i = left; + const pivotIndex = choosePivot(left,right); + const pivot = array[pivotIndex]; + [array[pivotIndex], array[right]] = [array[right], array[pivotIndex]]; + let i = left - 1; let j = right; - while (i <= j) { - while (array[i] < pivot) { - i++; - } - - while (array[j] > pivot) { - j--; - } + while (i < j) { + while (array[++i] < pivot); + while (array[--j] > pivot); - if (i <= j) { + if (i < j) { [array[i], array[j]] = [array[j], array[i]]; - i++; - j--; } } + [array[right], array[i]] = [array[i], array[right]]; return i; }; +/** + * @function choosePivot + * @description Chooses a pivot element randomly within the subarray. + * @param {number} left - The left index of the subarray. + * @param {number} right - The right index of the subarray. + * @returns {number} - The index of the chosen pivot element. + */ +const choosePivot = ( + left: number, + right: number +): number => { + return Math.floor(Math.random() * (right - left + 1)) + left; +}; + /** * Quicksort implementation * @@ -56,17 +66,15 @@ export const QuickSort = ( left: number = 0, right: number = array.length - 1 ) => { - let index; - if (array.length > 1) { - index = partition(array, left, right); + const index = partition(array, left, right); if (left < index - 1) { QuickSort(array, left, index - 1); } - if (index < right) { - QuickSort(array, index, right); + if (index + 1 < right) { + QuickSort(array, index + 1, right); } } From 7411314c0ae3096d44b9f7914f1fb5794cc9d4ab Mon Sep 17 00:00:00 2001 From: Ayoub Chegraoui Date: Fri, 27 Oct 2023 17:09:55 +0100 Subject: [PATCH 080/107] Feat: add euler's totient function (#213) --- maths/euler_totient.ts | 20 ++++++++++++++++++++ maths/test/euler_totient.test.ts | 24 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 maths/euler_totient.ts create mode 100644 maths/test/euler_totient.test.ts diff --git a/maths/euler_totient.ts b/maths/euler_totient.ts new file mode 100644 index 00000000..482281c4 --- /dev/null +++ b/maths/euler_totient.ts @@ -0,0 +1,20 @@ +/** + * @description counts the positive integers up to a given integer n that are relatively prime to n. + * @param {number} n - A natural number. + * @return {number} - euler's totient. + * @see https://en.wikipedia.org/wiki/Euler%27s_totient_function + * @example phi(4) = 2 + * @example phi(5) = 4 + */ +export const phi = (n: number): number => { + let result: number = n; + for (let i = 2; i * i <= n; i++) { + if (n % i == 0) { + while (n % i == 0) n = n / i; + result -= Math.floor(result / i); + } + } + if (n > 1) result -= Math.floor(result / n); + + return result; +}; diff --git a/maths/test/euler_totient.test.ts b/maths/test/euler_totient.test.ts new file mode 100644 index 00000000..4d1ec6b7 --- /dev/null +++ b/maths/test/euler_totient.test.ts @@ -0,0 +1,24 @@ +import { phi } from "../euler_totient"; + + +const cases: [number, number][] = [ + [4, 2], + [5, 4], + [7, 6], + [10, 4], + [999, 648], + [1000, 400], + [1000000, 400000], + [999999, 466560], + [999999999999878, 473684210526240], +]; + +describe("phi", () => { + + test.each(cases)( + "phi of %i should be %i", + (num, expected) => { + expect(phi(num)).toBe(expected); + }, + ); +}); From 9fe74ce836a7564c67f376394e90165081e8ba78 Mon Sep 17 00:00:00 2001 From: Ayoub Chegraoui Date: Mon, 30 Oct 2023 06:41:09 +0100 Subject: [PATCH 081/107] Feat: add coin change algorithm (#212) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Feat: add coin change algorithm * Use Infinity rather than just a large number --------- Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- dynamic_programming/coin_change.ts | 46 ++++++++++++++++++++ dynamic_programming/test/coin_change.test.ts | 37 ++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 dynamic_programming/coin_change.ts create mode 100644 dynamic_programming/test/coin_change.test.ts diff --git a/dynamic_programming/coin_change.ts b/dynamic_programming/coin_change.ts new file mode 100644 index 00000000..791aa5f1 --- /dev/null +++ b/dynamic_programming/coin_change.ts @@ -0,0 +1,46 @@ + +export interface CoinChange { + minCoins: number, + coins: number[] +} + +/** + * Given a set of categories of coins C and an amount of money S, the goal is: + * to give change for S but to use a minimum number of coins. Suppose each category of coin has an infinite number of pieces. + * @param money - amon of money. + * @param coins - The coins that are available. + * @returns CoinChange, the minimum number of coins, and which coins are selected + */ +export const coinChange = (money: number, coins: number[]): CoinChange => { + + const minCoins: number[] = Array(money + 1).fill(Infinity); + const lastCoin: number[] = Array(money + 1).fill(-1); + + minCoins[0] = 0; + + // Fill in the DP table + for (let i = 0; i < coins.length; i++) { + for (let j = 0; j <= money; j++) { + if (j >= coins[i]) { + if (minCoins[j] > 1 + minCoins[j - coins[i]]) { + minCoins[j] = 1 + minCoins[j - coins[i]]; + lastCoin[j] = coins[i]; + } + } + } + } + + const res: CoinChange = { + minCoins: minCoins[money], + coins: [] + } + + let total: number = money; + while (total > 0) { + res.coins.push(lastCoin[total]); + total -= lastCoin[total]; + } + + return res; +} + diff --git a/dynamic_programming/test/coin_change.test.ts b/dynamic_programming/test/coin_change.test.ts new file mode 100644 index 00000000..7155ef9c --- /dev/null +++ b/dynamic_programming/test/coin_change.test.ts @@ -0,0 +1,37 @@ +import { CoinChange, coinChange } from "../coin_change"; + + +interface TestCase { + money: number, + coins: number[], + expected: CoinChange +} + +const cases: TestCase[] = [ + { + money: 13, + coins: [7, 2, 3, 6], + expected: { + minCoins: 2, + coins: [6, 7] + } + }, + { + money: 10, + coins: [1, 5], + expected: { + minCoins: 2, + coins: [5, 5] + } + } +]; + +describe("Coin Change Algorithm Test", () => { + test.each(cases)( + "given money: $money, and coins: $coins the minimum coin change should return $expected", + ({money, coins, expected}) => { + const result = coinChange(money, coins); + expect(result).toEqual(expected); + } + ); +}); From 74331030d40c5d2318b98bb76e5b10ff18779298 Mon Sep 17 00:00:00 2001 From: Rohit Chaudhari <100275369+rohitkbc@users.noreply.github.com> Date: Sun, 3 Dec 2023 21:22:24 +0530 Subject: [PATCH 082/107] feat: Add Gitpod setup (#216) * Add gitpod setup * Update yml file * modified: .gitpod.yml * Modified : .gitpod.yml --- .gitpod.yml | 5 +++++ README.md | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000..46209a0a --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,5 @@ +tasks: + - init: | + npm install && npm test + + diff --git a/README.md b/README.md index 930e83b4..5412c60a 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,9 @@ TypeScript Repository of TheAlgorithms, which implements various algorithms and [![Contributions Welcome][welcome]](CONTRIBUTING.md) [![Discord chat][chat]][discord-server] - - + + Gitpod Ready-to-Code + --- From e0ae74498376dbbc7e309e9b4b8a6fcad5e863a2 Mon Sep 17 00:00:00 2001 From: tamaf96 <80266356+tamaf96@users.noreply.github.com> Date: Fri, 15 Dec 2023 13:25:29 +0100 Subject: [PATCH 083/107] feat: add treesort algorithm (#217) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add treesort algorithm * use existing data structure * make generic and add tests for string and date * fix typo * Fix typo --------- Co-authored-by: tamaf96 Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- DIRECTORY.md | 1 + sorts/test/tree_sort.test.ts | 33 +++++++++++++++++++++++++++++++++ sorts/tree_sort.ts | 18 ++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 sorts/test/tree_sort.test.ts create mode 100644 sorts/tree_sort.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 92c92ff3..de534ede 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -166,3 +166,4 @@ * [Selection Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/selection_sort.ts) * [Shell Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/shell_sort.ts) * [Swap Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/swap_sort.ts) + * [Tree Sort](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/sorts/tree_sort.ts) diff --git a/sorts/test/tree_sort.test.ts b/sorts/test/tree_sort.test.ts new file mode 100644 index 00000000..07cbca56 --- /dev/null +++ b/sorts/test/tree_sort.test.ts @@ -0,0 +1,33 @@ +import { treeSort } from "../tree_sort"; + +describe('TreeSort (numbers)', () => { + it.each([ + { input: [], expected: [] }, + { input: [1, 18, 3, 4, -5, 6], expected: [-5, 1, 3, 4, 6, 18] }, + { input: [7, 6, 2, 5.2, 11, 0], expected: [0, 2, 5.2, 6, 7, 11] }, + { input: [3, 3, -2, 1, 0], expected: [-2, 0, 1, 3, 3] }, + { input: [3, 0, -2.4, 1, 9, 8, -7, 6], expected: [-7, -2.4, 0, 1, 3, 6, 8, 9] }, + { input: [1, 0, -14, 0, 8.6, 6, 8], expected: [-14, 0, 0, 1, 6, 8, 8.6] }, + ])('should work for given input', ({ input, expected }) => { + expect(treeSort(input)).toEqual(expected); + }); +}); + +describe('TreeSort (strings)', () => { + it.each([ + { input: ["e","egr","sse","aas", "as","abs"], expected: ["aas","abs","as","e","egr","sse"] }, + ])('should work for given input', ({ input, expected }) => { + expect(treeSort(input)).toEqual(expected); + }); +}); + +describe('TreeSort (dates)', () => { + it.each([ + { input: [new Date("2019-01-16"),new Date("2019-01-01"),new Date("2022-05-20")], expected: [new Date("2019-01-01"),new Date("2019-01-16"),new Date("2022-05-20")] }, + ])('should work for given input', ({ input, expected }) => { + expect(treeSort(input)).toEqual(expected); + }); +}); + + + \ No newline at end of file diff --git a/sorts/tree_sort.ts b/sorts/tree_sort.ts new file mode 100644 index 00000000..e4369e52 --- /dev/null +++ b/sorts/tree_sort.ts @@ -0,0 +1,18 @@ +/** + * @author : tamaf96 + * @description + * Tree Sort sorts a list by building a binary search tree and traversing it. + * @param {T[]} arr - Array of comparable items + * @return {T[]} - The sorted Array. + * @see + */ + +import { BinarySearchTree } from "../data_structures/tree/binary_search_tree"; + +export const treeSort = (arr: T[]): T[] => { + const searchTree = new BinarySearchTree(); + for (const item of arr) { + searchTree.insert(item); + } + return searchTree.inOrderTraversal(); +}; From 4acf117fa277538feaed8d4c3ac4ca706a006ea3 Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Sat, 30 Dec 2023 10:43:02 -0800 Subject: [PATCH 084/107] fix: document heap sorts space complexity to O(1) (#219) --- sorts/heap_sort.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sorts/heap_sort.ts b/sorts/heap_sort.ts index ecc42995..e5541a77 100644 --- a/sorts/heap_sort.ts +++ b/sorts/heap_sort.ts @@ -4,7 +4,7 @@ * @see [Heap Sort](https://www.geeksforgeeks.org/heap-sort/) * @example MergeSort([7, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 7] * @Complexity_Analysis - * Space complexity - O(n) + * Space complexity - O(1) * Time complexity * Best case - O(nlogn) * Worst case - O(nlogn) From 6e78b6c2540d9d50b0f310cdfacb3a9fc979806f Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Sat, 30 Dec 2023 22:17:01 -0800 Subject: [PATCH 085/107] feat: Add kosajura algorithm for finding strong connected components (#218) --- graph/kosajaru.ts | 75 +++++++++++++++++++++++++++++++++++++ graph/test/kosajaru.test.ts | 72 +++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 graph/kosajaru.ts create mode 100644 graph/test/kosajaru.test.ts diff --git a/graph/kosajaru.ts b/graph/kosajaru.ts new file mode 100644 index 00000000..32338e76 --- /dev/null +++ b/graph/kosajaru.ts @@ -0,0 +1,75 @@ +// Compute the node priorities, which will be used to determine the order in which we perform transposed DFS. +const getNodePriorities = (graph: number[][], visited: boolean[], stack: number[], node: number) => { + if (visited[node]) { + return; + } + visited[node] = true; + + for (const dest of graph[node]) { + getNodePriorities(graph, visited, stack, dest); + } + // Nodes that end their DFS earlier are pushed onto the stack first and have lower priority. + stack.push(node); +} + +// Return the transpose of graph. The tranpose of a directed graph is a graph where each of the edges are flipped. +const transpose = (graph: number[][]): number[][] => { + let transposedGraph = Array(graph.length); + for (let i = 0; i < graph.length; ++i) { + transposedGraph[i] = []; + } + + for (let i = 0; i < graph.length; ++i) { + for (let j = 0; j < graph[i].length; ++j) { + transposedGraph[graph[i][j]].push(i); + } + } + + return transposedGraph; +} + +// Computes the SCC that contains the given node +const gatherScc = (graph: number[][], visited: boolean[], node: number, scc: number[]) => { + if (visited[node]) { + return; + } + visited[node] = true; + scc.push(node); + + for (const dest of graph[node]) { + gatherScc(graph, visited, dest, scc); + } +} + +/** + * @function kosajaru + * @description Given a graph, find the strongly connected components(SCC). A set of nodes form a SCC if there is a path between all pairs of points within that set. + * @Complexity_Analysis + * Time complexity: O(V + E). We perform two DFS twice, and make sure to visit each disconnected graph. Each DFS is O(V + E). + * Space Complexity: O(V + E). This space is required for the transposed graph. + * @param {[number, number][][]} graph - The graph in adjacency list form + * @return {number[][]} - An array of SCCs, where an SCC is an array with the indices of each node within that SCC. + * @see https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm + */ +export const kosajaru = (graph: number[][]): number[][] => { + let visited = Array(graph.length).fill(false); + + let stack: number[] = []; + for (let i = 0; i < graph.length; ++i) { + getNodePriorities(graph, visited, stack, i); + } + + const transposedGraph = transpose(graph); + + let sccs = []; + visited.fill(false); + for (let i = stack.length - 1; i >= 0; --i) { + if (!visited[stack[i]]) { + let scc: number[] = []; + gatherScc(transposedGraph, visited, stack[i], scc); + sccs.push(scc); + } + } + return sccs; +} + diff --git a/graph/test/kosajaru.test.ts b/graph/test/kosajaru.test.ts new file mode 100644 index 00000000..946b0201 --- /dev/null +++ b/graph/test/kosajaru.test.ts @@ -0,0 +1,72 @@ +import { kosajaru } from "../kosajaru"; + +describe("kosajaru", () => { + + it("it should return no sccs for empty graph", () => { + expect(kosajaru([])).toStrictEqual([]); + }); + + it("it should return one scc for graph with one element", () => { + expect(kosajaru([[]])).toStrictEqual([[0]]); + }); + + it("it should return one scc for graph with element that points to itself", () => { + expect(kosajaru([[0]])).toStrictEqual([[0]]); + }); + + it("it should return one scc for two element graph with cycle", () => { + expect(kosajaru([[1], [0]])).toStrictEqual([[0, 1]]); + }); + + it("should return one scc for each element for straight line", () => { + expect(kosajaru([[1], [2], [3], []])).toStrictEqual([[0], [1], [2], [3]]); + }); + + it("should return sccs for straight line with backedge in middle", () => { + expect(kosajaru([[1], [2], [3, 0], []])).toStrictEqual([[0, 2, 1], [3]]); + }); + + it("should return sccs for straight line with backedge from end to middle", () => { + expect(kosajaru([[1], [2], [3], [1]])).toStrictEqual([[0], [1, 3, 2]]); + }); + + it("should return scc for each element for graph with no edges", () => { + expect(kosajaru([[], [], [], []])).toStrictEqual([[3], [2], [1], [0]]); + }); + + it("should return sccs disconnected graph", () => { + expect(kosajaru([[1, 2], [0, 2], [0, 1], []])).toStrictEqual([[3], [0, 1, 2]]); + }); + + it("should return sccs disconnected graph", () => { + expect(kosajaru([[1, 2], [0, 2], [0, 1], [4], [5], [3]])).toStrictEqual([[3, 5, 4], [0, 1, 2]]); + }); + + it("should return single scc", () => { + expect(kosajaru([[1], [2], [3], [0, 4], [3]])).toStrictEqual([[0, 3, 2, 1, 4]]); + }); + + it("should return one scc for complete connected graph", () => { + const input = [[1, 2, 3, 4], [0, 2, 3, 4], [0, 1, 3, 4], [0, 1, 2, 4], [0, 1, 2, 3]]; + expect(kosajaru(input)).toStrictEqual([[0, 1, 2, 3, 4]]); + }); + + it("should return sccs", () => { + const input = [[1], [2], [0, 3], [4], []]; + expect(kosajaru(input)).toStrictEqual([[0, 2, 1], [3], [4]]); + }); + + it("should return sccs", () => { + const input = [[1], [2], [0, 3, 4], [0], [5], [6, 7], [2, 4], [8], [5, 9], [5]]; + const expected = [[0, 2, 1, 6, 5, 4, 8, 7, 9, 3]]; + expect(kosajaru(input)).toStrictEqual(expected); + }); + + it("should return sccs", () => { + const input = [[1], [0, 2], [0, 3], [4], [5, 7], [6], [4, 7], []]; + const expected = [[0, 1, 2], [3], [4, 6, 5], [7]]; + expect(kosajaru(input)).toStrictEqual(expected); + }); + +}) + From 90212facc1759cf32bff51a220c3d34f086e2572 Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Sat, 13 Jan 2024 07:24:46 -0800 Subject: [PATCH 086/107] feat: add tarjan algorithm for strongly connected components (#220) * feat: add tarjan algorithm for strongly connected components * Address review. Add notes on topological sort. --- graph/tarjan.ts | 70 +++++++++++++++++++++++++++++++++++ graph/test/tarjan.test.ts | 78 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 graph/tarjan.ts create mode 100644 graph/test/tarjan.test.ts diff --git a/graph/tarjan.ts b/graph/tarjan.ts new file mode 100644 index 00000000..7f2a2454 --- /dev/null +++ b/graph/tarjan.ts @@ -0,0 +1,70 @@ +/** + * @function tarjan + * @description Given a graph, find the strongly connected components(SCC) in reverse topological order. A set of nodes form a SCC if there is a path between all pairs of points within that set. + * @Complexity_Analysis + * Time complexity: O(V + E). We perform a DFS of (V + E) + * Space Complexity: O(V). We hold numerous structures all of which at worst holds O(V) nodes. + * @param {[number, number][][]} graph - The graph in adjacency list form + * @return {number[][]} - An array of SCCs, where an SCC is an array with the indices of each node within that SCC. The order of SCCs in the array are in reverse topological order. + * @see https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + */ +export const tarjan = (graph: number[][]): number[][] => { + if (graph.length === 0) { + return []; + } + + let index = 0; + // The order in which we discover nodes + let discovery: number[] = Array(graph.length); + // For each node, holds the furthest ancestor it can reach + let low: number[] = Array(graph.length).fill(undefined); + // Holds the nodes we have visited in a DFS traversal and are considering to group into a SCC + let stack: number[] = []; + // Holds the elements in the stack. + let stackContains = Array(graph.length).fill(false); + let sccs: number[][] = []; + + const dfs = (node: number) => { + discovery[node] = index; + low[node] = index; + ++index; + stack.push(node); + stackContains[node] = true; + + for (const child of graph[node]) { + if (low[child] === undefined) { + dfs(child); + if (low[child] < low[node]) { + // Child node loops back to this node's ancestor. Update the low node. + low[node] = low[child]; + } + } else if (stackContains[child] && low[node] > discovery[child]) { + // Found a backedge. Update the low for this node if needed. + low[node] = discovery[child]; + } + } + + if (discovery[node] == low[node]) { + // node is the root of a SCC. Gather the SCC's nodes from the stack. + let scc: number[] = []; + let i; + for (i = stack.length - 1; stack[i] != node; --i) { + scc.push(stack[i]); + stackContains[stack[i]] = false; + stack.pop(); + } + scc.push(stack[i]); + stackContains[stack[i]] = false; + stack.pop(); + sccs.push(scc); + } + } + + for (let i = 0; i < graph.length; ++i) { + if (low[i] === undefined) { + dfs(i); + } + } + return sccs; +} + diff --git a/graph/test/tarjan.test.ts b/graph/test/tarjan.test.ts new file mode 100644 index 00000000..f2eca081 --- /dev/null +++ b/graph/test/tarjan.test.ts @@ -0,0 +1,78 @@ +import { tarjan } from "../tarjan"; + +describe("tarjan", () => { + + it("it should return no sccs for empty graph", () => { + expect(tarjan([])).toStrictEqual([]); + }); + + it("it should return one scc for graph with one element", () => { + expect(tarjan([[]])).toStrictEqual([[0]]); + }); + + it("it should return one scc for graph with element that points to itself", () => { + expect(tarjan([[0]])).toStrictEqual([[0]]); + }); + + it("it should return one scc for two element graph with cycle", () => { + expect(tarjan([[1], [0]])).toStrictEqual([[1, 0]]); + }); + + it("should return one scc for each element for straight line", () => { + expect(tarjan([[1], [2], [3], []])).toStrictEqual([[3], [2], [1], [0]]); + }); + + it("should return sccs for straight line with backedge in middle", () => { + expect(tarjan([[1], [2], [3, 0], []])).toStrictEqual([[3], [2, 1, 0]]); + }); + + it("should return sccs for straight line with backedge from end to middle", () => { + expect(tarjan([[1], [2], [3], [1]])).toStrictEqual([[3, 2, 1], [0]]); + }); + + it("should return scc for each element for graph with no edges", () => { + expect(tarjan([[], [], [], []])).toStrictEqual([[0], [1], [2], [3]]); + }); + + it("should return sccs disconnected graph", () => { + expect(tarjan([[1, 2], [0, 2], [0, 1], []])).toStrictEqual([[2, 1, 0], [3]]); + }); + + it("should return sccs disconnected graph", () => { + expect(tarjan([[1, 2], [0, 2], [0, 1], [4], [5], [3]])).toStrictEqual([[2, 1, 0], [5, 4, 3]]); + }); + + it("should return single scc", () => { + expect(tarjan([[1], [2], [3], [0, 4], [3]])).toStrictEqual([[4, 3, 2, 1, 0]]); + }); + + it("should return one scc for complete connected graph", () => { + const input = [[1, 2, 3, 4], [0, 2, 3, 4], [0, 1, 3, 4], [0, 1, 2, 4], [0, 1, 2, 3]]; + expect(tarjan(input)).toStrictEqual([[4, 3, 2, 1, 0]]); + }); + + it("should return sccs", () => { + const input = [[1], [2], [0, 3], [4], []]; + expect(tarjan(input)).toStrictEqual([[4], [3], [2, 1, 0]]); + }); + + it("should return sccs", () => { + const input = [[1], [2], [0, 3, 4], [0], [5], [6, 7], [2, 4], [8], [5, 9], [5]]; + const expected = [[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]]; + expect(tarjan(input)).toStrictEqual(expected); + }); + + it("should return sccs", () => { + const input = [[1], [0, 2], [0, 3], [4], [5, 7], [6], [4, 7], []]; + const expected = [[7], [6, 5, 4], [3], [2, 1, 0]]; + expect(tarjan(input)).toStrictEqual(expected); + }); + + it("should return sccs where first scc cannot reach second scc", () => { + const input = [[1], [2], [0], [4], [5], [2, 3]]; + const expected = [[2, 1, 0], [5, 4, 3]]; + expect(tarjan(input)).toStrictEqual(expected); + }); + +}) + From c8a4b9827e6d44ec216355cc4186d636703a3816 Mon Sep 17 00:00:00 2001 From: Omar Ferreiro <27824673+IcarusTheFly@users.noreply.github.com> Date: Mon, 15 Jan 2024 23:41:22 +0100 Subject: [PATCH 087/107] docs: Remove not needed whitespaces in markdown files (#197) Co-authored-by: IcarusTheFly Co-authored-by: David Leal --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 920486e7..5af6436d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,14 +63,14 @@ should add unique value. #### Commit Messages Formatting - Prefer to use the [Conventional Commits](https://www.conventionalcommits.org/) format: `: `. If necessary, put any extra information in the description. -- Commit types include (but are not limited to): +- Commit types include (but are not limited to): - **docs**: Documentation only changes - **feat**: A new feature - **fix**: A bug fix - **test**: Adding or fixing tests - **chore**: CI / code quality / minor quality of life improvements -- **Examples**: +- **Examples**: - `feat: add quicksort algorithm` - `chore: fix spelling` - `fix: improper error message` From 9bea1357aa1605d20c02f75b62a0fae5f63709fd Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Wed, 31 Jan 2024 07:08:17 +0100 Subject: [PATCH 088/107] chore: add `upload_coverage_report.yml` (#224) * chore: add `upload_coverage_report.yml` * Update DIRECTORY.md --------- Co-authored-by: autoprettier --- .github/workflows/upload_coverage_report.yml | 32 ++++++++++++++++++++ .gitignore | 2 ++ DIRECTORY.md | 7 +++++ 3 files changed, 41 insertions(+) create mode 100644 .github/workflows/upload_coverage_report.yml diff --git a/.github/workflows/upload_coverage_report.yml b/.github/workflows/upload_coverage_report.yml new file mode 100644 index 00000000..0993cf49 --- /dev/null +++ b/.github/workflows/upload_coverage_report.yml @@ -0,0 +1,32 @@ +--- +name: upload_coverage_report + +'on': + workflow_dispatch: + push: + branches: + - master + pull_request: + +jobs: + upload_coverage_report: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "18.x" + + - name: Install dependencies + run: npm ci + + - name: Generate coverage report + run: npm test -- --coverage + + - name: Upload coverage to codecov + uses: codecov/codecov-action@v3 + with: + files: "coverage/coverage-final.json" + fail_ci_if_error: true +... diff --git a/.gitignore b/.gitignore index 1714facb..1cc076e7 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ yarn-error.log* # intelliJ workspace folder .idea + +/coverage diff --git a/DIRECTORY.md b/DIRECTORY.md index de534ede..3e6e6418 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -73,6 +73,7 @@ * [Tries](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/tries/tries.ts) ## Dynamic Programming + * [Coin Change](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/coin_change.ts) * [Knapsack](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/knapsack.ts) * [Lcs](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/lcs.ts) @@ -82,16 +83,20 @@ * [Dijkstra](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/dijkstra.ts) * [Floyd Warshall](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/floyd_warshall.ts) * [Johnson](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/johnson.ts) + * [Kosajaru](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/kosajaru.ts) * [Kruskal](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/kruskal.ts) * [Prim](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/prim.ts) + * [Tarjan](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/tarjan.ts) * Test * [Bellman Ford.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/bellman_ford.test.ts) * [Bipartite Graph.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/bipartite_graph.test.ts) * [Dijkstra.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/dijkstra.test.ts) * [Floyd Warshall.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/floyd_warshall.test.ts) * [Johnson.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/johnson.test.ts) + * [Kosajaru.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/kosajaru.test.ts) * [Kruskal.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/kruskal.test.ts) * [Prim.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/prim.test.ts) + * [Tarjan.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/graph/test/tarjan.test.ts) ## Maths * [Absolute Value](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/absolute_value.ts) @@ -103,6 +108,7 @@ * [Calculate Median](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/calculate_median.ts) * [Degrees To Radians](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/degrees_to_radians.ts) * [Digit Sum](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/digit_sum.ts) + * [Euler Totient](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/euler_totient.ts) * [Factorial](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/factorial.ts) * [Factors](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/factors.ts) * [Fibonacci](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/fibonacci.ts) @@ -123,6 +129,7 @@ * [Pascals Triangle](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/pascals_triangle.ts) * [Perfect Cube](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_cube.ts) * [Perfect Square](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_square.ts) + * [Prime Factorization](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/prime_factorization.ts) * [Primes](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/primes.ts) * [Pronic Number](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/pronic_number.ts) * [Radians To Degrees](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/radians_to_degrees.ts) From 296e4a5af4bf4dc3a921db96bd95e82112d0bb38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=86=E3=81=86=E3=81=86?= <143775446+ei-sugimoto@users.noreply.github.com> Date: Wed, 31 Jan 2024 23:01:30 +0900 Subject: [PATCH 089/107] feat: add perfect number (#221) * feat: add perfect numbers * Optimize isPerfectNumber function and update tests --- maths/perfect_number.ts | 27 +++++++++++++++++++++++++++ maths/test/perfect_numbers.test.ts | 18 ++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 maths/perfect_number.ts create mode 100644 maths/test/perfect_numbers.test.ts diff --git a/maths/perfect_number.ts b/maths/perfect_number.ts new file mode 100644 index 00000000..c528321a --- /dev/null +++ b/maths/perfect_number.ts @@ -0,0 +1,27 @@ +/** + * @function isPerfectNumber + * @abstract A function to determine if a number is a perfect number + * @param {number} n + * + * @example console.log(isPerfectNumber(6)) => true + * @example console.log(isPerfectNumber(28)) => true + * @example console.log(isPerfectNumber(12))=> false + */ + +export const isPerfectNumber = (n: number): boolean => { + if (n <= 0 || !Number.isInteger(n)) { + return false; + } + let sum = 1; + let sqrt = Math.sqrt(n); + for (let i = 2; i < sqrt; i++) { + if (n % i === 0) { + sum += i + n / i; + } + } + if (sqrt === Math.floor(sqrt)) { + sum += sqrt; + } + + return sum === n; +}; \ No newline at end of file diff --git a/maths/test/perfect_numbers.test.ts b/maths/test/perfect_numbers.test.ts new file mode 100644 index 00000000..7d2e92c9 --- /dev/null +++ b/maths/test/perfect_numbers.test.ts @@ -0,0 +1,18 @@ +import { isPerfectNumber } from "../perfect_number"; + +describe('perfect Numbers tests', () => { + it.each([ + [6, true], + [28, true], + [496, true], + [8128, true], + [12, false], + [42, false], + [100, false], + [0, false], + [-1, false], + [1.5, false], + ])('The return value of %i should be %s', (n, expectation) => { + expect(isPerfectNumber(n)).toBe(expectation); + }); +}); From 4f6cd6c264d047dcc1bf1045765f4d8968fee6d2 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Fri, 9 Feb 2024 18:01:56 +0100 Subject: [PATCH 090/107] tests: add missing tests of `isPalindrome` (#227) --- maths/test/is_palindrome.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maths/test/is_palindrome.test.ts b/maths/test/is_palindrome.test.ts index 23911cbf..ea15f48a 100644 --- a/maths/test/is_palindrome.test.ts +++ b/maths/test/is_palindrome.test.ts @@ -1,7 +1,7 @@ import { isPalindrome } from "../is_palindrome"; describe("isPalindrome", () => { - test.each([[5, true], [1234, false], [12321, true], [31343, false]])( + test.each([[0, true], [1, true], [5, true], [1234, false], [12321, true], [31343, false], [-1, false], [-11, false], [10, false]])( "correct output for %i", (nums, expected) => { expect(isPalindrome(nums)).toBe(expected); From 650d553366ad943ea7b12ea715cd46575a002d4a Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Wed, 14 Feb 2024 16:43:06 +0100 Subject: [PATCH 091/107] fix: handle squares properly in `isSquareFree` (#228) --- maths/is_square_free.ts | 2 +- maths/test/is_square_free.test.ts | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/maths/is_square_free.ts b/maths/is_square_free.ts index 0e55ab7f..79958a7a 100644 --- a/maths/is_square_free.ts +++ b/maths/is_square_free.ts @@ -14,7 +14,7 @@ export const isSquareFree = (n: number): boolean => { if (n % 2 === 0) n = n / 2; if (n % 2 === 0) return false; - for (let i: number = 3; i < Math.sqrt(n); i = i + 2) { + for (let i: number = 3; i <= Math.sqrt(n); i = i + 2) { if (n % i === 0) { n = n / i; if (n % i === 0) return false; diff --git a/maths/test/is_square_free.test.ts b/maths/test/is_square_free.test.ts index bbb16991..c2eeb99d 100644 --- a/maths/test/is_square_free.test.ts +++ b/maths/test/is_square_free.test.ts @@ -1,11 +1,14 @@ import { isSquareFree } from '../is_square_free'; describe('isSquareFree', () => { - test('should return correct boolean value', () => { - expect(isSquareFree(1)).toBe(true); - expect(isSquareFree(10)).toBe(true); - expect(isSquareFree(20)).toBe(false); - expect(isSquareFree(26)).toBe(true); - expect(isSquareFree(48)).toBe(false); + test.each([1, 2, 3, 5, 7, 10, 26, 2*3, 3*5*7, 11*13*17*19])( + "%i is square free", + (input) => { + expect(isSquareFree(input)).toBe(true); }); -}); \ No newline at end of file + test.each([20, 48, 2*7*7, 2*3*3, 5*5*7, 2*3*13*13*17, 4*4*4, 2*2, 3*3, 5*5, 100, 0])( + "%i is not square free", + (input) => { + expect(isSquareFree(input)).toBe(false); + }); +}); From 24cbb3bc5e7cbc75e50dace885fd9feed2a4ef1c Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Wed, 14 Feb 2024 16:44:43 +0100 Subject: [PATCH 092/107] test: cleanup `square_root.test.ts` (#229) --- maths/test/square_root.test.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/maths/test/square_root.test.ts b/maths/test/square_root.test.ts index 3dbd8658..366f867c 100644 --- a/maths/test/square_root.test.ts +++ b/maths/test/square_root.test.ts @@ -9,20 +9,16 @@ describe("squareRoot", () => { ); test.each([0, 1, 4, 9, 16, 25])( - "should return correct rational square root value", - () => { - (n: number) => { - expect(() => squareRoot(n)).toBeCloseTo(Math.sqrt(n)); - }; + "should return correct rational square root value for %i", + (n: number) => { + expect(squareRoot(n)).toBeCloseTo(Math.sqrt(n)); } ); test.each([2, 15, 20, 40, 99, 10032])( - "should return correct irrational square root value", - () => { - (n: number) => { - expect(() => squareRoot(n)).toBeCloseTo(Math.sqrt(n)); - }; + "should return correct irrational square root value %i", + (n: number) => { + expect(squareRoot(n)).toBeCloseTo(Math.sqrt(n)); } ); }); From 23ba61bf2aa8462786310d9b20d070c69d6a1743 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Wed, 14 Feb 2024 16:45:20 +0100 Subject: [PATCH 093/107] style: fix basic eslint warnings (#230) --- backtracking/all_combinations_of_size_k.ts | 4 ++-- bit_manipulation/add_binary.ts | 2 +- data_structures/heap/heap.ts | 8 +++---- data_structures/heap/test/heap.test.ts | 6 ++--- data_structures/queue/linked_queue.ts | 2 +- .../stack/test/linked_list_stack.test.ts | 2 +- dynamic_programming/knapsack.ts | 2 +- graph/bellman_ford.ts | 2 +- graph/dijkstra.ts | 6 ++--- graph/floyd_warshall.ts | 4 ++-- graph/johnson.ts | 14 +++++------ graph/kosajaru.ts | 10 ++++---- graph/kruskal.ts | 6 ++--- graph/prim.ts | 10 ++++---- graph/tarjan.ts | 12 +++++----- graph/test/bellman_ford.test.ts | 12 +++++----- graph/test/dijkstra.test.ts | 8 +++---- graph/test/floyd_warshall.test.ts | 10 ++++---- graph/test/johnson.test.ts | 22 ++++++++--------- graph/test/kruskal.test.ts | 22 ++++++++--------- graph/test/prim.test.ts | 24 +++++++++---------- maths/calculate_median.ts | 4 ++-- maths/matrix_multiplication.ts | 2 +- maths/pascals_triangle.ts | 6 ++--- maths/perfect_number.ts | 2 +- maths/prime_factorization.ts | 2 +- sorts/bubble_sort.ts | 2 +- sorts/quick_select.ts | 2 +- sorts/swap_sort.ts | 2 +- sorts/test/merge_sort.test.ts | 6 ++--- 30 files changed, 108 insertions(+), 108 deletions(-) diff --git a/backtracking/all_combinations_of_size_k.ts b/backtracking/all_combinations_of_size_k.ts index c2316982..23ee3760 100644 --- a/backtracking/all_combinations_of_size_k.ts +++ b/backtracking/all_combinations_of_size_k.ts @@ -10,8 +10,8 @@ * and repeat the same process for the next number. */ export function generateCombinations(n: number, k: number): number[][] { - let combinationsAcc: number[][] = []; - let currentCombination: number[] = []; + const combinationsAcc: number[][] = []; + const currentCombination: number[] = []; function generateAllCombos( n: number, diff --git a/bit_manipulation/add_binary.ts b/bit_manipulation/add_binary.ts index ebc05440..38ca43af 100644 --- a/bit_manipulation/add_binary.ts +++ b/bit_manipulation/add_binary.ts @@ -8,7 +8,7 @@ export function addBinary(firstBinaryNo: string, secondBinaryNo: string): string { let lengthOfFirstNumber: number = firstBinaryNo.length - 1; let lengthOfSecondNumber: number = secondBinaryNo.length - 1; - let solution: string[] = []; + const solution: string[] = []; let carry: number = 0; while ( lengthOfFirstNumber >= 0 || lengthOfSecondNumber >= 0) { diff --git a/data_structures/heap/heap.ts b/data_structures/heap/heap.ts index 5f8e8974..b5ab0ebc 100644 --- a/data_structures/heap/heap.ts +++ b/data_structures/heap/heap.ts @@ -50,7 +50,7 @@ export abstract class Heap { } public extract(): T { - let maxElement = this.heap[0]; + const maxElement = this.heap[0]; this.heap[0] = this.heap[this.size() - 1]; this.heap.pop(); this.sinkDown(); @@ -162,8 +162,8 @@ export class PriorityQueue extends MinHeap { } protected swap(a: number, b: number) { - let akey = this.keys_index(this.heap[a]); - let bkey = this.keys_index(this.heap[b]); + const akey = this.keys_index(this.heap[a]); + const bkey = this.keys_index(this.heap[b]); [this.keys[akey], this.keys[bkey]] = [this.keys[bkey], this.keys[akey]]; super.swap(a, b); } @@ -188,7 +188,7 @@ export class PriorityQueue extends MinHeap { this.insert(value); return; } - let key = this.keys[idx]; + const key = this.keys[idx]; if (this.compare(this.heap[key], value)) { // Do not do anything if the value in the heap already has a higher priority. return; diff --git a/data_structures/heap/test/heap.test.ts b/data_structures/heap/test/heap.test.ts index 9dc8f041..3b90fc9b 100644 --- a/data_structures/heap/test/heap.test.ts +++ b/data_structures/heap/test/heap.test.ts @@ -8,7 +8,7 @@ describe("MaxHeap", () => { beforeEach(() => { heap = new MaxHeap(); - for (let element of elements) { + for (const element of elements) { heap.insert(element); } }); @@ -61,7 +61,7 @@ describe("MinHeap", () => { beforeEach(() => { heap = new MinHeap(); - for (let element of elements) { + for (const element of elements) { heap.insert(element); } }); @@ -106,7 +106,7 @@ describe("MinHeap", () => { }); it("should increase priority", () => { - let heap = new PriorityQueue((a: number) => { return a; }, elements.length); + const heap = new PriorityQueue((a: number) => { return a; }, elements.length); elements.forEach((element: number) => { heap.insert(element); }); diff --git a/data_structures/queue/linked_queue.ts b/data_structures/queue/linked_queue.ts index c67c8285..bc90bd52 100644 --- a/data_structures/queue/linked_queue.ts +++ b/data_structures/queue/linked_queue.ts @@ -55,7 +55,7 @@ export class LinkedQueue implements Queue { } this.size--; - let head = this.head; // We store the head in order not to lose track of it + const head = this.head; // We store the head in order not to lose track of it this.head = this.head.next; // Update the the head to the next node return head.value; // Return the value of the head } diff --git a/data_structures/stack/test/linked_list_stack.test.ts b/data_structures/stack/test/linked_list_stack.test.ts index 2efc03d3..54f47c48 100644 --- a/data_structures/stack/test/linked_list_stack.test.ts +++ b/data_structures/stack/test/linked_list_stack.test.ts @@ -1,7 +1,7 @@ import { LinkedListStack } from "../linked_list_stack"; describe("Linked List Stack", () => { - let stack: LinkedListStack = new LinkedListStack(4); + const stack: LinkedListStack = new LinkedListStack(4); stack.push(1); stack.push(2); diff --git a/dynamic_programming/knapsack.ts b/dynamic_programming/knapsack.ts index 9be8a41a..f4026b1d 100644 --- a/dynamic_programming/knapsack.ts +++ b/dynamic_programming/knapsack.ts @@ -23,7 +23,7 @@ export const knapsack = ( const numberOfItems = weights.length; // Declaring a data structure to store calculated states/values - let dp: number[][] = new Array(numberOfItems + 1); + const dp: number[][] = new Array(numberOfItems + 1); for (let i = 0; i < dp.length; i++) { // Placing an array at each index of dp to make it a 2d matrix diff --git a/graph/bellman_ford.ts b/graph/bellman_ford.ts index 70e326d2..d3a901b3 100644 --- a/graph/bellman_ford.ts +++ b/graph/bellman_ford.ts @@ -12,7 +12,7 @@ export const bellmanFord = (graph: [number, number][][], start: number): number[] | undefined => { // We save the shortest distance to each node in `distances`. If a node is // unreachable from the start node, its distance is Infinity. - let distances = Array(graph.length).fill(Infinity); + const distances = Array(graph.length).fill(Infinity); distances[start] = 0; // On the i'th iteration, we compute all shortest paths that consists of i+1 diff --git a/graph/dijkstra.ts b/graph/dijkstra.ts index 1d5c05ae..edec2746 100644 --- a/graph/dijkstra.ts +++ b/graph/dijkstra.ts @@ -13,17 +13,17 @@ import { MinHeap, PriorityQueue } from '../data_structures/heap/heap'; export const dijkstra = (graph: [number, number][][], start: number): number[] => { // We use a priority queue to make sure we always visit the closest node. The // queue makes comparisons based on path weights. - let priorityQueue = new PriorityQueue((a: [number, number]) => { return a[0] }, graph.length, (a: [number, number], b: [number, number]) => { return a[1] < b[1] }); + const priorityQueue = new PriorityQueue((a: [number, number]) => { return a[0] }, graph.length, (a: [number, number], b: [number, number]) => { return a[1] < b[1] }); priorityQueue.insert([start, 0]); // We save the shortest distance to each node in `distances`. If a node is // unreachable from the start node, its distance is Infinity. - let distances = Array(graph.length).fill(Infinity); + const distances = Array(graph.length).fill(Infinity); distances[start] = 0; while (priorityQueue.size() > 0) { const [node, _] = priorityQueue.extract(); graph[node].forEach(([child, weight]) => { - let new_distance = distances[node] + weight; + const new_distance = distances[node] + weight; if (new_distance < distances[child]) { // Found a new shortest path to child node. Record its distance and add child to the queue. // If the child already exists in the queue, the priority will be updated. This will make sure the queue will be at most size V (number of vertices). diff --git a/graph/floyd_warshall.ts b/graph/floyd_warshall.ts index c8addc46..372b6712 100644 --- a/graph/floyd_warshall.ts +++ b/graph/floyd_warshall.ts @@ -10,12 +10,12 @@ */ export const floydWarshall = (graph: number[][]): number[][] => { let distances = structuredClone(graph); - let N = graph.length; + const N = graph.length; // We begin by setting the weighted adjacency matrix as the shortest paths. // For the k'th iteration, we try to relax the shortest paths by including node k in the path. for (let k = 0; k < N; ++k) { - let newDistances = []; + const newDistances = []; for (let i = 0; i < N; ++i) { newDistances.push(Array(N).fill(Infinity)); } diff --git a/graph/johnson.ts b/graph/johnson.ts index 7eac28ac..ea0204c7 100644 --- a/graph/johnson.ts +++ b/graph/johnson.ts @@ -12,25 +12,25 @@ import { dijkstra } from './dijkstra' * @see https://en.wikipedia.org/wiki/Johnson%27s_algorithm */ export const johnson = (graph: [number, number][][]): number[][] | undefined => { - let N = graph.length; + const N = graph.length; // Add a new node and 0 weighted edges from the new node to all existing nodes. - let newNodeGraph = structuredClone(graph); - let newNode: [number, number][] = []; + const newNodeGraph = structuredClone(graph); + const newNode: [number, number][] = []; for (let i = 0; i < N; ++i) { newNode.push([i, 0]); } newNodeGraph.push(newNode); // Compute distances from the new node to existing nodes using the Bellman-Ford algorithm. - let adjustedGraph = bellmanFord(newNodeGraph, N); + const adjustedGraph = bellmanFord(newNodeGraph, N); if (adjustedGraph === undefined) { // Found a negative weight cycle. return undefined; } for (let i = 0; i < N; ++i) { - for (let edge of graph[i]) { + for (const edge of graph[i]) { // Adjust edge weights using the Bellman Ford output weights. This ensure that: // 1. Each weight is non-negative. This is required for the Dijkstra algorithm. // 2. The shortest path from node i to node j consists of the same nodes with or without adjustment. @@ -38,10 +38,10 @@ export const johnson = (graph: [number, number][][]): number[][] | undefined => } } - let shortestPaths: number[][] = []; + const shortestPaths: number[][] = []; for (let i = 0; i < N; ++i) { // Compute Dijkstra weights for each node and re-adjust weights to their original values. - let dijkstraShorestPaths = dijkstra(graph, i); + const dijkstraShorestPaths = dijkstra(graph, i); for (let j = 0; j < N; ++j) { dijkstraShorestPaths[j] += adjustedGraph[j] - adjustedGraph[i]; } diff --git a/graph/kosajaru.ts b/graph/kosajaru.ts index 32338e76..d1498b0b 100644 --- a/graph/kosajaru.ts +++ b/graph/kosajaru.ts @@ -14,7 +14,7 @@ const getNodePriorities = (graph: number[][], visited: boolean[], stack: number[ // Return the transpose of graph. The tranpose of a directed graph is a graph where each of the edges are flipped. const transpose = (graph: number[][]): number[][] => { - let transposedGraph = Array(graph.length); + const transposedGraph = Array(graph.length); for (let i = 0; i < graph.length; ++i) { transposedGraph[i] = []; } @@ -52,20 +52,20 @@ const gatherScc = (graph: number[][], visited: boolean[], node: number, scc: num * @see https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm */ export const kosajaru = (graph: number[][]): number[][] => { - let visited = Array(graph.length).fill(false); + const visited = Array(graph.length).fill(false); - let stack: number[] = []; + const stack: number[] = []; for (let i = 0; i < graph.length; ++i) { getNodePriorities(graph, visited, stack, i); } const transposedGraph = transpose(graph); - let sccs = []; + const sccs = []; visited.fill(false); for (let i = stack.length - 1; i >= 0; --i) { if (!visited[stack[i]]) { - let scc: number[] = []; + const scc: number[] = []; gatherScc(transposedGraph, visited, stack[i], scc); sccs.push(scc); } diff --git a/graph/kruskal.ts b/graph/kruskal.ts index 073b62b1..750eb15f 100644 --- a/graph/kruskal.ts +++ b/graph/kruskal.ts @@ -13,15 +13,15 @@ import { DisjointSet } from '../data_structures/disjoint_set/disjoint_set'; */ export const kruskal = (edges: Edge[], num_vertices: number): [Edge[], number] => { let cost = 0; - let minimum_spanning_tree = []; + const minimum_spanning_tree = []; // Use a disjoint set to quickly join sets and find if vertices live in different sets - let sets = new DisjointSet(num_vertices); + const sets = new DisjointSet(num_vertices); // Sort the edges in ascending order by weight so that we can greedily add cheaper edges to the tree edges.sort((a, b) => a.weight - b.weight); - for (let edge of edges) { + for (const edge of edges) { if (sets.find(edge.a) !== sets.find(edge.b)) { // Node A and B live in different sets. Add edge(a, b) to the tree and join the nodes' sets together. minimum_spanning_tree.push(edge); diff --git a/graph/prim.ts b/graph/prim.ts index 5c36479a..722c1e16 100644 --- a/graph/prim.ts +++ b/graph/prim.ts @@ -13,11 +13,11 @@ export const prim = (graph: [number, number][][]): [Edge[], number] => { if (graph.length == 0) { return [[], 0]; } - let minimum_spanning_tree: Edge[] = []; + const minimum_spanning_tree: Edge[] = []; let total_weight = 0; - let priorityQueue = new PriorityQueue((e: Edge) => { return e.b }, graph.length, (a: Edge, b: Edge) => { return a.weight < b.weight }); - let visited = new Set(); + const priorityQueue = new PriorityQueue((e: Edge) => { return e.b }, graph.length, (a: Edge, b: Edge) => { return a.weight < b.weight }); + const visited = new Set(); // Start from the 0'th node. For fully connected graphs, we can start from any node and still produce the MST. visited.add(0); @@ -25,7 +25,7 @@ export const prim = (graph: [number, number][][]): [Edge[], number] => { while (!priorityQueue.isEmpty()) { // We have already visited vertex `edge.a`. If we have not visited `edge.b` yet, we add its outgoing edges to the PriorityQueue. - let edge = priorityQueue.extract(); + const edge = priorityQueue.extract(); if (visited.has(edge.b)) { continue; } @@ -40,7 +40,7 @@ export const prim = (graph: [number, number][][]): [Edge[], number] => { const add_children = (graph: [number, number][][], priorityQueue: PriorityQueue, node: number) => { for (let i = 0; i < graph[node].length; ++i) { - let out_edge = graph[node][i]; + const out_edge = graph[node][i]; // By increasing the priority, we ensure we only add each vertex to the queue one time, and the queue will be at most size V. priorityQueue.increasePriority(out_edge[0], new Edge(node, out_edge[0], out_edge[1])); } diff --git a/graph/tarjan.ts b/graph/tarjan.ts index 7f2a2454..27de35a7 100644 --- a/graph/tarjan.ts +++ b/graph/tarjan.ts @@ -15,14 +15,14 @@ export const tarjan = (graph: number[][]): number[][] => { let index = 0; // The order in which we discover nodes - let discovery: number[] = Array(graph.length); + const discovery: number[] = Array(graph.length); // For each node, holds the furthest ancestor it can reach - let low: number[] = Array(graph.length).fill(undefined); + const low: number[] = Array(graph.length).fill(undefined); // Holds the nodes we have visited in a DFS traversal and are considering to group into a SCC - let stack: number[] = []; + const stack: number[] = []; // Holds the elements in the stack. - let stackContains = Array(graph.length).fill(false); - let sccs: number[][] = []; + const stackContains = Array(graph.length).fill(false); + const sccs: number[][] = []; const dfs = (node: number) => { discovery[node] = index; @@ -46,7 +46,7 @@ export const tarjan = (graph: number[][]): number[][] => { if (discovery[node] == low[node]) { // node is the root of a SCC. Gather the SCC's nodes from the stack. - let scc: number[] = []; + const scc: number[] = []; let i; for (i = stack.length - 1; stack[i] != node; --i) { scc.push(stack[i]); diff --git a/graph/test/bellman_ford.test.ts b/graph/test/bellman_ford.test.ts index 77928a63..f99ee907 100644 --- a/graph/test/bellman_ford.test.ts +++ b/graph/test/bellman_ford.test.ts @@ -1,7 +1,7 @@ import { bellmanFord } from "../bellman_ford"; const init_graph = (N: number): [number, number][][] => { - let graph = Array(N); + const graph = Array(N); for (let i = 0; i < N; ++i) { graph[i] = []; } @@ -16,7 +16,7 @@ describe("bellmanFord", () => { } it("should return the correct value", () => { - let graph = init_graph(9); + const graph = init_graph(9); add_edge(graph, 0, 1, 4); add_edge(graph, 0, 7, 8); add_edge(graph, 1, 2, 8); @@ -38,7 +38,7 @@ describe("bellmanFord", () => { expect(bellmanFord([[]], 0)).toStrictEqual([0]); }); - let linear_graph = init_graph(4); + const linear_graph = init_graph(4); add_edge(linear_graph, 0, 1, 1); add_edge(linear_graph, 1, 2, 2); add_edge(linear_graph, 2, 3, 3); @@ -49,7 +49,7 @@ describe("bellmanFord", () => { } ); - let unreachable_graph = init_graph(3); + const unreachable_graph = init_graph(3); add_edge(unreachable_graph, 0, 1, 1); test.each([[0, [0, 1, Infinity]], [1, [1, 0, Infinity]], [2, [Infinity, Infinity, 0]]])( "correct result for graph with unreachable nodes with source node %i", @@ -61,7 +61,7 @@ describe("bellmanFord", () => { describe("bellmanFord negative cycle graphs", () => { it("should returned undefined for 2-node graph with negative cycle", () => { - let basic = init_graph(2); + const basic = init_graph(2); basic[0].push([1, 2]); basic[1].push([0, -3]); expect(bellmanFord(basic, 0)).toStrictEqual(undefined); @@ -69,7 +69,7 @@ describe("bellmanFord negative cycle graphs", () => { }); it("should returned undefined for graph with negative cycle", () => { - let negative = init_graph(5); + const negative = init_graph(5); negative[0].push([1, 6]); negative[0].push([3, 7]); negative[1].push([2, 5]); diff --git a/graph/test/dijkstra.test.ts b/graph/test/dijkstra.test.ts index eacf2e68..dfd0f436 100644 --- a/graph/test/dijkstra.test.ts +++ b/graph/test/dijkstra.test.ts @@ -3,7 +3,7 @@ import { dijkstra } from "../dijkstra"; describe("dijkstra", () => { const init_graph = (N: number): [number, number][][] => { - let graph = Array(N); + const graph = Array(N); for (let i = 0; i < N; ++i) { graph[i] = []; } @@ -16,7 +16,7 @@ describe("dijkstra", () => { } it("should return the correct value", () => { - let graph = init_graph(9); + const graph = init_graph(9); add_edge(graph, 0, 1, 4); add_edge(graph, 0, 7, 8); add_edge(graph, 1, 2, 8); @@ -38,7 +38,7 @@ describe("dijkstra", () => { expect(dijkstra([[]], 0)).toStrictEqual([0]); }); - let linear_graph = init_graph(4); + const linear_graph = init_graph(4); add_edge(linear_graph, 0, 1, 1); add_edge(linear_graph, 1, 2, 2); add_edge(linear_graph, 2, 3, 3); @@ -49,7 +49,7 @@ describe("dijkstra", () => { } ); - let unreachable_graph = init_graph(3); + const unreachable_graph = init_graph(3); add_edge(unreachable_graph, 0, 1, 1); test.each([[0, [0, 1, Infinity]], [1, [1, 0, Infinity]], [2, [Infinity, Infinity, 0]]])( "correct result for graph with unreachable nodes with source node %i", diff --git a/graph/test/floyd_warshall.test.ts b/graph/test/floyd_warshall.test.ts index 33cc67dc..81c04bdf 100644 --- a/graph/test/floyd_warshall.test.ts +++ b/graph/test/floyd_warshall.test.ts @@ -14,16 +14,16 @@ describe("floydWarshall", () => { }); it("should return the correct value", () => { - let graph = []; + const graph = []; for (let i = 1; i <= 5; ++i) { - let arr = []; + const arr = []; for (let j = 1; j <= 5; ++j) { arr.push(i * j); } graph.push(arr); } - let expected = [ + const expected = [ [ 1, 2, 3, 4, 5 ], [ 2, 4, 5, 6, 7 ], [ 3, 5, 6, 7, 8 ], @@ -34,7 +34,7 @@ describe("floydWarshall", () => { }); it("should return the correct value", () => { - let graph = [ + const graph = [ [0, 4, Infinity, Infinity, Infinity, Infinity, Infinity, 8, Infinity], [4, 0, 8, Infinity, Infinity, Infinity, Infinity, 11, Infinity], [Infinity, 8, 0, 7, Infinity, 4, Infinity, Infinity, 2], @@ -46,7 +46,7 @@ describe("floydWarshall", () => { [Infinity, Infinity, 2, Infinity, Infinity, Infinity, 6, 7, 0] ]; - let expected = [ + const expected = [ [0, 4, 12, 19, 21, 11, 9, 8, 14], [4, 0, 8, 15, 22, 12, 12, 11, 10], [12, 8, 0, 7, 14, 4, 6, 7, 2], diff --git a/graph/test/johnson.test.ts b/graph/test/johnson.test.ts index 24600879..625bb993 100644 --- a/graph/test/johnson.test.ts +++ b/graph/test/johnson.test.ts @@ -3,7 +3,7 @@ import { johnson } from "../johnson"; describe("johnson", () => { const init_graph = (N: number): [number, number][][] => { - let graph = Array(N); + const graph = Array(N); for (let i = 0; i < N; ++i) { graph[i] = []; } @@ -16,7 +16,7 @@ describe("johnson", () => { } it("should return the correct value", () => { - let graph = init_graph(9); + const graph = init_graph(9); add_edge(graph, 0, 1, 4); add_edge(graph, 0, 7, 8); add_edge(graph, 1, 2, 8); @@ -32,7 +32,7 @@ describe("johnson", () => { add_edge(graph, 6, 8, 6); add_edge(graph, 7, 8, 7); - let expected = [ + const expected = [ [0, 4, 12, 19, 21, 11, 9, 8, 14], [4, 0, 8, 15, 22, 12, 12, 11, 10], [12, 8, 0, 7, 14, 4, 6, 7, 2], @@ -47,14 +47,14 @@ describe("johnson", () => { }); it("should return the correct value for graph with negative weights", () => { - let graph = init_graph(4); + const graph = init_graph(4); graph[0].push([1, -5]); graph[0].push([2, 2]); graph[0].push([3, 3]); graph[1].push([2, 4]); graph[2].push([3, 1]); - let expected = [ + const expected = [ [ 0, -5, -1, 0 ], [ Infinity, 0, 4, 5 ], [ Infinity, Infinity, 0, 1 ], @@ -64,13 +64,13 @@ describe("johnson", () => { }); it("should return the undefined for two node graph with negative-weight cycle", () => { - let graph = init_graph(2); + const graph = init_graph(2); add_edge(graph, 0, 1, -1); expect(johnson(graph)).toStrictEqual(undefined); }); it("should return the undefined for three node graph with negative-weight cycle", () => { - let graph = init_graph(3); + const graph = init_graph(3); graph[0].push([1, -1]); graph[0].push([2, 7]); graph[1].push([2, -5]); @@ -87,20 +87,20 @@ describe("johnson", () => { }); it("should return the correct value for a linear graph", () => { - let linear_graph = init_graph(4); + const linear_graph = init_graph(4); add_edge(linear_graph, 0, 1, 1); add_edge(linear_graph, 1, 2, 2); add_edge(linear_graph, 2, 3, 3); - let expected = [[0, 1, 3, 6 ], [1, 0, 2, 5], [3, 2, 0, 3], [6, 5, 3, 0]]; + const expected = [[0, 1, 3, 6 ], [1, 0, 2, 5], [3, 2, 0, 3], [6, 5, 3, 0]]; expect(johnson(linear_graph)).toStrictEqual(expected); }); it("should return the correct value for a linear graph with unreachable node", () => { - let linear_graph = init_graph(3); + const linear_graph = init_graph(3); add_edge(linear_graph, 0, 1, 1); - let expected = [[0, 1, Infinity], [1, 0, Infinity], [Infinity, Infinity, 0]]; + const expected = [[0, 1, Infinity], [1, 0, Infinity], [Infinity, Infinity, 0]]; expect(johnson(linear_graph)).toStrictEqual(expected); }); }) diff --git a/graph/test/kruskal.test.ts b/graph/test/kruskal.test.ts index 7f3db6c0..f5490931 100644 --- a/graph/test/kruskal.test.ts +++ b/graph/test/kruskal.test.ts @@ -1,12 +1,12 @@ import { Edge, kruskal } from "../kruskal"; -let test_graph = (expected_tree_edges: Edge[], other_edges: Edge[], num_vertices: number, expected_cost: number) => { - let [tree_edges, cost] = kruskal(expected_tree_edges.concat(other_edges), num_vertices); +const test_graph = (expected_tree_edges: Edge[], other_edges: Edge[], num_vertices: number, expected_cost: number) => { + const [tree_edges, cost] = kruskal(expected_tree_edges.concat(other_edges), num_vertices); expect(cost).toStrictEqual(expected_cost); - for (let expected_edge of expected_tree_edges) { + for (const expected_edge of expected_tree_edges) { expect(tree_edges.includes(expected_edge)).toBeTruthy(); } - for (let unexpected_edge of other_edges) { + for (const unexpected_edge of other_edges) { expect(tree_edges.includes(unexpected_edge)).toBeFalsy(); } }; @@ -28,13 +28,13 @@ describe("kruskal", () => { }); it("should return the correct value", () => { - let expected_tree_edges = [ + const expected_tree_edges = [ new Edge(0, 1, 1), new Edge(1, 3, 2), new Edge(2, 3, 3), ]; - let other_edges = [ + const other_edges = [ new Edge(0, 2, 4), new Edge(0, 3, 5), new Edge(1, 2, 6), @@ -44,7 +44,7 @@ describe("kruskal", () => { }); it("should return the correct value", () => { - let expected_tree_edges = [ + const expected_tree_edges = [ new Edge(0, 2, 2), new Edge(1, 3, 9), new Edge(2, 6, 74), @@ -56,7 +56,7 @@ describe("kruskal", () => { new Edge(8, 9, 2), ] - let other_edges = [ + const other_edges = [ new Edge(0, 1, 10), new Edge(2, 4, 47), new Edge(4, 5, 42), @@ -69,12 +69,12 @@ describe("kruskal", () => { describe("kruskal forest", () => { it("should return empty tree for forest of 2 node trees", () => { - let edges = [new Edge(0, 1, 10), new Edge(2, 3, 15)]; + const edges = [new Edge(0, 1, 10), new Edge(2, 3, 15)]; test_graph(edges, [], 4, 25); }); it("should return the correct value", () => { - let expected_tree_edges = [ + const expected_tree_edges = [ // Tree 1 new Edge(0, 2, 2), new Edge(1, 3, 9), @@ -92,7 +92,7 @@ describe("kruskal forest", () => { new Edge(12, 13, 3), ] - let other_edges = [ + const other_edges = [ // Tree 1 new Edge(0, 1, 10), new Edge(2, 4, 47), diff --git a/graph/test/prim.test.ts b/graph/test/prim.test.ts index 763f1716..b9dac96c 100644 --- a/graph/test/prim.test.ts +++ b/graph/test/prim.test.ts @@ -1,30 +1,30 @@ import { Edge, prim } from "../prim"; -let edge_equal = (x: Edge, y: Edge): boolean => { +const edge_equal = (x: Edge, y: Edge): boolean => { return (x.a == y.a && x.b == y.b) || (x.a == y.b && x.b == y.a) && x.weight == y.weight; } -let test_graph = (expected_tree_edges: Edge[], other_edges: Edge[], num_vertices: number, expected_cost: number) => { +const test_graph = (expected_tree_edges: Edge[], other_edges: Edge[], num_vertices: number, expected_cost: number) => { // First make sure the graph is undirected - let graph: [number, number][][] = []; + const graph: [number, number][][] = []; for (let _ = 0; _ < num_vertices; ++_) { graph.push([]); } - for (let edge of expected_tree_edges) { + for (const edge of expected_tree_edges) { graph[edge.a].push([edge.b, edge.weight]); graph[edge.b].push([edge.a, edge.weight]); } - for (let edge of other_edges) { + for (const edge of other_edges) { graph[edge.a].push([edge.b, edge.weight]); graph[edge.b].push([edge.a, edge.weight]); } - let [tree_edges, cost] = prim(graph); + const [tree_edges, cost] = prim(graph); expect(cost).toStrictEqual(expected_cost); - for (let expected_edge of expected_tree_edges) { + for (const expected_edge of expected_tree_edges) { expect(tree_edges.find(edge => edge_equal(edge, expected_edge))).toBeTruthy(); } - for (let unexpected_edge of other_edges) { + for (const unexpected_edge of other_edges) { expect(tree_edges.find(edge => edge_equal(edge, unexpected_edge))).toBeFalsy(); } }; @@ -45,13 +45,13 @@ describe("prim", () => { }); it("should return the correct value", () => { - let expected_tree_edges = [ + const expected_tree_edges = [ new Edge(0, 1, 1), new Edge(1, 3, 2), new Edge(3, 2, 3), ]; - let other_edges = [ + const other_edges = [ new Edge(0, 2, 4), new Edge(0, 3, 5), new Edge(1, 2, 6), @@ -61,7 +61,7 @@ describe("prim", () => { }); it("should return the correct value", () => { - let expected_tree_edges = [ + const expected_tree_edges = [ new Edge(0, 2, 2), new Edge(1, 3, 9), new Edge(2, 6, 74), @@ -73,7 +73,7 @@ describe("prim", () => { new Edge(8, 9, 2), ] - let other_edges = [ + const other_edges = [ new Edge(0, 1, 10), new Edge(2, 4, 47), new Edge(4, 5, 42), diff --git a/maths/calculate_median.ts b/maths/calculate_median.ts index 5a6c98bc..27c8cac4 100644 --- a/maths/calculate_median.ts +++ b/maths/calculate_median.ts @@ -16,10 +16,10 @@ export const calculateMedian = (numbers: number[]): number => { const totalNumbers = numbers.length; if (totalNumbers % 2 === 0) { - let index = totalNumbers / 2; + const index = totalNumbers / 2; return (numbers[index - 1] + numbers[index]) / 2; } else { - let index = (totalNumbers + 1) / 2; + const index = (totalNumbers + 1) / 2; return numbers[index - 1]; } }; diff --git a/maths/matrix_multiplication.ts b/maths/matrix_multiplication.ts index 78b861aa..99a475f9 100644 --- a/maths/matrix_multiplication.ts +++ b/maths/matrix_multiplication.ts @@ -13,7 +13,7 @@ function matrixMultiplication(matA: number[][], b: number[][]): number[][]; function matrixMultiplication(matA: number[][], b: number): number[][]; function matrixMultiplication(matA: number[][], b: number[]): number[]; -function matrixMultiplication(matA: number[][], b: any): Number[][] | Number[] | null { +function matrixMultiplication(matA: number[][], b: any): number[][] | number[] | null { let matC: any = null; if (typeof b === 'number') { diff --git a/maths/pascals_triangle.ts b/maths/pascals_triangle.ts index cce4bfd1..337c77c6 100644 --- a/maths/pascals_triangle.ts +++ b/maths/pascals_triangle.ts @@ -15,15 +15,15 @@ * @see https://en.wikipedia.org/wiki/Pascal's_triangle */ export const pascalsTriangle = (n: number): number[] => { - let arr: number[][] = []; + const arr: number[][] = []; for (let i: number = 0; i < n; i++) { if (i === 0) { arr.push([1]); continue; } - let lastRow: number[] = arr[i - 1]; - let temp: number[] = []; + const lastRow: number[] = arr[i - 1]; + const temp: number[] = []; for (let j: number = 0; j < lastRow.length + 1; j++) { if (j === 0 || j === lastRow.length) { temp.push(1); diff --git a/maths/perfect_number.ts b/maths/perfect_number.ts index c528321a..9dec9024 100644 --- a/maths/perfect_number.ts +++ b/maths/perfect_number.ts @@ -13,7 +13,7 @@ export const isPerfectNumber = (n: number): boolean => { return false; } let sum = 1; - let sqrt = Math.sqrt(n); + const sqrt = Math.sqrt(n); for (let i = 2; i < sqrt; i++) { if (n % i === 0) { sum += i + n / i; diff --git a/maths/prime_factorization.ts b/maths/prime_factorization.ts index 19032730..872422e1 100644 --- a/maths/prime_factorization.ts +++ b/maths/prime_factorization.ts @@ -7,7 +7,7 @@ * @example factorize(5) = Map {5 => 1} */ export const factorize = (n: number): Map => { - let result: Map = new Map(); + const result: Map = new Map(); for (let i = 2; i * i <= n; i++) { while (n % i == 0) { diff --git a/sorts/bubble_sort.ts b/sorts/bubble_sort.ts index 8bbd1a21..3086051e 100644 --- a/sorts/bubble_sort.ts +++ b/sorts/bubble_sort.ts @@ -22,7 +22,7 @@ export const bubbleSort = (arr: number[]): number[] => { for (let i = 0; i < arr.length; i++) { for (let j = 0; j < arr.length-1; j++) { //iterating till the 2nd last element of array if (arr[j] > arr[j+1]) { //current indexed number > next indexed number - let temp: number = arr[j]; //swapping two numbers + const temp: number = arr[j]; //swapping two numbers arr[j] = arr[j+1]; arr[j+1] = temp; } diff --git a/sorts/quick_select.ts b/sorts/quick_select.ts index 23381ee2..91d03bfc 100644 --- a/sorts/quick_select.ts +++ b/sorts/quick_select.ts @@ -25,7 +25,7 @@ export const QuickSelect = ( } // Partition the array - let pivotIndex = partition(array, left, right); + const pivotIndex = partition(array, left, right); // The pivot is in its final sorted position if (k === pivotIndex) { diff --git a/sorts/swap_sort.ts b/sorts/swap_sort.ts index 68a83ced..722c33b5 100644 --- a/sorts/swap_sort.ts +++ b/sorts/swap_sort.ts @@ -12,7 +12,7 @@ export const minSwapsToSort = (inputArr: number[]): number => { sortedArray.sort() - let indexMap = new Map(); + const indexMap = new Map(); for (let i = 0; i < inputArr.length; i++) indexMap.set(inputArr[i],i); diff --git a/sorts/test/merge_sort.test.ts b/sorts/test/merge_sort.test.ts index 5b6f81fc..cc21b628 100644 --- a/sorts/test/merge_sort.test.ts +++ b/sorts/test/merge_sort.test.ts @@ -2,14 +2,14 @@ import { mergeSort } from "../merge_sort" describe("Merge Sort", () => { it("generating array with variable length and comparing with sorted array", () => { - let arrLenArr = [10, 200, 40000] + const arrLenArr = [10, 200, 40000] arrLenArr.forEach((arrLen: number) => { - let inBuiltSortArr = Array(arrLen) + const inBuiltSortArr = Array(arrLen) for (let i = 0; i < arrLen; i++) { inBuiltSortArr[i] = Math.random() * 10000 } - let mergeSortArray = inBuiltSortArr.slice() + const mergeSortArray = inBuiltSortArr.slice() inBuiltSortArr.sort((a, b) => a - b) expect(mergeSort(mergeSortArray)).toStrictEqual(inBuiltSortArr) From b3a3bd7efa940f9436841aac36f35eb12b0a42fc Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Sat, 2 Mar 2024 08:55:40 +0100 Subject: [PATCH 094/107] fix: handle the case when target is last in `jumpSearch` (#231) --- search/jump_search.ts | 6 +++--- search/test/jump_search.test.ts | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/search/jump_search.ts b/search/jump_search.ts index 45b44e02..e79061d8 100644 --- a/search/jump_search.ts +++ b/search/jump_search.ts @@ -25,13 +25,13 @@ export const jumpSearch = (array: number[], target: number): number => { let currentIdx: number = 0, stepSize: number = Math.floor(Math.sqrt(array.length)), nextIdx: number = stepSize; - + while (array[nextIdx - 1] < target) { currentIdx = nextIdx; nextIdx += stepSize; - if (nextIdx >= array.length) { - nextIdx = array.length - 1; + if (nextIdx > array.length) { + nextIdx = array.length; break; } } diff --git a/search/test/jump_search.test.ts b/search/test/jump_search.test.ts index 59737bdf..3687ccec 100644 --- a/search/test/jump_search.test.ts +++ b/search/test/jump_search.test.ts @@ -5,6 +5,15 @@ describe("Jump search", () => { [[], 1, -1], [[1, 2, 3, 4, 5], 4, 3], [[1, 3, 5, 8, 9], 4, -1], + [[1, 3, 5, 8], 8, 3], + [[1, 3, 5, 8], 9, -1], + [[1, 3, 5, 8], 7, -1], + [[1, 3, 5, 8, 10], 10, 4], + [[1, 3, 5, 8, 10], 11, -1], + [[1, 3, 5, 8, 10], 9, -1], + [[5], 5, 0], + [[5], 100, -1], + [[], 100, -1], ])( "of %o , searching for %o, expected %i", (array: any[], target: any, index: number) => { From 26ac72d61cbcf2b2c079afe2ae1b84c8056a5da5 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Mon, 4 Mar 2024 23:06:10 +0100 Subject: [PATCH 095/107] style: simplify `binaryLCM` (#233) --- maths/lowest_common_multiple.ts | 8 -------- maths/test/lowest_common_multiple.test.ts | 17 ++++++++++------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/maths/lowest_common_multiple.ts b/maths/lowest_common_multiple.ts index ec852425..95d266d3 100644 --- a/maths/lowest_common_multiple.ts +++ b/maths/lowest_common_multiple.ts @@ -38,14 +38,6 @@ export const naiveLCM = (nums: number[]): number => { //Note that due to utilizing GCF, which requires natural numbers, this method only accepts natural numbers. export const binaryLCM = (a: number, b: number): number => { - if (a < 0 || b < 0) { - throw new Error("numbers must be positive to determine lowest common multiple"); - } - - if (!Number.isInteger(a) || !Number.isInteger(b)) { - throw new Error("this method, which utilizes GCF, requires natural numbers."); - } - return a * b / greatestCommonFactor([a, b]); } diff --git a/maths/test/lowest_common_multiple.test.ts b/maths/test/lowest_common_multiple.test.ts index 55ea9a24..388dba28 100644 --- a/maths/test/lowest_common_multiple.test.ts +++ b/maths/test/lowest_common_multiple.test.ts @@ -29,10 +29,15 @@ describe("binaryLCM", () => { }, ); - test("only whole numbers should be accepted", () => { - expect(() => binaryLCM(-2, -3)).toThrowError( - "numbers must be positive to determine lowest common multiple", - ); + test("only natural numbers should be accepted", () => { + expect(() => binaryLCM(-2, -3)).toThrowError(); + expect(() => binaryLCM(2, -3)).toThrowError(); + expect(() => binaryLCM(-2, 3)).toThrowError(); + }); + + test("should throw when any of the inputs is not an int", () => { + expect(() => binaryLCM(1, 2.5)).toThrowError(); + expect(() => binaryLCM(1.5, 2)).toThrowError(); }); }); @@ -45,9 +50,7 @@ describe("lowestCommonMultiple", () => { ); test("only positive numbers should be accepted", () => { - expect(() => lowestCommonMultiple([-2, -3])).toThrowError( - "numbers must be positive to determine lowest common multiple", - ); + expect(() => lowestCommonMultiple([-2, -3])).toThrowError(); }); test("at least one number must be passed in", () => { From c5b12db2f8008400e699bad44e2679f99bf00332 Mon Sep 17 00:00:00 2001 From: Shankha Suvra Dam <71999854+SpiderMath@users.noreply.github.com> Date: Tue, 5 Mar 2024 11:19:38 +0530 Subject: [PATCH 096/107] feat: Added Double Factorial Iterative Implementation (#187) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update DIRECTORY.md * 🚀feat: added double factorial (iterative) * Update DIRECTORY.md * removed redundant if check, fix formatting * Update DIRECTORY.md --------- Co-authored-by: autoprettier Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- DIRECTORY.md | 2 ++ maths/double_factorial_iterative.ts | 29 +++++++++++++++++++ maths/test/double_factorial_iterative.test.ts | 7 +++++ 3 files changed, 38 insertions(+) create mode 100644 maths/double_factorial_iterative.ts create mode 100644 maths/test/double_factorial_iterative.test.ts diff --git a/DIRECTORY.md b/DIRECTORY.md index 3e6e6418..185bae95 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -108,6 +108,7 @@ * [Calculate Median](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/calculate_median.ts) * [Degrees To Radians](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/degrees_to_radians.ts) * [Digit Sum](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/digit_sum.ts) + * [Double Factorial Iterative](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/double_factorial_iterative.ts) * [Euler Totient](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/euler_totient.ts) * [Factorial](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/factorial.ts) * [Factors](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/factors.ts) @@ -128,6 +129,7 @@ * [Number Of Digits](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/number_of_digits.ts) * [Pascals Triangle](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/pascals_triangle.ts) * [Perfect Cube](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_cube.ts) + * [Perfect Number](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_number.ts) * [Perfect Square](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/perfect_square.ts) * [Prime Factorization](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/prime_factorization.ts) * [Primes](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/maths/primes.ts) diff --git a/maths/double_factorial_iterative.ts b/maths/double_factorial_iterative.ts new file mode 100644 index 00000000..6044eca0 --- /dev/null +++ b/maths/double_factorial_iterative.ts @@ -0,0 +1,29 @@ +/** + * @function DoubleFactorialIterative + * @description Calculate the double factorial of a number (iterative implementation) + * @summary In mathematics, double factorial of a number n is denoted by n!!. + * It is not to be confused with (n!)!, which is the factorial function iterated twice. + * The double factorial is the product of all positive integers upto n that have the same parity (odd or even) + * as n. + * Therefore, + * 9!! = 9 . 7 . 5 . 3 . 1 + * 10!! = 10 . 8 . 6 . 4 . 2 + * + * Please note that for factorials of even numbers, the series ends at 2. + * @see [Wikipedia](https://en.wikipedia.org/wiki/Double_factorial) + * @see [Mathworld](https://mathworld.wolfram.com/DoubleFactorial.html) + * @see [GeeksForGeeks](https://www.geeksforgeeks.org/double-factorial/) + * @example DoubleFactorialIterative(4) = 8 + * @example DoubleFactorialIterative(5) = 15 + */ +const DoubleFactorialIterative = (n: number) => { + if(n < 0) throw new RangeError("The number needs to be non-negative") + let doubleFactorial = 1 + + for(let i = n; i > 0; i -= 2) + doubleFactorial *= i + + return doubleFactorial +} + +export { DoubleFactorialIterative } diff --git a/maths/test/double_factorial_iterative.test.ts b/maths/test/double_factorial_iterative.test.ts new file mode 100644 index 00000000..3c221785 --- /dev/null +++ b/maths/test/double_factorial_iterative.test.ts @@ -0,0 +1,7 @@ +import { DoubleFactorialIterative } from "../double_factorial_iterative"; + +describe("Double Factorial", () => { + test.each([[4, 8], [5, 15], [10, 3840]])("%i!! = %i", (n, expected) => { + expect(DoubleFactorialIterative(n)).toBe(expected) + }) +}) \ No newline at end of file From c2d7aa6895b6655d5c0a5aead130803645a1d2eb Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Mon, 18 Mar 2024 18:33:33 +0100 Subject: [PATCH 097/107] Add and run prettier (#234) * chore: add `prettier` * style: run `prettier` * chore: check formatting in CI --- .github/workflows/ci.yml | 1 + .gitpod.yml | 2 - .prettierignore | 2 + .prettierrc | 15 + babel.config.js | 11 +- backtracking/all_combinations_of_size_k.ts | 20 +- backtracking/generateparentheses.ts | 26 +- .../test/all_combinations_of_size_k.test.ts | 33 +- backtracking/test/generateparentheses.test.ts | 140 +- bit_manipulation/add_binary.ts | 37 +- bit_manipulation/is_power_of_2.ts | 2 +- bit_manipulation/is_power_of_4.ts | 3 +- bit_manipulation/log_two.ts | 14 +- bit_manipulation/test/add_binary.test.ts | 52 +- bit_manipulation/test/is_power_of_2.test.ts | 25 +- bit_manipulation/test/is_power_of_4.test.ts | 4 +- bit_manipulation/test/log_two.test.ts | 15 +- ciphers/test/xor_cipher.test.ts | 10 +- data_structures/disjoint_set/disjoint_set.ts | 31 +- .../disjoint_set/test/disjoint_set.test.ts | 32 +- data_structures/heap/heap.ts | 158 +- data_structures/heap/test/heap.test.ts | 200 +- data_structures/list/doubly_linked_list.ts | 478 +- data_structures/list/linked_list.ts | 22 +- data_structures/list/singly_linked_list.ts | 149 +- .../list/test/doubly_linked_list.test.ts | 36 +- data_structures/list/test/linked_list.ts | 122 +- .../list/test/singly_linked_list.test.ts | 6 +- data_structures/map/hash_map.ts | 374 +- data_structures/map/map.ts | 20 +- data_structures/map/test/hash_map.test.ts | 218 +- data_structures/queue/array_queue.ts | 96 +- data_structures/queue/circular_queue.ts | 168 +- data_structures/queue/linked_queue.ts | 150 +- data_structures/queue/queue.ts | 12 +- data_structures/queue/stack_queue.ts | 134 +- .../queue/test/array_queue.test.ts | 4 +- .../queue/test/circular_queue.test.ts | 96 +- .../queue/test/linked_queue.test.ts | 4 +- data_structures/queue/test/queue.ts | 100 +- .../queue/test/stack_queue.test.ts | 6 +- data_structures/set/hash_map_set.ts | 28 +- data_structures/set/map_set.ts | 114 +- data_structures/set/set.ts | 12 +- data_structures/stack/linked_list_stack.ts | 126 +- data_structures/stack/stack.ts | 22 +- .../stack/test/linked_list_stack.test.ts | 50 +- data_structures/stack/test/stack.test.ts | 82 +- data_structures/tree/binary_search_tree.ts | 106 +- .../tree/test/binary_search_tree.test.ts | 68 +- data_structures/tries/test/tries.test.ts | 52 +- data_structures/tries/tries.ts | 24 +- dynamic_programming/coin_change.ts | 55 +- dynamic_programming/knapsack.ts | 25 +- dynamic_programming/lcs.ts | 70 +- dynamic_programming/test/coin_change.test.ts | 59 +- dynamic_programming/test/knapsack.test.ts | 20 +- dynamic_programming/test/lcs.test.ts | 36 +- graph/bellman_ford.ts | 16 +- graph/bipartite_graph.ts | 26 +- graph/dijkstra.ts | 35 +- graph/floyd_warshall.ts | 19 +- graph/johnson.ts | 31 +- graph/kosajaru.ts | 59 +- graph/kruskal.ts | 35 +- graph/prim.ts | 62 +- graph/tarjan.ts | 53 +- graph/test/bellman_ford.test.ts | 150 +- graph/test/bipartite_graph.test.ts | 72 +- graph/test/dijkstra.test.ts | 102 +- graph/test/floyd_warshall.test.ts | 68 +- graph/test/johnson.test.ts | 170 +- graph/test/kosajaru.test.ts | 164 +- graph/test/kruskal.test.ts | 99 +- graph/test/prim.test.ts | 89 +- graph/test/tarjan.test.ts | 176 +- jest.config.ts | 10 +- maths/absolute_value.ts | 4 +- maths/aliquot_sum.ts | 4 +- maths/armstrong_number.ts | 4 +- maths/binomial_coefficient.ts | 20 +- maths/calculate_mean.ts | 8 +- maths/calculate_median.ts | 24 +- maths/degrees_to_radians.ts | 20 +- maths/digit_sum.ts | 12 +- maths/double_factorial_iterative.ts | 17 +- maths/euler_totient.ts | 18 +- maths/factorial.ts | 6 +- maths/factors.ts | 26 +- maths/fibonacci.ts | 43 +- maths/find_min.ts | 26 +- maths/gaussian_elimination.ts | 28 +- maths/greatest_common_factor.ts | 14 +- maths/hamming_distance.ts | 3 +- maths/is_divisible.ts | 10 +- maths/is_even.ts | 14 +- maths/is_leap_year.ts | 6 +- maths/is_odd.ts | 14 +- maths/is_palindrome.ts | 20 +- maths/is_square_free.ts | 21 +- maths/juggler_sequence.ts | 8 +- maths/lowest_common_multiple.ts | 26 +- maths/matrix_multiplication.ts | 33 +- maths/number_of_digits.ts | 6 +- maths/pascals_triangle.ts | 22 +- maths/perfect_cube.ts | 4 +- maths/perfect_number.ts | 28 +- maths/perfect_square.ts | 4 +- maths/prime_factorization.ts | 30 +- maths/primes.ts | 46 +- maths/pronic_number.ts | 10 +- maths/radians_to_degrees.ts | 20 +- maths/series/hexagonal_numbers.ts | 5 +- maths/series/test/hexagonal_numbers.test.ts | 14 +- maths/sieve_of_eratosthenes.ts | 17 +- maths/signum.ts | 2 +- maths/square_root.ts | 16 +- maths/test/absolute_value.test.ts | 46 +- maths/test/aliquot_sum.test.ts | 14 +- maths/test/armstrong_number.test.ts | 12 +- maths/test/binomial_coefficient.test.ts | 58 +- maths/test/calculate_mean.test.ts | 50 +- maths/test/calculate_median.test.ts | 38 +- maths/test/degrees_to_radians.test.ts | 14 +- maths/test/digit_sum.test.ts | 32 +- maths/test/double_factorial_iterative.test.ts | 16 +- maths/test/euler_totient.test.ts | 37 +- maths/test/factorial.test.ts | 36 +- maths/test/factors.test.ts | 43 +- maths/test/fibonacci.test.ts | 16 +- maths/test/find_min.test.ts | 28 +- maths/test/gaussian_elimination.test.ts | 48 +- maths/test/greatest_common_factor.test.ts | 63 +- maths/test/hamming_distance.test.ts | 9 +- maths/test/is_divisible.test.ts | 70 +- maths/test/is_even.test.ts | 29 +- maths/test/is_leap_year.test.ts | 90 +- maths/test/is_odd.test.ts | 29 +- maths/test/is_palindrome.test.ts | 25 +- maths/test/is_square_free.test.ts | 34 +- maths/test/juggler_sequence.test.ts | 10 +- maths/test/lowest_common_multiple.test.ts | 119 +- maths/test/matrix_multiplication.test.ts | 30 +- maths/test/number_of_digits.test.ts | 31 +- maths/test/pascals_triangle.test.ts | 12 +- maths/test/perfect_cube.test.ts | 10 +- maths/test/perfect_numbers.test.ts | 10 +- maths/test/perfect_square.test.ts | 16 +- maths/test/prime_factorization.test.ts | 57 +- maths/test/primes.test.ts | 63 +- maths/test/pronic_number.test.ts | 8 +- maths/test/radians_to_degrees.test.ts | 14 +- maths/test/sieve_of_eratosthenes.test.ts | 30 +- maths/test/signum.test.ts | 9 +- maths/test/square_root.test.ts | 24 +- maths/test/ugly_numbers.test.ts | 10 +- maths/test/zellers_congruence.test.ts | 54 +- maths/ugly_numbers.ts | 16 +- maths/zellers_congruence.ts | 26 +- other/is_sorted_array.ts | 14 +- other/parse_nested_brackets.ts | 58 +- other/shuffle_array.ts | 12 +- other/test/is_sorted_array.test.ts | 18 +- other/test/parse_nested_brackets.test.ts | 36 +- other/test/shuffle_array.test.ts | 44 +- package-lock.json | 12904 ++++++++-------- package.json | 42 +- search/binary_search.ts | 84 +- search/interpolation_search.ts | 40 +- search/jump_search.ts | 93 +- search/linear_search.ts | 12 +- search/sentinel_search.ts | 44 +- search/test/binary_search.test.ts | 67 +- search/test/interpolation_search.test.ts | 21 +- search/test/jump_search.test.ts | 46 +- search/test/linear_search.test.ts | 12 +- search/test/sentinel_search.test.ts | 18 +- sorts/bogo_sort.ts | 12 +- sorts/bubble_sort.ts | 39 +- sorts/counting_sort.ts | 28 +- sorts/cycle_sort.ts | 131 +- sorts/gnome_sort.ts | 14 +- sorts/heap_sort.ts | 61 +- sorts/insertion_sort.ts | 14 +- sorts/quick_select.ts | 52 +- sorts/quick_sort.ts | 39 +- sorts/selection_sort.ts | 10 +- sorts/shell_sort.ts | 26 +- sorts/swap_sort.ts | 37 +- sorts/test/bogo_sort.test.ts | 26 +- sorts/test/bubble_sort.test.ts | 30 +- sorts/test/counting_sort.test.ts | 20 +- sorts/test/cycle_sort.test.ts | 36 +- sorts/test/gnome_sort.test.ts | 12 +- sorts/test/heap_sort.test.ts | 34 +- sorts/test/insertion_sort.test.ts | 26 +- sorts/test/merge_sort.test.ts | 6 +- sorts/test/quick_select.test.ts | 48 +- sorts/test/quick_sort.test.ts | 34 +- sorts/test/selection_sort.test.ts | 20 +- sorts/test/shell_sort.test.ts | 30 +- sorts/test/swap_sort.test.ts | 25 +- sorts/test/tree_sort.test.ts | 50 +- sorts/tree_sort.ts | 10 +- tsconfig.json | 19 +- 205 files changed, 11151 insertions(+), 10755 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a84c9fa0..cff9701c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,3 +16,4 @@ jobs: node-version: "18.x" - run: npm ci - run: npm test + - run: npm run check-style diff --git a/.gitpod.yml b/.gitpod.yml index 46209a0a..5ba99cbb 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,5 +1,3 @@ tasks: - init: | npm install && npm test - - diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..1305111f --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +.github +*.md diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..a85cb7eb --- /dev/null +++ b/.prettierrc @@ -0,0 +1,15 @@ +{ + "arrowParens": "always", + "bracketSpacing": true, + "endOfLine": "lf", + "insertPragma": false, + "printWidth": 80, + "proseWrap": "preserve", + "quoteProps": "as-needed", + "requirePragma": false, + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "none", + "useTabs": false +} diff --git a/babel.config.js b/babel.config.js index 924d02bb..7b976f52 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,7 +1,6 @@ module.exports = { - presets: [ - ['@babel/preset-env', { targets: { node: 'current' } }], - '@babel/preset-typescript' - ] -}; - + presets: [ + ['@babel/preset-env', { targets: { node: 'current' } }], + '@babel/preset-typescript' + ] +} diff --git a/backtracking/all_combinations_of_size_k.ts b/backtracking/all_combinations_of_size_k.ts index 23ee3760..67e18bf6 100644 --- a/backtracking/all_combinations_of_size_k.ts +++ b/backtracking/all_combinations_of_size_k.ts @@ -10,8 +10,8 @@ * and repeat the same process for the next number. */ export function generateCombinations(n: number, k: number): number[][] { - const combinationsAcc: number[][] = []; - const currentCombination: number[] = []; + const combinationsAcc: number[][] = [] + const currentCombination: number[] = [] function generateAllCombos( n: number, @@ -20,19 +20,19 @@ export function generateCombinations(n: number, k: number): number[][] { ): number[][] { if (k === 0) { if (currentCombination.length > 0) { - combinationsAcc.push(currentCombination.slice()); + combinationsAcc.push(currentCombination.slice()) } - return combinationsAcc; + return combinationsAcc } - const endCursor = n - k + 2; + const endCursor = n - k + 2 for (let i = startCursor; i < endCursor; i++) { - currentCombination.push(i); - generateAllCombos(n, k - 1, i + 1); - currentCombination.pop(); + currentCombination.push(i) + generateAllCombos(n, k - 1, i + 1) + currentCombination.pop() } - return combinationsAcc; + return combinationsAcc } - return generateAllCombos(n, k, 1); + return generateAllCombos(n, k, 1) } diff --git a/backtracking/generateparentheses.ts b/backtracking/generateparentheses.ts index e2c93662..a998ac34 100644 --- a/backtracking/generateparentheses.ts +++ b/backtracking/generateparentheses.ts @@ -6,26 +6,30 @@ */ const generateParentheses = (n: number): string[] => { - const result: string[] = []; + const result: string[] = [] - const solve = (chars: string, openParentheses: number, closedParentheses: number) => { + const solve = ( + chars: string, + openParentheses: number, + closedParentheses: number + ) => { if (openParentheses === n && closedParentheses === n) { - result.push(chars); - return; + result.push(chars) + return } if (openParentheses <= n) { - solve(chars + "(", openParentheses + 1, closedParentheses); + solve(chars + '(', openParentheses + 1, closedParentheses) } if (closedParentheses < openParentheses) { - solve(chars + ")", openParentheses, closedParentheses + 1); + solve(chars + ')', openParentheses, closedParentheses + 1) } - }; + } - solve("", 0, 0); + solve('', 0, 0) - return result; -}; + return result +} -export { generateParentheses }; +export { generateParentheses } diff --git a/backtracking/test/all_combinations_of_size_k.test.ts b/backtracking/test/all_combinations_of_size_k.test.ts index 09639406..96e2526c 100644 --- a/backtracking/test/all_combinations_of_size_k.test.ts +++ b/backtracking/test/all_combinations_of_size_k.test.ts @@ -1,4 +1,4 @@ -import { generateCombinations } from "../all_combinations_of_size_k"; +import { generateCombinations } from '../all_combinations_of_size_k' const cases = [ [ @@ -7,20 +7,31 @@ const cases = [ [ [1, 2], [1, 3], + [2, 3] + ] + ], + [ + 4, + 2, + [ + [1, 2], + [1, 3], + [1, 4], [2, 3], - ], + [2, 4], + [3, 4] + ] ], - [4, 2, [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]], [0, 0, []], - [2, 3, []], -] as const; + [2, 3, []] +] as const -describe("AllCombinationsOfSizeK", () => { +describe('AllCombinationsOfSizeK', () => { it.each(cases)( - "create all combinations given n=%p and k=%p", + 'create all combinations given n=%p and k=%p', (n, k, expectedCombos) => { - const combinations = generateCombinations(n, k); - expect(combinations).toEqual(expectedCombos); + const combinations = generateCombinations(n, k) + expect(combinations).toEqual(expectedCombos) } - ); -}); + ) +}) diff --git a/backtracking/test/generateparentheses.test.ts b/backtracking/test/generateparentheses.test.ts index c3752d34..42751fd2 100644 --- a/backtracking/test/generateparentheses.test.ts +++ b/backtracking/test/generateparentheses.test.ts @@ -1,83 +1,83 @@ -import { generateParentheses } from "../generateparentheses"; +import { generateParentheses } from '../generateparentheses' const cases: [number, string[]][] = [ - [0, [""]], - [1, ["()"]], - [2, ["(())", "()()"]], - [3, ["((()))", "(()())", "(())()", "()(())", "()()()"]], + [0, ['']], + [1, ['()']], + [2, ['(())', '()()']], + [3, ['((()))', '(()())', '(())()', '()(())', '()()()']], [ 4, [ - "(((())))", - "((()()))", - "((())())", - "((()))()", - "(()(()))", - "(()()())", - "(()())()", - "(())(())", - "(())()()", - "()((()))", - "()(()())", - "()(())()", - "()()(())", - "()()()()", - ], + '(((())))', + '((()()))', + '((())())', + '((()))()', + '(()(()))', + '(()()())', + '(()())()', + '(())(())', + '(())()()', + '()((()))', + '()(()())', + '()(())()', + '()()(())', + '()()()()' + ] ], [ 5, [ - "((((()))))", - "(((()())))", - "(((())()))", - "(((()))())", - "(((())))()", - "((()(())))", - "((()()()))", - "((()())())", - "((()()))()", - "((())(()))", - "((())()())", - "((())())()", - "((()))(())", - "((()))()()", - "(()((())))", - "(()(()()))", - "(()(())())", - "(()(()))()", - "(()()(()))", - "(()()()())", - "(()()())()", - "(()())(())", - "(()())()()", - "(())((()))", - "(())(()())", - "(())(())()", - "(())()(())", - "(())()()()", - "()(((())))", - "()((()()))", - "()((())())", - "()((()))()", - "()(()(()))", - "()(()()())", - "()(()())()", - "()(())(())", - "()(())()()", - "()()((()))", - "()()(()())", - "()()(())()", - "()()()(())", - "()()()()()", - ], - ], -]; + '((((()))))', + '(((()())))', + '(((())()))', + '(((()))())', + '(((())))()', + '((()(())))', + '((()()()))', + '((()())())', + '((()()))()', + '((())(()))', + '((())()())', + '((())())()', + '((()))(())', + '((()))()()', + '(()((())))', + '(()(()()))', + '(()(())())', + '(()(()))()', + '(()()(()))', + '(()()()())', + '(()()())()', + '(()())(())', + '(()())()()', + '(())((()))', + '(())(()())', + '(())(())()', + '(())()(())', + '(())()()()', + '()(((())))', + '()((()()))', + '()((())())', + '()((()))()', + '()(()(()))', + '()(()()())', + '()(()())()', + '()(())(())', + '()(())()()', + '()()((()))', + '()()(()())', + '()()(())()', + '()()()(())', + '()()()()()' + ] + ] +] -describe("Generate Parentheses", () => { +describe('Generate Parentheses', () => { test.each(cases)( - "generate all valid parentheses of input %n", + 'generate all valid parentheses of input %n', (n: number, expected: string[]) => { - expect(generateParentheses(n)).toStrictEqual(expected); + expect(generateParentheses(n)).toStrictEqual(expected) } - ); -}); + ) +}) diff --git a/bit_manipulation/add_binary.ts b/bit_manipulation/add_binary.ts index 38ca43af..7e6ecd03 100644 --- a/bit_manipulation/add_binary.ts +++ b/bit_manipulation/add_binary.ts @@ -5,23 +5,28 @@ * @param secondBinaryNo - The second binary string. * @returns The binary sum of the input strings. */ -export function addBinary(firstBinaryNo: string, secondBinaryNo: string): string { - let lengthOfFirstNumber: number = firstBinaryNo.length - 1; - let lengthOfSecondNumber: number = secondBinaryNo.length - 1; - const solution: string[] = []; - let carry: number = 0; +export function addBinary( + firstBinaryNo: string, + secondBinaryNo: string +): string { + let lengthOfFirstNumber: number = firstBinaryNo.length - 1 + let lengthOfSecondNumber: number = secondBinaryNo.length - 1 + const solution: string[] = [] + let carry: number = 0 - while ( lengthOfFirstNumber >= 0 || lengthOfSecondNumber >= 0) { - let sum: number = carry; - if (lengthOfFirstNumber >= 0) sum += parseInt(firstBinaryNo.charAt(lengthOfFirstNumber)); - if (lengthOfSecondNumber >= 0) sum += parseInt(secondBinaryNo.charAt(lengthOfSecondNumber)); - solution.push((sum % 2).toString()); - carry = Math.floor(sum / 2); - lengthOfFirstNumber--; - lengthOfSecondNumber--; - } + while (lengthOfFirstNumber >= 0 || lengthOfSecondNumber >= 0) { + let sum: number = carry + if (lengthOfFirstNumber >= 0) + sum += parseInt(firstBinaryNo.charAt(lengthOfFirstNumber)) + if (lengthOfSecondNumber >= 0) + sum += parseInt(secondBinaryNo.charAt(lengthOfSecondNumber)) + solution.push((sum % 2).toString()) + carry = Math.floor(sum / 2) + lengthOfFirstNumber-- + lengthOfSecondNumber-- + } - if (carry !== 0) solution.push(carry.toString()); + if (carry !== 0) solution.push(carry.toString()) - return solution.reverse().join(''); + return solution.reverse().join('') } diff --git a/bit_manipulation/is_power_of_2.ts b/bit_manipulation/is_power_of_2.ts index 487c1a8c..2edcea31 100644 --- a/bit_manipulation/is_power_of_2.ts +++ b/bit_manipulation/is_power_of_2.ts @@ -22,4 +22,4 @@ * @returns {boolean} */ -export const isPowerOfTwo = (n: number): boolean => n > 0 && (n & (n - 1)) === 0 \ No newline at end of file +export const isPowerOfTwo = (n: number): boolean => n > 0 && (n & (n - 1)) === 0 diff --git a/bit_manipulation/is_power_of_4.ts b/bit_manipulation/is_power_of_4.ts index e7a57bc5..1e5e2d5a 100644 --- a/bit_manipulation/is_power_of_4.ts +++ b/bit_manipulation/is_power_of_4.ts @@ -12,4 +12,5 @@ * const result = isPowerOfFour(16); // Returns true (16 is 4^2) * const result2 = isPowerOfFour(5); // Returns false (5 is not a power of four) */ -export const isPowerOfFour = (n: number): boolean => ((n > 0) && ((n & n - 1) === 0) && (n % 3 === 1)) +export const isPowerOfFour = (n: number): boolean => + n > 0 && (n & (n - 1)) === 0 && n % 3 === 1 diff --git a/bit_manipulation/log_two.ts b/bit_manipulation/log_two.ts index 6fb40f2d..7246c8ce 100644 --- a/bit_manipulation/log_two.ts +++ b/bit_manipulation/log_two.ts @@ -6,10 +6,10 @@ * @returns {number} Log2 approximation equal to floor(log2(n)) */ export const logTwo = (n: number): number => { - let result = 0 - while (n >> 1) { - n >>= 1 - result++ - } - return result -} \ No newline at end of file + let result = 0 + while (n >> 1) { + n >>= 1 + result++ + } + return result +} diff --git a/bit_manipulation/test/add_binary.test.ts b/bit_manipulation/test/add_binary.test.ts index e8ce1776..e3fe52fc 100644 --- a/bit_manipulation/test/add_binary.test.ts +++ b/bit_manipulation/test/add_binary.test.ts @@ -1,33 +1,33 @@ -import { addBinary } from "../add_binary"; +import { addBinary } from '../add_binary' describe('Add Binary Number', () => { - it('should add two binary numbers with no carry', () => { - const result = addBinary('1101', '1011'); - expect(result).toBe('11000'); - }); + it('should add two binary numbers with no carry', () => { + const result = addBinary('1101', '1011') + expect(result).toBe('11000') + }) - it('should add two binary numbers with carry', () => { - const result = addBinary('1111', '1111'); - expect(result).toBe('11110'); - }); + it('should add two binary numbers with carry', () => { + const result = addBinary('1111', '1111') + expect(result).toBe('11110') + }) - it('should add two different-length binary numbers', () => { - const result = addBinary('1101', '111'); - expect(result).toBe('10100'); - }); + it('should add two different-length binary numbers', () => { + const result = addBinary('1101', '111') + expect(result).toBe('10100') + }) - it('should add two empty binary numbers', () => { - const result = addBinary('', ''); - expect(result).toBe(''); - }); + it('should add two empty binary numbers', () => { + const result = addBinary('', '') + expect(result).toBe('') + }) - it('should add one empty binary number to a non-empty number', () => { - const result = addBinary('1010', ''); - expect(result).toBe('1010'); - }); + it('should add one empty binary number to a non-empty number', () => { + const result = addBinary('1010', '') + expect(result).toBe('1010') + }) - it('should add one non-empty binary number to an empty number', () => { - const result = addBinary('', '1101'); - expect(result).toBe('1101'); - }); -}); \ No newline at end of file + it('should add one non-empty binary number to an empty number', () => { + const result = addBinary('', '1101') + expect(result).toBe('1101') + }) +}) diff --git a/bit_manipulation/test/is_power_of_2.test.ts b/bit_manipulation/test/is_power_of_2.test.ts index 1276e6d1..8993947b 100644 --- a/bit_manipulation/test/is_power_of_2.test.ts +++ b/bit_manipulation/test/is_power_of_2.test.ts @@ -1,14 +1,13 @@ -import { isPowerOfTwo } from "../is_power_of_2" +import { isPowerOfTwo } from '../is_power_of_2' - -describe('IsPowerOfTwo' , () => { - it.each([ - [0, false], - [1, true], - [4, true], - [1024, true], - [1025, false], - ])('Check if %i is a power of 2 or not', (number, expected) => { - expect(isPowerOfTwo(number)).toBe(expected); - }); -}) \ No newline at end of file +describe('IsPowerOfTwo', () => { + it.each([ + [0, false], + [1, true], + [4, true], + [1024, true], + [1025, false] + ])('Check if %i is a power of 2 or not', (number, expected) => { + expect(isPowerOfTwo(number)).toBe(expected) + }) +}) diff --git a/bit_manipulation/test/is_power_of_4.test.ts b/bit_manipulation/test/is_power_of_4.test.ts index a9b31c47..1851f708 100644 --- a/bit_manipulation/test/is_power_of_4.test.ts +++ b/bit_manipulation/test/is_power_of_4.test.ts @@ -1,4 +1,4 @@ -import { isPowerOfFour } from "../is_power_of_4" +import { isPowerOfFour } from '../is_power_of_4' describe('IsPowerOfFour', () => { it.each([ @@ -11,4 +11,4 @@ describe('IsPowerOfFour', () => { ])('should return the number %i is power of four or not', (n, expected) => { expect(isPowerOfFour(n)).toBe(expected) }) -}) \ No newline at end of file +}) diff --git a/bit_manipulation/test/log_two.test.ts b/bit_manipulation/test/log_two.test.ts index ff168ad3..923341f4 100644 --- a/bit_manipulation/test/log_two.test.ts +++ b/bit_manipulation/test/log_two.test.ts @@ -1,10 +1,7 @@ -import { logTwo } from "../log_two" +import { logTwo } from '../log_two' -describe('LogTwoTests' , () => { - test.each([...Array(100).keys()].map(i => [i + 1]))( - 'log2(%i)', - (input) => { - expect(logTwo(input)).toBe(Math.floor(Math.log2(input))); - } - ); -}) \ No newline at end of file +describe('LogTwoTests', () => { + test.each([...Array(100).keys()].map((i) => [i + 1]))('log2(%i)', (input) => { + expect(logTwo(input)).toBe(Math.floor(Math.log2(input))) + }) +}) diff --git a/ciphers/test/xor_cipher.test.ts b/ciphers/test/xor_cipher.test.ts index b8def4a6..0607d6a3 100644 --- a/ciphers/test/xor_cipher.test.ts +++ b/ciphers/test/xor_cipher.test.ts @@ -1,8 +1,8 @@ -import { XORCipher } from '../xor_cipher'; +import { XORCipher } from '../xor_cipher' describe('Testing XORCipher function', () => { it('passing a string & number as an argument', () => { - expect(XORCipher('test', 32)).toBe('TEST'); - expect(XORCipher('TEST', 32)).toBe('test'); - }); -}); + expect(XORCipher('test', 32)).toBe('TEST') + expect(XORCipher('TEST', 32)).toBe('test') + }) +}) diff --git a/data_structures/disjoint_set/disjoint_set.ts b/data_structures/disjoint_set/disjoint_set.ts index f627e8ec..1d8ce49f 100644 --- a/data_structures/disjoint_set/disjoint_set.ts +++ b/data_structures/disjoint_set/disjoint_set.ts @@ -6,9 +6,9 @@ * The find operation uses path compression. * This allows the time complexity of the find operation be O(alpha(n)). * alpha(n) being the inverse Ackermann function. - * + * * The join operation uses union by size: The smaller set is joined to the bigger one. - * + * * You can perform the following operations on the disjoint set: * - find: Determine which subset a particular element is in - O(alpha(n)) * - join: Join two subsets into a single subset - O(1) @@ -16,15 +16,15 @@ */ export class DisjointSet { /** Direct parent for an element */ - private head: number[]; + private head: number[] /** Size of the subtree above an element */ - private size: number[]; + private size: number[] constructor(n: number) { // Initially each set has its own id element - this.head = Array.from({ length: n }, (_, index) => index); - this.size = Array(n).fill(1); + this.head = Array.from({ length: n }, (_, index) => index) + this.size = Array(n).fill(1) } /** @@ -33,39 +33,38 @@ export class DisjointSet { find(index: number): number { if (this.head[index] != index) { // Use path compression (set an edge between the element and its head) - this.head[index] = this.find(this.head[index]); + this.head[index] = this.find(this.head[index]) } - return this.head[index]; + return this.head[index] } - /** * Join two sets */ join(first: number, second: number): void { // Get the root of each set to join - let firstHead = this.find(first); - let secondHead = this.find(second); + let firstHead = this.find(first) + let secondHead = this.find(second) // If they're the same (same set) - if (firstHead === secondHead) return; + if (firstHead === secondHead) return // Keep the bigger set in firstHead if (this.size[firstHead] < this.size[secondHead]) { - [firstHead, secondHead] = [secondHead, firstHead]; + ;[firstHead, secondHead] = [secondHead, firstHead] } // Join the smallest set with the bigger one - this.head[secondHead] = firstHead; + this.head[secondHead] = firstHead // Update size of the bigger set after join - this.size[firstHead] += this.size[secondHead]; + this.size[firstHead] += this.size[secondHead] } /** * Check whether two elements are in the same set */ isSame(first: number, second: number): boolean { - return this.find(first) === this.find(second); + return this.find(first) === this.find(second) } } diff --git a/data_structures/disjoint_set/test/disjoint_set.test.ts b/data_structures/disjoint_set/test/disjoint_set.test.ts index 3409426a..7e300e13 100644 --- a/data_structures/disjoint_set/test/disjoint_set.test.ts +++ b/data_structures/disjoint_set/test/disjoint_set.test.ts @@ -1,24 +1,24 @@ -import { DisjointSet } from "../disjoint_set" +import { DisjointSet } from '../disjoint_set' -describe("DisjointSet", () => { - let ds: DisjointSet; +describe('DisjointSet', () => { + let ds: DisjointSet beforeEach(() => { // Ensure create a new DisjoinSet instance on every test - ds = new DisjointSet(10); - }); + ds = new DisjointSet(10) + }) - it("should show proper head element after join", () => { - expect(ds.find(0)).toEqual(0); + it('should show proper head element after join', () => { + expect(ds.find(0)).toEqual(0) - ds.join(1, 4); - ds.join(2, 3); - expect(ds.isSame(1, 4)).toEqual(true); - expect(ds.isSame(2, 3)).toEqual(true); - expect(ds.isSame(1, 3)).toEqual(false); + ds.join(1, 4) + ds.join(2, 3) + expect(ds.isSame(1, 4)).toEqual(true) + expect(ds.isSame(2, 3)).toEqual(true) + expect(ds.isSame(1, 3)).toEqual(false) - ds.join(4, 3); - expect(ds.isSame(1, 3)).toEqual(true); - expect(ds.isSame(2, 9)).toEqual(false); - }); + ds.join(4, 3) + expect(ds.isSame(1, 3)).toEqual(true) + expect(ds.isSame(2, 9)).toEqual(false) + }) }) diff --git a/data_structures/heap/heap.ts b/data_structures/heap/heap.ts index b5ab0ebc..100ce1b3 100644 --- a/data_structures/heap/heap.ts +++ b/data_structures/heap/heap.ts @@ -12,13 +12,13 @@ */ export abstract class Heap { - protected heap: T[]; + protected heap: T[] // A comparison function. Returns true if a should be the parent of b. - protected compare: (a: T, b: T) => boolean; + protected compare: (a: T, b: T) => boolean constructor(compare: (a: T, b: T) => boolean) { - this.heap = []; - this.compare = compare; + this.heap = [] + this.compare = compare } /** @@ -27,174 +27,188 @@ export abstract class Heap { * In a minHeap the value at parentIndex should be smaller than the value at childIndex * */ - private isRightlyPlaced( childIndex: number, parentIndex: number) { - return this.compare(this.heap[parentIndex], this.heap[childIndex]); + private isRightlyPlaced(childIndex: number, parentIndex: number) { + return this.compare(this.heap[parentIndex], this.heap[childIndex]) } /** * In a maxHeap the index with the larger value is returned * In a minHeap the index with the smaller value is returned */ - private getChildIndexToSwap(leftChildIndex: number, rightChildIndex: number): number { + private getChildIndexToSwap( + leftChildIndex: number, + rightChildIndex: number + ): number { if (rightChildIndex >= this.size()) { - return leftChildIndex; + return leftChildIndex } return this.compare(this.heap[leftChildIndex], this.heap[rightChildIndex]) ? leftChildIndex - : rightChildIndex; + : rightChildIndex } public insert(value: T): void { - this.heap.push(value); - this.bubbleUp(); + this.heap.push(value) + this.bubbleUp() } public extract(): T { - const maxElement = this.heap[0]; - this.heap[0] = this.heap[this.size() - 1]; - this.heap.pop(); - this.sinkDown(); - return maxElement; + const maxElement = this.heap[0] + this.heap[0] = this.heap[this.size() - 1] + this.heap.pop() + this.sinkDown() + return maxElement } public size(): number { - return this.heap.length; + return this.heap.length } public isEmpty(): boolean { - return this.size() === 0; + return this.size() === 0 } protected swap(a: number, b: number) { - [this.heap[a], this.heap[b]] = [ - this.heap[b], - this.heap[a], - ]; + ;[this.heap[a], this.heap[b]] = [this.heap[b], this.heap[a]] } protected bubbleUp(index = this.size() - 1): void { - let parentIndex; + let parentIndex while (index > 0) { - parentIndex = Math.floor((index - 1) / 2); - if (this.isRightlyPlaced(index, parentIndex)) break; - this.swap(parentIndex, index); - index = parentIndex; + parentIndex = Math.floor((index - 1) / 2) + if (this.isRightlyPlaced(index, parentIndex)) break + this.swap(parentIndex, index) + index = parentIndex } } private sinkDown(): void { - let index = 0; - let leftChildIndex = this.getLeftChildIndex(index); - let rightChildIndex = this.getRightChildIndex(index); - let childIndexToSwap; + let index = 0 + let leftChildIndex = this.getLeftChildIndex(index) + let rightChildIndex = this.getRightChildIndex(index) + let childIndexToSwap while (this.heap[leftChildIndex] || this.heap[rightChildIndex]) { childIndexToSwap = this.getChildIndexToSwap( leftChildIndex, rightChildIndex - ); - if (this.isRightlyPlaced(childIndexToSwap, index)) break; - this.swap(childIndexToSwap, index); - index = childIndexToSwap; - leftChildIndex = this.getLeftChildIndex(index); - rightChildIndex = this.getRightChildIndex(index); + ) + if (this.isRightlyPlaced(childIndexToSwap, index)) break + this.swap(childIndexToSwap, index) + index = childIndexToSwap + leftChildIndex = this.getLeftChildIndex(index) + rightChildIndex = this.getRightChildIndex(index) } } private getLeftChildIndex(index: number): number { - return index * 2 + 1; + return index * 2 + 1 } private getRightChildIndex(index: number): number { - return index * 2 + 2; + return index * 2 + 2 } public check(): void { - return this._check(); + return this._check() } private _check(index: number = 0): void { - if (!this.heap[index]) return; - const leftChildIndex = this.getLeftChildIndex(index); - const rightChildIndex = this.getRightChildIndex(index); + if (!this.heap[index]) return + const leftChildIndex = this.getLeftChildIndex(index) + const rightChildIndex = this.getRightChildIndex(index) if ( this.heap[leftChildIndex] && !this.isRightlyPlaced(leftChildIndex, index) ) - throw new Error("Heap does not adhere to heap invariant"); + throw new Error('Heap does not adhere to heap invariant') if ( this.heap[rightChildIndex] && !this.isRightlyPlaced(rightChildIndex, index) ) - throw new Error("Heap does not adhere to heap invariant"); + throw new Error('Heap does not adhere to heap invariant') - this._check(leftChildIndex); - this._check(rightChildIndex); + this._check(leftChildIndex) + this._check(rightChildIndex) } } export class MinHeap extends Heap { - constructor(compare = (a: T, b: T) => { return a < b }) { - super(compare); + constructor( + compare = (a: T, b: T) => { + return a < b + } + ) { + super(compare) } } export class MaxHeap extends Heap { - constructor(compare = (a: T, b: T) => { return a > b }) { - super(compare); + constructor( + compare = (a: T, b: T) => { + return a > b + } + ) { + super(compare) } } // Priority queue that supports increasePriority() in O(log(n)). The limitation is that there can only be a single element for each key, and the max number or keys must be specified at heap construction. Most of the functions are wrappers around MinHeap functions and update the keys array. export class PriorityQueue extends MinHeap { // Maps from the n'th node to its index within the heap. - private keys: number[]; + private keys: number[] // Maps from element to its index with keys. - private keys_index: (a: T) => number; + private keys_index: (a: T) => number - constructor(keys_index: (a: T) => number, num_keys: number, compare = (a: T, b: T) => { return a < b }) { - super(compare); - this.keys = Array(num_keys).fill(-1); - this.keys_index = keys_index; + constructor( + keys_index: (a: T) => number, + num_keys: number, + compare = (a: T, b: T) => { + return a < b + } + ) { + super(compare) + this.keys = Array(num_keys).fill(-1) + this.keys_index = keys_index } protected swap(a: number, b: number) { - const akey = this.keys_index(this.heap[a]); - const bkey = this.keys_index(this.heap[b]); - [this.keys[akey], this.keys[bkey]] = [this.keys[bkey], this.keys[akey]]; - super.swap(a, b); + const akey = this.keys_index(this.heap[a]) + const bkey = this.keys_index(this.heap[b]) + ;[this.keys[akey], this.keys[bkey]] = [this.keys[bkey], this.keys[akey]] + super.swap(a, b) } public insert(value: T) { - this.keys[this.keys_index(value)] = this.size(); - super.insert(value); + this.keys[this.keys_index(value)] = this.size() + super.insert(value) } public extract(): T { // Unmark the the highest priority element and set key to zero for the last element in the heap. - this.keys[this.keys_index(this.heap[0])] = -1; + this.keys[this.keys_index(this.heap[0])] = -1 if (this.size() > 1) { - this.keys[this.keys_index(this.heap[this.size() - 1])] = 0; + this.keys[this.keys_index(this.heap[this.size() - 1])] = 0 } - return super.extract(); + return super.extract() } public increasePriority(idx: number, value: T) { if (this.keys[idx] == -1) { // If the key does not exist, insert the value. - this.insert(value); - return; + this.insert(value) + return } - const key = this.keys[idx]; + const key = this.keys[idx] if (this.compare(this.heap[key], value)) { // Do not do anything if the value in the heap already has a higher priority. - return; + return } // Increase the priority and bubble it up the heap. - this.heap[key] = value; - this.bubbleUp(key); + this.heap[key] = value + this.bubbleUp(key) } } diff --git a/data_structures/heap/test/heap.test.ts b/data_structures/heap/test/heap.test.ts index 3b90fc9b..9b513335 100644 --- a/data_structures/heap/test/heap.test.ts +++ b/data_structures/heap/test/heap.test.ts @@ -1,133 +1,139 @@ -import { MaxHeap, MinHeap, PriorityQueue } from "../heap"; +import { MaxHeap, MinHeap, PriorityQueue } from '../heap' -describe("MaxHeap", () => { - let heap: MaxHeap; +describe('MaxHeap', () => { + let heap: MaxHeap const elements: number[] = [ - 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18, - ]; + 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18 + ] beforeEach(() => { - heap = new MaxHeap(); + heap = new MaxHeap() for (const element of elements) { - heap.insert(element); + heap.insert(element) } - }); + }) - it("should initialize a heap from input array", () => { - expect(heap.isEmpty()).toEqual(false); - heap.check(); - }); + it('should initialize a heap from input array', () => { + expect(heap.isEmpty()).toEqual(false) + heap.check() + }) - it("should remove and return the max element in the heap", () => { - const maxValue = heap.extract(); + it('should remove and return the max element in the heap', () => { + const maxValue = heap.extract() - expect(maxValue).toEqual(81); - heap.check(); - }); + expect(maxValue).toEqual(81) + heap.check() + }) - it("should insert a new element and bubble Up the element to it correct index in the heap", () => { - heap.insert(61); - heap.check(); - }); + it('should insert a new element and bubble Up the element to it correct index in the heap', () => { + heap.insert(61) + heap.check() + }) const extract_all = (heap: MaxHeap) => { - [...elements].sort((a, b) => b - a).forEach((element: number) => { - expect(heap.extract()).toEqual(element); - }); - heap.check(); - expect(heap.size()).toEqual(0); + ;[...elements] + .sort((a, b) => b - a) + .forEach((element: number) => { + expect(heap.extract()).toEqual(element) + }) + heap.check() + expect(heap.size()).toEqual(0) } - it("should remove and return the max elements in order", () => { - extract_all(heap); - }); + it('should remove and return the max elements in order', () => { + extract_all(heap) + }) - it("should insert all, then remove and return the max elements in order", () => { - heap = new MaxHeap(); + it('should insert all, then remove and return the max elements in order', () => { + heap = new MaxHeap() elements.forEach((element: number) => { - heap.insert(element); - }); - heap.check(); - expect(heap.size()).toEqual(elements.length); - extract_all(heap); - }); -}); - -describe("MinHeap", () => { - let heap: MinHeap; + heap.insert(element) + }) + heap.check() + expect(heap.size()).toEqual(elements.length) + extract_all(heap) + }) +}) + +describe('MinHeap', () => { + let heap: MinHeap const elements: number[] = [ - 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18, - ]; + 12, 4, 43, 42, 9, 7, 39, 16, 55, 1, 51, 34, 81, 18 + ] beforeEach(() => { - heap = new MinHeap(); + heap = new MinHeap() for (const element of elements) { - heap.insert(element); + heap.insert(element) } - }); + }) - it("should initialize a heap from input array", () => { - expect(heap.isEmpty()).toEqual(false); - heap.check(); - }); + it('should initialize a heap from input array', () => { + expect(heap.isEmpty()).toEqual(false) + heap.check() + }) - it("should remove and return the min element in the heap", () => { - const minValue = heap.extract(); + it('should remove and return the min element in the heap', () => { + const minValue = heap.extract() - expect(minValue).toEqual(1); - heap.check(); - }); + expect(minValue).toEqual(1) + heap.check() + }) - it("should insert a new element and bubble Up the element to it correct index in the heap", () => { - heap.insert(24); - heap.check(); - }); + it('should insert a new element and bubble Up the element to it correct index in the heap', () => { + heap.insert(24) + heap.check() + }) const extract_all = (heap: MinHeap, elements: number[]) => { - [...elements].sort((a, b) => a - b).forEach((element: number) => { - expect(heap.extract()).toEqual(element); - }); - heap.check(); - expect(heap.size()).toEqual(0); + ;[...elements] + .sort((a, b) => a - b) + .forEach((element: number) => { + expect(heap.extract()).toEqual(element) + }) + heap.check() + expect(heap.size()).toEqual(0) } - it("should remove and return the min elements in order", () => { - extract_all(heap, elements); - }); + it('should remove and return the min elements in order', () => { + extract_all(heap, elements) + }) - it("should insert all, then remove and return the min elements in order", () => { - heap = new MinHeap(); + it('should insert all, then remove and return the min elements in order', () => { + heap = new MinHeap() elements.forEach((element: number) => { - heap.insert(element); - }); - heap.check(); - expect(heap.size()).toEqual(elements.length); - extract_all(heap, elements); - }); - - it("should increase priority", () => { - const heap = new PriorityQueue((a: number) => { return a; }, elements.length); + heap.insert(element) + }) + heap.check() + expect(heap.size()).toEqual(elements.length) + extract_all(heap, elements) + }) + + it('should increase priority', () => { + const heap = new PriorityQueue((a: number) => { + return a + }, elements.length) elements.forEach((element: number) => { - heap.insert(element); - }); - heap.check(); - expect(heap.size()).toEqual(elements.length); - - heap.increasePriority(55, 14); - heap.increasePriority(18, 16); - heap.increasePriority(81, 72); - heap.increasePriority(9, 0); - heap.increasePriority(43, 33); + heap.insert(element) + }) + heap.check() + expect(heap.size()).toEqual(elements.length) + + heap.increasePriority(55, 14) + heap.increasePriority(18, 16) + heap.increasePriority(81, 72) + heap.increasePriority(9, 0) + heap.increasePriority(43, 33) // decreasing priority should do nothing - heap.increasePriority(72, 100); - heap.increasePriority(12, 24); - heap.increasePriority(39, 40); + heap.increasePriority(72, 100) + heap.increasePriority(12, 24) + heap.increasePriority(39, 40) - heap.check(); + heap.check() // Elements after increasing priority const newElements: number[] = [ - 12, 4, 33, 42, 0, 7, 39, 16, 14, 1, 51, 34, 72, 16, - ]; - extract_all(heap, newElements); - }); -}); + 12, 4, 33, 42, 0, 7, 39, 16, 14, 1, 51, 34, 72, 16 + ] + extract_all(heap, newElements) + }) +}) diff --git a/data_structures/list/doubly_linked_list.ts b/data_structures/list/doubly_linked_list.ts index 7ed7447f..7cb90f4e 100644 --- a/data_structures/list/doubly_linked_list.ts +++ b/data_structures/list/doubly_linked_list.ts @@ -1,4 +1,4 @@ -import { LinkedList } from "./linked_list"; +import { LinkedList } from './linked_list' /** * This is an implementation of a Doubly Linked List. @@ -13,270 +13,270 @@ import { LinkedList } from "./linked_list"; * @property length The length of the list. */ export class DoublyLinkedList implements LinkedList { - private head?: DoublyLinkedListNode = undefined; - private tail?: DoublyLinkedListNode = undefined; - private length: number = 0; - - /** - * Checks if the list is empty. - * - * @returns {boolean} Whether the list is empty or not. - */ - isEmpty(): boolean { - return !this.head; + private head?: DoublyLinkedListNode = undefined + private tail?: DoublyLinkedListNode = undefined + private length: number = 0 + + /** + * Checks if the list is empty. + * + * @returns {boolean} Whether the list is empty or not. + */ + isEmpty(): boolean { + return !this.head + } + + /** + * Gets a value of a node at a specific index. + * Time complexity: O(n) + * + * @param index The index of the node. + * @returns The value of a node at the specified index. + */ + get(index: number): T | null { + if (index < 0 || index >= this.length) { + return null } - /** - * Gets a value of a node at a specific index. - * Time complexity: O(n) - * - * @param index The index of the node. - * @returns The value of a node at the specified index. - */ - get(index: number): T | null { - if (index < 0 || index >= this.length) { - return null; - } - - let currentNode: DoublyLinkedListNode | undefined = this.head; - for (let i: number = 0; i < index; i++) { - currentNode = currentNode?.next; - } - - return currentNode?.value ?? null; + let currentNode: DoublyLinkedListNode | undefined = this.head + for (let i: number = 0; i < index; i++) { + currentNode = currentNode?.next } - /** - * Inserts a node at the head of the list. - * Time complexity: O(1) - * - * @param value The value of the node being inserted. - */ - push(value: T): void { - const newNode = new DoublyLinkedListNode(value); - - if (!this.head) { - this.head = newNode; - this.tail = newNode; - } else { - this.head.prev = newNode; - newNode.next = this.head; - this.head = newNode; - } - - this.length++; + return currentNode?.value ?? null + } + + /** + * Inserts a node at the head of the list. + * Time complexity: O(1) + * + * @param value The value of the node being inserted. + */ + push(value: T): void { + const newNode = new DoublyLinkedListNode(value) + + if (!this.head) { + this.head = newNode + this.tail = newNode + } else { + this.head.prev = newNode + newNode.next = this.head + this.head = newNode } - /** - * Removes a node from the head of the list. - * Time complexity: O(1) - * - * @returns The value of the node that was removed. - * @throws Index out of bounds if the list is empty. - */ - pop(): T { - if (!this.head) { - throw new Error("Index out of bounds"); - } - - const removedNode = this.head; - - if (this.head === this.tail) { - this.tail = undefined; - } else { - this.head.next!.prev = undefined; - } - - this.head = this.head.next; - this.length--; - - return removedNode.value; + this.length++ + } + + /** + * Removes a node from the head of the list. + * Time complexity: O(1) + * + * @returns The value of the node that was removed. + * @throws Index out of bounds if the list is empty. + */ + pop(): T { + if (!this.head) { + throw new Error('Index out of bounds') } - /** - * Inserts a node at the tail of the list. - * Time complexity: O(1) - * - * @param value The value of the node being inserted. - */ - append(value: T): void { - const newNode = new DoublyLinkedListNode(value); - - if (!this.head) { - this.head = newNode; - } else { - this.tail!.next = newNode; - newNode.prev = this.tail; - } - - this.tail = newNode; - this.length++; - } + const removedNode = this.head - /** - * Removes a node from the tail of the list. - * Time complexity: O(1) - * - * @returns The value of the node that was removed. - * @throws Index out of bounds if the list is empty. - */ - removeTail(): T { - if (!this.head) { - throw new Error("Index out of bounds"); - } - - const removedNode = this.tail; - - if (this.head === this.tail) { - this.head = undefined; - } else { - this.tail!.prev!.next = undefined; - } - - this.tail = this.tail!.prev; - this.length--; - - return removedNode!.value; + if (this.head === this.tail) { + this.tail = undefined + } else { + this.head.next!.prev = undefined } - /** - * Inserts a node at a specific index. - * Time complexity: O(n) - * - * @param index The index where the node will be inserted. - * @param value The value of the node being inserted. - * @throws Index out of bounds if the index is not valid. - */ - insertAt(index: number, value: T): void { - if (index < 0 || index > this.length) { - throw new Error("Index out of bounds"); - } - - if (index === 0) { - this.push(value); - return; - } - - if (index === this.length) { - this.append(value); - return; - } - - const newNode = new DoublyLinkedListNode(value); - let prevNode: DoublyLinkedListNode | undefined = this.head; - for (let i: number = 0; i < index - 1; i++) { - prevNode = prevNode?.next; - } - const nextNode = prevNode?.next; - - prevNode!.next = newNode; - newNode.prev = prevNode; - newNode.next = nextNode; - nextNode!.prev = newNode; - - this.length++; + this.head = this.head.next + this.length-- + + return removedNode.value + } + + /** + * Inserts a node at the tail of the list. + * Time complexity: O(1) + * + * @param value The value of the node being inserted. + */ + append(value: T): void { + const newNode = new DoublyLinkedListNode(value) + + if (!this.head) { + this.head = newNode + } else { + this.tail!.next = newNode + newNode.prev = this.tail } - /** - * Removes a node at a specific index. - * Time complexity: O(n) - * - * @param index The index of the node to be removed. - * @returns The value of the node that was removed. - * @throws Index out of bounds if the index is not valid. - */ - removeAt(index: number): T { - if (index < 0 || index >= this.length) { - throw new Error("Index out of bounds"); - } - - if (index === 0) { - return this.pop(); - } - - if (index === this.length - 1) { - return this.removeTail(); - } - - let removedNode: DoublyLinkedListNode | undefined = this.head; - for (let i: number = 0; i < index; i++) { - removedNode = removedNode?.next; - } - removedNode!.prev!.next = removedNode!.next; - removedNode!.next!.prev = removedNode!.prev; - - this.length--; - - return removedNode!.value; + this.tail = newNode + this.length++ + } + + /** + * Removes a node from the tail of the list. + * Time complexity: O(1) + * + * @returns The value of the node that was removed. + * @throws Index out of bounds if the list is empty. + */ + removeTail(): T { + if (!this.head) { + throw new Error('Index out of bounds') } - /** - * Reverses the list. - * Time complexity: O(n) - * - * @returns The reversed list or null if the list is empty. - */ - reverse(): DoublyLinkedList | null { - if (!this.head) { - return null; - } + const removedNode = this.tail - let currentNode: DoublyLinkedListNode | undefined = this.head; - let nextNode: DoublyLinkedListNode | undefined = undefined; - let prevNode: DoublyLinkedListNode | undefined = undefined; + if (this.head === this.tail) { + this.head = undefined + } else { + this.tail!.prev!.next = undefined + } - while (currentNode) { - nextNode = currentNode.next; - prevNode = currentNode.prev; + this.tail = this.tail!.prev + this.length-- + + return removedNode!.value + } + + /** + * Inserts a node at a specific index. + * Time complexity: O(n) + * + * @param index The index where the node will be inserted. + * @param value The value of the node being inserted. + * @throws Index out of bounds if the index is not valid. + */ + insertAt(index: number, value: T): void { + if (index < 0 || index > this.length) { + throw new Error('Index out of bounds') + } - currentNode.next = prevNode; - currentNode.prev = nextNode; + if (index === 0) { + this.push(value) + return + } - prevNode = currentNode; - currentNode = nextNode; - } + if (index === this.length) { + this.append(value) + return + } - this.tail = this.head; - this.head = prevNode; + const newNode = new DoublyLinkedListNode(value) + let prevNode: DoublyLinkedListNode | undefined = this.head + for (let i: number = 0; i < index - 1; i++) { + prevNode = prevNode?.next + } + const nextNode = prevNode?.next + + prevNode!.next = newNode + newNode.prev = prevNode + newNode.next = nextNode + nextNode!.prev = newNode + + this.length++ + } + + /** + * Removes a node at a specific index. + * Time complexity: O(n) + * + * @param index The index of the node to be removed. + * @returns The value of the node that was removed. + * @throws Index out of bounds if the index is not valid. + */ + removeAt(index: number): T { + if (index < 0 || index >= this.length) { + throw new Error('Index out of bounds') + } - return this; + if (index === 0) { + return this.pop() } - /** - * Clears the list. - */ - clear(): void { - this.head = undefined; - this.tail = undefined; - this.length = 0; + if (index === this.length - 1) { + return this.removeTail() } - /** - * Converts the list to an array. - * - * @returns The array representation of the list. - */ - toArray(): T[] { - const array: T[] = []; + let removedNode: DoublyLinkedListNode | undefined = this.head + for (let i: number = 0; i < index; i++) { + removedNode = removedNode?.next + } + removedNode!.prev!.next = removedNode!.next + removedNode!.next!.prev = removedNode!.prev + + this.length-- + + return removedNode!.value + } + + /** + * Reverses the list. + * Time complexity: O(n) + * + * @returns The reversed list or null if the list is empty. + */ + reverse(): DoublyLinkedList | null { + if (!this.head) { + return null + } - let currentNode: DoublyLinkedListNode | undefined = this.head; + let currentNode: DoublyLinkedListNode | undefined = this.head + let nextNode: DoublyLinkedListNode | undefined = undefined + let prevNode: DoublyLinkedListNode | undefined = undefined - while (currentNode) { - array.push(currentNode.value); - currentNode = currentNode.next; - } + while (currentNode) { + nextNode = currentNode.next + prevNode = currentNode.prev - return array; + currentNode.next = prevNode + currentNode.prev = nextNode + + prevNode = currentNode + currentNode = nextNode } - /** - * Gets the length of the list. - * - * @returns The length of the list. - */ - getLength(): number { - return this.length; + this.tail = this.head + this.head = prevNode + + return this + } + + /** + * Clears the list. + */ + clear(): void { + this.head = undefined + this.tail = undefined + this.length = 0 + } + + /** + * Converts the list to an array. + * + * @returns The array representation of the list. + */ + toArray(): T[] { + const array: T[] = [] + + let currentNode: DoublyLinkedListNode | undefined = this.head + + while (currentNode) { + array.push(currentNode.value) + currentNode = currentNode.next } + + return array + } + + /** + * Gets the length of the list. + * + * @returns The length of the list. + */ + getLength(): number { + return this.length + } } /** @@ -288,9 +288,9 @@ export class DoublyLinkedList implements LinkedList { * @property prev The previous node before this node. */ class DoublyLinkedListNode { - constructor( - public value: T, - public next?: DoublyLinkedListNode, - public prev?: DoublyLinkedListNode - ) {} + constructor( + public value: T, + public next?: DoublyLinkedListNode, + public prev?: DoublyLinkedListNode + ) {} } diff --git a/data_structures/list/linked_list.ts b/data_structures/list/linked_list.ts index 596af23b..8c6eee94 100644 --- a/data_structures/list/linked_list.ts +++ b/data_structures/list/linked_list.ts @@ -2,15 +2,15 @@ * An interface for linked lists, which shares the common methods. */ export interface LinkedList { - isEmpty(): boolean; - get(index: number): T | null | undefined; - push(data: T): void; - pop(): T | undefined; - append(data: T): void; - removeTail(): T | undefined; - insertAt(index: number, data: T): void; - removeAt(index: number): T | undefined; - clear(): void; - toArray(): (T | undefined)[]; - getLength(): number; + isEmpty(): boolean + get(index: number): T | null | undefined + push(data: T): void + pop(): T | undefined + append(data: T): void + removeTail(): T | undefined + insertAt(index: number, data: T): void + removeAt(index: number): T | undefined + clear(): void + toArray(): (T | undefined)[] + getLength(): number } diff --git a/data_structures/list/singly_linked_list.ts b/data_structures/list/singly_linked_list.ts index 56172a8c..0a3ef7b2 100644 --- a/data_structures/list/singly_linked_list.ts +++ b/data_structures/list/singly_linked_list.ts @@ -1,4 +1,4 @@ -import { LinkedList } from "./linked_list"; +import { LinkedList } from './linked_list' /** * Represents a node in a linked list. @@ -8,7 +8,10 @@ import { LinkedList } from "./linked_list"; * @property next A reference to the next node in the list. Can reference to null, if there is no next element. */ class ListNode { - constructor(public data: T, public next?: ListNode) {} + constructor( + public data: T, + public next?: ListNode + ) {} } /** @@ -23,17 +26,17 @@ class ListNode { * @property length The length of the list. */ export class SinglyLinkedList implements LinkedList { - private head?: ListNode; - private tail?: ListNode; - private length: number; + private head?: ListNode + private tail?: ListNode + private length: number /** * Creates a new, empty linked list. */ constructor() { - this.head = undefined; - this.tail = undefined; - this.length = 0; + this.head = undefined + this.tail = undefined + this.length = 0 } /** @@ -42,7 +45,7 @@ export class SinglyLinkedList implements LinkedList { * @returns Whether the list is empty or not. */ isEmpty(): boolean { - return !this.head; + return !this.head } /** @@ -54,23 +57,23 @@ export class SinglyLinkedList implements LinkedList { */ get(index: number): T | null { if (index < 0 || index >= this.length) { - return null; + return null } if (this.isEmpty()) { - return null; + return null } - let currentNode: ListNode = this.head!; + let currentNode: ListNode = this.head! for (let i: number = 0; i < index; i++) { if (!currentNode.next) { - return null; + return null } - currentNode = currentNode.next; + currentNode = currentNode.next } - return currentNode.data; + return currentNode.data } /** @@ -80,17 +83,17 @@ export class SinglyLinkedList implements LinkedList { * @param data The data to be inserted. */ push(data: T): void { - const node: ListNode = new ListNode(data); + const node: ListNode = new ListNode(data) if (this.isEmpty()) { - this.head = node; - this.tail = node; + this.head = node + this.tail = node } else { - node.next = this.head; - this.head = node; + node.next = this.head + this.head = node } - this.length++; + this.length++ } /** @@ -102,14 +105,14 @@ export class SinglyLinkedList implements LinkedList { */ pop(): T { if (this.isEmpty()) { - throw new Error('Index out of bounds'); + throw new Error('Index out of bounds') } - const node: ListNode = this.head!; - this.head = this.head!.next; - this.length--; + const node: ListNode = this.head! + this.head = this.head!.next + this.length-- - return node.data; + return node.data } /** @@ -119,16 +122,16 @@ export class SinglyLinkedList implements LinkedList { * @param data The data of the node being inserted. */ append(data: T): void { - const node: ListNode = new ListNode(data); + const node: ListNode = new ListNode(data) if (this.isEmpty()) { - this.head = node; + this.head = node } else { - this.tail!.next = node; + this.tail!.next = node } - this.tail = node; - this.length++; + this.tail = node + this.length++ } /** @@ -140,27 +143,27 @@ export class SinglyLinkedList implements LinkedList { */ removeTail(): T { if (!this.head) { - throw new Error('Index out of bounds'); + throw new Error('Index out of bounds') } - const currentTail = this.tail; + const currentTail = this.tail if (this.head === this.tail) { - this.head = undefined; - this.tail = undefined; - this.length--; + this.head = undefined + this.tail = undefined + this.length-- - return currentTail!.data; + return currentTail!.data } - let currentNode: ListNode = this.head; + let currentNode: ListNode = this.head while (currentNode.next !== currentTail) { - currentNode = currentNode.next!; + currentNode = currentNode.next! } - this.tail = currentNode; - this.length--; + this.tail = currentNode + this.length-- - return currentTail!.data; + return currentTail!.data } /** @@ -173,32 +176,32 @@ export class SinglyLinkedList implements LinkedList { */ insertAt(index: number, data: T): void { if (index < 0 || index > this.length) { - throw new Error('Index out of bounds'); + throw new Error('Index out of bounds') } if (index === 0) { - this.push(data); + this.push(data) - return; + return } if (index === this.length) { - this.append(data); + this.append(data) - return; + return } - const newNode = new ListNode(data); - let currentNode: ListNode | undefined = this.head; + const newNode = new ListNode(data) + let currentNode: ListNode | undefined = this.head for (let i: number = 0; i < index - 1; i++) { - currentNode = currentNode?.next; + currentNode = currentNode?.next } - const nextNode = currentNode?.next; - currentNode!.next = newNode; - newNode.next = nextNode; + const nextNode = currentNode?.next + currentNode!.next = newNode + newNode.next = nextNode - this.length++; + this.length++ } /** @@ -211,40 +214,40 @@ export class SinglyLinkedList implements LinkedList { */ removeAt(index: number): T { if (index < 0 || index >= this.length) { - throw new Error('Index out of bounds'); + throw new Error('Index out of bounds') } if (index === 0) { - return this.pop(); + return this.pop() } if (index === this.length - 1) { - return this.removeTail(); + return this.removeTail() } - let previousNode: ListNode | undefined; - let currentNode: ListNode | undefined = this.head; + let previousNode: ListNode | undefined + let currentNode: ListNode | undefined = this.head for (let i: number = 0; i < index; i++) { if (i === index - 1) { - previousNode = currentNode; + previousNode = currentNode } - currentNode = currentNode?.next; + currentNode = currentNode?.next } - previousNode!.next = currentNode?.next; - this.length--; + previousNode!.next = currentNode?.next + this.length-- - return currentNode!.data; + return currentNode!.data } /** * Clears the list. */ clear(): void { - this.head = undefined; - this.tail = undefined; - this.length = 0; + this.head = undefined + this.tail = undefined + this.length = 0 } /** @@ -253,15 +256,15 @@ export class SinglyLinkedList implements LinkedList { * @returns The array representation of the list. */ toArray(): T[] { - const array: T[] = []; - let currentNode: ListNode | undefined = this.head; + const array: T[] = [] + let currentNode: ListNode | undefined = this.head while (currentNode) { - array.push(currentNode.data); - currentNode = currentNode.next; + array.push(currentNode.data) + currentNode = currentNode.next } - return array; + return array } /** @@ -270,6 +273,6 @@ export class SinglyLinkedList implements LinkedList { * @returns The length of the list. */ getLength(): number { - return this.length; + return this.length } } diff --git a/data_structures/list/test/doubly_linked_list.test.ts b/data_structures/list/test/doubly_linked_list.test.ts index 2e41d3af..f0c611cd 100644 --- a/data_structures/list/test/doubly_linked_list.test.ts +++ b/data_structures/list/test/doubly_linked_list.test.ts @@ -1,24 +1,24 @@ -import { DoublyLinkedList } from "../doubly_linked_list"; -import { testLinkedList } from "./linked_list"; +import { DoublyLinkedList } from '../doubly_linked_list' +import { testLinkedList } from './linked_list' -describe("DoublyLinkedList", () => { - testLinkedList(DoublyLinkedList); +describe('DoublyLinkedList', () => { + testLinkedList(DoublyLinkedList) - it("should reverse the list", () => { - const list: DoublyLinkedList = new DoublyLinkedList(); + it('should reverse the list', () => { + const list: DoublyLinkedList = new DoublyLinkedList() - list.append(1); - list.append(2); - list.append(3); - list.reverse(); + list.append(1) + list.append(2) + list.append(3) + list.reverse() - expect(list.get(0)).toBe(3); - expect(list.get(1)).toBe(2); - }); + expect(list.get(0)).toBe(3) + expect(list.get(1)).toBe(2) + }) - it("should return null for reverse when list is empty", () => { - const list: DoublyLinkedList = new DoublyLinkedList(); + it('should return null for reverse when list is empty', () => { + const list: DoublyLinkedList = new DoublyLinkedList() - expect(list.reverse()).toBeNull(); - }); -}); + expect(list.reverse()).toBeNull() + }) +}) diff --git a/data_structures/list/test/linked_list.ts b/data_structures/list/test/linked_list.ts index 5717ab15..6d76c930 100644 --- a/data_structures/list/test/linked_list.ts +++ b/data_structures/list/test/linked_list.ts @@ -1,109 +1,109 @@ -import { LinkedList } from "../linked_list"; +import { LinkedList } from '../linked_list' -type LinkedListConstructor = new () => LinkedList; +type LinkedListConstructor = new () => LinkedList export function testLinkedList(LinkedList: LinkedListConstructor) { describe('with filled list (push)', () => { - let list: LinkedList = new LinkedList; + let list: LinkedList = new LinkedList() beforeEach(() => { - list = new LinkedList(); - list.push(1); - list.push(2); - list.push(3); - }); + list = new LinkedList() + list.push(1) + list.push(2) + list.push(3) + }) it('should return false for isEmpty when list is not empty', () => { - expect(list.isEmpty()).toBeFalsy(); - }); + expect(list.isEmpty()).toBeFalsy() + }) it('should return correct node for get', () => { - expect(list.get(1)).toBe(2); - }); + expect(list.get(1)).toBe(2) + }) it('should push nodes to the list and return correct head and tail', () => { - expect(list.get(0)).toBe(3); - expect(list.get(2)).toBe(1); - }); + expect(list.get(0)).toBe(3) + expect(list.get(2)).toBe(1) + }) it('should pop nodes from the list and return correct head and tail', () => { - expect(list.pop()).toBe(3); - expect(list.get(0)).toBe(2); - expect(list.get(1)).toBe(1); - }); - }); + expect(list.pop()).toBe(3) + expect(list.get(0)).toBe(2) + expect(list.get(1)).toBe(1) + }) + }) describe('with filled list (append)', () => { - let list: LinkedList = new LinkedList(); + let list: LinkedList = new LinkedList() beforeEach(() => { - list = new LinkedList(); - list.append(1); - list.append(2); - list.append(3); - }); + list = new LinkedList() + list.append(1) + list.append(2) + list.append(3) + }) it('should append nodes to the list and return correct head and tail', () => { - expect(list.get(0)).toBe(1); - expect(list.get(2)).toBe(3); - }); + expect(list.get(0)).toBe(1) + expect(list.get(2)).toBe(3) + }) it('should remove tail from the list and return correct head and tail', () => { - expect(list.removeTail()).toBe(3); - expect(list.get(0)).toBe(1); - expect(list.get(1)).toBe(2); - }); + expect(list.removeTail()).toBe(3) + expect(list.get(0)).toBe(1) + expect(list.get(1)).toBe(2) + }) it('should insert nodes at the correct index', () => { - list.insertAt(1, 4); + list.insertAt(1, 4) - expect(list.get(1)).toBe(4); - }); + expect(list.get(1)).toBe(4) + }) it('should remove nodes at the correct index', () => { - expect(list.removeAt(1)).toBe(2); - }); + expect(list.removeAt(1)).toBe(2) + }) it('should return null for removeAt when index is out of bounds', () => { - expect(() => list.removeAt(3)).toThrowError('Index out of bounds'); - }); + expect(() => list.removeAt(3)).toThrowError('Index out of bounds') + }) it('should clear the list', () => { - list.clear(); + list.clear() - expect(list.isEmpty()).toBeTruthy(); - }); + expect(list.isEmpty()).toBeTruthy() + }) it('should convert the list to an array', () => { - expect(list.toArray()).toEqual([1, 2, 3]); - }); + expect(list.toArray()).toEqual([1, 2, 3]) + }) it('should return correct length', () => { - expect(list.getLength()).toBe(3); - }); - }); + expect(list.getLength()).toBe(3) + }) + }) describe('with empty list', () => { - let list: LinkedList; + let list: LinkedList beforeEach(() => { - list = new LinkedList(); - }); + list = new LinkedList() + }) it('should return true for isEmpty when list is empty', () => { - expect(list.isEmpty()).toBeTruthy(); - }); + expect(list.isEmpty()).toBeTruthy() + }) it('should return null for get when index is out of bounds', () => { - expect(list.get(1)).toBeNull(); - }); + expect(list.get(1)).toBeNull() + }) it('should throw error for pop when list is empty', () => { - expect(() => list.pop()).toThrowError('Index out of bounds'); - }); + expect(() => list.pop()).toThrowError('Index out of bounds') + }) it('should return null for removeTail when list is empty', () => { - expect(() => list.removeTail()).toThrowError('Index out of bounds'); - }); - }); -} \ No newline at end of file + expect(() => list.removeTail()).toThrowError('Index out of bounds') + }) + }) +} diff --git a/data_structures/list/test/singly_linked_list.test.ts b/data_structures/list/test/singly_linked_list.test.ts index 0754c5e6..80ef33d5 100644 --- a/data_structures/list/test/singly_linked_list.test.ts +++ b/data_structures/list/test/singly_linked_list.test.ts @@ -1,4 +1,4 @@ -import { SinglyLinkedList } from "../singly_linked_list"; -import { testLinkedList } from "./linked_list"; +import { SinglyLinkedList } from '../singly_linked_list' +import { testLinkedList } from './linked_list' -describe("Singly linked list", () => testLinkedList(SinglyLinkedList)); \ No newline at end of file +describe('Singly linked list', () => testLinkedList(SinglyLinkedList)) diff --git a/data_structures/map/hash_map.ts b/data_structures/map/hash_map.ts index 900848a5..ed121110 100644 --- a/data_structures/map/hash_map.ts +++ b/data_structures/map/hash_map.ts @@ -1,4 +1,4 @@ -import { Map } from "./map"; +import { Map } from './map' /** * Represents a hash map. @@ -14,210 +14,210 @@ import { Map } from "./map"; * @param loadFactor The load factor to determine when to resize the hash map. */ export class HashMap implements Map { - private size!: number; - private buckets!: MapEntry[][]; - private readonly loadFactor = 0.75; - - constructor() { - this.clear(); + private size!: number + private buckets!: MapEntry[][] + private readonly loadFactor = 0.75 + + constructor() { + this.clear() + } + + /** + * Gets the size. + * + * @returns The size. + */ + getSize(): number { + return this.size + } + + /** + * Sets a key-value pair. + * + * @param key The key. + * @param value The value. + */ + set(key: K, value: V): void { + const loadFactor = this.size / this.buckets.length + if (loadFactor > this.loadFactor) { + this.resize() } - /** - * Gets the size. - * - * @returns The size. - */ - getSize(): number { - return this.size; - } + const index = this.hash(key) + const bucket = this.buckets[index] - /** - * Sets a key-value pair. - * - * @param key The key. - * @param value The value. - */ - set(key: K, value: V): void { - const loadFactor = this.size / this.buckets.length; - if (loadFactor > this.loadFactor) { - this.resize(); - } - - const index = this.hash(key); - const bucket = this.buckets[index]; - - if (bucket.length === 0) { - bucket.push(new MapEntry(key, value)); - this.size++; - return; - } - - for (const entry of bucket) { - if (entry.key === key) { - entry.value = value; - return; - } - } - - bucket.push(new MapEntry(key, value)); - this.size++; + if (bucket.length === 0) { + bucket.push(new MapEntry(key, value)) + this.size++ + return } - /** - * Gets a value. - * - * @param key The key to get the value for. - * @returns The value or null if the key does not exist. - */ - get(key: K): V | null { - const index = this.hash(key); - const bucket = this.buckets[index]; - - for (const entry of bucket) { - if (entry.key === key) { - return entry.value; - } - } - - return null; + for (const entry of bucket) { + if (entry.key === key) { + entry.value = value + return + } } - /** - * Deletes a key-value pair. - * - * @param key The key whose key-value pair to delete. - */ - delete(key: K): void { - const index = this.hash(key); - const bucket = this.buckets[index]; - - for (const entry of bucket) { - if (entry.key === key) { - bucket.splice(bucket.indexOf(entry), 1); - this.size--; - return; - } - } + bucket.push(new MapEntry(key, value)) + this.size++ + } + + /** + * Gets a value. + * + * @param key The key to get the value for. + * @returns The value or null if the key does not exist. + */ + get(key: K): V | null { + const index = this.hash(key) + const bucket = this.buckets[index] + + for (const entry of bucket) { + if (entry.key === key) { + return entry.value + } } - /** - * Checks if a key exists. - * - * @param key The key. - * @returns Whether the key exists. - */ - has(key: K): boolean { - const index = this.hash(key); - const bucket = this.buckets[index]; - - for (const entry of bucket) { - if (entry.key === key) { - return true; - } - } - - return false; + return null + } + + /** + * Deletes a key-value pair. + * + * @param key The key whose key-value pair to delete. + */ + delete(key: K): void { + const index = this.hash(key) + const bucket = this.buckets[index] + + for (const entry of bucket) { + if (entry.key === key) { + bucket.splice(bucket.indexOf(entry), 1) + this.size-- + return + } } - - /** - * Clears the hash map. - */ - clear(): void { - this.size = 0; - this.initializeBuckets(16); + } + + /** + * Checks if a key exists. + * + * @param key The key. + * @returns Whether the key exists. + */ + has(key: K): boolean { + const index = this.hash(key) + const bucket = this.buckets[index] + + for (const entry of bucket) { + if (entry.key === key) { + return true + } } - /** - * Gets all keys. - * - * @returns The keys. - */ - keys(): K[] { - const keys: K[] = []; - for (const bucket of this.buckets) { - for (const entry of bucket) { - keys.push(entry.key); - } - } - - return keys; + return false + } + + /** + * Clears the hash map. + */ + clear(): void { + this.size = 0 + this.initializeBuckets(16) + } + + /** + * Gets all keys. + * + * @returns The keys. + */ + keys(): K[] { + const keys: K[] = [] + for (const bucket of this.buckets) { + for (const entry of bucket) { + keys.push(entry.key) + } } - /** - * Gets all values. - * - * @returns The values. - */ - values(): V[] { - const values: V[] = []; - for (const bucket of this.buckets) { - for (const entry of bucket) { - values.push(entry.value); - } - } - - return values; + return keys + } + + /** + * Gets all values. + * + * @returns The values. + */ + values(): V[] { + const values: V[] = [] + for (const bucket of this.buckets) { + for (const entry of bucket) { + values.push(entry.value) + } } - /** - * Gets all entries. - * - * @returns The entries. - */ - entries(): MapEntry[] { - const entries: MapEntry[] = []; - for (const bucket of this.buckets) { - for (const entry of bucket) { - entries.push(entry); - } - } - - return entries; + return values + } + + /** + * Gets all entries. + * + * @returns The entries. + */ + entries(): MapEntry[] { + const entries: MapEntry[] = [] + for (const bucket of this.buckets) { + for (const entry of bucket) { + entries.push(entry) + } } - /** - * Initializes the buckets. - * - * @param amount The amount of buckets to initialize. - */ - private initializeBuckets(amount: number): void { - this.buckets = []; - for (let i = 0; i < amount; i++) { - this.buckets.push([]); - } + return entries + } + + /** + * Initializes the buckets. + * + * @param amount The amount of buckets to initialize. + */ + private initializeBuckets(amount: number): void { + this.buckets = [] + for (let i = 0; i < amount; i++) { + this.buckets.push([]) } - - /** - * Hashes a key to an index. - * This implementation uses the djb2 algorithm, which might not be the best. - * Feel free to change it to something else. - * - * @param key The key. - * @return The index. - */ - protected hash(key: K): number { - let hash = 0; - - for (let i = 0; i < String(key).length; i++) { - hash = (hash << 5) - hash + String(key).charCodeAt(i); - } - - return hash % this.buckets.length; + } + + /** + * Hashes a key to an index. + * This implementation uses the djb2 algorithm, which might not be the best. + * Feel free to change it to something else. + * + * @param key The key. + * @return The index. + */ + protected hash(key: K): number { + let hash = 0 + + for (let i = 0; i < String(key).length; i++) { + hash = (hash << 5) - hash + String(key).charCodeAt(i) } - /** - * Resizes the hash map by doubling the amount of buckets. - */ - private resize(): void { - const entries = this.entries(); + return hash % this.buckets.length + } + + /** + * Resizes the hash map by doubling the amount of buckets. + */ + private resize(): void { + const entries = this.entries() - this.initializeBuckets(this.buckets.length * 2); - this.size = 0; + this.initializeBuckets(this.buckets.length * 2) + this.size = 0 - for (const entry of entries) { - this.set(entry.key, entry.value); - } + for (const entry of entries) { + this.set(entry.key, entry.value) } + } } /** @@ -229,11 +229,11 @@ export class HashMap implements Map { * @param value The value. */ export class MapEntry { - key: K; - value: V; + key: K + value: V - constructor(key: K, value: V) { - this.key = key; - this.value = value; - } + constructor(key: K, value: V) { + this.key = key + this.value = value + } } diff --git a/data_structures/map/map.ts b/data_structures/map/map.ts index ff2a9fc3..4c3bab55 100644 --- a/data_structures/map/map.ts +++ b/data_structures/map/map.ts @@ -1,16 +1,16 @@ -import { MapEntry } from "./hash_map"; +import { MapEntry } from './hash_map' /** * This interface is a representation of the Map data structure. */ export interface Map { - getSize(): number; - set(key: K, value: V): void; - get(key: K): V | null; - delete(key: K): void; - has(key: K): boolean; - clear(): void; - keys(): K[]; - values(): V[]; - entries(): MapEntry[]; + getSize(): number + set(key: K, value: V): void + get(key: K): V | null + delete(key: K): void + has(key: K): boolean + clear(): void + keys(): K[] + values(): V[] + entries(): MapEntry[] } diff --git a/data_structures/map/test/hash_map.test.ts b/data_structures/map/test/hash_map.test.ts index 16640e97..c2927a28 100644 --- a/data_structures/map/test/hash_map.test.ts +++ b/data_structures/map/test/hash_map.test.ts @@ -1,109 +1,109 @@ -import { HashMap } from "../../map/hash_map"; - -describe("Hash Map", () => { - let hashMap: HashMap; - beforeEach(() => { - hashMap = new HashMap(); - }); - - it("should set a value", () => { - hashMap.set("a", 1); - - expect(hashMap.values()).toEqual([1]); - }); - - it("should override a value", () => { - hashMap.set("a", 1); - hashMap.set("a", 2); - - expect(hashMap.values()).toEqual([2]); - }); - - it("should get a value", () => { - hashMap.set("a", 1); - - expect(hashMap.get("a")).toBe(1); - }); - - it("should get null if key does not exist", () => { - expect(hashMap.get("a")).toBeNull(); - }); - - it("should delete a value", () => { - hashMap.set("a", 1); - hashMap.delete("a"); - - expect(hashMap.get("a")).toBeNull(); - }); - - it("should do nothing on delete if key does not exist", () => { - hashMap.delete("a"); - - expect(hashMap.get("a")).toBeNull(); - }); - - it("should return true if key exists", () => { - hashMap.set("a", 1); - - expect(hashMap.has("a")).toBe(true); - }); - - it("should return false if key does not exist", () => { - expect(hashMap.has("a")).toBe(false); - }); - - it("should clear the hash table", () => { - hashMap.set("a", 1); - hashMap.set("b", 2); - hashMap.set("c", 3); - hashMap.clear(); - - expect(hashMap.getSize()).toBe(0); - }); - - it("should return all keys", () => { - hashMap.set("a", 1); - hashMap.set("b", 2); - hashMap.set("c", 3); - - expect(hashMap.keys()).toEqual(["a", "b", "c"]); - }); - - it("should return all values", () => { - hashMap.set("a", 1); - hashMap.set("b", 2); - hashMap.set("c", 3); - - expect(hashMap.values()).toEqual([1, 2, 3]); - }); - - it("should return all key-value pairs", () => { - hashMap.set("a", 1); - hashMap.set("b", 2); - hashMap.set("c", 3); - - expect(hashMap.entries()).toEqual([ - { key: "a", value: 1 }, - { key: "b", value: 2 }, - { key: "c", value: 3 }, - ]); - }); - - it("should keep entries when trigger resize", () => { - hashMap.set('a', 1); - hashMap.set('b', 2); - hashMap.set('c', 3); - hashMap.set('d', 4); - hashMap.set('e', 5); - hashMap.set('f', 6); - hashMap.set('g', 7); - hashMap.set('h', 8); - hashMap.set('i', 9); - hashMap.set('j', 10); - hashMap.set('k', 11); - hashMap.set('l', 12); - hashMap.set('m', 13); - hashMap.set('n', 14); - expect(hashMap.getSize()).toBe(14); - }) -}); +import { HashMap } from '../../map/hash_map' + +describe('Hash Map', () => { + let hashMap: HashMap + beforeEach(() => { + hashMap = new HashMap() + }) + + it('should set a value', () => { + hashMap.set('a', 1) + + expect(hashMap.values()).toEqual([1]) + }) + + it('should override a value', () => { + hashMap.set('a', 1) + hashMap.set('a', 2) + + expect(hashMap.values()).toEqual([2]) + }) + + it('should get a value', () => { + hashMap.set('a', 1) + + expect(hashMap.get('a')).toBe(1) + }) + + it('should get null if key does not exist', () => { + expect(hashMap.get('a')).toBeNull() + }) + + it('should delete a value', () => { + hashMap.set('a', 1) + hashMap.delete('a') + + expect(hashMap.get('a')).toBeNull() + }) + + it('should do nothing on delete if key does not exist', () => { + hashMap.delete('a') + + expect(hashMap.get('a')).toBeNull() + }) + + it('should return true if key exists', () => { + hashMap.set('a', 1) + + expect(hashMap.has('a')).toBe(true) + }) + + it('should return false if key does not exist', () => { + expect(hashMap.has('a')).toBe(false) + }) + + it('should clear the hash table', () => { + hashMap.set('a', 1) + hashMap.set('b', 2) + hashMap.set('c', 3) + hashMap.clear() + + expect(hashMap.getSize()).toBe(0) + }) + + it('should return all keys', () => { + hashMap.set('a', 1) + hashMap.set('b', 2) + hashMap.set('c', 3) + + expect(hashMap.keys()).toEqual(['a', 'b', 'c']) + }) + + it('should return all values', () => { + hashMap.set('a', 1) + hashMap.set('b', 2) + hashMap.set('c', 3) + + expect(hashMap.values()).toEqual([1, 2, 3]) + }) + + it('should return all key-value pairs', () => { + hashMap.set('a', 1) + hashMap.set('b', 2) + hashMap.set('c', 3) + + expect(hashMap.entries()).toEqual([ + { key: 'a', value: 1 }, + { key: 'b', value: 2 }, + { key: 'c', value: 3 } + ]) + }) + + it('should keep entries when trigger resize', () => { + hashMap.set('a', 1) + hashMap.set('b', 2) + hashMap.set('c', 3) + hashMap.set('d', 4) + hashMap.set('e', 5) + hashMap.set('f', 6) + hashMap.set('g', 7) + hashMap.set('h', 8) + hashMap.set('i', 9) + hashMap.set('j', 10) + hashMap.set('k', 11) + hashMap.set('l', 12) + hashMap.set('m', 13) + hashMap.set('n', 14) + expect(hashMap.getSize()).toBe(14) + }) +}) diff --git a/data_structures/queue/array_queue.ts b/data_structures/queue/array_queue.ts index 19027768..0f53c270 100644 --- a/data_structures/queue/array_queue.ts +++ b/data_structures/queue/array_queue.ts @@ -5,60 +5,60 @@ * The time complexity of the operations is O(n). */ import { Queue } from './queue' -export class ArrayQueue implements Queue{ - private queue: T[] = []; +export class ArrayQueue implements Queue { + private queue: T[] = [] - /** - * Returns the number of items in the queue. - * - * @returns {number} The number of items in the queue. - */ - length(): number { - return this.queue.length; - } + /** + * Returns the number of items in the queue. + * + * @returns {number} The number of items in the queue. + */ + length(): number { + return this.queue.length + } - /** - * Checks if the queue is empty. - * - * @returns {boolean} Whether the queue is empty or not. - */ - isEmpty(): boolean { - return this.queue.length === 0; - } + /** + * Checks if the queue is empty. + * + * @returns {boolean} Whether the queue is empty or not. + */ + isEmpty(): boolean { + return this.queue.length === 0 + } - /** - * Adds an item to the queue. - * - * @param item The item being added to the queue. - */ - enqueue(item: T): void { - this.queue.push(item); - } + /** + * Adds an item to the queue. + * + * @param item The item being added to the queue. + */ + enqueue(item: T): void { + this.queue.push(item) + } - /** - * Removes an item from the queue and returns it. - * - * @throws Queue Underflow if the queue is empty. - * @returns The item that was removed from the queue. - */ - dequeue(): T { - if (this.isEmpty()) { - throw new Error("Queue Underflow"); - } - - return this.queue.shift() as T; + /** + * Removes an item from the queue and returns it. + * + * @throws Queue Underflow if the queue is empty. + * @returns The item that was removed from the queue. + */ + dequeue(): T { + if (this.isEmpty()) { + throw new Error('Queue Underflow') } - /** - * Returns the item at the front of the queue. - * - * @returns The item at the front of the queue or null if the queue is empty. - */ - peek(): T | null { - if (this.isEmpty()) { - return null; - } + return this.queue.shift() as T + } - return this.queue[0]; + /** + * Returns the item at the front of the queue. + * + * @returns The item at the front of the queue or null if the queue is empty. + */ + peek(): T | null { + if (this.isEmpty()) { + return null } + + return this.queue[0] + } } diff --git a/data_structures/queue/circular_queue.ts b/data_structures/queue/circular_queue.ts index ce42e059..8d278163 100644 --- a/data_structures/queue/circular_queue.ts +++ b/data_structures/queue/circular_queue.ts @@ -8,102 +8,102 @@ * @param {number} size The size of the queue. */ export class CircularQueue { - private queue: T[]; - private frontIndex: number; - private rearIndex: number; - private size: number; + private queue: T[] + private frontIndex: number + private rearIndex: number + private size: number - constructor(size: number) { - this.queue = new Array(size); - this.frontIndex = -1; - this.rearIndex = -1; - this.size = size; - } + constructor(size: number) { + this.queue = new Array(size) + this.frontIndex = -1 + this.rearIndex = -1 + this.size = size + } - /** - * Adds an item to the queue. - * - * @param item The item being added to the queue. - */ - enqueue(item: T): void { - if ( - (this.frontIndex == 0 && this.rearIndex == this.size - 1) || - this.rearIndex == (this.frontIndex - 1) % (this.size - 1) - ) { - throw new Error("Queue is full"); - } else if (this.frontIndex == -1) { - this.frontIndex = 0; - this.rearIndex = 0; - this.queue[this.rearIndex] = item; - } else if (this.rearIndex == this.size - 1 && this.frontIndex != 0) { - this.rearIndex = 0; - this.queue[this.rearIndex] = item; - } else { - this.rearIndex++; - this.queue[this.rearIndex] = item; - } + /** + * Adds an item to the queue. + * + * @param item The item being added to the queue. + */ + enqueue(item: T): void { + if ( + (this.frontIndex == 0 && this.rearIndex == this.size - 1) || + this.rearIndex == (this.frontIndex - 1) % (this.size - 1) + ) { + throw new Error('Queue is full') + } else if (this.frontIndex == -1) { + this.frontIndex = 0 + this.rearIndex = 0 + this.queue[this.rearIndex] = item + } else if (this.rearIndex == this.size - 1 && this.frontIndex != 0) { + this.rearIndex = 0 + this.queue[this.rearIndex] = item + } else { + this.rearIndex++ + this.queue[this.rearIndex] = item } + } - /** - * Removes an item from the queue and returns it. - * - * @throws Queue Underflow if the queue is empty. - * @returns The item that was removed from the queue. - */ - dequeue(): T | undefined { - if (this.frontIndex == -1) { - throw new Error("Queue is empty"); - } - - const item = this.queue[this.frontIndex]; - if (this.frontIndex == this.rearIndex) { - this.frontIndex = -1; - this.rearIndex = -1; - } else if (this.frontIndex == this.size - 1) { - this.frontIndex = 0; - } else { - this.frontIndex++; - } + /** + * Removes an item from the queue and returns it. + * + * @throws Queue Underflow if the queue is empty. + * @returns The item that was removed from the queue. + */ + dequeue(): T | undefined { + if (this.frontIndex == -1) { + throw new Error('Queue is empty') + } - return item; + const item = this.queue[this.frontIndex] + if (this.frontIndex == this.rearIndex) { + this.frontIndex = -1 + this.rearIndex = -1 + } else if (this.frontIndex == this.size - 1) { + this.frontIndex = 0 + } else { + this.frontIndex++ } - /** - * Returns the item at the front of the queue. - * - * @returns The item at the front of the queue or null if the queue is empty. - */ - peek(): T | null | undefined { - if (this.frontIndex == -1) { - return null; - } + return item + } - return this.queue[this.frontIndex]; + /** + * Returns the item at the front of the queue. + * + * @returns The item at the front of the queue or null if the queue is empty. + */ + peek(): T | null | undefined { + if (this.frontIndex == -1) { + return null } - /** - * Checks if the queue is empty. - * - * @returns {boolean} Whether the queue is empty or not. - */ - isEmpty(): boolean { - return this.frontIndex == -1; - } + return this.queue[this.frontIndex] + } - /** - * Returns the number of items in the queue. - * - * @returns {number} The number of items in the queue. - */ - length(): number { - if (this.frontIndex == -1) { - return 0; - } + /** + * Checks if the queue is empty. + * + * @returns {boolean} Whether the queue is empty or not. + */ + isEmpty(): boolean { + return this.frontIndex == -1 + } - if (this.rearIndex >= this.frontIndex) { - return this.rearIndex - this.frontIndex + 1; - } + /** + * Returns the number of items in the queue. + * + * @returns {number} The number of items in the queue. + */ + length(): number { + if (this.frontIndex == -1) { + return 0 + } - return this.size - (this.frontIndex - this.rearIndex - 1); + if (this.rearIndex >= this.frontIndex) { + return this.rearIndex - this.frontIndex + 1 } + + return this.size - (this.frontIndex - this.rearIndex - 1) + } } diff --git a/data_structures/queue/linked_queue.ts b/data_structures/queue/linked_queue.ts index bc90bd52..280447cc 100644 --- a/data_structures/queue/linked_queue.ts +++ b/data_structures/queue/linked_queue.ts @@ -1,8 +1,8 @@ -import { Queue } from "./queue"; +import { Queue } from './queue' type Node = { - value: T, - next?: Node, + value: T + next?: Node } /** @@ -12,84 +12,76 @@ type Node = { * The first element that was added to the queue will be the first one to be removed. */ export class LinkedQueue implements Queue { - - public size: number; - public head?: Node; - private tail?: Node; - - constructor() { - this.head = this.tail = undefined; - this.size = 0; - } - - /** - * Adds an item to the queue. - * - * @param item The item being added to the queue. - */ - enqueue(item: T): void { - const node = { value: item } as Node; // Creates a new node - this.size++ // Increase the length of the Queue - - - if (!this.tail) { - this.tail = this.head = node; - return; - } - this.tail.next = node; // Updates the next tail to the node created - this.tail = node; // The tail of the Queue then becomes the node created!! - - } - - - /** - * Removes an item from the queue and returns it. - * - * @throws Queue Underflow if the queue is empty. - * @returns The item that was removed from the queue. - */ - dequeue(): T | undefined { - - if (!this.head) { - throw new Error("Queue Underflow"); - } - - this.size--; - const head = this.head; // We store the head in order not to lose track of it - this.head = this.head.next; // Update the the head to the next node - return head.value; // Return the value of the head + public size: number + public head?: Node + private tail?: Node + + constructor() { + this.head = this.tail = undefined + this.size = 0 + } + + /** + * Adds an item to the queue. + * + * @param item The item being added to the queue. + */ + enqueue(item: T): void { + const node = { value: item } as Node // Creates a new node + this.size++ // Increase the length of the Queue + + if (!this.tail) { + this.tail = this.head = node + return } - - - /** - * Returns the item at the front of the queue. - * - * @returns The item at the front of the queue or null if the queue is empty. - */ - peek(): T | undefined | null { - - if (this.isEmpty()) { - return null; - } - return this.head?.value; - } - - /** - * Checks if the queue is empty. - * - * @returns {boolean} Whether the queue is empty or not. - */ - isEmpty(): boolean { - return this.size === 0 + this.tail.next = node // Updates the next tail to the node created + this.tail = node // The tail of the Queue then becomes the node created!! + } + + /** + * Removes an item from the queue and returns it. + * + * @throws Queue Underflow if the queue is empty. + * @returns The item that was removed from the queue. + */ + dequeue(): T | undefined { + if (!this.head) { + throw new Error('Queue Underflow') } - /** - * Returns the number of items in the queue. - * - * @returns {number} The number of items in the queue. - */ - length(): number { - return this.size; + this.size-- + const head = this.head // We store the head in order not to lose track of it + this.head = this.head.next // Update the the head to the next node + return head.value // Return the value of the head + } + + /** + * Returns the item at the front of the queue. + * + * @returns The item at the front of the queue or null if the queue is empty. + */ + peek(): T | undefined | null { + if (this.isEmpty()) { + return null } + return this.head?.value + } + + /** + * Checks if the queue is empty. + * + * @returns {boolean} Whether the queue is empty or not. + */ + isEmpty(): boolean { + return this.size === 0 + } + + /** + * Returns the number of items in the queue. + * + * @returns {number} The number of items in the queue. + */ + length(): number { + return this.size + } } - diff --git a/data_structures/queue/queue.ts b/data_structures/queue/queue.ts index 81b3c61f..08763dc1 100644 --- a/data_structures/queue/queue.ts +++ b/data_structures/queue/queue.ts @@ -1,7 +1,7 @@ export interface Queue { - enqueue(item: T): void - dequeue(): T | undefined - peek(): T | undefined | null - isEmpty(): boolean - length(): number -} \ No newline at end of file + enqueue(item: T): void + dequeue(): T | undefined + peek(): T | undefined | null + isEmpty(): boolean + length(): number +} diff --git a/data_structures/queue/stack_queue.ts b/data_structures/queue/stack_queue.ts index e6f129d0..d20f1028 100644 --- a/data_structures/queue/stack_queue.ts +++ b/data_structures/queue/stack_queue.ts @@ -7,85 +7,85 @@ * The other stack acts as a dequeue stack which helps in dequeuing the elements */ -import { Stack } from "../stack/stack"; -import { Queue } from "./queue"; +import { Stack } from '../stack/stack' +import { Queue } from './queue' export class StackQueue implements Queue { - private enqueueStack: Stack = new Stack(); - private dequeueStack: Stack = new Stack(); + private enqueueStack: Stack = new Stack() + private dequeueStack: Stack = new Stack() - /** - * Returns the length of the Queue - * - * @returns {number} the length of the Queue - */ - length(): number { - return this.enqueueStack.length() + this.dequeueStack.length(); - } + /** + * Returns the length of the Queue + * + * @returns {number} the length of the Queue + */ + length(): number { + return this.enqueueStack.length() + this.dequeueStack.length() + } - /** - * Checks if the queue is empty. - * - * @returns {boolean} Whether the queue is empty or not. - */ - isEmpty(): boolean { - return this.enqueueStack.isEmpty() && this.dequeueStack.isEmpty(); - } + /** + * Checks if the queue is empty. + * + * @returns {boolean} Whether the queue is empty or not. + */ + isEmpty(): boolean { + return this.enqueueStack.isEmpty() && this.dequeueStack.isEmpty() + } - /** - * Adds an item to the queue. - * We always add a new item to the enqueueStack. - * @param item The item being added to the queue. - */ - enqueue(item: T): void { - this.enqueueStack.push(item); - } + /** + * Adds an item to the queue. + * We always add a new item to the enqueueStack. + * @param item The item being added to the queue. + */ + enqueue(item: T): void { + this.enqueueStack.push(item) + } - /** - * Shifts the elements from the enqueueStack to the dequeueStack - * In the worst case, all the elements from the enqueue stack needs to shifted, which needs O(n) time. - * However, after the shift, elements can de dequeued at O(1). - * This helps in dequeuing the elements in amortized O(1) time. - */ - private shift(): void { - while (!this.enqueueStack.isEmpty()) { - const enqueueStackTop = this.enqueueStack.pop(); - this.dequeueStack.push(enqueueStackTop); - } + /** + * Shifts the elements from the enqueueStack to the dequeueStack + * In the worst case, all the elements from the enqueue stack needs to shifted, which needs O(n) time. + * However, after the shift, elements can de dequeued at O(1). + * This helps in dequeuing the elements in amortized O(1) time. + */ + private shift(): void { + while (!this.enqueueStack.isEmpty()) { + const enqueueStackTop = this.enqueueStack.pop() + this.dequeueStack.push(enqueueStackTop) } + } - /** - * Removes an item from the queue and returns it. - * - * @throws Queue Underflow if the queue is empty. - * @returns The item that was removed from the queue. - */ - dequeue(): T { - if (this.isEmpty()) { - throw new Error("Queue Underflow"); - } - - if (this.dequeueStack.isEmpty()) { - this.shift(); - } + /** + * Removes an item from the queue and returns it. + * + * @throws Queue Underflow if the queue is empty. + * @returns The item that was removed from the queue. + */ + dequeue(): T { + if (this.isEmpty()) { + throw new Error('Queue Underflow') + } - return this.dequeueStack.pop(); + if (this.dequeueStack.isEmpty()) { + this.shift() } - /** - * Returns the item at the front of the queue. - * - * @returns The item at the front of the queue or null if the queue is empty. - */ - peek(): T | null { - if (this.isEmpty()) { - return null; - } + return this.dequeueStack.pop() + } - if (this.dequeueStack.isEmpty()) { - this.shift(); - } + /** + * Returns the item at the front of the queue. + * + * @returns The item at the front of the queue or null if the queue is empty. + */ + peek(): T | null { + if (this.isEmpty()) { + return null + } - return this.dequeueStack.top(); + if (this.dequeueStack.isEmpty()) { + this.shift() } + + return this.dequeueStack.top() + } } diff --git a/data_structures/queue/test/array_queue.test.ts b/data_structures/queue/test/array_queue.test.ts index 9bc6f48f..f080b545 100644 --- a/data_structures/queue/test/array_queue.test.ts +++ b/data_structures/queue/test/array_queue.test.ts @@ -1,4 +1,4 @@ -import { ArrayQueue } from "../array_queue"; +import { ArrayQueue } from '../array_queue' import { testQueue } from './queue' -describe("Array Queue", () => testQueue(ArrayQueue)); +describe('Array Queue', () => testQueue(ArrayQueue)) diff --git a/data_structures/queue/test/circular_queue.test.ts b/data_structures/queue/test/circular_queue.test.ts index 042e5d81..059216fe 100644 --- a/data_structures/queue/test/circular_queue.test.ts +++ b/data_structures/queue/test/circular_queue.test.ts @@ -1,65 +1,65 @@ -import { CircularQueue } from "../circular_queue"; +import { CircularQueue } from '../circular_queue' -describe("Circular Queue", () => { - let queue: CircularQueue; +describe('Circular Queue', () => { + let queue: CircularQueue - beforeEach(() => { - queue = new CircularQueue(5); - }); + beforeEach(() => { + queue = new CircularQueue(5) + }) - it("should enqueue an element", () => { - queue.enqueue(1); + it('should enqueue an element', () => { + queue.enqueue(1) - expect(queue.peek()).toBe(1); - }); + expect(queue.peek()).toBe(1) + }) - it("should throw an error on enqueue when queue is full", () => { - queue.enqueue(1); - queue.enqueue(2); - queue.enqueue(3); - queue.enqueue(4); - queue.enqueue(5); + it('should throw an error on enqueue when queue is full', () => { + queue.enqueue(1) + queue.enqueue(2) + queue.enqueue(3) + queue.enqueue(4) + queue.enqueue(5) - expect(() => queue.enqueue(6)).toThrowError("Queue is full"); - }); + expect(() => queue.enqueue(6)).toThrowError('Queue is full') + }) - it("should dequeue an element", () => { - queue.enqueue(1); - queue.enqueue(2); + it('should dequeue an element', () => { + queue.enqueue(1) + queue.enqueue(2) - expect(queue.dequeue()).toBe(1); - }); + expect(queue.dequeue()).toBe(1) + }) - it("should throw an error on dequeue when queue is empty", () => { - expect(() => queue.dequeue()).toThrowError("Queue is empty"); - }); + it('should throw an error on dequeue when queue is empty', () => { + expect(() => queue.dequeue()).toThrowError('Queue is empty') + }) - it("should peek an element", () => { - queue.enqueue(1); - queue.enqueue(2); + it('should peek an element', () => { + queue.enqueue(1) + queue.enqueue(2) - expect(queue.peek()).toBe(1); - }); + expect(queue.peek()).toBe(1) + }) - it("should return null on peek when queue is empty", () => { - expect(queue.peek()).toBeNull(); - }); + it('should return null on peek when queue is empty', () => { + expect(queue.peek()).toBeNull() + }) - it("should return true on isEmpty when queue is empty", () => { - expect(queue.isEmpty()).toBeTruthy(); - }); + it('should return true on isEmpty when queue is empty', () => { + expect(queue.isEmpty()).toBeTruthy() + }) - it("should return false on isEmpty when queue is not empty", () => { - queue.enqueue(1); + it('should return false on isEmpty when queue is not empty', () => { + queue.enqueue(1) - expect(queue.isEmpty()).toBeFalsy(); - }); + expect(queue.isEmpty()).toBeFalsy() + }) - it("should return the correct length", () => { - queue.enqueue(1); - queue.enqueue(2); - queue.enqueue(3); + it('should return the correct length', () => { + queue.enqueue(1) + queue.enqueue(2) + queue.enqueue(3) - expect(queue.length()).toBe(3); - }); -}); + expect(queue.length()).toBe(3) + }) +}) diff --git a/data_structures/queue/test/linked_queue.test.ts b/data_structures/queue/test/linked_queue.test.ts index 408c1aa7..79b94169 100644 --- a/data_structures/queue/test/linked_queue.test.ts +++ b/data_structures/queue/test/linked_queue.test.ts @@ -1,4 +1,4 @@ import { testQueue } from './queue' -import { LinkedQueue } from '../linked_queue'; +import { LinkedQueue } from '../linked_queue' -describe("Linked Queue", () => testQueue(LinkedQueue)); +describe('Linked Queue', () => testQueue(LinkedQueue)) diff --git a/data_structures/queue/test/queue.ts b/data_structures/queue/test/queue.ts index 5fb57564..26535712 100644 --- a/data_structures/queue/test/queue.ts +++ b/data_structures/queue/test/queue.ts @@ -1,54 +1,54 @@ -import { Queue } from '../queue'; +import { Queue } from '../queue' type QueueConstructor = new () => Queue export function testQueue(Queue: QueueConstructor) { - it("enqueue should add a new element to the queue", () => { - const queue = new Queue(); - queue.enqueue(1); - expect(queue.length()).toBe(1); - }); - - it("isEmpty should return true on empty queue", () => { - const queue = new Queue(); - expect(queue.isEmpty()).toBeTruthy(); - }); - - it("isEmpty should return false on not empty queue", () => { - const queue = new Queue(); - queue.enqueue(1); - expect(queue.isEmpty()).toBeFalsy(); - }); - - it("front should return the first value", () => { - const queue = new Queue(); - queue.enqueue(1); - expect(queue.peek()).toBe(1); - }); - - it("front should return null when the queue is empty", () => { - const queue = new Queue(); - expect(queue.peek()).toBe(null); - }); - - it("length should return the number of elements in the queue", () => { - const queue = new Queue(); - queue.enqueue(1); - queue.enqueue(1); - queue.enqueue(1); - expect(queue.length()).toBe(3); - }); - - it("dequeue should remove the first element", () => { - const queue = new Queue(); - queue.enqueue(1); - queue.enqueue(2); - queue.enqueue(3); - queue.dequeue(); - expect(queue.length()).toBe(2); - }); - - it("dequeue should throw error on empty queue", () => { - const queue = new Queue(); - expect(() => queue.dequeue()).toThrow("Queue Underflow"); - }); + it('enqueue should add a new element to the queue', () => { + const queue = new Queue() + queue.enqueue(1) + expect(queue.length()).toBe(1) + }) + + it('isEmpty should return true on empty queue', () => { + const queue = new Queue() + expect(queue.isEmpty()).toBeTruthy() + }) + + it('isEmpty should return false on not empty queue', () => { + const queue = new Queue() + queue.enqueue(1) + expect(queue.isEmpty()).toBeFalsy() + }) + + it('front should return the first value', () => { + const queue = new Queue() + queue.enqueue(1) + expect(queue.peek()).toBe(1) + }) + + it('front should return null when the queue is empty', () => { + const queue = new Queue() + expect(queue.peek()).toBe(null) + }) + + it('length should return the number of elements in the queue', () => { + const queue = new Queue() + queue.enqueue(1) + queue.enqueue(1) + queue.enqueue(1) + expect(queue.length()).toBe(3) + }) + + it('dequeue should remove the first element', () => { + const queue = new Queue() + queue.enqueue(1) + queue.enqueue(2) + queue.enqueue(3) + queue.dequeue() + expect(queue.length()).toBe(2) + }) + + it('dequeue should throw error on empty queue', () => { + const queue = new Queue() + expect(() => queue.dequeue()).toThrow('Queue Underflow') + }) } diff --git a/data_structures/queue/test/stack_queue.test.ts b/data_structures/queue/test/stack_queue.test.ts index ab8240bf..538e0503 100644 --- a/data_structures/queue/test/stack_queue.test.ts +++ b/data_structures/queue/test/stack_queue.test.ts @@ -1,4 +1,4 @@ -import { testQueue } from './queue'; -import { StackQueue } from '../stack_queue'; +import { testQueue } from './queue' +import { StackQueue } from '../stack_queue' -describe("Stack Based Queue", () => testQueue(StackQueue)); \ No newline at end of file +describe('Stack Based Queue', () => testQueue(StackQueue)) diff --git a/data_structures/set/hash_map_set.ts b/data_structures/set/hash_map_set.ts index ade41cbb..ddb86543 100644 --- a/data_structures/set/hash_map_set.ts +++ b/data_structures/set/hash_map_set.ts @@ -1,6 +1,6 @@ -import { Map } from "../map/map"; -import { HashMap } from "../map/hash_map"; -import { MapSet } from "./map_set"; +import { Map } from '../map/map' +import { HashMap } from '../map/hash_map' +import { MapSet } from './map_set' /** * This class is a representation of the Set data structure based on a hash map. @@ -9,16 +9,16 @@ import { MapSet } from "./map_set"; * @extends MapSet */ export class HashMapSet extends MapSet { - constructor() { - super(); - } + constructor() { + super() + } - /** - * Initializes the map used to store the set. - * - * @returns {Map} The map used to store the set. - */ - protected initMap(): Map { - return new HashMap(); - } + /** + * Initializes the map used to store the set. + * + * @returns {Map} The map used to store the set. + */ + protected initMap(): Map { + return new HashMap() + } } diff --git a/data_structures/set/map_set.ts b/data_structures/set/map_set.ts index 11e8c2f2..ce4f8ebc 100644 --- a/data_structures/set/map_set.ts +++ b/data_structures/set/map_set.ts @@ -1,5 +1,5 @@ -import { Map } from "./map"; -import { Set } from "./set"; +import { Map } from './map' +import { Set } from './set' /** * This class is a representation of the Set data structure based on a hash map. @@ -9,67 +9,67 @@ import { Set } from "./set"; * @property {Map} map The map used to store the set. */ export abstract class MapSet implements Set { - private map: Map; + private map: Map - constructor() { - this.map = this.initMap(); - } + constructor() { + this.map = this.initMap() + } - /** - * Initializes the map used to store the set. - */ - protected abstract initMap(): Map; + /** + * Initializes the map used to store the set. + */ + protected abstract initMap(): Map - /** - * Adds a new element to the set. - * - * @param value The value to add to the set. - */ - add(value: K): void { - this.map.set(value, null); - } + /** + * Adds a new element to the set. + * + * @param value The value to add to the set. + */ + add(value: K): void { + this.map.set(value, null) + } - /** - * Removes an element from the set. - * - * @param value The value to remove from the set. - */ - delete(value: K): void { - this.map.delete(value); - } + /** + * Removes an element from the set. + * + * @param value The value to remove from the set. + */ + delete(value: K): void { + this.map.delete(value) + } - /** - * Checks if the set contains a given value. - * - * @param value The value to check for. - * @returns Whether the set contains the value. - */ - has(value: K): boolean { - return this.map.has(value); - } + /** + * Checks if the set contains a given value. + * + * @param value The value to check for. + * @returns Whether the set contains the value. + */ + has(value: K): boolean { + return this.map.has(value) + } - /** - * Removes all elements from the set. - */ - clear(): void { - this.map.clear(); - } + /** + * Removes all elements from the set. + */ + clear(): void { + this.map.clear() + } - /** - * Returns an array of all the values in the set. - * - * @returns An array of all the values in the set. - */ - values(): K[] { - return this.map.keys(); - } + /** + * Returns an array of all the values in the set. + * + * @returns An array of all the values in the set. + */ + values(): K[] { + return this.map.keys() + } - /** - * Returns the number of elements in the set. - * - * @returns The number of elements in the set. - */ - getSize(): number { - return this.map.getSize(); - } + /** + * Returns the number of elements in the set. + * + * @returns The number of elements in the set. + */ + getSize(): number { + return this.map.getSize() + } } diff --git a/data_structures/set/set.ts b/data_structures/set/set.ts index 3d814d41..2b3c1d83 100644 --- a/data_structures/set/set.ts +++ b/data_structures/set/set.ts @@ -2,10 +2,10 @@ * This interface is a representation of the Set data structure. */ export interface Set { - getSize(): number; - add(value: K): void; - delete(value: K): void; - has(value: K): boolean; - clear(): void; - values(): K[]; + getSize(): number + add(value: K): void + delete(value: K): void + has(value: K): boolean + clear(): void + values(): K[] } diff --git a/data_structures/stack/linked_list_stack.ts b/data_structures/stack/linked_list_stack.ts index 11b1dbd9..8c07b4ce 100644 --- a/data_structures/stack/linked_list_stack.ts +++ b/data_structures/stack/linked_list_stack.ts @@ -1,4 +1,4 @@ -import { SinglyLinkedList } from "../list/singly_linked_list"; +import { SinglyLinkedList } from '../list/singly_linked_list' /** * This is an implementation of a stack, based on a linked list. @@ -7,76 +7,76 @@ import { SinglyLinkedList } from "../list/singly_linked_list"; * to determine which element is next in the list. */ export class LinkedListStack { - private list: SinglyLinkedList; - private limit: number; + private list: SinglyLinkedList + private limit: number - /** - * Creates a new stack object. - */ - constructor(limit: number = Number.MAX_VALUE) { - this.list = new SinglyLinkedList(); - this.limit = limit; - } - - /** - * Gets the top element of the stack. - * Time complexity: constant (O(1)) - * - * @returns The top element of the stack. - */ - top(): T | null { - if (this.list.isEmpty()) { - return null; - } + /** + * Creates a new stack object. + */ + constructor(limit: number = Number.MAX_VALUE) { + this.list = new SinglyLinkedList() + this.limit = limit + } - return this.list.get(0)!; + /** + * Gets the top element of the stack. + * Time complexity: constant (O(1)) + * + * @returns The top element of the stack. + */ + top(): T | null { + if (this.list.isEmpty()) { + return null } - /** - * Inserts a new element on the top of the stack. - * Time complexity: constant (O(1)) - * - * @param data The data of the element to insert. - * @throws Stack overflow, if the new element does not fit in the limit. - */ - push(data: T): void { - if (this.list.getLength() + 1 > this.limit) { - throw new Error('Stack overflow') - } + return this.list.get(0)! + } - this.list.push(data); + /** + * Inserts a new element on the top of the stack. + * Time complexity: constant (O(1)) + * + * @param data The data of the element to insert. + * @throws Stack overflow, if the new element does not fit in the limit. + */ + push(data: T): void { + if (this.list.getLength() + 1 > this.limit) { + throw new Error('Stack overflow') } - /** - * Removes the top element from the stack. - * Time complexity: constant (O(1)) - * - * @returns The previous top element. - * @throws Stack underflow, if the stack has no elements to pop. - */ - pop(): T { - if (this.list.isEmpty()) { - throw new Error('Stack underflow') - } + this.list.push(data) + } - return this.list.pop(); + /** + * Removes the top element from the stack. + * Time complexity: constant (O(1)) + * + * @returns The previous top element. + * @throws Stack underflow, if the stack has no elements to pop. + */ + pop(): T { + if (this.list.isEmpty()) { + throw new Error('Stack underflow') } - /** - * Gets the amount of elements in the stack. - * - * @returns The amount of elements in the stack. - */ - length(): number { - return this.list.getLength(); - } + return this.list.pop() + } - /** - * Gets whether the stack is empty or not. - * - * @returns Whether the stack is empty or not. - */ - isEmpty(): boolean { - return this.list.isEmpty(); - } -} \ No newline at end of file + /** + * Gets the amount of elements in the stack. + * + * @returns The amount of elements in the stack. + */ + length(): number { + return this.list.getLength() + } + + /** + * Gets whether the stack is empty or not. + * + * @returns Whether the stack is empty or not. + */ + isEmpty(): boolean { + return this.list.isEmpty() + } +} diff --git a/data_structures/stack/stack.ts b/data_structures/stack/stack.ts index 60affe13..3a660bca 100644 --- a/data_structures/stack/stack.ts +++ b/data_structures/stack/stack.ts @@ -5,15 +5,15 @@ * This is a class-based implementation of a Stack. */ export class Stack { - private stack: T[] = []; - private limit: number; + private stack: T[] = [] + private limit: number /** * constructor of the stack, can set a limit, if not provided there is no limit to the stack. * @param {number} [limit=Number.MAX_VALUE] the limit of the stack */ constructor(limit: number = Number.MAX_VALUE) { - this.limit = limit; + this.limit = limit } /** @@ -23,10 +23,10 @@ export class Stack { */ push(value: T) { if (this.length() + 1 > this.limit) { - throw new Error('Stack Overflow'); + throw new Error('Stack Overflow') } - this.stack.push(value); + this.stack.push(value) } /** @@ -37,10 +37,10 @@ export class Stack { */ pop(): T { if (this.length() !== 0) { - return this.stack.pop() as T; + return this.stack.pop() as T } - throw new Error('Stack Underflow'); + throw new Error('Stack Underflow') } /** @@ -49,7 +49,7 @@ export class Stack { * @return {number} the number of elements in the stack */ length(): number { - return this.stack.length; + return this.stack.length } /** @@ -58,7 +58,7 @@ export class Stack { * @return {boolean} returns true if the stack is empty, otherwise false */ isEmpty(): boolean { - return this.length() === 0; + return this.length() === 0 } /** @@ -68,9 +68,9 @@ export class Stack { */ top(): T | null { if (this.length() !== 0) { - return this.stack[this.length() - 1]; + return this.stack[this.length() - 1] } - return null; + return null } } diff --git a/data_structures/stack/test/linked_list_stack.test.ts b/data_structures/stack/test/linked_list_stack.test.ts index 54f47c48..0595c063 100644 --- a/data_structures/stack/test/linked_list_stack.test.ts +++ b/data_structures/stack/test/linked_list_stack.test.ts @@ -1,32 +1,32 @@ -import { LinkedListStack } from "../linked_list_stack"; +import { LinkedListStack } from '../linked_list_stack' -describe("Linked List Stack", () => { - const stack: LinkedListStack = new LinkedListStack(4); +describe('Linked List Stack', () => { + const stack: LinkedListStack = new LinkedListStack(4) - stack.push(1); - stack.push(2); - stack.push(3); + stack.push(1) + stack.push(2) + stack.push(3) - it("should get the top element from the stack", () => { - expect(stack.top()).toBe(3); - }); + it('should get the top element from the stack', () => { + expect(stack.top()).toBe(3) + }) - it("should remove the top element from the stack and give the new top element", () => { - expect(stack.pop()).toBe(3); - expect(stack.top()).toBe(2); - }); + it('should remove the top element from the stack and give the new top element', () => { + expect(stack.pop()).toBe(3) + expect(stack.top()).toBe(2) + }) - it("should add a new element on top", () => { - expect(stack.push(4)); - }); + it('should add a new element on top', () => { + expect(stack.push(4)) + }) - it("should fail to add the second element on top, because of a stack overflow", () => { - stack.push(4); - expect(() => stack.push(5)).toThrowError('Stack overflow'); - }); + it('should fail to add the second element on top, because of a stack overflow', () => { + stack.push(4) + expect(() => stack.push(5)).toThrowError('Stack overflow') + }) - it('should fail to pop the top element on an empty stack', () => { - const s: LinkedListStack = new LinkedListStack(); - expect(() => s.pop()).toThrowError('Stack underflow'); - }); -}); \ No newline at end of file + it('should fail to pop the top element on an empty stack', () => { + const s: LinkedListStack = new LinkedListStack() + expect(() => s.pop()).toThrowError('Stack underflow') + }) +}) diff --git a/data_structures/stack/test/stack.test.ts b/data_structures/stack/test/stack.test.ts index 514ba4b7..8112de4d 100644 --- a/data_structures/stack/test/stack.test.ts +++ b/data_structures/stack/test/stack.test.ts @@ -1,68 +1,68 @@ -import { Stack } from '../stack'; +import { Stack } from '../stack' describe('Testing Stack data structure', () => { it('push should add a new element to the stack', () => { - const stack = new Stack(); - stack.push(2); + const stack = new Stack() + stack.push(2) - expect(stack.length()).toBe(1); - }); + expect(stack.length()).toBe(1) + }) it('push should throw error on reach limit', () => { - const stack = new Stack(2); - stack.push(2); - stack.push(3); + const stack = new Stack(2) + stack.push(2) + stack.push(3) - expect(() => stack.push(4)).toThrow('Stack Overflow'); - }); + expect(() => stack.push(4)).toThrow('Stack Overflow') + }) it('isEmpty should return true on empty stack', () => { - const stack = new Stack(); - expect(stack.isEmpty()).toBeTruthy(); - }); + const stack = new Stack() + expect(stack.isEmpty()).toBeTruthy() + }) it('isEmpty should return false on not empty stack', () => { - const stack = new Stack(); - stack.push(2); + const stack = new Stack() + stack.push(2) - expect(stack.isEmpty()).toBeFalsy(); - }); + expect(stack.isEmpty()).toBeFalsy() + }) it('top should return the last value', () => { - const stack = new Stack(); - stack.push(2); + const stack = new Stack() + stack.push(2) - expect(stack.top()).toBe(2); - }); + expect(stack.top()).toBe(2) + }) it('top should return null when the stack is empty', () => { - const stack = new Stack(); + const stack = new Stack() - expect(stack.top()).toBe(null); - }); + expect(stack.top()).toBe(null) + }) it('length should return the number of elements in the stack', () => { - const stack = new Stack(); - stack.push(2); - stack.push(2); - stack.push(2); + const stack = new Stack() + stack.push(2) + stack.push(2) + stack.push(2) - expect(stack.length()).toBe(3); - }); + expect(stack.length()).toBe(3) + }) it('pop should remove the last element and return it', () => { - const stack = new Stack(); - stack.push(1); - stack.push(2); - stack.push(3); + const stack = new Stack() + stack.push(1) + stack.push(2) + stack.push(3) - expect(stack.pop()).toBe(3); - expect(stack.length()).toBe(2); - }); + expect(stack.pop()).toBe(3) + expect(stack.length()).toBe(2) + }) it('pop should throw an exception if the stack is empty', () => { - const stack = new Stack(); + const stack = new Stack() - expect(() => stack.pop()).toThrow('Stack Underflow'); - }); -}); + expect(() => stack.pop()).toThrow('Stack Underflow') + }) +}) diff --git a/data_structures/tree/binary_search_tree.ts b/data_structures/tree/binary_search_tree.ts index f9e4afdc..62fc4604 100644 --- a/data_structures/tree/binary_search_tree.ts +++ b/data_structures/tree/binary_search_tree.ts @@ -7,7 +7,7 @@ class TreeNode { constructor( public data: T, public leftChild?: TreeNode, - public rightChild?: TreeNode, + public rightChild?: TreeNode ) {} } @@ -27,7 +27,7 @@ class TreeNode { * @template T The data type of the values in the binary tree. */ export class BinarySearchTree { - rootNode?: TreeNode; + rootNode?: TreeNode /** * Instantiates the binary search tree. @@ -35,7 +35,7 @@ export class BinarySearchTree { * @param rootNode The root node. */ constructor() { - this.rootNode = undefined; + this.rootNode = undefined } /** @@ -44,7 +44,7 @@ export class BinarySearchTree { * @returns Whether the binary search tree is empty. */ isEmpty(): boolean { - return this.rootNode === undefined; + return this.rootNode === undefined } /** @@ -54,27 +54,27 @@ export class BinarySearchTree { */ has(data: T): boolean { if (!this.rootNode) { - return false; + return false } - let currentNode = this.rootNode; + let currentNode = this.rootNode while (currentNode.data !== data) { if (data > currentNode.data) { if (!currentNode.rightChild) { - return false; + return false } - currentNode = currentNode.rightChild; + currentNode = currentNode.rightChild } else { if (!currentNode.leftChild) { - return false; + return false } - currentNode = currentNode.leftChild; + currentNode = currentNode.leftChild } } - return true; + return true } /** @@ -85,25 +85,25 @@ export class BinarySearchTree { */ insert(data: T): void { if (!this.rootNode) { - this.rootNode = new TreeNode(data); - return; + this.rootNode = new TreeNode(data) + return } - let currentNode: TreeNode = this.rootNode; + let currentNode: TreeNode = this.rootNode while (true) { if (data > currentNode.data) { if (currentNode.rightChild) { - currentNode = currentNode.rightChild; + currentNode = currentNode.rightChild } else { - currentNode.rightChild = new TreeNode(data); - return; + currentNode.rightChild = new TreeNode(data) + return } } else { if (currentNode.leftChild) { - currentNode = currentNode.leftChild; + currentNode = currentNode.leftChild } else { - currentNode.leftChild = new TreeNode(data); - return; + currentNode.leftChild = new TreeNode(data) + return } } } @@ -116,14 +116,14 @@ export class BinarySearchTree { */ findMin(): T { if (!this.rootNode) { - throw new Error('Empty tree.'); + throw new Error('Empty tree.') } const traverse = (node: TreeNode): T => { - return !node.leftChild ? node.data : traverse(node.leftChild); - }; + return !node.leftChild ? node.data : traverse(node.leftChild) + } - return traverse(this.rootNode); + return traverse(this.rootNode) } /** @@ -133,14 +133,14 @@ export class BinarySearchTree { */ findMax(): T { if (!this.rootNode) { - throw new Error('Empty tree.'); + throw new Error('Empty tree.') } const traverse = (node: TreeNode): T => { - return !node.rightChild ? node.data : traverse(node.rightChild); - }; + return !node.rightChild ? node.data : traverse(node.rightChild) + } - return traverse(this.rootNode); + return traverse(this.rootNode) } /** @@ -151,22 +151,22 @@ export class BinarySearchTree { * @returns */ inOrderTraversal(array: T[] = []): T[] { - if (!this.rootNode) { - return array; + if (!this.rootNode) { + return array } const traverse = (node?: TreeNode, array: T[] = []): T[] => { if (!node) { - return array; + return array } - traverse(node.leftChild, array); - array.push(node.data); - traverse(node.rightChild, array); - return array; - }; + traverse(node.leftChild, array) + array.push(node.data) + traverse(node.rightChild, array) + return array + } - return traverse(this.rootNode); + return traverse(this.rootNode) } /** @@ -178,22 +178,22 @@ export class BinarySearchTree { */ preOrderTraversal(array: T[] = []): T[] { if (!this.rootNode) { - return array; + return array } const traverse = (node?: TreeNode, array: T[] = []): T[] => { if (!node) { - return array; + return array } - array.push(node.data); - traverse(node.leftChild, array); - traverse(node.rightChild, array); + array.push(node.data) + traverse(node.leftChild, array) + traverse(node.rightChild, array) - return array; - }; + return array + } - return traverse(this.rootNode); + return traverse(this.rootNode) } /** @@ -205,21 +205,21 @@ export class BinarySearchTree { */ postOrderTraversal(array: T[] = []): T[] { if (!this.rootNode) { - return array; + return array } const traverse = (node?: TreeNode, array: T[] = []): T[] => { if (!node) { - return array; + return array } - traverse(node.leftChild, array); - traverse(node.rightChild, array); - array.push(node.data); + traverse(node.leftChild, array) + traverse(node.rightChild, array) + array.push(node.data) - return array; - }; + return array + } - return traverse(this.rootNode); + return traverse(this.rootNode) } } diff --git a/data_structures/tree/test/binary_search_tree.test.ts b/data_structures/tree/test/binary_search_tree.test.ts index 69121985..f018c8c1 100644 --- a/data_structures/tree/test/binary_search_tree.test.ts +++ b/data_structures/tree/test/binary_search_tree.test.ts @@ -1,55 +1,57 @@ -import { BinarySearchTree } from '../binary_search_tree'; +import { BinarySearchTree } from '../binary_search_tree' describe('BinarySearchTree', () => { describe('with filled binary search tree (insert)', () => { - let binarySearchTree: BinarySearchTree; + let binarySearchTree: BinarySearchTree beforeEach(() => { - binarySearchTree = new BinarySearchTree(); - binarySearchTree.insert(25); - binarySearchTree.insert(80); - binarySearchTree.insert(12); - binarySearchTree.insert(5); - binarySearchTree.insert(64); - }); + binarySearchTree = new BinarySearchTree() + binarySearchTree.insert(25) + binarySearchTree.insert(80) + binarySearchTree.insert(12) + binarySearchTree.insert(5) + binarySearchTree.insert(64) + }) it('should return false for isEmpty when binary search tree is not empty', () => { - expect(binarySearchTree.isEmpty()).toBeFalsy(); - }); + expect(binarySearchTree.isEmpty()).toBeFalsy() + }) it('should return correct root node for search', () => { - expect(binarySearchTree.rootNode?.data).toBe(25); - }); + expect(binarySearchTree.rootNode?.data).toBe(25) + }) it('should return whether an element is in the set', () => { - expect(binarySearchTree.has(5)).toBe(true); - expect(binarySearchTree.has(42)).toBe(false); - }); + expect(binarySearchTree.has(5)).toBe(true) + expect(binarySearchTree.has(42)).toBe(false) + }) it('should traverse in in-order through the tree', () => { - expect(binarySearchTree.inOrderTraversal()).toStrictEqual([5, 12, 25, 64, 80]); - }); + expect(binarySearchTree.inOrderTraversal()).toStrictEqual([ + 5, 12, 25, 64, 80 + ]) + }) it('should traverse in pre-order through the tree', () => { - console.log(binarySearchTree.preOrderTraversal()); + console.log(binarySearchTree.preOrderTraversal()) - expect( - binarySearchTree.preOrderTraversal(), - ).toStrictEqual([25, 12, 5, 80, 64]); - }); + expect(binarySearchTree.preOrderTraversal()).toStrictEqual([ + 25, 12, 5, 80, 64 + ]) + }) it('should traverse in post-order through the tree', () => { - expect( - binarySearchTree.postOrderTraversal(), - ).toStrictEqual([5, 12, 64, 80, 25]); - }); + expect(binarySearchTree.postOrderTraversal()).toStrictEqual([ + 5, 12, 64, 80, 25 + ]) + }) it('should return the minimum value of the binary search tree', () => { - expect(binarySearchTree.findMin()).toBe(5); - }); + expect(binarySearchTree.findMin()).toBe(5) + }) it('should return the maximum value of the binary search tree', () => { - expect(binarySearchTree.findMax()).toBe(80); - }); - }); -}); + expect(binarySearchTree.findMax()).toBe(80) + }) + }) +}) diff --git a/data_structures/tries/test/tries.test.ts b/data_structures/tries/test/tries.test.ts index 89319c6d..b4212157 100644 --- a/data_structures/tries/test/tries.test.ts +++ b/data_structures/tries/test/tries.test.ts @@ -1,40 +1,40 @@ -import { Trie } from "../tries"; +import { Trie } from '../tries' describe('Trie', () => { - let trie: Trie; + let trie: Trie beforeEach(() => { - trie = new Trie(); - }); + trie = new Trie() + }) it('should add and find a word', () => { - trie.add('apple'); - expect(trie.find('apple')).toBe(true); - }); + trie.add('apple') + expect(trie.find('apple')).toBe(true) + }) it('should not find a word that was not added', () => { - trie.add('apple'); - expect(trie.find('banana')).toBe(false); - }); + trie.add('apple') + expect(trie.find('banana')).toBe(false) + }) it('should not find a partial word', () => { - trie.add('apple'); - expect(trie.find('app')).toBe(false); - }); + trie.add('apple') + expect(trie.find('app')).toBe(false) + }) it('should add and find multiple words', () => { - trie.add('apple'); - trie.add('banana'); - trie.add('cherry'); - expect(trie.find('apple')).toBe(true); - expect(trie.find('banana')).toBe(true); - expect(trie.find('cherry')).toBe(true); - }); + trie.add('apple') + trie.add('banana') + trie.add('cherry') + expect(trie.find('apple')).toBe(true) + expect(trie.find('banana')).toBe(true) + expect(trie.find('cherry')).toBe(true) + }) it('should find words with a common prefix', () => { - trie.add('apple'); - trie.add('appetizer'); - expect(trie.find('app', true)).toBe(true); - expect(trie.find('app', false)).toBe(false); - }); -}); + trie.add('apple') + trie.add('appetizer') + expect(trie.find('app', true)).toBe(true) + expect(trie.find('app', false)).toBe(false) + }) +}) diff --git a/data_structures/tries/tries.ts b/data_structures/tries/tries.ts index 1bf6ac27..78dc1432 100644 --- a/data_structures/tries/tries.ts +++ b/data_structures/tries/tries.ts @@ -5,12 +5,12 @@ class TrieNode { /** * An object that stores child nodes for each character in the alphabet. */ - children: { [key: string]: TrieNode } = {}; + children: { [key: string]: TrieNode } = {} /** * Indicates whether the node represents the end of a word. */ - isWord: boolean = false; + isWord: boolean = false } /** @@ -20,7 +20,7 @@ export class Trie { /** * The root node of the Trie. */ - root: TrieNode = new TrieNode(); + root: TrieNode = new TrieNode() /** * Creates a new Trie instance. @@ -35,11 +35,11 @@ export class Trie { private insertNode(node: TrieNode, word: string): void { for (const char of word) { if (!node.children[char]) { - node.children[char] = new TrieNode(); + node.children[char] = new TrieNode() } - node = node.children[char]; + node = node.children[char] } - node.isWord = true; + node.isWord = true } /** @@ -52,7 +52,7 @@ export class Trie { * @returns True if the word (or prefix) is found in the Trie; otherwise, false. */ public find(word: string, isPrefixMatch: boolean = false): boolean { - return this.searchNode(this.root, word, isPrefixMatch); + return this.searchNode(this.root, word, isPrefixMatch) } /** @@ -62,8 +62,8 @@ export class Trie { * @returns The Trie instance, allowing for method chaining. */ public add(word: string): this { - this.insertNode(this.root, word); - return this; + this.insertNode(this.root, word) + return this } /** @@ -82,10 +82,10 @@ export class Trie { ): boolean { for (const char of word) { if (!node.children[char]) { - return false; + return false } - node = node.children[char]; + node = node.children[char] } - return prefixMatch || node.isWord; + return prefixMatch || node.isWord } } diff --git a/dynamic_programming/coin_change.ts b/dynamic_programming/coin_change.ts index 791aa5f1..0734fb9a 100644 --- a/dynamic_programming/coin_change.ts +++ b/dynamic_programming/coin_change.ts @@ -1,7 +1,6 @@ - export interface CoinChange { - minCoins: number, - coins: number[] + minCoins: number + coins: number[] } /** @@ -12,35 +11,33 @@ export interface CoinChange { * @returns CoinChange, the minimum number of coins, and which coins are selected */ export const coinChange = (money: number, coins: number[]): CoinChange => { - - const minCoins: number[] = Array(money + 1).fill(Infinity); - const lastCoin: number[] = Array(money + 1).fill(-1); - - minCoins[0] = 0; - - // Fill in the DP table - for (let i = 0; i < coins.length; i++) { - for (let j = 0; j <= money; j++) { - if (j >= coins[i]) { - if (minCoins[j] > 1 + minCoins[j - coins[i]]) { - minCoins[j] = 1 + minCoins[j - coins[i]]; - lastCoin[j] = coins[i]; - } - } + const minCoins: number[] = Array(money + 1).fill(Infinity) + const lastCoin: number[] = Array(money + 1).fill(-1) + + minCoins[0] = 0 + + // Fill in the DP table + for (let i = 0; i < coins.length; i++) { + for (let j = 0; j <= money; j++) { + if (j >= coins[i]) { + if (minCoins[j] > 1 + minCoins[j - coins[i]]) { + minCoins[j] = 1 + minCoins[j - coins[i]] + lastCoin[j] = coins[i] } + } } + } - const res: CoinChange = { - minCoins: minCoins[money], - coins: [] - } + const res: CoinChange = { + minCoins: minCoins[money], + coins: [] + } - let total: number = money; - while (total > 0) { - res.coins.push(lastCoin[total]); - total -= lastCoin[total]; - } + let total: number = money + while (total > 0) { + res.coins.push(lastCoin[total]) + total -= lastCoin[total] + } - return res; + return res } - diff --git a/dynamic_programming/knapsack.ts b/dynamic_programming/knapsack.ts index f4026b1d..853e50ab 100644 --- a/dynamic_programming/knapsack.ts +++ b/dynamic_programming/knapsack.ts @@ -16,18 +16,18 @@ export const knapsack = ( ) => { if (weights.length != values.length) { throw new Error( - "weights and values arrays should have same number of elements" - ); + 'weights and values arrays should have same number of elements' + ) } - const numberOfItems = weights.length; + const numberOfItems = weights.length // Declaring a data structure to store calculated states/values - const dp: number[][] = new Array(numberOfItems + 1); + const dp: number[][] = new Array(numberOfItems + 1) for (let i = 0; i < dp.length; i++) { // Placing an array at each index of dp to make it a 2d matrix - dp[i] = new Array(capacity + 1); + dp[i] = new Array(capacity + 1) } // Loop traversing each state of dp @@ -36,24 +36,21 @@ export const knapsack = ( if (i == 0) { if (j >= weights[i]) { // grab the first item if it's weight is less than remaining weight (j) - dp[i][j] = values[i]; + dp[i][j] = values[i] } else { // if weight[i] is more than remaining weight (j) leave it - dp[i][j] = 0; + dp[i][j] = 0 } } else if (j < weights[i]) { // if weight of current item (weights[i]) is more than remaining weight (j), leave the current item and just carry on previous items - dp[i][j] = dp[i - 1][j]; + dp[i][j] = dp[i - 1][j] } else { // select the maximum of (if current weight is collected thus adding it's value) and (if current weight is not collected thus not adding it's value) - dp[i][j] = Math.max( - dp[i - 1][j - weights[i]] + values[i], - dp[i - 1][j] - ); + dp[i][j] = Math.max(dp[i - 1][j - weights[i]] + values[i], dp[i - 1][j]) } } } // Return the final maximized value at last position of dp matrix - return dp[numberOfItems - 1][capacity]; -}; + return dp[numberOfItems - 1][capacity] +} diff --git a/dynamic_programming/lcs.ts b/dynamic_programming/lcs.ts index 654d3934..910dc23a 100644 --- a/dynamic_programming/lcs.ts +++ b/dynamic_programming/lcs.ts @@ -5,42 +5,44 @@ * @returns The longest common subsequence as a string. */ -export const longestCommonSubsequence = (text1: string, text2: string): string => { - const m = text1.length; - const n = text2.length; - - // Create a 2D array to store the lengths of LCS - const dp: number[][] = Array.from({ length: m + 1 }, () => - Array(n + 1).fill(0) - ); - - // Fill in the DP table - for (let i = 1; i <= m; i++) { - for (let j = 1; j <= n; j++) { - if (text1[i - 1] === text2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1; - } else { - dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); - } - } - } - - // Reconstruct the LCS from the DP table - let i = m; - let j = n; - const lcs: string[] = []; - while (i > 0 && j > 0) { +export const longestCommonSubsequence = ( + text1: string, + text2: string +): string => { + const m = text1.length + const n = text2.length + + // Create a 2D array to store the lengths of LCS + const dp: number[][] = Array.from({ length: m + 1 }, () => + Array(n + 1).fill(0) + ) + + // Fill in the DP table + for (let i = 1; i <= m; i++) { + for (let j = 1; j <= n; j++) { if (text1[i - 1] === text2[j - 1]) { - lcs.unshift(text1[i - 1]); - i--; - j--; - } else if (dp[i - 1][j] > dp[i][j - 1]) { - i--; + dp[i][j] = dp[i - 1][j - 1] + 1 } else { - j--; + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) } } - - return lcs.join(''); } - \ No newline at end of file + + // Reconstruct the LCS from the DP table + let i = m + let j = n + const lcs: string[] = [] + while (i > 0 && j > 0) { + if (text1[i - 1] === text2[j - 1]) { + lcs.unshift(text1[i - 1]) + i-- + j-- + } else if (dp[i - 1][j] > dp[i][j - 1]) { + i-- + } else { + j-- + } + } + + return lcs.join('') +} diff --git a/dynamic_programming/test/coin_change.test.ts b/dynamic_programming/test/coin_change.test.ts index 7155ef9c..83b7f88b 100644 --- a/dynamic_programming/test/coin_change.test.ts +++ b/dynamic_programming/test/coin_change.test.ts @@ -1,37 +1,36 @@ -import { CoinChange, coinChange } from "../coin_change"; - +import { CoinChange, coinChange } from '../coin_change' interface TestCase { - money: number, - coins: number[], - expected: CoinChange + money: number + coins: number[] + expected: CoinChange } const cases: TestCase[] = [ - { - money: 13, - coins: [7, 2, 3, 6], - expected: { - minCoins: 2, - coins: [6, 7] - } - }, - { - money: 10, - coins: [1, 5], - expected: { - minCoins: 2, - coins: [5, 5] - } + { + money: 13, + coins: [7, 2, 3, 6], + expected: { + minCoins: 2, + coins: [6, 7] + } + }, + { + money: 10, + coins: [1, 5], + expected: { + minCoins: 2, + coins: [5, 5] } -]; + } +] -describe("Coin Change Algorithm Test", () => { - test.each(cases)( - "given money: $money, and coins: $coins the minimum coin change should return $expected", - ({money, coins, expected}) => { - const result = coinChange(money, coins); - expect(result).toEqual(expected); - } - ); -}); +describe('Coin Change Algorithm Test', () => { + test.each(cases)( + 'given money: $money, and coins: $coins the minimum coin change should return $expected', + ({ money, coins, expected }) => { + const result = coinChange(money, coins) + expect(result).toEqual(expected) + } + ) +}) diff --git a/dynamic_programming/test/knapsack.test.ts b/dynamic_programming/test/knapsack.test.ts index c2767712..e7ba1beb 100644 --- a/dynamic_programming/test/knapsack.test.ts +++ b/dynamic_programming/test/knapsack.test.ts @@ -1,4 +1,4 @@ -import { knapsack } from "../knapsack"; +import { knapsack } from '../knapsack' const cases: [number, number[], number[], number][] = [ [15, [6, 5, 6, 6, 3, 7], [5, 6, 4, 6, 5, 2], 17], @@ -8,16 +8,16 @@ const cases: [number, number[], number[], number][] = [ 5, [1, 1, 1, 1, 1], [1000000000, 1000000000, 1000000000, 1000000000, 1000000000], - 5000000000, - ], -]; + 5000000000 + ] +] -describe("Knapsack Algorithm Test", () => { +describe('Knapsack Algorithm Test', () => { test.each(cases)( - "given %p capacity available, with weights %p and values %p, knapsack should return %p", + 'given %p capacity available, with weights %p and values %p, knapsack should return %p', (capacity, weights, values, expectedResult) => { - const result = knapsack(capacity, weights, values); - expect(result).toBe(expectedResult); + const result = knapsack(capacity, weights, values) + expect(result).toBe(expectedResult) } - ); -}); + ) +}) diff --git a/dynamic_programming/test/lcs.test.ts b/dynamic_programming/test/lcs.test.ts index c1374b07..a5242b5f 100644 --- a/dynamic_programming/test/lcs.test.ts +++ b/dynamic_programming/test/lcs.test.ts @@ -1,28 +1,28 @@ -import { longestCommonSubsequence } from "../lcs"; +import { longestCommonSubsequence } from '../lcs' -describe("longestCommonSubsequence", () => { - it("should return the longest common subsequence", () => { - expect(longestCommonSubsequence("ABCD", "ACDF")).toBe("ACD"); +describe('longestCommonSubsequence', () => { + it('should return the longest common subsequence', () => { + expect(longestCommonSubsequence('ABCD', 'ACDF')).toBe('ACD') - expect(longestCommonSubsequence("AGGTAB", "GXTXAYB")).toBe("GTAB"); + expect(longestCommonSubsequence('AGGTAB', 'GXTXAYB')).toBe('GTAB') - expect(longestCommonSubsequence("abcdef", "xyz")).toBe(""); + expect(longestCommonSubsequence('abcdef', 'xyz')).toBe('') - expect(longestCommonSubsequence("", "")).toBe(""); - }); + expect(longestCommonSubsequence('', '')).toBe('') + }) - it("should handle cases with spaces and special characters", () => { - expect(longestCommonSubsequence("A B C D", "A C D E")).toBe("A C D"); + it('should handle cases with spaces and special characters', () => { + expect(longestCommonSubsequence('A B C D', 'A C D E')).toBe('A C D') - expect(longestCommonSubsequence("1234$%^", "!@#$%^")).toBe("$%^"); - }); + expect(longestCommonSubsequence('1234$%^', '!@#$%^')).toBe('$%^') + }) - it("should handle cases with longer input strings", () => { + it('should handle cases with longer input strings', () => { expect( longestCommonSubsequence( - "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", - "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + 'Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' ) - ).toBe("e iumoor it t oeetr ag li."); - }); -}); + ).toBe('e iumoor it t oeetr ag li.') + }) +}) diff --git a/graph/bellman_ford.ts b/graph/bellman_ford.ts index d3a901b3..7f22acae 100644 --- a/graph/bellman_ford.ts +++ b/graph/bellman_ford.ts @@ -9,11 +9,14 @@ * @return {number[] | undefined} - The shortest path to each node, undefined if there is negative weight cycle * @see https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm */ -export const bellmanFord = (graph: [number, number][][], start: number): number[] | undefined => { +export const bellmanFord = ( + graph: [number, number][][], + start: number +): number[] | undefined => { // We save the shortest distance to each node in `distances`. If a node is // unreachable from the start node, its distance is Infinity. - const distances = Array(graph.length).fill(Infinity); - distances[start] = 0; + const distances = Array(graph.length).fill(Infinity) + distances[start] = 0 // On the i'th iteration, we compute all shortest paths that consists of i+1 // nodes. If we compute this V-1 times, we will have computed all simple @@ -21,7 +24,7 @@ export const bellmanFord = (graph: [number, number][][], start: number): number[ for (let i = 0; i < graph.length - 1; ++i) { for (let node = 0; node < graph.length; ++node) { for (const [child, weight] of graph[node]) { - const new_distance = distances[node] + weight; + const new_distance = distances[node] + weight if (new_distance < distances[child]) { distances[child] = new_distance } @@ -35,11 +38,10 @@ export const bellmanFord = (graph: [number, number][][], start: number): number[ for (let node = 0; node < graph.length; ++node) { for (const [child, weight] of graph[node]) { if (distances[child] > distances[node] + weight) { - return undefined; + return undefined } } } - return distances; + return distances } - diff --git a/graph/bipartite_graph.ts b/graph/bipartite_graph.ts index ffcefff8..cdcda462 100644 --- a/graph/bipartite_graph.ts +++ b/graph/bipartite_graph.ts @@ -5,42 +5,40 @@ const dfs = ( color: number ): boolean => { if (colors[node] !== 0) { - return colors[node] === color; + return colors[node] === color } - colors[node] = color; + colors[node] = color for (const neighbor of graph[node]) { if (!dfs(graph, colors, neighbor, -color)) { - return false; + return false } } - return true; -}; - + return true +} /** * Determines if a given graph is bipartite. * - * A Bipartite Graph is a graph whose vertices can be divided into two independent sets, - * U and V such that every edge (u, v) either connects a vertex from U to V or a vertex from + * A Bipartite Graph is a graph whose vertices can be divided into two independent sets, + * U and V such that every edge (u, v) either connects a vertex from U to V or a vertex from * V to U * * @param {number[][]} graph - The graph represented as an adjacency list. * @returns {boolean} - `true` if the graph is bipartite, `false` otherwise. */ - export const isBipartite = (graph: number[][]): boolean => { - const n: number = graph.length; - const colors: number[] = new Array(n).fill(0); + const n: number = graph.length + const colors: number[] = new Array(n).fill(0) for (let i = 0; i < n; i++) { if (colors[i] === 0 && !dfs(graph, colors, i, 1)) { - return false; + return false } } - return true; -}; + return true +} diff --git a/graph/dijkstra.ts b/graph/dijkstra.ts index edec2746..7804a592 100644 --- a/graph/dijkstra.ts +++ b/graph/dijkstra.ts @@ -1,4 +1,4 @@ -import { MinHeap, PriorityQueue } from '../data_structures/heap/heap'; +import { MinHeap, PriorityQueue } from '../data_structures/heap/heap' /** * @function dijkstra * @description Compute the shortest path from a source node to all other nodes. The input graph is in adjacency list form. It is a multidimensional array of edges. graph[i] holds the edges for the i'th node. Each edge is a 2-tuple where the 0'th item is the destination node, and the 1'th item is the edge weight. @@ -10,28 +10,39 @@ import { MinHeap, PriorityQueue } from '../data_structures/heap/heap'; * @return {number[]} - The shortest path to each node * @see https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm */ -export const dijkstra = (graph: [number, number][][], start: number): number[] => { +export const dijkstra = ( + graph: [number, number][][], + start: number +): number[] => { // We use a priority queue to make sure we always visit the closest node. The // queue makes comparisons based on path weights. - const priorityQueue = new PriorityQueue((a: [number, number]) => { return a[0] }, graph.length, (a: [number, number], b: [number, number]) => { return a[1] < b[1] }); - priorityQueue.insert([start, 0]); + const priorityQueue = new PriorityQueue( + (a: [number, number]) => { + return a[0] + }, + graph.length, + (a: [number, number], b: [number, number]) => { + return a[1] < b[1] + } + ) + priorityQueue.insert([start, 0]) // We save the shortest distance to each node in `distances`. If a node is // unreachable from the start node, its distance is Infinity. - const distances = Array(graph.length).fill(Infinity); - distances[start] = 0; + const distances = Array(graph.length).fill(Infinity) + distances[start] = 0 while (priorityQueue.size() > 0) { - const [node, _] = priorityQueue.extract(); + const [node, _] = priorityQueue.extract() graph[node].forEach(([child, weight]) => { - const new_distance = distances[node] + weight; + const new_distance = distances[node] + weight if (new_distance < distances[child]) { // Found a new shortest path to child node. Record its distance and add child to the queue. // If the child already exists in the queue, the priority will be updated. This will make sure the queue will be at most size V (number of vertices). - priorityQueue.increasePriority(child, [child, weight]); - distances[child] = new_distance; + priorityQueue.increasePriority(child, [child, weight]) + distances[child] = new_distance } - }); + }) } - return distances; + return distances } diff --git a/graph/floyd_warshall.ts b/graph/floyd_warshall.ts index 372b6712..b6da6ed2 100644 --- a/graph/floyd_warshall.ts +++ b/graph/floyd_warshall.ts @@ -9,15 +9,15 @@ * @see https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm */ export const floydWarshall = (graph: number[][]): number[][] => { - let distances = structuredClone(graph); - const N = graph.length; + let distances = structuredClone(graph) + const N = graph.length // We begin by setting the weighted adjacency matrix as the shortest paths. // For the k'th iteration, we try to relax the shortest paths by including node k in the path. for (let k = 0; k < N; ++k) { - const newDistances = []; + const newDistances = [] for (let i = 0; i < N; ++i) { - newDistances.push(Array(N).fill(Infinity)); + newDistances.push(Array(N).fill(Infinity)) } for (let i = 0; i < N; ++i) { @@ -25,13 +25,14 @@ export const floydWarshall = (graph: number[][]): number[][] => { // The shortest path from node i to j is the minimum of: // 1. the shortest path (i -> j) without node k // 2. the sum of the shortest path (i -> k) and (k -> j) - newDistances[i][j] = Math.min(distances[i][j], distances[i][k] + distances[k][j]); + newDistances[i][j] = Math.min( + distances[i][j], + distances[i][k] + distances[k][j] + ) } } - distances = newDistances; + distances = newDistances } - return distances; + return distances } - - diff --git a/graph/johnson.ts b/graph/johnson.ts index ea0204c7..989f3e8c 100644 --- a/graph/johnson.ts +++ b/graph/johnson.ts @@ -11,22 +11,24 @@ import { dijkstra } from './dijkstra' * @return {number[][]} - A matrix holding the shortest path for each pair of nodes. matrix[i][j] holds the distance of the shortest path (i -> j). * @see https://en.wikipedia.org/wiki/Johnson%27s_algorithm */ -export const johnson = (graph: [number, number][][]): number[][] | undefined => { - const N = graph.length; +export const johnson = ( + graph: [number, number][][] +): number[][] | undefined => { + const N = graph.length // Add a new node and 0 weighted edges from the new node to all existing nodes. - const newNodeGraph = structuredClone(graph); - const newNode: [number, number][] = []; + const newNodeGraph = structuredClone(graph) + const newNode: [number, number][] = [] for (let i = 0; i < N; ++i) { - newNode.push([i, 0]); + newNode.push([i, 0]) } - newNodeGraph.push(newNode); + newNodeGraph.push(newNode) // Compute distances from the new node to existing nodes using the Bellman-Ford algorithm. - const adjustedGraph = bellmanFord(newNodeGraph, N); + const adjustedGraph = bellmanFord(newNodeGraph, N) if (adjustedGraph === undefined) { // Found a negative weight cycle. - return undefined; + return undefined } for (let i = 0; i < N; ++i) { @@ -34,19 +36,18 @@ export const johnson = (graph: [number, number][][]): number[][] | undefined => // Adjust edge weights using the Bellman Ford output weights. This ensure that: // 1. Each weight is non-negative. This is required for the Dijkstra algorithm. // 2. The shortest path from node i to node j consists of the same nodes with or without adjustment. - edge[1] += adjustedGraph[i] - adjustedGraph[edge[0]]; + edge[1] += adjustedGraph[i] - adjustedGraph[edge[0]] } } - const shortestPaths: number[][] = []; + const shortestPaths: number[][] = [] for (let i = 0; i < N; ++i) { // Compute Dijkstra weights for each node and re-adjust weights to their original values. - const dijkstraShorestPaths = dijkstra(graph, i); + const dijkstraShorestPaths = dijkstra(graph, i) for (let j = 0; j < N; ++j) { - dijkstraShorestPaths[j] += adjustedGraph[j] - adjustedGraph[i]; + dijkstraShorestPaths[j] += adjustedGraph[j] - adjustedGraph[i] } - shortestPaths.push(dijkstraShorestPaths); + shortestPaths.push(dijkstraShorestPaths) } - return shortestPaths; + return shortestPaths } - diff --git a/graph/kosajaru.ts b/graph/kosajaru.ts index d1498b0b..b0a653de 100644 --- a/graph/kosajaru.ts +++ b/graph/kosajaru.ts @@ -1,43 +1,53 @@ // Compute the node priorities, which will be used to determine the order in which we perform transposed DFS. -const getNodePriorities = (graph: number[][], visited: boolean[], stack: number[], node: number) => { +const getNodePriorities = ( + graph: number[][], + visited: boolean[], + stack: number[], + node: number +) => { if (visited[node]) { - return; + return } - visited[node] = true; + visited[node] = true for (const dest of graph[node]) { - getNodePriorities(graph, visited, stack, dest); + getNodePriorities(graph, visited, stack, dest) } // Nodes that end their DFS earlier are pushed onto the stack first and have lower priority. - stack.push(node); + stack.push(node) } // Return the transpose of graph. The tranpose of a directed graph is a graph where each of the edges are flipped. const transpose = (graph: number[][]): number[][] => { - const transposedGraph = Array(graph.length); + const transposedGraph = Array(graph.length) for (let i = 0; i < graph.length; ++i) { - transposedGraph[i] = []; + transposedGraph[i] = [] } for (let i = 0; i < graph.length; ++i) { for (let j = 0; j < graph[i].length; ++j) { - transposedGraph[graph[i][j]].push(i); + transposedGraph[graph[i][j]].push(i) } } - return transposedGraph; + return transposedGraph } // Computes the SCC that contains the given node -const gatherScc = (graph: number[][], visited: boolean[], node: number, scc: number[]) => { +const gatherScc = ( + graph: number[][], + visited: boolean[], + node: number, + scc: number[] +) => { if (visited[node]) { - return; + return } - visited[node] = true; - scc.push(node); + visited[node] = true + scc.push(node) for (const dest of graph[node]) { - gatherScc(graph, visited, dest, scc); + gatherScc(graph, visited, dest, scc) } } @@ -52,24 +62,23 @@ const gatherScc = (graph: number[][], visited: boolean[], node: number, scc: num * @see https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm */ export const kosajaru = (graph: number[][]): number[][] => { - const visited = Array(graph.length).fill(false); + const visited = Array(graph.length).fill(false) - const stack: number[] = []; + const stack: number[] = [] for (let i = 0; i < graph.length; ++i) { - getNodePriorities(graph, visited, stack, i); + getNodePriorities(graph, visited, stack, i) } - const transposedGraph = transpose(graph); + const transposedGraph = transpose(graph) - const sccs = []; - visited.fill(false); + const sccs = [] + visited.fill(false) for (let i = stack.length - 1; i >= 0; --i) { if (!visited[stack[i]]) { - const scc: number[] = []; - gatherScc(transposedGraph, visited, stack[i], scc); - sccs.push(scc); + const scc: number[] = [] + gatherScc(transposedGraph, visited, stack[i], scc) + sccs.push(scc) } } - return sccs; + return sccs } - diff --git a/graph/kruskal.ts b/graph/kruskal.ts index 750eb15f..f28bb5ce 100644 --- a/graph/kruskal.ts +++ b/graph/kruskal.ts @@ -1,4 +1,4 @@ -import { DisjointSet } from '../data_structures/disjoint_set/disjoint_set'; +import { DisjointSet } from '../data_structures/disjoint_set/disjoint_set' /** * @function kruskal @@ -11,35 +11,38 @@ import { DisjointSet } from '../data_structures/disjoint_set/disjoint_set'; * @return {Edge[], number} - [The edges of the minimum spanning tree, the sum of the weights of the edges in the tree] * @see https://en.wikipedia.org/wiki/Kruskal%27s_algorithm */ -export const kruskal = (edges: Edge[], num_vertices: number): [Edge[], number] => { - let cost = 0; - const minimum_spanning_tree = []; +export const kruskal = ( + edges: Edge[], + num_vertices: number +): [Edge[], number] => { + let cost = 0 + const minimum_spanning_tree = [] // Use a disjoint set to quickly join sets and find if vertices live in different sets - const sets = new DisjointSet(num_vertices); + const sets = new DisjointSet(num_vertices) // Sort the edges in ascending order by weight so that we can greedily add cheaper edges to the tree - edges.sort((a, b) => a.weight - b.weight); + edges.sort((a, b) => a.weight - b.weight) for (const edge of edges) { if (sets.find(edge.a) !== sets.find(edge.b)) { // Node A and B live in different sets. Add edge(a, b) to the tree and join the nodes' sets together. - minimum_spanning_tree.push(edge); - cost += edge.weight; - sets.join(edge.a, edge.b); + minimum_spanning_tree.push(edge) + cost += edge.weight + sets.join(edge.a, edge.b) } } - return [minimum_spanning_tree, cost]; + return [minimum_spanning_tree, cost] } export class Edge { - a: number = 0; - b: number = 0; - weight: number = 0; + a: number = 0 + b: number = 0 + weight: number = 0 constructor(a: number, b: number, weight: number) { - this.a = a; - this.b = b; - this.weight = weight; + this.a = a + this.b = b + this.weight = weight } } diff --git a/graph/prim.ts b/graph/prim.ts index 722c1e16..3261c633 100644 --- a/graph/prim.ts +++ b/graph/prim.ts @@ -11,49 +11,63 @@ import { PriorityQueue } from '../data_structures/heap/heap' */ export const prim = (graph: [number, number][][]): [Edge[], number] => { if (graph.length == 0) { - return [[], 0]; + return [[], 0] } - const minimum_spanning_tree: Edge[] = []; - let total_weight = 0; + const minimum_spanning_tree: Edge[] = [] + let total_weight = 0 - const priorityQueue = new PriorityQueue((e: Edge) => { return e.b }, graph.length, (a: Edge, b: Edge) => { return a.weight < b.weight }); - const visited = new Set(); + const priorityQueue = new PriorityQueue( + (e: Edge) => { + return e.b + }, + graph.length, + (a: Edge, b: Edge) => { + return a.weight < b.weight + } + ) + const visited = new Set() // Start from the 0'th node. For fully connected graphs, we can start from any node and still produce the MST. - visited.add(0); - add_children(graph, priorityQueue, 0); + visited.add(0) + add_children(graph, priorityQueue, 0) while (!priorityQueue.isEmpty()) { // We have already visited vertex `edge.a`. If we have not visited `edge.b` yet, we add its outgoing edges to the PriorityQueue. - const edge = priorityQueue.extract(); + const edge = priorityQueue.extract() if (visited.has(edge.b)) { - continue; + continue } - minimum_spanning_tree.push(edge); - total_weight += edge.weight; - visited.add(edge.b); - add_children(graph, priorityQueue, edge.b); + minimum_spanning_tree.push(edge) + total_weight += edge.weight + visited.add(edge.b) + add_children(graph, priorityQueue, edge.b) } - return [minimum_spanning_tree, total_weight]; + return [minimum_spanning_tree, total_weight] } -const add_children = (graph: [number, number][][], priorityQueue: PriorityQueue, node: number) => { +const add_children = ( + graph: [number, number][][], + priorityQueue: PriorityQueue, + node: number +) => { for (let i = 0; i < graph[node].length; ++i) { - const out_edge = graph[node][i]; + const out_edge = graph[node][i] // By increasing the priority, we ensure we only add each vertex to the queue one time, and the queue will be at most size V. - priorityQueue.increasePriority(out_edge[0], new Edge(node, out_edge[0], out_edge[1])); + priorityQueue.increasePriority( + out_edge[0], + new Edge(node, out_edge[0], out_edge[1]) + ) } } export class Edge { - a: number = 0; - b: number = 0; - weight: number = 0; + a: number = 0 + b: number = 0 + weight: number = 0 constructor(a: number, b: number, weight: number) { - this.a = a; - this.b = b; - this.weight = weight; + this.a = a + this.b = b + this.weight = weight } } - diff --git a/graph/tarjan.ts b/graph/tarjan.ts index 27de35a7..c193fe45 100644 --- a/graph/tarjan.ts +++ b/graph/tarjan.ts @@ -10,61 +10,60 @@ */ export const tarjan = (graph: number[][]): number[][] => { if (graph.length === 0) { - return []; + return [] } - let index = 0; + let index = 0 // The order in which we discover nodes - const discovery: number[] = Array(graph.length); + const discovery: number[] = Array(graph.length) // For each node, holds the furthest ancestor it can reach - const low: number[] = Array(graph.length).fill(undefined); + const low: number[] = Array(graph.length).fill(undefined) // Holds the nodes we have visited in a DFS traversal and are considering to group into a SCC - const stack: number[] = []; + const stack: number[] = [] // Holds the elements in the stack. - const stackContains = Array(graph.length).fill(false); - const sccs: number[][] = []; + const stackContains = Array(graph.length).fill(false) + const sccs: number[][] = [] const dfs = (node: number) => { - discovery[node] = index; - low[node] = index; - ++index; - stack.push(node); - stackContains[node] = true; + discovery[node] = index + low[node] = index + ++index + stack.push(node) + stackContains[node] = true for (const child of graph[node]) { if (low[child] === undefined) { - dfs(child); + dfs(child) if (low[child] < low[node]) { // Child node loops back to this node's ancestor. Update the low node. - low[node] = low[child]; + low[node] = low[child] } } else if (stackContains[child] && low[node] > discovery[child]) { // Found a backedge. Update the low for this node if needed. - low[node] = discovery[child]; + low[node] = discovery[child] } } if (discovery[node] == low[node]) { // node is the root of a SCC. Gather the SCC's nodes from the stack. - const scc: number[] = []; - let i; + const scc: number[] = [] + let i for (i = stack.length - 1; stack[i] != node; --i) { - scc.push(stack[i]); - stackContains[stack[i]] = false; - stack.pop(); + scc.push(stack[i]) + stackContains[stack[i]] = false + stack.pop() } - scc.push(stack[i]); - stackContains[stack[i]] = false; - stack.pop(); - sccs.push(scc); + scc.push(stack[i]) + stackContains[stack[i]] = false + stack.pop() + sccs.push(scc) } } for (let i = 0; i < graph.length; ++i) { if (low[i] === undefined) { - dfs(i); + dfs(i) } } - return sccs; + return sccs } - diff --git a/graph/test/bellman_ford.test.ts b/graph/test/bellman_ford.test.ts index f99ee907..ad483fa3 100644 --- a/graph/test/bellman_ford.test.ts +++ b/graph/test/bellman_ford.test.ts @@ -1,88 +1,102 @@ -import { bellmanFord } from "../bellman_ford"; +import { bellmanFord } from '../bellman_ford' const init_graph = (N: number): [number, number][][] => { - const graph = Array(N); + const graph = Array(N) for (let i = 0; i < N; ++i) { - graph[i] = []; + graph[i] = [] } - return graph; + return graph } -describe("bellmanFord", () => { - - const add_edge = (graph: [number, number][][], a: number, b: number, weight: number) => { - graph[a].push([b, weight]); - graph[b].push([a, weight]); +describe('bellmanFord', () => { + const add_edge = ( + graph: [number, number][][], + a: number, + b: number, + weight: number + ) => { + graph[a].push([b, weight]) + graph[b].push([a, weight]) } - it("should return the correct value", () => { - const graph = init_graph(9); - add_edge(graph, 0, 1, 4); - add_edge(graph, 0, 7, 8); - add_edge(graph, 1, 2, 8); - add_edge(graph, 1, 7, 11); - add_edge(graph, 2, 3, 7); - add_edge(graph, 2, 5, 4); - add_edge(graph, 2, 8, 2); - add_edge(graph, 3, 4, 9); - add_edge(graph, 3, 5, 14); - add_edge(graph, 4, 5, 10); - add_edge(graph, 5, 6, 2); - add_edge(graph, 6, 7, 1); - add_edge(graph, 6, 8, 6); - add_edge(graph, 7, 8, 7); - expect(bellmanFord(graph, 0)).toStrictEqual([0, 4, 12, 19, 21, 11, 9, 8, 14]); - }); + it('should return the correct value', () => { + const graph = init_graph(9) + add_edge(graph, 0, 1, 4) + add_edge(graph, 0, 7, 8) + add_edge(graph, 1, 2, 8) + add_edge(graph, 1, 7, 11) + add_edge(graph, 2, 3, 7) + add_edge(graph, 2, 5, 4) + add_edge(graph, 2, 8, 2) + add_edge(graph, 3, 4, 9) + add_edge(graph, 3, 5, 14) + add_edge(graph, 4, 5, 10) + add_edge(graph, 5, 6, 2) + add_edge(graph, 6, 7, 1) + add_edge(graph, 6, 8, 6) + add_edge(graph, 7, 8, 7) + expect(bellmanFord(graph, 0)).toStrictEqual([ + 0, 4, 12, 19, 21, 11, 9, 8, 14 + ]) + }) - it("should return the correct value for single element graph", () => { - expect(bellmanFord([[]], 0)).toStrictEqual([0]); - }); + it('should return the correct value for single element graph', () => { + expect(bellmanFord([[]], 0)).toStrictEqual([0]) + }) - const linear_graph = init_graph(4); - add_edge(linear_graph, 0, 1, 1); - add_edge(linear_graph, 1, 2, 2); - add_edge(linear_graph, 2, 3, 3); - test.each([[0, [0, 1, 3, 6]], [1, [1, 0, 2, 5]], [2, [3, 2, 0, 3]], [3, [6, 5, 3, 0]]])( - "correct result for linear graph with source node %i", + const linear_graph = init_graph(4) + add_edge(linear_graph, 0, 1, 1) + add_edge(linear_graph, 1, 2, 2) + add_edge(linear_graph, 2, 3, 3) + test.each([ + [0, [0, 1, 3, 6]], + [1, [1, 0, 2, 5]], + [2, [3, 2, 0, 3]], + [3, [6, 5, 3, 0]] + ])( + 'correct result for linear graph with source node %i', (source, result) => { - expect(bellmanFord(linear_graph, source)).toStrictEqual(result); + expect(bellmanFord(linear_graph, source)).toStrictEqual(result) } - ); + ) - const unreachable_graph = init_graph(3); - add_edge(unreachable_graph, 0, 1, 1); - test.each([[0, [0, 1, Infinity]], [1, [1, 0, Infinity]], [2, [Infinity, Infinity, 0]]])( - "correct result for graph with unreachable nodes with source node %i", + const unreachable_graph = init_graph(3) + add_edge(unreachable_graph, 0, 1, 1) + test.each([ + [0, [0, 1, Infinity]], + [1, [1, 0, Infinity]], + [2, [Infinity, Infinity, 0]] + ])( + 'correct result for graph with unreachable nodes with source node %i', (source, result) => { - expect(bellmanFord(unreachable_graph, source)).toStrictEqual(result); + expect(bellmanFord(unreachable_graph, source)).toStrictEqual(result) } - ); + ) }) -describe("bellmanFord negative cycle graphs", () => { - it("should returned undefined for 2-node graph with negative cycle", () => { - const basic = init_graph(2); - basic[0].push([1, 2]); - basic[1].push([0, -3]); - expect(bellmanFord(basic, 0)).toStrictEqual(undefined); - expect(bellmanFord(basic, 1)).toStrictEqual(undefined); - }); +describe('bellmanFord negative cycle graphs', () => { + it('should returned undefined for 2-node graph with negative cycle', () => { + const basic = init_graph(2) + basic[0].push([1, 2]) + basic[1].push([0, -3]) + expect(bellmanFord(basic, 0)).toStrictEqual(undefined) + expect(bellmanFord(basic, 1)).toStrictEqual(undefined) + }) - it("should returned undefined for graph with negative cycle", () => { - const negative = init_graph(5); - negative[0].push([1, 6]); - negative[0].push([3, 7]); - negative[1].push([2, 5]); - negative[1].push([3, 8]); - negative[1].push([4, -4]); - negative[2].push([1, -4]); - negative[3].push([2, -3]); - negative[3].push([4, 9]); - negative[4].push([0, 3]); - negative[4].push([2, 7]); + it('should returned undefined for graph with negative cycle', () => { + const negative = init_graph(5) + negative[0].push([1, 6]) + negative[0].push([3, 7]) + negative[1].push([2, 5]) + negative[1].push([3, 8]) + negative[1].push([4, -4]) + negative[2].push([1, -4]) + negative[3].push([2, -3]) + negative[3].push([4, 9]) + negative[4].push([0, 3]) + negative[4].push([2, 7]) for (let i = 0; i < 5; ++i) { - expect(bellmanFord(negative, i)).toStrictEqual(undefined); + expect(bellmanFord(negative, i)).toStrictEqual(undefined) } - }); -}); - + }) +}) diff --git a/graph/test/bipartite_graph.test.ts b/graph/test/bipartite_graph.test.ts index 050060ba..3e036479 100644 --- a/graph/test/bipartite_graph.test.ts +++ b/graph/test/bipartite_graph.test.ts @@ -1,33 +1,43 @@ -import { isBipartite } from "../bipartite_graph"; +import { isBipartite } from '../bipartite_graph' describe('isBipartite', () => { - it('should return true for a bipartite graph', () => { - const graph = [[1, 3], [0, 2], [1, 3], [0, 2]]; - const result = isBipartite(graph); - expect(result).toBe(true); - }); - - it('should return true for an empty graph', () => { - const graph: number[][] = []; - const result = isBipartite(graph); - expect(result).toBe(true); - }); - - it('should return true for a single node graph', () => { - const graph = [[]]; - const result = isBipartite(graph); - expect(result).toBe(true); - }); - - it('should return false for a non-bipartite graph', () => { - const graph = [[1, 2, 3], [0, 2], [0, 1, 3], [0, 2]]; - const result = isBipartite(graph); - expect(result).toBe(false); - }); - - it('should return true for a disconnected bipartite graph', () => { - const graph = [[1, 2], [0], [0], [4], [3]]; - const result = isBipartite(graph); - expect(result).toBe(true); - }); - }); \ No newline at end of file + it('should return true for a bipartite graph', () => { + const graph = [ + [1, 3], + [0, 2], + [1, 3], + [0, 2] + ] + const result = isBipartite(graph) + expect(result).toBe(true) + }) + + it('should return true for an empty graph', () => { + const graph: number[][] = [] + const result = isBipartite(graph) + expect(result).toBe(true) + }) + + it('should return true for a single node graph', () => { + const graph = [[]] + const result = isBipartite(graph) + expect(result).toBe(true) + }) + + it('should return false for a non-bipartite graph', () => { + const graph = [ + [1, 2, 3], + [0, 2], + [0, 1, 3], + [0, 2] + ] + const result = isBipartite(graph) + expect(result).toBe(false) + }) + + it('should return true for a disconnected bipartite graph', () => { + const graph = [[1, 2], [0], [0], [4], [3]] + const result = isBipartite(graph) + expect(result).toBe(true) + }) +}) diff --git a/graph/test/dijkstra.test.ts b/graph/test/dijkstra.test.ts index dfd0f436..e12575e8 100644 --- a/graph/test/dijkstra.test.ts +++ b/graph/test/dijkstra.test.ts @@ -1,61 +1,73 @@ -import { dijkstra } from "../dijkstra"; - -describe("dijkstra", () => { +import { dijkstra } from '../dijkstra' +describe('dijkstra', () => { const init_graph = (N: number): [number, number][][] => { - const graph = Array(N); + const graph = Array(N) for (let i = 0; i < N; ++i) { - graph[i] = []; + graph[i] = [] } - return graph; + return graph } - const add_edge = (graph: [number, number][][], a: number, b: number, weight: number) => { - graph[a].push([b, weight]); - graph[b].push([a, weight]); + const add_edge = ( + graph: [number, number][][], + a: number, + b: number, + weight: number + ) => { + graph[a].push([b, weight]) + graph[b].push([a, weight]) } - it("should return the correct value", () => { - const graph = init_graph(9); - add_edge(graph, 0, 1, 4); - add_edge(graph, 0, 7, 8); - add_edge(graph, 1, 2, 8); - add_edge(graph, 1, 7, 11); - add_edge(graph, 2, 3, 7); - add_edge(graph, 2, 5, 4); - add_edge(graph, 2, 8, 2); - add_edge(graph, 3, 4, 9); - add_edge(graph, 3, 5, 14); - add_edge(graph, 4, 5, 10); - add_edge(graph, 5, 6, 2); - add_edge(graph, 6, 7, 1); - add_edge(graph, 6, 8, 6); - add_edge(graph, 7, 8, 7); - expect(dijkstra(graph, 0)).toStrictEqual([0, 4, 12, 19, 21, 11, 9, 8, 14]); - }); + it('should return the correct value', () => { + const graph = init_graph(9) + add_edge(graph, 0, 1, 4) + add_edge(graph, 0, 7, 8) + add_edge(graph, 1, 2, 8) + add_edge(graph, 1, 7, 11) + add_edge(graph, 2, 3, 7) + add_edge(graph, 2, 5, 4) + add_edge(graph, 2, 8, 2) + add_edge(graph, 3, 4, 9) + add_edge(graph, 3, 5, 14) + add_edge(graph, 4, 5, 10) + add_edge(graph, 5, 6, 2) + add_edge(graph, 6, 7, 1) + add_edge(graph, 6, 8, 6) + add_edge(graph, 7, 8, 7) + expect(dijkstra(graph, 0)).toStrictEqual([0, 4, 12, 19, 21, 11, 9, 8, 14]) + }) - it("should return the correct value for single element graph", () => { - expect(dijkstra([[]], 0)).toStrictEqual([0]); - }); + it('should return the correct value for single element graph', () => { + expect(dijkstra([[]], 0)).toStrictEqual([0]) + }) - const linear_graph = init_graph(4); - add_edge(linear_graph, 0, 1, 1); - add_edge(linear_graph, 1, 2, 2); - add_edge(linear_graph, 2, 3, 3); - test.each([[0, [0, 1, 3, 6]], [1, [1, 0, 2, 5]], [2, [3, 2, 0, 3]], [3, [6, 5, 3, 0]]])( - "correct result for linear graph with source node %i", + const linear_graph = init_graph(4) + add_edge(linear_graph, 0, 1, 1) + add_edge(linear_graph, 1, 2, 2) + add_edge(linear_graph, 2, 3, 3) + test.each([ + [0, [0, 1, 3, 6]], + [1, [1, 0, 2, 5]], + [2, [3, 2, 0, 3]], + [3, [6, 5, 3, 0]] + ])( + 'correct result for linear graph with source node %i', (source, result) => { - expect(dijkstra(linear_graph, source)).toStrictEqual(result); + expect(dijkstra(linear_graph, source)).toStrictEqual(result) } - ); + ) - const unreachable_graph = init_graph(3); - add_edge(unreachable_graph, 0, 1, 1); - test.each([[0, [0, 1, Infinity]], [1, [1, 0, Infinity]], [2, [Infinity, Infinity, 0]]])( - "correct result for graph with unreachable nodes with source node %i", + const unreachable_graph = init_graph(3) + add_edge(unreachable_graph, 0, 1, 1) + test.each([ + [0, [0, 1, Infinity]], + [1, [1, 0, Infinity]], + [2, [Infinity, Infinity, 0]] + ])( + 'correct result for graph with unreachable nodes with source node %i', (source, result) => { - expect(dijkstra(unreachable_graph, source)).toStrictEqual(result); + expect(dijkstra(unreachable_graph, source)).toStrictEqual(result) } - ); + ) }) - diff --git a/graph/test/floyd_warshall.test.ts b/graph/test/floyd_warshall.test.ts index 81c04bdf..4893c4b7 100644 --- a/graph/test/floyd_warshall.test.ts +++ b/graph/test/floyd_warshall.test.ts @@ -1,39 +1,47 @@ -import { floydWarshall } from "../floyd_warshall"; +import { floydWarshall } from '../floyd_warshall' -describe("floydWarshall", () => { - it("should return the correct value for zero element graph", () => { - expect(floydWarshall([])).toEqual([]); - }); +describe('floydWarshall', () => { + it('should return the correct value for zero element graph', () => { + expect(floydWarshall([])).toEqual([]) + }) - it("should return the correct value for one element graph", () => { - expect(floydWarshall([[1]])).toStrictEqual([[1]]); - }); + it('should return the correct value for one element graph', () => { + expect(floydWarshall([[1]])).toStrictEqual([[1]]) + }) - it("should return the correct value for two element graph", () => { - expect(floydWarshall([[10, 4], [3, 6]])).toStrictEqual([[7, 4], [3, 6]]); - }); + it('should return the correct value for two element graph', () => { + expect( + floydWarshall([ + [10, 4], + [3, 6] + ]) + ).toStrictEqual([ + [7, 4], + [3, 6] + ]) + }) - it("should return the correct value", () => { - const graph = []; + it('should return the correct value', () => { + const graph = [] for (let i = 1; i <= 5; ++i) { - const arr = []; + const arr = [] for (let j = 1; j <= 5; ++j) { - arr.push(i * j); + arr.push(i * j) } - graph.push(arr); + graph.push(arr) } const expected = [ - [ 1, 2, 3, 4, 5 ], - [ 2, 4, 5, 6, 7 ], - [ 3, 5, 6, 7, 8 ], - [ 4, 6, 7, 8, 9 ], - [ 5, 7, 8, 9, 10 ] - ]; - expect(floydWarshall(graph)).toStrictEqual(expected); - }); - - it("should return the correct value", () => { + [1, 2, 3, 4, 5], + [2, 4, 5, 6, 7], + [3, 5, 6, 7, 8], + [4, 6, 7, 8, 9], + [5, 7, 8, 9, 10] + ] + expect(floydWarshall(graph)).toStrictEqual(expected) + }) + + it('should return the correct value', () => { const graph = [ [0, 4, Infinity, Infinity, Infinity, Infinity, Infinity, 8, Infinity], [4, 0, 8, Infinity, Infinity, Infinity, Infinity, 11, Infinity], @@ -44,7 +52,7 @@ describe("floydWarshall", () => { [Infinity, Infinity, Infinity, Infinity, Infinity, 2, 0, 1, 6], [8, 11, Infinity, Infinity, Infinity, Infinity, 1, 0, 7], [Infinity, Infinity, 2, Infinity, Infinity, Infinity, 6, 7, 0] - ]; + ] const expected = [ [0, 4, 12, 19, 21, 11, 9, 8, 14], @@ -58,6 +66,6 @@ describe("floydWarshall", () => { [14, 10, 2, 9, 16, 6, 6, 7, 0] ] - expect(floydWarshall(graph)).toStrictEqual(expected); - }); -}); + expect(floydWarshall(graph)).toStrictEqual(expected) + }) +}) diff --git a/graph/test/johnson.test.ts b/graph/test/johnson.test.ts index 625bb993..12ffec65 100644 --- a/graph/test/johnson.test.ts +++ b/graph/test/johnson.test.ts @@ -1,36 +1,40 @@ -import { johnson } from "../johnson"; - -describe("johnson", () => { +import { johnson } from '../johnson' +describe('johnson', () => { const init_graph = (N: number): [number, number][][] => { - const graph = Array(N); + const graph = Array(N) for (let i = 0; i < N; ++i) { - graph[i] = []; + graph[i] = [] } - return graph; + return graph } - const add_edge = (graph: [number, number][][], a: number, b: number, weight: number) => { - graph[a].push([b, weight]); - graph[b].push([a, weight]); + const add_edge = ( + graph: [number, number][][], + a: number, + b: number, + weight: number + ) => { + graph[a].push([b, weight]) + graph[b].push([a, weight]) } - it("should return the correct value", () => { - const graph = init_graph(9); - add_edge(graph, 0, 1, 4); - add_edge(graph, 0, 7, 8); - add_edge(graph, 1, 2, 8); - add_edge(graph, 1, 7, 11); - add_edge(graph, 2, 3, 7); - add_edge(graph, 2, 5, 4); - add_edge(graph, 2, 8, 2); - add_edge(graph, 3, 4, 9); - add_edge(graph, 3, 5, 14); - add_edge(graph, 4, 5, 10); - add_edge(graph, 5, 6, 2); - add_edge(graph, 6, 7, 1); - add_edge(graph, 6, 8, 6); - add_edge(graph, 7, 8, 7); + it('should return the correct value', () => { + const graph = init_graph(9) + add_edge(graph, 0, 1, 4) + add_edge(graph, 0, 7, 8) + add_edge(graph, 1, 2, 8) + add_edge(graph, 1, 7, 11) + add_edge(graph, 2, 3, 7) + add_edge(graph, 2, 5, 4) + add_edge(graph, 2, 8, 2) + add_edge(graph, 3, 4, 9) + add_edge(graph, 3, 5, 14) + add_edge(graph, 4, 5, 10) + add_edge(graph, 5, 6, 2) + add_edge(graph, 6, 7, 1) + add_edge(graph, 6, 8, 6) + add_edge(graph, 7, 8, 7) const expected = [ [0, 4, 12, 19, 21, 11, 9, 8, 14], @@ -43,65 +47,73 @@ describe("johnson", () => { [8, 11, 7, 14, 13, 3, 1, 0, 7], [14, 10, 2, 9, 16, 6, 6, 7, 0] ] - expect(johnson(graph)).toStrictEqual(expected); - }); + expect(johnson(graph)).toStrictEqual(expected) + }) - it("should return the correct value for graph with negative weights", () => { - const graph = init_graph(4); - graph[0].push([1, -5]); - graph[0].push([2, 2]); - graph[0].push([3, 3]); - graph[1].push([2, 4]); - graph[2].push([3, 1]); + it('should return the correct value for graph with negative weights', () => { + const graph = init_graph(4) + graph[0].push([1, -5]) + graph[0].push([2, 2]) + graph[0].push([3, 3]) + graph[1].push([2, 4]) + graph[2].push([3, 1]) const expected = [ - [ 0, -5, -1, 0 ], - [ Infinity, 0, 4, 5 ], - [ Infinity, Infinity, 0, 1 ], - [ Infinity, Infinity, Infinity, 0 ] + [0, -5, -1, 0], + [Infinity, 0, 4, 5], + [Infinity, Infinity, 0, 1], + [Infinity, Infinity, Infinity, 0] ] - expect(johnson(graph)).toStrictEqual(expected); - }); - - it("should return the undefined for two node graph with negative-weight cycle", () => { - const graph = init_graph(2); - add_edge(graph, 0, 1, -1); - expect(johnson(graph)).toStrictEqual(undefined); - }); - - it("should return the undefined for three node graph with negative-weight cycle", () => { - const graph = init_graph(3); - graph[0].push([1, -1]); - graph[0].push([2, 7]); - graph[1].push([2, -5]); - graph[2].push([0, 4]); - expect(johnson(graph)).toStrictEqual(undefined); - }); - - it("should return the correct value for zero element graph", () => { - expect(johnson([])).toStrictEqual([]); - }); - - it("should return the correct value for single element graph", () => { - expect(johnson([[]])).toStrictEqual([[0]]); - }); - - it("should return the correct value for a linear graph", () => { - const linear_graph = init_graph(4); - add_edge(linear_graph, 0, 1, 1); - add_edge(linear_graph, 1, 2, 2); - add_edge(linear_graph, 2, 3, 3); + expect(johnson(graph)).toStrictEqual(expected) + }) + + it('should return the undefined for two node graph with negative-weight cycle', () => { + const graph = init_graph(2) + add_edge(graph, 0, 1, -1) + expect(johnson(graph)).toStrictEqual(undefined) + }) + + it('should return the undefined for three node graph with negative-weight cycle', () => { + const graph = init_graph(3) + graph[0].push([1, -1]) + graph[0].push([2, 7]) + graph[1].push([2, -5]) + graph[2].push([0, 4]) + expect(johnson(graph)).toStrictEqual(undefined) + }) + + it('should return the correct value for zero element graph', () => { + expect(johnson([])).toStrictEqual([]) + }) + + it('should return the correct value for single element graph', () => { + expect(johnson([[]])).toStrictEqual([[0]]) + }) + + it('should return the correct value for a linear graph', () => { + const linear_graph = init_graph(4) + add_edge(linear_graph, 0, 1, 1) + add_edge(linear_graph, 1, 2, 2) + add_edge(linear_graph, 2, 3, 3) - const expected = [[0, 1, 3, 6 ], [1, 0, 2, 5], [3, 2, 0, 3], [6, 5, 3, 0]]; - expect(johnson(linear_graph)).toStrictEqual(expected); - }); + const expected = [ + [0, 1, 3, 6], + [1, 0, 2, 5], + [3, 2, 0, 3], + [6, 5, 3, 0] + ] + expect(johnson(linear_graph)).toStrictEqual(expected) + }) - it("should return the correct value for a linear graph with unreachable node", () => { - const linear_graph = init_graph(3); - add_edge(linear_graph, 0, 1, 1); + it('should return the correct value for a linear graph with unreachable node', () => { + const linear_graph = init_graph(3) + add_edge(linear_graph, 0, 1, 1) - const expected = [[0, 1, Infinity], [1, 0, Infinity], [Infinity, Infinity, 0]]; - expect(johnson(linear_graph)).toStrictEqual(expected); - }); + const expected = [ + [0, 1, Infinity], + [1, 0, Infinity], + [Infinity, Infinity, 0] + ] + expect(johnson(linear_graph)).toStrictEqual(expected) + }) }) - diff --git a/graph/test/kosajaru.test.ts b/graph/test/kosajaru.test.ts index 946b0201..25886701 100644 --- a/graph/test/kosajaru.test.ts +++ b/graph/test/kosajaru.test.ts @@ -1,72 +1,94 @@ -import { kosajaru } from "../kosajaru"; - -describe("kosajaru", () => { - - it("it should return no sccs for empty graph", () => { - expect(kosajaru([])).toStrictEqual([]); - }); - - it("it should return one scc for graph with one element", () => { - expect(kosajaru([[]])).toStrictEqual([[0]]); - }); - - it("it should return one scc for graph with element that points to itself", () => { - expect(kosajaru([[0]])).toStrictEqual([[0]]); - }); - - it("it should return one scc for two element graph with cycle", () => { - expect(kosajaru([[1], [0]])).toStrictEqual([[0, 1]]); - }); - - it("should return one scc for each element for straight line", () => { - expect(kosajaru([[1], [2], [3], []])).toStrictEqual([[0], [1], [2], [3]]); - }); - - it("should return sccs for straight line with backedge in middle", () => { - expect(kosajaru([[1], [2], [3, 0], []])).toStrictEqual([[0, 2, 1], [3]]); - }); - - it("should return sccs for straight line with backedge from end to middle", () => { - expect(kosajaru([[1], [2], [3], [1]])).toStrictEqual([[0], [1, 3, 2]]); - }); - - it("should return scc for each element for graph with no edges", () => { - expect(kosajaru([[], [], [], []])).toStrictEqual([[3], [2], [1], [0]]); - }); - - it("should return sccs disconnected graph", () => { - expect(kosajaru([[1, 2], [0, 2], [0, 1], []])).toStrictEqual([[3], [0, 1, 2]]); - }); - - it("should return sccs disconnected graph", () => { - expect(kosajaru([[1, 2], [0, 2], [0, 1], [4], [5], [3]])).toStrictEqual([[3, 5, 4], [0, 1, 2]]); - }); - - it("should return single scc", () => { - expect(kosajaru([[1], [2], [3], [0, 4], [3]])).toStrictEqual([[0, 3, 2, 1, 4]]); - }); - - it("should return one scc for complete connected graph", () => { - const input = [[1, 2, 3, 4], [0, 2, 3, 4], [0, 1, 3, 4], [0, 1, 2, 4], [0, 1, 2, 3]]; - expect(kosajaru(input)).toStrictEqual([[0, 1, 2, 3, 4]]); - }); - - it("should return sccs", () => { - const input = [[1], [2], [0, 3], [4], []]; - expect(kosajaru(input)).toStrictEqual([[0, 2, 1], [3], [4]]); - }); - - it("should return sccs", () => { - const input = [[1], [2], [0, 3, 4], [0], [5], [6, 7], [2, 4], [8], [5, 9], [5]]; - const expected = [[0, 2, 1, 6, 5, 4, 8, 7, 9, 3]]; - expect(kosajaru(input)).toStrictEqual(expected); - }); - - it("should return sccs", () => { - const input = [[1], [0, 2], [0, 3], [4], [5, 7], [6], [4, 7], []]; - const expected = [[0, 1, 2], [3], [4, 6, 5], [7]]; - expect(kosajaru(input)).toStrictEqual(expected); - }); - +import { kosajaru } from '../kosajaru' + +describe('kosajaru', () => { + it('it should return no sccs for empty graph', () => { + expect(kosajaru([])).toStrictEqual([]) + }) + + it('it should return one scc for graph with one element', () => { + expect(kosajaru([[]])).toStrictEqual([[0]]) + }) + + it('it should return one scc for graph with element that points to itself', () => { + expect(kosajaru([[0]])).toStrictEqual([[0]]) + }) + + it('it should return one scc for two element graph with cycle', () => { + expect(kosajaru([[1], [0]])).toStrictEqual([[0, 1]]) + }) + + it('should return one scc for each element for straight line', () => { + expect(kosajaru([[1], [2], [3], []])).toStrictEqual([[0], [1], [2], [3]]) + }) + + it('should return sccs for straight line with backedge in middle', () => { + expect(kosajaru([[1], [2], [3, 0], []])).toStrictEqual([[0, 2, 1], [3]]) + }) + + it('should return sccs for straight line with backedge from end to middle', () => { + expect(kosajaru([[1], [2], [3], [1]])).toStrictEqual([[0], [1, 3, 2]]) + }) + + it('should return scc for each element for graph with no edges', () => { + expect(kosajaru([[], [], [], []])).toStrictEqual([[3], [2], [1], [0]]) + }) + + it('should return sccs disconnected graph', () => { + expect(kosajaru([[1, 2], [0, 2], [0, 1], []])).toStrictEqual([ + [3], + [0, 1, 2] + ]) + }) + + it('should return sccs disconnected graph', () => { + expect(kosajaru([[1, 2], [0, 2], [0, 1], [4], [5], [3]])).toStrictEqual([ + [3, 5, 4], + [0, 1, 2] + ]) + }) + + it('should return single scc', () => { + expect(kosajaru([[1], [2], [3], [0, 4], [3]])).toStrictEqual([ + [0, 3, 2, 1, 4] + ]) + }) + + it('should return one scc for complete connected graph', () => { + const input = [ + [1, 2, 3, 4], + [0, 2, 3, 4], + [0, 1, 3, 4], + [0, 1, 2, 4], + [0, 1, 2, 3] + ] + expect(kosajaru(input)).toStrictEqual([[0, 1, 2, 3, 4]]) + }) + + it('should return sccs', () => { + const input = [[1], [2], [0, 3], [4], []] + expect(kosajaru(input)).toStrictEqual([[0, 2, 1], [3], [4]]) + }) + + it('should return sccs', () => { + const input = [ + [1], + [2], + [0, 3, 4], + [0], + [5], + [6, 7], + [2, 4], + [8], + [5, 9], + [5] + ] + const expected = [[0, 2, 1, 6, 5, 4, 8, 7, 9, 3]] + expect(kosajaru(input)).toStrictEqual(expected) + }) + + it('should return sccs', () => { + const input = [[1], [0, 2], [0, 3], [4], [5, 7], [6], [4, 7], []] + const expected = [[0, 1, 2], [3], [4, 6, 5], [7]] + expect(kosajaru(input)).toStrictEqual(expected) + }) }) - diff --git a/graph/test/kruskal.test.ts b/graph/test/kruskal.test.ts index f5490931..bb7207e2 100644 --- a/graph/test/kruskal.test.ts +++ b/graph/test/kruskal.test.ts @@ -1,49 +1,55 @@ -import { Edge, kruskal } from "../kruskal"; - -const test_graph = (expected_tree_edges: Edge[], other_edges: Edge[], num_vertices: number, expected_cost: number) => { - const [tree_edges, cost] = kruskal(expected_tree_edges.concat(other_edges), num_vertices); - expect(cost).toStrictEqual(expected_cost); +import { Edge, kruskal } from '../kruskal' + +const test_graph = ( + expected_tree_edges: Edge[], + other_edges: Edge[], + num_vertices: number, + expected_cost: number +) => { + const [tree_edges, cost] = kruskal( + expected_tree_edges.concat(other_edges), + num_vertices + ) + expect(cost).toStrictEqual(expected_cost) for (const expected_edge of expected_tree_edges) { - expect(tree_edges.includes(expected_edge)).toBeTruthy(); + expect(tree_edges.includes(expected_edge)).toBeTruthy() } for (const unexpected_edge of other_edges) { - expect(tree_edges.includes(unexpected_edge)).toBeFalsy(); + expect(tree_edges.includes(unexpected_edge)).toBeFalsy() } -}; - - -describe("kruskal", () => { +} - it("should return empty tree for empty graph", () => { - expect(kruskal([], 0)).toStrictEqual([[], 0]); - }); +describe('kruskal', () => { + it('should return empty tree for empty graph', () => { + expect(kruskal([], 0)).toStrictEqual([[], 0]) + }) - it("should return empty tree for single element graph", () => { - expect(kruskal([], 1)).toStrictEqual([[], 0]); - }); + it('should return empty tree for single element graph', () => { + expect(kruskal([], 1)).toStrictEqual([[], 0]) + }) - it("should return correct value for two element graph", () => { - const edge = new Edge(0, 1, 5); - expect(kruskal([edge], 2)).toStrictEqual([[edge], 5]); - }); + it('should return correct value for two element graph', () => { + const edge = new Edge(0, 1, 5) + expect(kruskal([edge], 2)).toStrictEqual([[edge], 5]) + }) - it("should return the correct value", () => { + it('should return the correct value', () => { const expected_tree_edges = [ new Edge(0, 1, 1), new Edge(1, 3, 2), - new Edge(2, 3, 3), - ]; + new Edge(2, 3, 3) + ] const other_edges = [ new Edge(0, 2, 4), new Edge(0, 3, 5), - new Edge(1, 2, 6), - ]; + new Edge(1, 2, 6) + ] - test_graph(expected_tree_edges, other_edges, 7, 6); - }); + test_graph(expected_tree_edges, other_edges, 7, 6) + }) - it("should return the correct value", () => { + it('should return the correct value', () => { const expected_tree_edges = [ new Edge(0, 2, 2), new Edge(1, 3, 9), @@ -53,27 +59,26 @@ describe("kruskal", () => { new Edge(4, 9, 9), new Edge(5, 7, 5), new Edge(7, 9, 4), - new Edge(8, 9, 2), + new Edge(8, 9, 2) ] const other_edges = [ new Edge(0, 1, 10), new Edge(2, 4, 47), - new Edge(4, 5, 42), - ]; - - test_graph(expected_tree_edges, other_edges, 10, 116); - }); + new Edge(4, 5, 42) + ] + test_graph(expected_tree_edges, other_edges, 10, 116) + }) }) -describe("kruskal forest", () => { - it("should return empty tree for forest of 2 node trees", () => { - const edges = [new Edge(0, 1, 10), new Edge(2, 3, 15)]; - test_graph(edges, [], 4, 25); - }); +describe('kruskal forest', () => { + it('should return empty tree for forest of 2 node trees', () => { + const edges = [new Edge(0, 1, 10), new Edge(2, 3, 15)] + test_graph(edges, [], 4, 25) + }) - it("should return the correct value", () => { + it('should return the correct value', () => { const expected_tree_edges = [ // Tree 1 new Edge(0, 2, 2), @@ -89,7 +94,7 @@ describe("kruskal forest", () => { // Tree 2 new Edge(10, 11, 1), new Edge(11, 13, 2), - new Edge(12, 13, 3), + new Edge(12, 13, 3) ] const other_edges = [ @@ -101,9 +106,9 @@ describe("kruskal forest", () => { // Tree 2 new Edge(10, 12, 4), new Edge(10, 13, 5), - new Edge(11, 12, 6), - ]; + new Edge(11, 12, 6) + ] - test_graph(expected_tree_edges, other_edges, 14, 122); - }); -}); + test_graph(expected_tree_edges, other_edges, 14, 122) + }) +}) diff --git a/graph/test/prim.test.ts b/graph/test/prim.test.ts index b9dac96c..2f476632 100644 --- a/graph/test/prim.test.ts +++ b/graph/test/prim.test.ts @@ -1,66 +1,76 @@ -import { Edge, prim } from "../prim"; +import { Edge, prim } from '../prim' const edge_equal = (x: Edge, y: Edge): boolean => { - return (x.a == y.a && x.b == y.b) || (x.a == y.b && x.b == y.a) && x.weight == y.weight; + return ( + (x.a == y.a && x.b == y.b) || + (x.a == y.b && x.b == y.a && x.weight == y.weight) + ) } -const test_graph = (expected_tree_edges: Edge[], other_edges: Edge[], num_vertices: number, expected_cost: number) => { +const test_graph = ( + expected_tree_edges: Edge[], + other_edges: Edge[], + num_vertices: number, + expected_cost: number +) => { // First make sure the graph is undirected - const graph: [number, number][][] = []; + const graph: [number, number][][] = [] for (let _ = 0; _ < num_vertices; ++_) { - graph.push([]); + graph.push([]) } for (const edge of expected_tree_edges) { - graph[edge.a].push([edge.b, edge.weight]); - graph[edge.b].push([edge.a, edge.weight]); + graph[edge.a].push([edge.b, edge.weight]) + graph[edge.b].push([edge.a, edge.weight]) } for (const edge of other_edges) { - graph[edge.a].push([edge.b, edge.weight]); - graph[edge.b].push([edge.a, edge.weight]); + graph[edge.a].push([edge.b, edge.weight]) + graph[edge.b].push([edge.a, edge.weight]) } - const [tree_edges, cost] = prim(graph); - expect(cost).toStrictEqual(expected_cost); + const [tree_edges, cost] = prim(graph) + expect(cost).toStrictEqual(expected_cost) for (const expected_edge of expected_tree_edges) { - expect(tree_edges.find(edge => edge_equal(edge, expected_edge))).toBeTruthy(); + expect( + tree_edges.find((edge) => edge_equal(edge, expected_edge)) + ).toBeTruthy() } for (const unexpected_edge of other_edges) { - expect(tree_edges.find(edge => edge_equal(edge, unexpected_edge))).toBeFalsy(); + expect( + tree_edges.find((edge) => edge_equal(edge, unexpected_edge)) + ).toBeFalsy() } -}; - - -describe("prim", () => { +} - it("should return empty tree for empty graph", () => { - expect(prim([])).toStrictEqual([[], 0]); - }); +describe('prim', () => { + it('should return empty tree for empty graph', () => { + expect(prim([])).toStrictEqual([[], 0]) + }) - it("should return empty tree for single element graph", () => { - expect(prim([])).toStrictEqual([[], 0]); - }); + it('should return empty tree for single element graph', () => { + expect(prim([])).toStrictEqual([[], 0]) + }) - it("should return correct value for two element graph", () => { - expect(prim([[[1, 5]], []])).toStrictEqual([[new Edge(0, 1, 5)], 5]); - }); + it('should return correct value for two element graph', () => { + expect(prim([[[1, 5]], []])).toStrictEqual([[new Edge(0, 1, 5)], 5]) + }) - it("should return the correct value", () => { + it('should return the correct value', () => { const expected_tree_edges = [ new Edge(0, 1, 1), new Edge(1, 3, 2), - new Edge(3, 2, 3), - ]; + new Edge(3, 2, 3) + ] const other_edges = [ new Edge(0, 2, 4), new Edge(0, 3, 5), - new Edge(1, 2, 6), - ]; + new Edge(1, 2, 6) + ] - test_graph(expected_tree_edges, other_edges, 4, 6); - }); + test_graph(expected_tree_edges, other_edges, 4, 6) + }) - it("should return the correct value", () => { + it('should return the correct value', () => { const expected_tree_edges = [ new Edge(0, 2, 2), new Edge(1, 3, 9), @@ -70,16 +80,15 @@ describe("prim", () => { new Edge(4, 9, 9), new Edge(5, 7, 5), new Edge(7, 9, 4), - new Edge(8, 9, 2), + new Edge(8, 9, 2) ] const other_edges = [ new Edge(0, 1, 10), new Edge(2, 4, 47), - new Edge(4, 5, 42), - ]; - - test_graph(expected_tree_edges, other_edges, 10, 116); - }); + new Edge(4, 5, 42) + ] + test_graph(expected_tree_edges, other_edges, 10, 116) + }) }) diff --git a/graph/test/tarjan.test.ts b/graph/test/tarjan.test.ts index f2eca081..6ccbcb92 100644 --- a/graph/test/tarjan.test.ts +++ b/graph/test/tarjan.test.ts @@ -1,78 +1,100 @@ -import { tarjan } from "../tarjan"; - -describe("tarjan", () => { - - it("it should return no sccs for empty graph", () => { - expect(tarjan([])).toStrictEqual([]); - }); - - it("it should return one scc for graph with one element", () => { - expect(tarjan([[]])).toStrictEqual([[0]]); - }); - - it("it should return one scc for graph with element that points to itself", () => { - expect(tarjan([[0]])).toStrictEqual([[0]]); - }); - - it("it should return one scc for two element graph with cycle", () => { - expect(tarjan([[1], [0]])).toStrictEqual([[1, 0]]); - }); - - it("should return one scc for each element for straight line", () => { - expect(tarjan([[1], [2], [3], []])).toStrictEqual([[3], [2], [1], [0]]); - }); - - it("should return sccs for straight line with backedge in middle", () => { - expect(tarjan([[1], [2], [3, 0], []])).toStrictEqual([[3], [2, 1, 0]]); - }); - - it("should return sccs for straight line with backedge from end to middle", () => { - expect(tarjan([[1], [2], [3], [1]])).toStrictEqual([[3, 2, 1], [0]]); - }); - - it("should return scc for each element for graph with no edges", () => { - expect(tarjan([[], [], [], []])).toStrictEqual([[0], [1], [2], [3]]); - }); - - it("should return sccs disconnected graph", () => { - expect(tarjan([[1, 2], [0, 2], [0, 1], []])).toStrictEqual([[2, 1, 0], [3]]); - }); - - it("should return sccs disconnected graph", () => { - expect(tarjan([[1, 2], [0, 2], [0, 1], [4], [5], [3]])).toStrictEqual([[2, 1, 0], [5, 4, 3]]); - }); - - it("should return single scc", () => { - expect(tarjan([[1], [2], [3], [0, 4], [3]])).toStrictEqual([[4, 3, 2, 1, 0]]); - }); - - it("should return one scc for complete connected graph", () => { - const input = [[1, 2, 3, 4], [0, 2, 3, 4], [0, 1, 3, 4], [0, 1, 2, 4], [0, 1, 2, 3]]; - expect(tarjan(input)).toStrictEqual([[4, 3, 2, 1, 0]]); - }); - - it("should return sccs", () => { - const input = [[1], [2], [0, 3], [4], []]; - expect(tarjan(input)).toStrictEqual([[4], [3], [2, 1, 0]]); - }); - - it("should return sccs", () => { - const input = [[1], [2], [0, 3, 4], [0], [5], [6, 7], [2, 4], [8], [5, 9], [5]]; - const expected = [[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]]; - expect(tarjan(input)).toStrictEqual(expected); - }); - - it("should return sccs", () => { - const input = [[1], [0, 2], [0, 3], [4], [5, 7], [6], [4, 7], []]; - const expected = [[7], [6, 5, 4], [3], [2, 1, 0]]; - expect(tarjan(input)).toStrictEqual(expected); - }); - - it("should return sccs where first scc cannot reach second scc", () => { - const input = [[1], [2], [0], [4], [5], [2, 3]]; - const expected = [[2, 1, 0], [5, 4, 3]]; - expect(tarjan(input)).toStrictEqual(expected); - }); - +import { tarjan } from '../tarjan' + +describe('tarjan', () => { + it('it should return no sccs for empty graph', () => { + expect(tarjan([])).toStrictEqual([]) + }) + + it('it should return one scc for graph with one element', () => { + expect(tarjan([[]])).toStrictEqual([[0]]) + }) + + it('it should return one scc for graph with element that points to itself', () => { + expect(tarjan([[0]])).toStrictEqual([[0]]) + }) + + it('it should return one scc for two element graph with cycle', () => { + expect(tarjan([[1], [0]])).toStrictEqual([[1, 0]]) + }) + + it('should return one scc for each element for straight line', () => { + expect(tarjan([[1], [2], [3], []])).toStrictEqual([[3], [2], [1], [0]]) + }) + + it('should return sccs for straight line with backedge in middle', () => { + expect(tarjan([[1], [2], [3, 0], []])).toStrictEqual([[3], [2, 1, 0]]) + }) + + it('should return sccs for straight line with backedge from end to middle', () => { + expect(tarjan([[1], [2], [3], [1]])).toStrictEqual([[3, 2, 1], [0]]) + }) + + it('should return scc for each element for graph with no edges', () => { + expect(tarjan([[], [], [], []])).toStrictEqual([[0], [1], [2], [3]]) + }) + + it('should return sccs disconnected graph', () => { + expect(tarjan([[1, 2], [0, 2], [0, 1], []])).toStrictEqual([[2, 1, 0], [3]]) + }) + + it('should return sccs disconnected graph', () => { + expect(tarjan([[1, 2], [0, 2], [0, 1], [4], [5], [3]])).toStrictEqual([ + [2, 1, 0], + [5, 4, 3] + ]) + }) + + it('should return single scc', () => { + expect(tarjan([[1], [2], [3], [0, 4], [3]])).toStrictEqual([ + [4, 3, 2, 1, 0] + ]) + }) + + it('should return one scc for complete connected graph', () => { + const input = [ + [1, 2, 3, 4], + [0, 2, 3, 4], + [0, 1, 3, 4], + [0, 1, 2, 4], + [0, 1, 2, 3] + ] + expect(tarjan(input)).toStrictEqual([[4, 3, 2, 1, 0]]) + }) + + it('should return sccs', () => { + const input = [[1], [2], [0, 3], [4], []] + expect(tarjan(input)).toStrictEqual([[4], [3], [2, 1, 0]]) + }) + + it('should return sccs', () => { + const input = [ + [1], + [2], + [0, 3, 4], + [0], + [5], + [6, 7], + [2, 4], + [8], + [5, 9], + [5] + ] + const expected = [[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]] + expect(tarjan(input)).toStrictEqual(expected) + }) + + it('should return sccs', () => { + const input = [[1], [0, 2], [0, 3], [4], [5, 7], [6], [4, 7], []] + const expected = [[7], [6, 5, 4], [3], [2, 1, 0]] + expect(tarjan(input)).toStrictEqual(expected) + }) + + it('should return sccs where first scc cannot reach second scc', () => { + const input = [[1], [2], [0], [4], [5], [2, 3]] + const expected = [ + [2, 1, 0], + [5, 4, 3] + ] + expect(tarjan(input)).toStrictEqual(expected) + }) }) - diff --git a/jest.config.ts b/jest.config.ts index b4517396..bb992001 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,9 +1,9 @@ -import type { Config } from "@jest/types"; +import type { Config } from '@jest/types' // Sync object const config: Config.InitialOptions = { verbose: true, transform: { - "^.+\\.tsx?$": "ts-jest", - }, -}; -export default config; + '^.+\\.tsx?$': 'ts-jest' + } +} +export default config diff --git a/maths/absolute_value.ts b/maths/absolute_value.ts index a9c7f88f..3ae45574 100644 --- a/maths/absolute_value.ts +++ b/maths/absolute_value.ts @@ -12,5 +12,5 @@ export const absoluteValue = (number: number): number => { // if input number is less than 0, convert it to positive via double negation // e.g. if n = -2, then return -(-2) = 2 - return number < 0 ? -number : number; -}; + return number < 0 ? -number : number +} diff --git a/maths/aliquot_sum.ts b/maths/aliquot_sum.ts index aac91846..0cfeb1db 100644 --- a/maths/aliquot_sum.ts +++ b/maths/aliquot_sum.ts @@ -20,8 +20,8 @@ export const aliquotSum = (num: number): number => { let sum = 0 for (let i = 1; i <= num / 2; i++) { - if (num % i === 0) sum += i; + if (num % i === 0) sum += i } return sum -} \ No newline at end of file +} diff --git a/maths/armstrong_number.ts b/maths/armstrong_number.ts index d8452ed6..9f47a26c 100644 --- a/maths/armstrong_number.ts +++ b/maths/armstrong_number.ts @@ -1,4 +1,4 @@ -/** +/** * @function armstrongNumber * @description Check if the provided number is an Armstrong number or not. * @summary Armstrong numbers are numbers, the sum of whose digits each raised @@ -14,7 +14,7 @@ * @example armstrongNumber(10) = false */ export const armstrongNumber = (num: number): boolean => { - if (typeof num !== 'number' || num <= 0) return false; + if (typeof num !== 'number' || num <= 0) return false let compNum = 0 let cloneNum = num diff --git a/maths/binomial_coefficient.ts b/maths/binomial_coefficient.ts index 9ba1572a..b2bca7ec 100644 --- a/maths/binomial_coefficient.ts +++ b/maths/binomial_coefficient.ts @@ -1,4 +1,4 @@ -import { factorial } from "./factorial"; +import { factorial } from './factorial' /** * @function binomialCoefficient * @description Calculate the binomial coefficient (n choose k) of two input numbers. @@ -12,13 +12,13 @@ import { factorial } from "./factorial"; */ export const binomialCoefficient = (n: number, k: number): number => { - // Check if k is larger than n or negative - if (k > n || k < 0) { - return 0; - } + // Check if k is larger than n or negative + if (k > n || k < 0) { + return 0 + } - // Calculate the binomial coefficient using the implemented factorial - const numerator = factorial(n); - const denominator = factorial(k) * factorial(n - k); - return numerator / denominator; -}; + // Calculate the binomial coefficient using the implemented factorial + const numerator = factorial(n) + const denominator = factorial(k) * factorial(n - k) + return numerator / denominator +} diff --git a/maths/calculate_mean.ts b/maths/calculate_mean.ts index e52140cf..4230a680 100644 --- a/maths/calculate_mean.ts +++ b/maths/calculate_mean.ts @@ -10,12 +10,12 @@ export const calculateMean = (numbers: number[]): number => { if (numbers.length < 1) { - throw new TypeError("Invalid Input"); + throw new TypeError('Invalid Input') } // This loop sums all values in the 'numbers' array using an array reducer - const sum = numbers.reduce((sum, current) => sum + current, 0); + const sum = numbers.reduce((sum, current) => sum + current, 0) // Divide sum by the length of the 'numbers' array. - return sum / numbers.length; -}; + return sum / numbers.length +} diff --git a/maths/calculate_median.ts b/maths/calculate_median.ts index 27c8cac4..b32ec389 100644 --- a/maths/calculate_median.ts +++ b/maths/calculate_median.ts @@ -9,17 +9,17 @@ */ export const calculateMedian = (numbers: number[]): number => { - if (numbers.length < 1) { - throw new TypeError("Input array must contain at least one number."); - } + if (numbers.length < 1) { + throw new TypeError('Input array must contain at least one number.') + } - const totalNumbers = numbers.length; + const totalNumbers = numbers.length - if (totalNumbers % 2 === 0) { - const index = totalNumbers / 2; - return (numbers[index - 1] + numbers[index]) / 2; - } else { - const index = (totalNumbers + 1) / 2; - return numbers[index - 1]; - } -}; + if (totalNumbers % 2 === 0) { + const index = totalNumbers / 2 + return (numbers[index - 1] + numbers[index]) / 2 + } else { + const index = (totalNumbers + 1) / 2 + return numbers[index - 1] + } +} diff --git a/maths/degrees_to_radians.ts b/maths/degrees_to_radians.ts index 1a648173..1a3fca3f 100644 --- a/maths/degrees_to_radians.ts +++ b/maths/degrees_to_radians.ts @@ -1,11 +1,11 @@ -/** * A function to get radians from the degrees -* @param {number} degree - The input integer -* @return {number} radians of degrees -* @example degreesToRadians(45) => 0.7853 | degreesToRadians(90) => 1.5708 -* @see https://en.m.wikipedia.org/wiki/Radian -* @author MohdFaisalBidda  -*/ +/** * A function to get radians from the degrees + * @param {number} degree - The input integer + * @return {number} radians of degrees + * @example degreesToRadians(45) => 0.7853 | degreesToRadians(90) => 1.5708 + * @see https://en.m.wikipedia.org/wiki/Radian + * @author MohdFaisalBidda  + */ -export const degreesToRadians =(degrees:number):number =>{ - return degrees * Math.PI/180; -} \ No newline at end of file +export const degreesToRadians = (degrees: number): number => { + return (degrees * Math.PI) / 180 +} diff --git a/maths/digit_sum.ts b/maths/digit_sum.ts index 58a9f677..34be6730 100644 --- a/maths/digit_sum.ts +++ b/maths/digit_sum.ts @@ -10,14 +10,14 @@ export const digitSum = (num: number): number => { if (num < 0 || !Number.isInteger(num)) { - throw new Error("only natural numbers are supported"); + throw new Error('only natural numbers are supported') } - let sum = 0; + let sum = 0 while (num != 0) { - sum += num % 10; - num = Math.floor(num / 10); + sum += num % 10 + num = Math.floor(num / 10) } - return sum; -}; + return sum +} diff --git a/maths/double_factorial_iterative.ts b/maths/double_factorial_iterative.ts index 6044eca0..d9e043ec 100644 --- a/maths/double_factorial_iterative.ts +++ b/maths/double_factorial_iterative.ts @@ -1,14 +1,14 @@ /** * @function DoubleFactorialIterative * @description Calculate the double factorial of a number (iterative implementation) - * @summary In mathematics, double factorial of a number n is denoted by n!!. - * It is not to be confused with (n!)!, which is the factorial function iterated twice. + * @summary In mathematics, double factorial of a number n is denoted by n!!. + * It is not to be confused with (n!)!, which is the factorial function iterated twice. * The double factorial is the product of all positive integers upto n that have the same parity (odd or even) - * as n. - * Therefore, - * 9!! = 9 . 7 . 5 . 3 . 1 + * as n. + * Therefore, + * 9!! = 9 . 7 . 5 . 3 . 1 * 10!! = 10 . 8 . 6 . 4 . 2 - * + * * Please note that for factorials of even numbers, the series ends at 2. * @see [Wikipedia](https://en.wikipedia.org/wiki/Double_factorial) * @see [Mathworld](https://mathworld.wolfram.com/DoubleFactorial.html) @@ -17,11 +17,10 @@ * @example DoubleFactorialIterative(5) = 15 */ const DoubleFactorialIterative = (n: number) => { - if(n < 0) throw new RangeError("The number needs to be non-negative") + if (n < 0) throw new RangeError('The number needs to be non-negative') let doubleFactorial = 1 - for(let i = n; i > 0; i -= 2) - doubleFactorial *= i + for (let i = n; i > 0; i -= 2) doubleFactorial *= i return doubleFactorial } diff --git a/maths/euler_totient.ts b/maths/euler_totient.ts index 482281c4..29ccf432 100644 --- a/maths/euler_totient.ts +++ b/maths/euler_totient.ts @@ -7,14 +7,14 @@ * @example phi(5) = 4 */ export const phi = (n: number): number => { - let result: number = n; - for (let i = 2; i * i <= n; i++) { - if (n % i == 0) { - while (n % i == 0) n = n / i; - result -= Math.floor(result / i); - } + let result: number = n + for (let i = 2; i * i <= n; i++) { + if (n % i == 0) { + while (n % i == 0) n = n / i + result -= Math.floor(result / i) } - if (n > 1) result -= Math.floor(result / n); + } + if (n > 1) result -= Math.floor(result / n) - return result; -}; + return result +} diff --git a/maths/factorial.ts b/maths/factorial.ts index 0eb3e744..17dc348f 100644 --- a/maths/factorial.ts +++ b/maths/factorial.ts @@ -9,8 +9,8 @@ */ export const factorial = (num: number): number => { if (num < 0 || !Number.isInteger(num)) { - throw new Error("only natural numbers are supported"); + throw new Error('only natural numbers are supported') } - return num === 0 ? 1 : num * factorial(num - 1); -}; + return num === 0 ? 1 : num * factorial(num - 1) +} diff --git a/maths/factors.ts b/maths/factors.ts index f592ae2b..e2f77de9 100644 --- a/maths/factors.ts +++ b/maths/factors.ts @@ -9,20 +9,20 @@ * @example findFactors(16) = [1,3,5,15] */ export const findFactors = (num: number): Set => { - if (num <= 0 || !Number.isInteger(num)) { - throw new Error("Only natural numbers are supported."); - } + if (num <= 0 || !Number.isInteger(num)) { + throw new Error('Only natural numbers are supported.') + } - const res: Set = new Set(); - // Iterates from 1 to square root of num & pushes factors into the res set. - for (let i = 1; i * i <= num; i++) { - if (num % i === 0) { - res.add(i); + const res: Set = new Set() + // Iterates from 1 to square root of num & pushes factors into the res set. + for (let i = 1; i * i <= num; i++) { + if (num % i === 0) { + res.add(i) - const sqrtFactor = Math.floor(num / i); - res.add(sqrtFactor); - } + const sqrtFactor = Math.floor(num / i) + res.add(sqrtFactor) } + } - return res; -}; + return res +} diff --git a/maths/fibonacci.ts b/maths/fibonacci.ts index 4280a083..c1f6417d 100644 --- a/maths/fibonacci.ts +++ b/maths/fibonacci.ts @@ -11,31 +11,32 @@ * @author MohdFaisalBidda */ function* generateFibonacci(): Generator { - let a = 0; - let b = 1; + let a = 0 + let b = 1 while (true) { - yield a; - const c = a + b; - a = b; - b = c; + yield a + const c = a + b + a = b + b = c } } export const nthFibonacci = (number: number): number => { - if (isNaN(number)) throw new Error('The input needs to be a number'); - if (!Number.isInteger(number) || number < 0) throw new Error('The input needs to be a non-negative integer'); + if (isNaN(number)) throw new Error('The input needs to be a number') + if (!Number.isInteger(number) || number < 0) + throw new Error('The input needs to be a non-negative integer') if (number === 0) { - return 0; + return 0 } - - const fibonacciGenerator = generateFibonacci(); - let result = 0; + + const fibonacciGenerator = generateFibonacci() + let result = 0 for (let i = 0; i <= number; ++i) { - result = fibonacciGenerator.next().value; + result = fibonacciGenerator.next().value } - return result; -}; + return result +} /** * A function to get nth Fibonacci number recursively. **Note: This recursive approach increases the time complexity** @@ -51,18 +52,17 @@ export const nthFibonacci = (number: number): number => { */ export const nthFibonacciRecursively = (number: number): number => { if (number === 0) { - return 0; + return 0 } if (number <= 2) { - return 1; + return 1 } return ( nthFibonacciRecursively(number - 1) + nthFibonacciRecursively(number - 2) - ); -}; - + ) +} /** * @param number The index of the number in the Fibonacci sequence. @@ -76,4 +76,5 @@ const sqrt5 = Math.sqrt(5) const phi = (1 + sqrt5) / 2 const psi = (1 - sqrt5) / 2 -export const nthFibonacciUsingFormula = (n : number) => Math.round((phi ** n - psi ** n) / sqrt5) \ No newline at end of file +export const nthFibonacciUsingFormula = (n: number) => + Math.round((phi ** n - psi ** n) / sqrt5) diff --git a/maths/find_min.ts b/maths/find_min.ts index 26ea663a..b93182d7 100644 --- a/maths/find_min.ts +++ b/maths/find_min.ts @@ -9,17 +9,17 @@ * @example findMin([0.8,0.2,0.3,0.5]) = 0.2 * @example findMin([1,0.1,-1]) = -1 */ - export const findMin = (nums: number[]): number => { - if (nums.length === 0) { - throw new Error("array must have length of 1 or greater"); +export const findMin = (nums: number[]): number => { + if (nums.length === 0) { + throw new Error('array must have length of 1 or greater') + } + + let minimumSeen: number = nums[0] + for (const num of nums) { + if (num < minimumSeen) { + minimumSeen = num } - - let minimumSeen: number = nums[0]; - for (const num of nums) { - if (num < minimumSeen) { - minimumSeen = num; - } - } - - return minimumSeen; - }; \ No newline at end of file + } + + return minimumSeen +} diff --git a/maths/gaussian_elimination.ts b/maths/gaussian_elimination.ts index 660d4fbe..04e65a99 100644 --- a/maths/gaussian_elimination.ts +++ b/maths/gaussian_elimination.ts @@ -5,31 +5,31 @@ * @returns {number[]} An array representing the solutions to the equations. */ export function gaussianElimination(matrix: number[][]): number[] { - const result: number[] = new Array(matrix.length); + const result: number[] = new Array(matrix.length) function partialPivot(): void { for (let row = 0; row < matrix.length; row++) { - let pivotRow = row; + let pivotRow = row for (let column = row + 1; column < matrix.length; column++) { if (Math.abs(matrix[column][row]) > Math.abs(matrix[pivotRow][row])) { - pivotRow = column; + pivotRow = column } } if (pivotRow !== row) { for (let column = row; column <= matrix.length; column++) { - [matrix[row][column], matrix[pivotRow][column]] = [ + ;[matrix[row][column], matrix[pivotRow][column]] = [ matrix[pivotRow][column], - matrix[row][column], - ]; + matrix[row][column] + ] } } for (let column = row + 1; column < matrix.length; column++) { - const factor = matrix[column][row] / matrix[row][row]; + const factor = matrix[column][row] / matrix[row][row] for (let k = row; k <= matrix.length; k++) { - matrix[column][k] -= factor * matrix[row][k]; + matrix[column][k] -= factor * matrix[row][k] } } } @@ -37,16 +37,16 @@ export function gaussianElimination(matrix: number[][]): number[] { function backSubstitute(): void { for (let row = matrix.length - 1; row >= 0; row--) { - let sum = 0; + let sum = 0 for (let column = row + 1; column < matrix.length; column++) { - sum += matrix[row][column] * result[column]; + sum += matrix[row][column] * result[column] } - result[row] = (matrix[row][matrix.length] - sum) / matrix[row][row]; + result[row] = (matrix[row][matrix.length] - sum) / matrix[row][row] } } - partialPivot(); - backSubstitute(); + partialPivot() + backSubstitute() - return result; + return result } diff --git a/maths/greatest_common_factor.ts b/maths/greatest_common_factor.ts index 48afa1f3..21ef23cf 100644 --- a/maths/greatest_common_factor.ts +++ b/maths/greatest_common_factor.ts @@ -11,19 +11,19 @@ export const binaryGCF = (a: number, b: number): number => { if (!Number.isInteger(a) || !Number.isInteger(b) || a < 0 || b < 0) { - throw new Error("numbers must be natural to determine factors"); + throw new Error('numbers must be natural to determine factors') } while (b) { - [a, b] = [b, a % b] + ;[a, b] = [b, a % b] } - return a; + return a } export const greatestCommonFactor = (nums: number[]): number => { if (nums.length === 0) { - throw new Error("at least one number must be passed in"); + throw new Error('at least one number must be passed in') } - - return nums.reduce(binaryGCF); -}; \ No newline at end of file + + return nums.reduce(binaryGCF) +} diff --git a/maths/hamming_distance.ts b/maths/hamming_distance.ts index 2828dc52..9680e87c 100644 --- a/maths/hamming_distance.ts +++ b/maths/hamming_distance.ts @@ -13,7 +13,8 @@ * @example hammingDistance('happy', 'homie') */ const hammingDistance = (str1: string, str2: string) => { - if (str1.length !== str2.length) throw new Error('Strings must of the same length.') + if (str1.length !== str2.length) + throw new Error('Strings must of the same length.') let dist = 0 diff --git a/maths/is_divisible.ts b/maths/is_divisible.ts index 57f0bbe2..ce5018c7 100644 --- a/maths/is_divisible.ts +++ b/maths/is_divisible.ts @@ -9,8 +9,8 @@ */ export const isDivisible = (num1: number, num2: number): boolean => { - if (num2 === 0) { - throw new Error('Cannot divide by 0'); - } - return num1 % num2 === 0; -}; + if (num2 === 0) { + throw new Error('Cannot divide by 0') + } + return num1 % num2 === 0 +} diff --git a/maths/is_even.ts b/maths/is_even.ts index df8fbdd5..0281ecc7 100644 --- a/maths/is_even.ts +++ b/maths/is_even.ts @@ -7,10 +7,10 @@ * @example isEven(1) = false * @example isEven(2) = true */ - export const isEven = (num: number): boolean => { - if (!Number.isInteger(num)) { - throw new Error("only integers can be even or odd"); - } - - return num % 2 === 0; - }; \ No newline at end of file +export const isEven = (num: number): boolean => { + if (!Number.isInteger(num)) { + throw new Error('only integers can be even or odd') + } + + return num % 2 === 0 +} diff --git a/maths/is_leap_year.ts b/maths/is_leap_year.ts index 3aafbf04..cb9a0dc2 100644 --- a/maths/is_leap_year.ts +++ b/maths/is_leap_year.ts @@ -11,8 +11,8 @@ export const isLeapYear = (year: number): boolean => { if (year <= 0 || !Number.isInteger(year)) { - throw new Error("year must be a natural number > 0"); + throw new Error('year must be a natural number > 0') } - return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); -}; + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) +} diff --git a/maths/is_odd.ts b/maths/is_odd.ts index 529c7f5b..0948b8cb 100644 --- a/maths/is_odd.ts +++ b/maths/is_odd.ts @@ -7,10 +7,10 @@ * @example isOdd(1) = true * @example isOdd(2) = false */ - export const isOdd = (num: number): boolean => { - if (!Number.isInteger(num)) { - throw new Error("only integers can be even or odd"); - } - - return num % 2 !== 0; - }; \ No newline at end of file +export const isOdd = (num: number): boolean => { + if (!Number.isInteger(num)) { + throw new Error('only integers can be even or odd') + } + + return num % 2 !== 0 +} diff --git a/maths/is_palindrome.ts b/maths/is_palindrome.ts index c5ed9f07..ac62b412 100644 --- a/maths/is_palindrome.ts +++ b/maths/is_palindrome.ts @@ -7,15 +7,15 @@ * @return {boolean} Wether the number is a Palindrome or not. */ export const isPalindrome = (number: number): boolean => { - if (number < 0 || (number % 10 === 0 && number !== 0)) { - return false; - } + if (number < 0 || (number % 10 === 0 && number !== 0)) { + return false + } - let reversed: number = 0; - while (number > reversed) { - reversed = reversed * 10 + (number % 10); - number = Math.floor(number / 10); - } + let reversed: number = 0 + while (number > reversed) { + reversed = reversed * 10 + (number % 10) + number = Math.floor(number / 10) + } - return number === reversed || number === Math.floor(reversed / 10); -}; + return number === reversed || number === Math.floor(reversed / 10) +} diff --git a/maths/is_square_free.ts b/maths/is_square_free.ts index 79958a7a..b34b32a1 100644 --- a/maths/is_square_free.ts +++ b/maths/is_square_free.ts @@ -9,16 +9,15 @@ */ export const isSquareFree = (n: number): boolean => { + if (n < 0) throw new Error('number must be a natural number > 0') + if (n % 2 === 0) n = n / 2 + if (n % 2 === 0) return false - if (n < 0) throw new Error("number must be a natural number > 0"); - if (n % 2 === 0) n = n / 2; - if (n % 2 === 0) return false; - - for (let i: number = 3; i <= Math.sqrt(n); i = i + 2) { - if (n % i === 0) { - n = n / i; - if (n % i === 0) return false; - } + for (let i: number = 3; i <= Math.sqrt(n); i = i + 2) { + if (n % i === 0) { + n = n / i + if (n % i === 0) return false } - return true; -} \ No newline at end of file + } + return true +} diff --git a/maths/juggler_sequence.ts b/maths/juggler_sequence.ts index 6ddddd16..852ec7bf 100644 --- a/maths/juggler_sequence.ts +++ b/maths/juggler_sequence.ts @@ -14,10 +14,10 @@ * @see https://en.wikipedia.org/wiki/Juggler_sequence */ export const jugglerSequence = (a: number, n: number) => { - let k: number = a; + let k: number = a for (let i: number = 0; i < n; i++) { - k = Math.floor(Math.pow(k, (k % 2 === 0 ? 1 : 3) / 2)); + k = Math.floor(Math.pow(k, (k % 2 === 0 ? 1 : 3) / 2)) } - return k; -}; + return k +} diff --git a/maths/lowest_common_multiple.ts b/maths/lowest_common_multiple.ts index 95d266d3..a3ccecd0 100644 --- a/maths/lowest_common_multiple.ts +++ b/maths/lowest_common_multiple.ts @@ -9,27 +9,29 @@ * @example LowestCommonMultiple(5, 8, 3) = 120 */ -import { greatestCommonFactor } from "./greatest_common_factor"; +import { greatestCommonFactor } from './greatest_common_factor' //A naive solution which requires no additional mathematical algorithm export const naiveLCM = (nums: number[]): number => { if (nums.some((num) => num < 0)) { - throw new Error("numbers must be positive to determine lowest common multiple"); + throw new Error( + 'numbers must be positive to determine lowest common multiple' + ) } if (nums.length === 0) { - throw new Error("at least one number must be passed in"); + throw new Error('at least one number must be passed in') } - const max_num = Math.max(...nums); - let current_num = max_num; + const max_num = Math.max(...nums) + let current_num = max_num while (true) { - if (nums.every((num) => current_num % num === 0)){ - return current_num; + if (nums.every((num) => current_num % num === 0)) { + return current_num } else { - current_num += max_num; + current_num += max_num } } } @@ -38,13 +40,13 @@ export const naiveLCM = (nums: number[]): number => { //Note that due to utilizing GCF, which requires natural numbers, this method only accepts natural numbers. export const binaryLCM = (a: number, b: number): number => { - return a * b / greatestCommonFactor([a, b]); + return (a * b) / greatestCommonFactor([a, b]) } export const lowestCommonMultiple = (nums: number[]): number => { if (nums.length === 0) { - throw new Error("at least one number must be passed in"); + throw new Error('at least one number must be passed in') } - return nums.reduce(binaryLCM); -} \ No newline at end of file + return nums.reduce(binaryLCM) +} diff --git a/maths/matrix_multiplication.ts b/maths/matrix_multiplication.ts index 99a475f9..7eed4368 100644 --- a/maths/matrix_multiplication.ts +++ b/maths/matrix_multiplication.ts @@ -9,36 +9,43 @@ * @example GreatestCommonFactor([[1, 2], [3, 4]], [1, 2]) = [5, 11] */ -function matrixMultiplication(matA: number[][], b: number[][]): number[][]; -function matrixMultiplication(matA: number[][], b: number): number[][]; -function matrixMultiplication(matA: number[][], b: number[]): number[]; +function matrixMultiplication(matA: number[][], b: number[][]): number[][] +function matrixMultiplication(matA: number[][], b: number): number[][] +function matrixMultiplication(matA: number[][], b: number[]): number[] -function matrixMultiplication(matA: number[][], b: any): number[][] | number[] | null { - let matC: any = null; +function matrixMultiplication( + matA: number[][], + b: any +): number[][] | number[] | null { + let matC: any = null if (typeof b === 'number') { - matC = matA.map(row => row.map(colVal => colVal * b)); + matC = matA.map((row) => row.map((colVal) => colVal * b)) } else { if (matA[0].length !== b.length) { - return null; + return null } if (typeof b[0] === 'number') { - matC = matA.map(row => row.reduce((sum, colVal, i) => sum + colVal * b[i], 0)); + matC = matA.map((row) => + row.reduce((sum, colVal, i) => sum + colVal * b[i], 0) + ) } else { - matC = new Array(matA.length).fill(null).map(() => new Array(b[0].length).fill(0)); - let i: number, j: number, k: number; + matC = new Array(matA.length) + .fill(null) + .map(() => new Array(b[0].length).fill(0)) + let i: number, j: number, k: number for (i = 0; i < matA.length; i++) { for (j = 0; j < b[0].length; j++) { for (k = 0; k < matA[0].length; k++) { - matC[i][j] += matA[i][k] * b[k][j]; + matC[i][j] += matA[i][k] * b[k][j] } } } } } - return matC; + return matC } -export { matrixMultiplication }; +export { matrixMultiplication } diff --git a/maths/number_of_digits.ts b/maths/number_of_digits.ts index e517cfda..ef46d1c1 100644 --- a/maths/number_of_digits.ts +++ b/maths/number_of_digits.ts @@ -11,8 +11,8 @@ export const numberOfDigits = (num: number): number => { if (num <= 0 || !Number.isInteger(num)) { - throw new Error("only natural numbers are supported"); + throw new Error('only natural numbers are supported') } - return Math.floor(Math.log10(num)) + 1; -}; \ No newline at end of file + return Math.floor(Math.log10(num)) + 1 +} diff --git a/maths/pascals_triangle.ts b/maths/pascals_triangle.ts index 337c77c6..d3c5bb22 100644 --- a/maths/pascals_triangle.ts +++ b/maths/pascals_triangle.ts @@ -15,26 +15,26 @@ * @see https://en.wikipedia.org/wiki/Pascal's_triangle */ export const pascalsTriangle = (n: number): number[] => { - const arr: number[][] = []; + const arr: number[][] = [] for (let i: number = 0; i < n; i++) { if (i === 0) { - arr.push([1]); - continue; + arr.push([1]) + continue } - const lastRow: number[] = arr[i - 1]; - const temp: number[] = []; + const lastRow: number[] = arr[i - 1] + const temp: number[] = [] for (let j: number = 0; j < lastRow.length + 1; j++) { if (j === 0 || j === lastRow.length) { - temp.push(1); - continue; + temp.push(1) + continue } - temp.push(lastRow[j - 1] + lastRow[j]); + temp.push(lastRow[j - 1] + lastRow[j]) } - arr.push(temp); + arr.push(temp) } - return arr[arr.length - 1]; -}; + return arr[arr.length - 1] +} diff --git a/maths/perfect_cube.ts b/maths/perfect_cube.ts index 5f76b539..0aec6c09 100644 --- a/maths/perfect_cube.ts +++ b/maths/perfect_cube.ts @@ -5,5 +5,5 @@ */ export const perfectCube = (n: number): boolean => { - return Math.round(n ** (1 / 3)) ** 3 === n; -}; + return Math.round(n ** (1 / 3)) ** 3 === n +} diff --git a/maths/perfect_number.ts b/maths/perfect_number.ts index 9dec9024..8832ddac 100644 --- a/maths/perfect_number.ts +++ b/maths/perfect_number.ts @@ -9,19 +9,19 @@ */ export const isPerfectNumber = (n: number): boolean => { - if (n <= 0 || !Number.isInteger(n)) { - return false; - } - let sum = 1; - const sqrt = Math.sqrt(n); - for (let i = 2; i < sqrt; i++) { - if (n % i === 0) { - sum += i + n / i; - } - } - if (sqrt === Math.floor(sqrt)) { - sum += sqrt; + if (n <= 0 || !Number.isInteger(n)) { + return false + } + let sum = 1 + const sqrt = Math.sqrt(n) + for (let i = 2; i < sqrt; i++) { + if (n % i === 0) { + sum += i + n / i } + } + if (sqrt === Math.floor(sqrt)) { + sum += sqrt + } - return sum === n; -}; \ No newline at end of file + return sum === n +} diff --git a/maths/perfect_square.ts b/maths/perfect_square.ts index c7f6c279..22f0d594 100644 --- a/maths/perfect_square.ts +++ b/maths/perfect_square.ts @@ -7,5 +7,5 @@ */ export const perfectSquare = (num: number) => { - return Number.isInteger(Math.sqrt(num)); -}; + return Number.isInteger(Math.sqrt(num)) +} diff --git a/maths/prime_factorization.ts b/maths/prime_factorization.ts index 872422e1..34f76473 100644 --- a/maths/prime_factorization.ts +++ b/maths/prime_factorization.ts @@ -7,21 +7,21 @@ * @example factorize(5) = Map {5 => 1} */ export const factorize = (n: number): Map => { - const result: Map = new Map(); + const result: Map = new Map() - for (let i = 2; i * i <= n; i++) { - while (n % i == 0) { - let occurence = result.get(i); - if (!occurence) occurence = 0; - result.set(i, occurence + 1); - n = n / i; - } - } - if (n > 1) { - let occurence = result.get(n); - if (!occurence) occurence = 0; - result.set(n, occurence + 1); + for (let i = 2; i * i <= n; i++) { + while (n % i == 0) { + let occurence = result.get(i) + if (!occurence) occurence = 0 + result.set(i, occurence + 1) + n = n / i } + } + if (n > 1) { + let occurence = result.get(n) + if (!occurence) occurence = 0 + result.set(n, occurence + 1) + } - return result; -}; + return result +} diff --git a/maths/primes.ts b/maths/primes.ts index e6deab08..fb604700 100644 --- a/maths/primes.ts +++ b/maths/primes.ts @@ -8,25 +8,25 @@ */ export function sieveOfEratosthenes(limit: number): number[] { if (!Number.isInteger(limit) || limit <= 1) { - throw new Error("limit should be an integer greater than 1"); + throw new Error('limit should be an integer greater than 1') } - const maybePrime: boolean[] = new Array(limit + 1).fill(true); + const maybePrime: boolean[] = new Array(limit + 1).fill(true) for (let i = 2; i * i <= limit; i++) { - if (!maybePrime[i]) continue; + if (!maybePrime[i]) continue for (let j = i * i; j <= limit; j += i) { - maybePrime[j] = false; + maybePrime[j] = false } } - const primes: number[] = []; + const primes: number[] = [] for (let i = 2; i < maybePrime.length; i++) { if (maybePrime[i]) { - primes.push(i); + primes.push(i) } } - return primes; + return primes } /** @@ -35,26 +35,26 @@ export function sieveOfEratosthenes(limit: number): number[] { * Inspired by https://gist.github.com/e-nikolov/cd94db0de2a6b70da144124ae93a6458 */ export function* primeGenerator() { - type NumberGen = Generator; + type NumberGen = Generator function* filter(input: NumberGen, prime: number): NumberGen { while (true) { - const {done, value} = input.next(); - if (done) break; - if (value % prime !== 0) yield value; + const { done, value } = input.next() + if (done) break + if (value % prime !== 0) yield value } } let chain: NumberGen = (function* () { - let i = 2; - while (true) yield i++; - })(); + let i = 2 + while (true) yield i++ + })() while (true) { - const {done, value} = chain.next(); - if (done) break; - yield value; - chain = filter(chain, value); + const { done, value } = chain.next() + if (done) break + yield value + chain = filter(chain, value) } } @@ -70,18 +70,18 @@ export function* primeGenerator() { export const isPrime = (num: number): boolean => { // raise corresponding errors upon invalid inputs if (num <= 0 || !Number.isInteger(num)) { - throw new Error("only natural numbers are supported"); + throw new Error('only natural numbers are supported') } // handle input being 1 - if (num === 1) return false; + if (num === 1) return false // iterate from 2 to the square root of num to find a factor // return false upon finding a factor for (let i = 2; i <= Math.sqrt(num); i++) { - if (num % i === 0) return false; + if (num % i === 0) return false } // if the entire loop runs without finding a factor, return true - return true; -}; + return true +} diff --git a/maths/pronic_number.ts b/maths/pronic_number.ts index d3aa607d..9d95a4e5 100644 --- a/maths/pronic_number.ts +++ b/maths/pronic_number.ts @@ -4,7 +4,7 @@ * @summary Pronic numbers, or oblong numbers as they are often referred to as, * are numbers which are the product of two consecutive integers. That is, * they are numbers of the form n*(n+1) - * + * * For example, 20 is a pronic number since 20 = 4 * 5 * @param num The number to check for being pronic * @returns {boolean} Whether the number is pronic or not @@ -15,10 +15,14 @@ */ const pronicNumber = (n: number) => { if (isNaN(n)) throw new Error('The input needs to be a number') - if (!Number.isInteger(n) || n < 0) throw new Error('The input needs to be a non-negative integer') + if (!Number.isInteger(n) || n < 0) + throw new Error('The input needs to be a non-negative integer') if (n === 0) return true - return !Number.isInteger(Math.sqrt(n)) && Math.floor(Math.sqrt(n)) * Math.ceil(Math.sqrt(n)) === n + return ( + !Number.isInteger(Math.sqrt(n)) && + Math.floor(Math.sqrt(n)) * Math.ceil(Math.sqrt(n)) === n + ) } export { pronicNumber } diff --git a/maths/radians_to_degrees.ts b/maths/radians_to_degrees.ts index c7617f16..50ee2a70 100644 --- a/maths/radians_to_degrees.ts +++ b/maths/radians_to_degrees.ts @@ -1,11 +1,11 @@ -/** * A function to get degrees from the radians -* @param {number} radians - The input integer -* @return {number} degrees of radians -* @example radiansToDegrees(0.7853) => 45 | radiansTiDegrees(1.5708) => 90 -* @see https://en.m.wikipedia.org/wiki/Radian -* @author MohdFaisalBidda  -*/ +/** * A function to get degrees from the radians + * @param {number} radians - The input integer + * @return {number} degrees of radians + * @example radiansToDegrees(0.7853) => 45 | radiansTiDegrees(1.5708) => 90 + * @see https://en.m.wikipedia.org/wiki/Radian + * @author MohdFaisalBidda  + */ -export const radiansToDegrees =(radians:number):number =>{ - return radians * 180/Math.PI; -} \ No newline at end of file +export const radiansToDegrees = (radians: number): number => { + return (radians * 180) / Math.PI +} diff --git a/maths/series/hexagonal_numbers.ts b/maths/series/hexagonal_numbers.ts index d0856fc2..faa40f4f 100644 --- a/maths/series/hexagonal_numbers.ts +++ b/maths/series/hexagonal_numbers.ts @@ -4,7 +4,7 @@ * @summary A hexagonal number, hₙ, is a figurate number which represents the number * of distinct dots in a pattern of dots consisting of the outlines of regular * hexagons with sides upto 'n' dots, when the hexagons are overlaid so that they share a common vertex - * + * * The nth hexagonal number, hₙ, is calculated by the formula: * hₙ = n * (2n - 1) * @see [Wikipedia](https://en.wikipedia.org/wiki/Hexagonal_number) @@ -16,7 +16,8 @@ */ export const HexagonalNumbers = (n: number): number[] => { if (isNaN(n)) throw new Error('The input needs to be a number') - if (!Number.isInteger(n) || n < 0) throw new Error('The input needs to be a non-negative integer') + if (!Number.isInteger(n) || n < 0) + throw new Error('The input needs to be a non-negative integer') const hexagonalNumbers = [] for (let i = 1; i <= n; i++) { diff --git a/maths/series/test/hexagonal_numbers.test.ts b/maths/series/test/hexagonal_numbers.test.ts index f06467f9..fca4b289 100644 --- a/maths/series/test/hexagonal_numbers.test.ts +++ b/maths/series/test/hexagonal_numbers.test.ts @@ -1,15 +1,17 @@ -import { HexagonalNumbers } from "../hexagonal_numbers"; +import { HexagonalNumbers } from '../hexagonal_numbers' -describe("HexagonalNumbers", () => { - it("should return the first 10 hexagonal numbers", () => { - expect(HexagonalNumbers(10)).toStrictEqual([1, 6, 15, 28, 45, 66, 91, 120, 153, 190]); +describe('HexagonalNumbers', () => { + it('should return the first 10 hexagonal numbers', () => { + expect(HexagonalNumbers(10)).toStrictEqual([ + 1, 6, 15, 28, 45, 66, 91, 120, 153, 190 + ]) }) - it("should return the first 5 hexagonal numbers", () => { + it('should return the first 5 hexagonal numbers', () => { expect(HexagonalNumbers(5)).toStrictEqual([1, 6, 15, 28, 45]) }) - it("should return zero hexagonal numbers", () => { + it('should return zero hexagonal numbers', () => { expect(HexagonalNumbers(0)).toStrictEqual([]) }) }) diff --git a/maths/sieve_of_eratosthenes.ts b/maths/sieve_of_eratosthenes.ts index d7fe21db..b0ccce9a 100644 --- a/maths/sieve_of_eratosthenes.ts +++ b/maths/sieve_of_eratosthenes.ts @@ -1,27 +1,26 @@ /** * @function sieveOfEratosthenes - * @description Find the prime numbers between 2 and n + * @description Find the prime numbers between 2 and n * @param {number} n - numbers set the limit that the algorithm needs to look to find the primes * @return {number[]} - List of prime numbers * @see https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes\ - * @example sieveOfEratosthenes(5) = [2,3,5] + * @example sieveOfEratosthenes(5) = [2,3,5] * @example sieveOfEratosthenes(10) = [2,3,5,7] */ export function sieveOfEratosthenes(n: number): number[] { if (n < 0 || !Number.isInteger(n)) { - throw new Error("Only natural numbers are supported"); + throw new Error('Only natural numbers are supported') } - const numbers = new Array(n + 1) - .fill(true) - const primeNumbers: number[] = []; + const numbers = new Array(n + 1).fill(true) + const primeNumbers: number[] = [] for (let i = 2; i <= n; i++) { if (numbers[i]) { - primeNumbers.push(i); + primeNumbers.push(i) for (let j = i + i; j <= n; j += i) { - numbers[j] = false; + numbers[j] = false } } } - return primeNumbers; + return primeNumbers } diff --git a/maths/signum.ts b/maths/signum.ts index 259a61ba..934fe9fb 100644 --- a/maths/signum.ts +++ b/maths/signum.ts @@ -1,7 +1,7 @@ /** * @function signum * @description Returns the sign of a number - * @summary The signum function is an odd mathematical function, which returns the + * @summary The signum function is an odd mathematical function, which returns the * sign of the provided real number. * It can return 3 values: 1 for values greater than zero, 0 for zero itself, * and -1 for values less than zero diff --git a/maths/square_root.ts b/maths/square_root.ts index 04a8eda0..4528bd61 100644 --- a/maths/square_root.ts +++ b/maths/square_root.ts @@ -10,17 +10,17 @@ */ export const squareRoot = (num: number, precision: number = 1e-15): number => { - if (num < 0) throw new Error("number must be non-negative number"); - if (num === 0) return 0; + if (num < 0) throw new Error('number must be non-negative number') + if (num === 0) return 0 - let sqrt: number = num; - let curr: number; + let sqrt: number = num + let curr: number while (true) { - curr = 0.5 * (sqrt + num / sqrt); + curr = 0.5 * (sqrt + num / sqrt) if (Math.abs(curr - sqrt) < precision) { - return sqrt; + return sqrt } - sqrt = curr; + sqrt = curr } -}; +} diff --git a/maths/test/absolute_value.test.ts b/maths/test/absolute_value.test.ts index 534c0983..ce453139 100644 --- a/maths/test/absolute_value.test.ts +++ b/maths/test/absolute_value.test.ts @@ -1,28 +1,28 @@ -import { absoluteValue } from "../absolute_value"; +import { absoluteValue } from '../absolute_value' -describe("absoluteValue", () => { - it("should return the absolute value of zero", () => { - const absoluteValueOfZero = absoluteValue(0); - expect(absoluteValueOfZero).toBe(0); - }); +describe('absoluteValue', () => { + it('should return the absolute value of zero', () => { + const absoluteValueOfZero = absoluteValue(0) + expect(absoluteValueOfZero).toBe(0) + }) - it("should return the absolute value of a negative integer", () => { - const absoluteValueOfNegativeInteger = absoluteValue(-34); - expect(absoluteValueOfNegativeInteger).toBe(34); - }); + it('should return the absolute value of a negative integer', () => { + const absoluteValueOfNegativeInteger = absoluteValue(-34) + expect(absoluteValueOfNegativeInteger).toBe(34) + }) - it("should return the absolute value of a positive integer", () => { - const absoluteValueOfPositiveInteger = absoluteValue(50); - expect(absoluteValueOfPositiveInteger).toBe(50); - }); + it('should return the absolute value of a positive integer', () => { + const absoluteValueOfPositiveInteger = absoluteValue(50) + expect(absoluteValueOfPositiveInteger).toBe(50) + }) - it("should return the absolute value of a positive floating number", () => { - const absoluteValueOfPositiveFloating = absoluteValue(20.2034); - expect(absoluteValueOfPositiveFloating).toBe(20.2034); - }); + it('should return the absolute value of a positive floating number', () => { + const absoluteValueOfPositiveFloating = absoluteValue(20.2034) + expect(absoluteValueOfPositiveFloating).toBe(20.2034) + }) - it("should return the absolute value of a negative floating number", () => { - const absoluteValueOfNegativeFloating = absoluteValue(-20.2034); - expect(absoluteValueOfNegativeFloating).toBe(20.2034); - }); -}); + it('should return the absolute value of a negative floating number', () => { + const absoluteValueOfNegativeFloating = absoluteValue(-20.2034) + expect(absoluteValueOfNegativeFloating).toBe(20.2034) + }) +}) diff --git a/maths/test/aliquot_sum.test.ts b/maths/test/aliquot_sum.test.ts index b575cdc1..258b5f69 100644 --- a/maths/test/aliquot_sum.test.ts +++ b/maths/test/aliquot_sum.test.ts @@ -1,5 +1,13 @@ -import { aliquotSum } from "../aliquot_sum"; +import { aliquotSum } from '../aliquot_sum' -test.each([[15, 9], [18, 21], [28, 28], [100, 117], [169, 14], [1729, 511], [15625, 3906]])("Aliquot Sum of %i is %i", (num, expected) => { +test.each([ + [15, 9], + [18, 21], + [28, 28], + [100, 117], + [169, 14], + [1729, 511], + [15625, 3906] +])('Aliquot Sum of %i is %i', (num, expected) => { expect(aliquotSum(num)).toBe(expected) -}) \ No newline at end of file +}) diff --git a/maths/test/armstrong_number.test.ts b/maths/test/armstrong_number.test.ts index d35f28c3..2e958596 100644 --- a/maths/test/armstrong_number.test.ts +++ b/maths/test/armstrong_number.test.ts @@ -1,5 +1,13 @@ -import { armstrongNumber } from "../armstrong_number" +import { armstrongNumber } from '../armstrong_number' -test.each([[9, true], [-310, false], [0, false], [407, true], [420, false], [92727, true], [13579, false]])('i is an Armstrong number or not', (num, expected) => { +test.each([ + [9, true], + [-310, false], + [0, false], + [407, true], + [420, false], + [92727, true], + [13579, false] +])('i is an Armstrong number or not', (num, expected) => { expect(armstrongNumber(num)).toBe(expected) }) diff --git a/maths/test/binomial_coefficient.test.ts b/maths/test/binomial_coefficient.test.ts index 661566ff..ceb21529 100644 --- a/maths/test/binomial_coefficient.test.ts +++ b/maths/test/binomial_coefficient.test.ts @@ -1,34 +1,34 @@ -import { binomialCoefficient } from '../binomial_coefficient'; +import { binomialCoefficient } from '../binomial_coefficient' describe('binomialCoefficient', () => { - it('should calculate the correct binomial coefficient', () => { - // Test cases with expected results - const testCases: [number, number, number][] = [ - [5, 2, 10], - [10, 3, 120], - [6, 0, 1], - [4, 4, 1], - [7, 5, 21], - [10, 10, 1], - ]; + it('should calculate the correct binomial coefficient', () => { + // Test cases with expected results + const testCases: [number, number, number][] = [ + [5, 2, 10], + [10, 3, 120], + [6, 0, 1], + [4, 4, 1], + [7, 5, 21], + [10, 10, 1] + ] - // Iterate through each test case and verify the result - testCases.forEach(([n, k, expected]) => { - const result = binomialCoefficient(n, k); - expect(result).toEqual(expected); - }); - }); + // Iterate through each test case and verify the result + testCases.forEach(([n, k, expected]) => { + const result = binomialCoefficient(n, k) + expect(result).toEqual(expected) + }) + }) - it('should return 0 if k is larger than n or negative', () => { - const invalidCases: [number, number][] = [ - [5, 6], // k is larger than n - [10, -3], // k is negative - [5, 10], // k is larger than n - ]; + it('should return 0 if k is larger than n or negative', () => { + const invalidCases: [number, number][] = [ + [5, 6], // k is larger than n + [10, -3], // k is negative + [5, 10] // k is larger than n + ] - invalidCases.forEach(([n, k]) => { - const result = binomialCoefficient(n, k); - expect(result).toEqual(0); - }); - }); -}); + invalidCases.forEach(([n, k]) => { + const result = binomialCoefficient(n, k) + expect(result).toEqual(0) + }) + }) +}) diff --git a/maths/test/calculate_mean.test.ts b/maths/test/calculate_mean.test.ts index 36d7963e..4c1ce840 100644 --- a/maths/test/calculate_mean.test.ts +++ b/maths/test/calculate_mean.test.ts @@ -1,31 +1,31 @@ -import { calculateMean } from "../calculate_mean"; +import { calculateMean } from '../calculate_mean' -describe("Tests for AverageMean", () => { - it("should be a function", () => { - expect(typeof calculateMean).toEqual("function"); - }); +describe('Tests for AverageMean', () => { + it('should be a function', () => { + expect(typeof calculateMean).toEqual('function') + }) - it("should throw error for invalid input", () => { - expect(() => calculateMean([])).toThrow(); - }); + it('should throw error for invalid input', () => { + expect(() => calculateMean([])).toThrow() + }) - it("should return the mean of an array of consecutive numbers", () => { - const meanFunction = calculateMean([1, 2, 3, 4]); - expect(meanFunction).toBe(2.5); - }); + it('should return the mean of an array of consecutive numbers', () => { + const meanFunction = calculateMean([1, 2, 3, 4]) + expect(meanFunction).toBe(2.5) + }) - it("should return the mean of an array of numbers", () => { - const meanFunction = calculateMean([10, 40, 100, 20]); - expect(meanFunction).toBe(42.5); - }); + it('should return the mean of an array of numbers', () => { + const meanFunction = calculateMean([10, 40, 100, 20]) + expect(meanFunction).toBe(42.5) + }) - it("should return the mean of an array of decimal numbers", () => { - const meanFunction = calculateMean([1.3, 12.67, 99.14, 20]); - expect(meanFunction).toBe(33.2775); - }); + it('should return the mean of an array of decimal numbers', () => { + const meanFunction = calculateMean([1.3, 12.67, 99.14, 20]) + expect(meanFunction).toBe(33.2775) + }) - it("should return the mean of an array of numbers, including negatives", () => { - const meanFunction = calculateMean([10, -40, 100, -20]); - expect(meanFunction).toBe(12.5); - }); -}); + it('should return the mean of an array of numbers, including negatives', () => { + const meanFunction = calculateMean([10, -40, 100, -20]) + expect(meanFunction).toBe(12.5) + }) +}) diff --git a/maths/test/calculate_median.test.ts b/maths/test/calculate_median.test.ts index b9aa345e..4fd3e0e9 100644 --- a/maths/test/calculate_median.test.ts +++ b/maths/test/calculate_median.test.ts @@ -1,23 +1,23 @@ -import { calculateMedian } from "../calculate_median"; +import { calculateMedian } from '../calculate_median' -describe("Tests for CalculateMedian", () => { - it("should be a function", () => { - expect(typeof calculateMedian).toEqual("function"); - }); +describe('Tests for CalculateMedian', () => { + it('should be a function', () => { + expect(typeof calculateMedian).toEqual('function') + }) - it("should throw error for invalid input", () => { - expect(() => calculateMedian([])).toThrowError( - "Input array must contain at least one number." - ); - }); + it('should throw error for invalid input', () => { + expect(() => calculateMedian([])).toThrowError( + 'Input array must contain at least one number.' + ) + }) - it("should return the median of an array of numbers - even length", () => { - const medianFunction = calculateMedian([1, 2, 3, 4]); - expect(medianFunction).toBe(2.5); - }); + it('should return the median of an array of numbers - even length', () => { + const medianFunction = calculateMedian([1, 2, 3, 4]) + expect(medianFunction).toBe(2.5) + }) - it("should return the median of an array of numbers - odd length", () => { - const medianFunction = calculateMedian([1, 2, 3, 4, 6, 8, 9]); - expect(medianFunction).toBe(4); - }); -}); + it('should return the median of an array of numbers - odd length', () => { + const medianFunction = calculateMedian([1, 2, 3, 4, 6, 8, 9]) + expect(medianFunction).toBe(4) + }) +}) diff --git a/maths/test/degrees_to_radians.test.ts b/maths/test/degrees_to_radians.test.ts index ac472b69..b891e603 100644 --- a/maths/test/degrees_to_radians.test.ts +++ b/maths/test/degrees_to_radians.test.ts @@ -1,7 +1,7 @@ -import {degreesToRadians} from '../degrees_to_radians'; - - test("DegreesToRadians", () => { - expect(degreesToRadians(0)).toBe(0); - expect(degreesToRadians(45)).toBe(0.7853981633974483); - expect(degreesToRadians(90)).toBe(1.5707963267948966); -}); \ No newline at end of file +import { degreesToRadians } from '../degrees_to_radians' + +test('DegreesToRadians', () => { + expect(degreesToRadians(0)).toBe(0) + expect(degreesToRadians(45)).toBe(0.7853981633974483) + expect(degreesToRadians(90)).toBe(1.5707963267948966) +}) diff --git a/maths/test/digit_sum.test.ts b/maths/test/digit_sum.test.ts index efb4a207..49574acf 100644 --- a/maths/test/digit_sum.test.ts +++ b/maths/test/digit_sum.test.ts @@ -1,19 +1,23 @@ -import { digitSum } from "../digit_sum"; +import { digitSum } from '../digit_sum' -describe("digitSum", () => { +describe('digitSum', () => { test.each([-42, -0.1, -1, 0.2, 3.3, NaN, -Infinity, Infinity])( - "should throw an error for non natural number %d", + 'should throw an error for non natural number %d', (num) => { expect(() => digitSum(num)).toThrowError( - "only natural numbers are supported", - ); - }, - ); + 'only natural numbers are supported' + ) + } + ) - test.each([[0,0], [1, 1], [12, 3], [123, 6], [9045, 18], [1234567890, 45]])( - "of %i should be %i", - (num, expected) => { - expect(digitSum(num)).toBe(expected); - }, - ); -}); + test.each([ + [0, 0], + [1, 1], + [12, 3], + [123, 6], + [9045, 18], + [1234567890, 45] + ])('of %i should be %i', (num, expected) => { + expect(digitSum(num)).toBe(expected) + }) +}) diff --git a/maths/test/double_factorial_iterative.test.ts b/maths/test/double_factorial_iterative.test.ts index 3c221785..0fb1106b 100644 --- a/maths/test/double_factorial_iterative.test.ts +++ b/maths/test/double_factorial_iterative.test.ts @@ -1,7 +1,11 @@ -import { DoubleFactorialIterative } from "../double_factorial_iterative"; +import { DoubleFactorialIterative } from '../double_factorial_iterative' -describe("Double Factorial", () => { - test.each([[4, 8], [5, 15], [10, 3840]])("%i!! = %i", (n, expected) => { - expect(DoubleFactorialIterative(n)).toBe(expected) - }) -}) \ No newline at end of file +describe('Double Factorial', () => { + test.each([ + [4, 8], + [5, 15], + [10, 3840] + ])('%i!! = %i', (n, expected) => { + expect(DoubleFactorialIterative(n)).toBe(expected) + }) +}) diff --git a/maths/test/euler_totient.test.ts b/maths/test/euler_totient.test.ts index 4d1ec6b7..1e32ac9e 100644 --- a/maths/test/euler_totient.test.ts +++ b/maths/test/euler_totient.test.ts @@ -1,24 +1,19 @@ -import { phi } from "../euler_totient"; - +import { phi } from '../euler_totient' const cases: [number, number][] = [ - [4, 2], - [5, 4], - [7, 6], - [10, 4], - [999, 648], - [1000, 400], - [1000000, 400000], - [999999, 466560], - [999999999999878, 473684210526240], -]; - -describe("phi", () => { + [4, 2], + [5, 4], + [7, 6], + [10, 4], + [999, 648], + [1000, 400], + [1000000, 400000], + [999999, 466560], + [999999999999878, 473684210526240] +] - test.each(cases)( - "phi of %i should be %i", - (num, expected) => { - expect(phi(num)).toBe(expected); - }, - ); -}); +describe('phi', () => { + test.each(cases)('phi of %i should be %i', (num, expected) => { + expect(phi(num)).toBe(expected) + }) +}) diff --git a/maths/test/factorial.test.ts b/maths/test/factorial.test.ts index f53b415c..53b1485f 100644 --- a/maths/test/factorial.test.ts +++ b/maths/test/factorial.test.ts @@ -1,23 +1,25 @@ -import { factorial } from "../factorial"; +import { factorial } from '../factorial' -describe("factorial", () => { +describe('factorial', () => { test.each([-0.1, -1, -2, -42, 0.01, 0.42, 0.5, 1.337])( - "should throw an error for non natural number %d", + 'should throw an error for non natural number %d', (num) => { expect(() => factorial(num)).toThrowError( - "only natural numbers are supported", - ); - }, - ); + 'only natural numbers are supported' + ) + } + ) - test.each([[1, 1], [3, 6], [5, 120], [10, 3628800]])( - "of %i should be %i", - (num, expected) => { - expect(factorial(num)).toBe(expected); - }, - ); + test.each([ + [1, 1], + [3, 6], + [5, 120], + [10, 3628800] + ])('of %i should be %i', (num, expected) => { + expect(factorial(num)).toBe(expected) + }) - test("of 1 should be 0 by definition", () => { - expect(factorial(0)).toBe(1); - }); -}); + test('of 1 should be 0 by definition', () => { + expect(factorial(0)).toBe(1) + }) +}) diff --git a/maths/test/factors.test.ts b/maths/test/factors.test.ts index 3d560851..42ad9baf 100644 --- a/maths/test/factors.test.ts +++ b/maths/test/factors.test.ts @@ -1,25 +1,22 @@ -import { findFactors } from "../factors"; +import { findFactors } from '../factors' -describe("findFactors", () => { - test.each([-890, -5.56, -7, 0, 0.73, 4.2, NaN, -Infinity, Infinity])( - "should throw an error for non natural number %d", - (num) => { - expect(() => findFactors(num)).toThrowError( - "Only natural numbers are supported." - ); - } - ); +describe('findFactors', () => { + test.each([-890, -5.56, -7, 0, 0.73, 4.2, NaN, -Infinity, Infinity])( + 'should throw an error for non natural number %d', + (num) => { + expect(() => findFactors(num)).toThrowError( + 'Only natural numbers are supported.' + ) + } + ) - test.each([ - [1, new Set([1])], - [2, new Set([1, 2])], - [4, new Set([1, 2, 4])], - [6, new Set([1, 2, 3, 6])], - [16, new Set([1, 2, 4, 8, 16])], - ])( - "of %i should return the correct set of its factors", - (num, expected) => { - expect(findFactors(num)).toStrictEqual(expected); - } - ); -}); + test.each([ + [1, new Set([1])], + [2, new Set([1, 2])], + [4, new Set([1, 2, 4])], + [6, new Set([1, 2, 3, 6])], + [16, new Set([1, 2, 4, 8, 16])] + ])('of %i should return the correct set of its factors', (num, expected) => { + expect(findFactors(num)).toStrictEqual(expected) + }) +}) diff --git a/maths/test/fibonacci.test.ts b/maths/test/fibonacci.test.ts index 9d48d2a4..4496a830 100644 --- a/maths/test/fibonacci.test.ts +++ b/maths/test/fibonacci.test.ts @@ -1,4 +1,8 @@ -import { nthFibonacciUsingFormula, nthFibonacci, nthFibonacciRecursively } from '../fibonacci'; +import { + nthFibonacciUsingFormula, + nthFibonacci, + nthFibonacciRecursively +} from '../fibonacci' const test = (func: (n: number) => number) => it.each([ @@ -7,8 +11,8 @@ const test = (func: (n: number) => number) => [2, 1], [5, 5], [10, 55], - [15, 610], - ])('fib(%i) = %i', (n, expected) => expect(func(n)).toBe(expected)); -describe('Fibonacci iterative', () => test(nthFibonacci)); -describe('Fibonacci recursive', () => test(nthFibonacciRecursively)); -describe('Fibonacci Using formula', () => test(nthFibonacciUsingFormula)); + [15, 610] + ])('fib(%i) = %i', (n, expected) => expect(func(n)).toBe(expected)) +describe('Fibonacci iterative', () => test(nthFibonacci)) +describe('Fibonacci recursive', () => test(nthFibonacciRecursively)) +describe('Fibonacci Using formula', () => test(nthFibonacciUsingFormula)) diff --git a/maths/test/find_min.test.ts b/maths/test/find_min.test.ts index e7b1d32d..70200be3 100644 --- a/maths/test/find_min.test.ts +++ b/maths/test/find_min.test.ts @@ -1,16 +1,18 @@ -import { findMin } from "../find_min"; +import { findMin } from '../find_min' -describe("findMin", () => { - test.each([[[1,2,3,4,5,6], 1], [[87,6,13,999], 6], [[0.8,0.2,0.3,0.5], 0.2], [[1,0.1,-1], -1]])( - "of this array should be %i", - (nums, expected) => { - expect(findMin(nums)).toBe(expected); - }, - ); +describe('findMin', () => { + test.each([ + [[1, 2, 3, 4, 5, 6], 1], + [[87, 6, 13, 999], 6], + [[0.8, 0.2, 0.3, 0.5], 0.2], + [[1, 0.1, -1], -1] + ])('of this array should be %i', (nums, expected) => { + expect(findMin(nums)).toBe(expected) + }) - test("of arrays with length 0 should error", () => { + test('of arrays with length 0 should error', () => { expect(() => findMin([])).toThrowError( - "array must have length of 1 or greater", - ); - }); -}); \ No newline at end of file + 'array must have length of 1 or greater' + ) + }) +}) diff --git a/maths/test/gaussian_elimination.test.ts b/maths/test/gaussian_elimination.test.ts index b428d196..6e53428d 100644 --- a/maths/test/gaussian_elimination.test.ts +++ b/maths/test/gaussian_elimination.test.ts @@ -1,41 +1,41 @@ -import { gaussianElimination } from "../gaussian_elimination"; +import { gaussianElimination } from '../gaussian_elimination' -describe("gaussianElimination", () => { - it("should solve system of linear equations", () => { +describe('gaussianElimination', () => { + it('should solve system of linear equations', () => { const A: number[][] = [ [3.0, 2.0, -4.0, 3.0], [2.0, 3.0, 3.0, 15.0], - [5.0, -3, 1.0, 14.0], - ]; + [5.0, -3, 1.0, 14.0] + ] - let solution: number[] = gaussianElimination(A); - solution = solution.map((x) => Math.round(x)); + let solution: number[] = gaussianElimination(A) + solution = solution.map((x) => Math.round(x)) - expect(solution.map((x) => Math.round(x))).toEqual([3, 1, 2]); - }); + expect(solution.map((x) => Math.round(x))).toEqual([3, 1, 2]) + }) - it("should solve a 2x2 system of linear equations", () => { + it('should solve a 2x2 system of linear equations', () => { const A: number[][] = [ [2.0, 1.0, 5.0], - [1.0, -3.0, 6.0], - ]; + [1.0, -3.0, 6.0] + ] - let solution: number[] = gaussianElimination(A); - solution = solution.map((x) => Math.round(x)); + let solution: number[] = gaussianElimination(A) + solution = solution.map((x) => Math.round(x)) - expect(solution.map((x) => Math.round(x))).toEqual([3, -1]); - }); + expect(solution.map((x) => Math.round(x))).toEqual([3, -1]) + }) - it("should handle a system with no solution", () => { + it('should handle a system with no solution', () => { const A: number[][] = [ [1.0, 2.0, 3.0, 4.0], [2.0, 4.0, 6.0, 7.0], - [3.0, 6.0, 9.0, 10.0], - ]; + [3.0, 6.0, 9.0, 10.0] + ] - let solution: number[] = gaussianElimination(A); - solution = solution.filter((value) => !isNaN(value)); + let solution: number[] = gaussianElimination(A) + solution = solution.filter((value) => !isNaN(value)) - expect(solution).toEqual([]); - }); -}); + expect(solution).toEqual([]) + }) +}) diff --git a/maths/test/greatest_common_factor.test.ts b/maths/test/greatest_common_factor.test.ts index 4d219fde..68f2c75a 100644 --- a/maths/test/greatest_common_factor.test.ts +++ b/maths/test/greatest_common_factor.test.ts @@ -1,37 +1,42 @@ -import { binaryGCF, greatestCommonFactor } from "../greatest_common_factor"; +import { binaryGCF, greatestCommonFactor } from '../greatest_common_factor' -describe("binaryGCF", () => { - test.each([[12, 8, 4], [1, 199, 1], [88, 40, 8], [288, 160, 32]])( - "of given two numbers is correct", - (numa, numb, expected) => { - expect(binaryGCF(numa, numb)).toBe(expected); - }, - ); +describe('binaryGCF', () => { + test.each([ + [12, 8, 4], + [1, 199, 1], + [88, 40, 8], + [288, 160, 32] + ])('of given two numbers is correct', (numa, numb, expected) => { + expect(binaryGCF(numa, numb)).toBe(expected) + }) - test("only whole numbers should be accepted", () => { + test('only whole numbers should be accepted', () => { expect(() => binaryGCF(0.5, 0.8)).toThrowError( - "numbers must be natural to determine factors", - ); - }); + 'numbers must be natural to determine factors' + ) + }) - test("only positive numbers should be accepted", () => { + test('only positive numbers should be accepted', () => { expect(() => binaryGCF(-2, 4)).toThrowError( - "numbers must be natural to determine factors", - ); - }); -}); + 'numbers must be natural to determine factors' + ) + }) +}) -describe("greatestCommonFactor", () => { - test.each([[[7], 7], [[12, 8], 4], [[1, 199], 1], [[88, 40, 32], 8], [[288, 160, 64], 32]])( - "of given list is correct", - (nums, expected) => { - expect(greatestCommonFactor(nums)).toBe(expected); - }, - ); +describe('greatestCommonFactor', () => { + test.each([ + [[7], 7], + [[12, 8], 4], + [[1, 199], 1], + [[88, 40, 32], 8], + [[288, 160, 64], 32] + ])('of given list is correct', (nums, expected) => { + expect(greatestCommonFactor(nums)).toBe(expected) + }) - test("the list should consist of at least one number", () => { + test('the list should consist of at least one number', () => { expect(() => greatestCommonFactor([])).toThrowError( - "at least one number must be passed in", - ); - }); -}); \ No newline at end of file + 'at least one number must be passed in' + ) + }) +}) diff --git a/maths/test/hamming_distance.test.ts b/maths/test/hamming_distance.test.ts index c14df646..7226cf01 100644 --- a/maths/test/hamming_distance.test.ts +++ b/maths/test/hamming_distance.test.ts @@ -1,5 +1,10 @@ -import { hammingDistance } from "../hamming_distance" +import { hammingDistance } from '../hamming_distance' -test.each([['happy', 'homie', 4], ['hole', 'home', 1], ['cathrine', 'caroline', 3], ['happiness', 'dizziness', 4]])('Hamming Distance', (str1, str2, result) => { +test.each([ + ['happy', 'homie', 4], + ['hole', 'home', 1], + ['cathrine', 'caroline', 3], + ['happiness', 'dizziness', 4] +])('Hamming Distance', (str1, str2, result) => { expect(hammingDistance(str1, str2)).toBe(result) }) diff --git a/maths/test/is_divisible.test.ts b/maths/test/is_divisible.test.ts index 7952903c..c0635662 100644 --- a/maths/test/is_divisible.test.ts +++ b/maths/test/is_divisible.test.ts @@ -1,41 +1,35 @@ -import { isDivisible } from "../is_divisible"; +import { isDivisible } from '../is_divisible' -describe("isDivisible", () => { - test.each([ - [1, 1], - [6, 3], - [101, 1], - [5555, 5], - [143, 13], - [535, 107], - [855144, 999], - [100000, 10], - [1.5, 0.5] - ])( - "%f is divisible by %f", - (num1, num2) => { - expect(isDivisible(num1, num2)).toBe(true); - }, - ); +describe('isDivisible', () => { + test.each([ + [1, 1], + [6, 3], + [101, 1], + [5555, 5], + [143, 13], + [535, 107], + [855144, 999], + [100000, 10], + [1.5, 0.5] + ])('%f is divisible by %f', (num1, num2) => { + expect(isDivisible(num1, num2)).toBe(true) + }) - test.each([ - [1, 2], - [61, 3], - [120, 11], - [5556, 5], - [10, 9], - [75623, 3], - [45213, 11], - [784, 24], - [1.2, 0.35] - ])( - "%f is not divisible by %f", - (num1, num2) => { - expect(isDivisible(num1, num2)).toBe(false); - }, - ); + test.each([ + [1, 2], + [61, 3], + [120, 11], + [5556, 5], + [10, 9], + [75623, 3], + [45213, 11], + [784, 24], + [1.2, 0.35] + ])('%f is not divisible by %f', (num1, num2) => { + expect(isDivisible(num1, num2)).toBe(false) + }) - test("should not divide by 0", () => { - expect(() => isDivisible(10, 0)).toThrow(); - }); -}); \ No newline at end of file + test('should not divide by 0', () => { + expect(() => isDivisible(10, 0)).toThrow() + }) +}) diff --git a/maths/test/is_even.test.ts b/maths/test/is_even.test.ts index 571211f7..4a1ef0e8 100644 --- a/maths/test/is_even.test.ts +++ b/maths/test/is_even.test.ts @@ -1,16 +1,17 @@ -import { isEven } from "../is_even"; +import { isEven } from '../is_even' -describe("isEven", () => { - test.each([[2, true], [1, false], [0, true], [-1, false], [-2, true]])( - "correct output for for %i", - (nums, expected) => { - expect(isEven(nums)).toBe(expected); - }, - ); +describe('isEven', () => { + test.each([ + [2, true], + [1, false], + [0, true], + [-1, false], + [-2, true] + ])('correct output for for %i', (nums, expected) => { + expect(isEven(nums)).toBe(expected) + }) - test("only whole numbers should be accepted", () => { - expect(() => isEven(0.5)).toThrowError( - "only integers can be even or odd", - ); - }); -}); \ No newline at end of file + test('only whole numbers should be accepted', () => { + expect(() => isEven(0.5)).toThrowError('only integers can be even or odd') + }) +}) diff --git a/maths/test/is_leap_year.test.ts b/maths/test/is_leap_year.test.ts index 05d3d25c..8cddccb5 100644 --- a/maths/test/is_leap_year.test.ts +++ b/maths/test/is_leap_year.test.ts @@ -1,66 +1,70 @@ -import { isLeapYear } from "../is_leap_year"; +import { isLeapYear } from '../is_leap_year' -describe("isLeapYear", () => { +describe('isLeapYear', () => { test.each([4, 8, 12, 2004])( - "a year is a leap year it is divisible by 4 but not by 400 like %i", + 'a year is a leap year it is divisible by 4 but not by 400 like %i', (year) => { - expect(year % 4 === 0).toBe(true); - expect(year % 400 === 0).toBe(false); - expect(isLeapYear(year)).toBe(true); - }, - ); + expect(year % 4 === 0).toBe(true) + expect(year % 400 === 0).toBe(false) + expect(isLeapYear(year)).toBe(true) + } + ) test.each([400, 800, 1200, 1600, 2000, 2400, 40000])( - "a year is a leap year it is divisible by 400 like %i", + 'a year is a leap year it is divisible by 400 like %i', (year) => { - expect(year % 400 === 0).toBe(true); - expect(isLeapYear(year)).toBe(true); - }, - ); + expect(year % 400 === 0).toBe(true) + expect(isLeapYear(year)).toBe(true) + } + ) test.each([1, 313, 1997, 2001, 2021, 13337])( - "a year is not a leap year if it is not divisible by 4 like %i", + 'a year is not a leap year if it is not divisible by 4 like %i', (year) => { - expect(year % 4 === 0).toBe(false); - expect(isLeapYear(year)).toBe(false); - }, - ); + expect(year % 4 === 0).toBe(false) + expect(isLeapYear(year)).toBe(false) + } + ) test.each([100, 200, 300, 700, 2100])( - "a year is not a leap year if it is divisible by 100 but not by 400 like %i", + 'a year is not a leap year if it is divisible by 100 but not by 400 like %i', (year) => { - expect(year % 100 === 0).toBe(true); - expect(year % 400 === 0).toBe(false); - expect(isLeapYear(year)).toBe(false); - }, - ); + expect(year % 100 === 0).toBe(true) + expect(year % 400 === 0).toBe(false) + expect(isLeapYear(year)).toBe(false) + } + ) test.each([1, 2022, 3000000])( - "a year is supported if it is a natural number > 0 like %i", + 'a year is supported if it is a natural number > 0 like %i', (year) => { - expect(year > 0).toBe(true); - expect(Number.isInteger(year)).toBe(true); - expect(() => isLeapYear(year)).not.toThrow(); - }, - ); + expect(year > 0).toBe(true) + expect(Number.isInteger(year)).toBe(true) + expect(() => isLeapYear(year)).not.toThrow() + } + ) test.each([-1, -10, -Infinity])( - "a year is not supported if it is negative like %i", + 'a year is not supported if it is negative like %i', (year) => { - expect(year < 0).toBe(true); - expect(() => isLeapYear(year)).toThrow("year must be a natural number > 0"); - }, - ); + expect(year < 0).toBe(true) + expect(() => isLeapYear(year)).toThrow( + 'year must be a natural number > 0' + ) + } + ) test.each([0.1, 1.2, 4.2])( - "a year is not supported if it is not an integer %d", + 'a year is not supported if it is not an integer %d', (year) => { - expect(Number.isInteger(year)).toBe(false); - expect(() => isLeapYear(year)).toThrow("year must be a natural number > 0"); - }, - ); + expect(Number.isInteger(year)).toBe(false) + expect(() => isLeapYear(year)).toThrow( + 'year must be a natural number > 0' + ) + } + ) - test("a year is not supported if it is 0", () => { - expect(() => isLeapYear(0)).toThrow("year must be a natural number > 0"); + test('a year is not supported if it is 0', () => { + expect(() => isLeapYear(0)).toThrow('year must be a natural number > 0') }) -}); +}) diff --git a/maths/test/is_odd.test.ts b/maths/test/is_odd.test.ts index 2d305cf8..c5cb0580 100644 --- a/maths/test/is_odd.test.ts +++ b/maths/test/is_odd.test.ts @@ -1,16 +1,17 @@ -import { isOdd } from "../is_odd"; +import { isOdd } from '../is_odd' -describe("isOdd", () => { - test.each([[2, false], [1, true], [0, false], [-1, true], [-2, false]])( - "correct output for for %i", - (nums, expected) => { - expect(isOdd(nums)).toBe(expected); - }, - ); +describe('isOdd', () => { + test.each([ + [2, false], + [1, true], + [0, false], + [-1, true], + [-2, false] + ])('correct output for for %i', (nums, expected) => { + expect(isOdd(nums)).toBe(expected) + }) - test("only whole numbers should be accepted", () => { - expect(() => isOdd(0.5)).toThrowError( - "only integers can be even or odd", - ); - }); -}); \ No newline at end of file + test('only whole numbers should be accepted', () => { + expect(() => isOdd(0.5)).toThrowError('only integers can be even or odd') + }) +}) diff --git a/maths/test/is_palindrome.test.ts b/maths/test/is_palindrome.test.ts index ea15f48a..e492dfe8 100644 --- a/maths/test/is_palindrome.test.ts +++ b/maths/test/is_palindrome.test.ts @@ -1,10 +1,17 @@ -import { isPalindrome } from "../is_palindrome"; +import { isPalindrome } from '../is_palindrome' -describe("isPalindrome", () => { - test.each([[0, true], [1, true], [5, true], [1234, false], [12321, true], [31343, false], [-1, false], [-11, false], [10, false]])( - "correct output for %i", - (nums, expected) => { - expect(isPalindrome(nums)).toBe(expected); - }, - ); -}); \ No newline at end of file +describe('isPalindrome', () => { + test.each([ + [0, true], + [1, true], + [5, true], + [1234, false], + [12321, true], + [31343, false], + [-1, false], + [-11, false], + [10, false] + ])('correct output for %i', (nums, expected) => { + expect(isPalindrome(nums)).toBe(expected) + }) +}) diff --git a/maths/test/is_square_free.test.ts b/maths/test/is_square_free.test.ts index c2eeb99d..810a6640 100644 --- a/maths/test/is_square_free.test.ts +++ b/maths/test/is_square_free.test.ts @@ -1,14 +1,26 @@ -import { isSquareFree } from '../is_square_free'; +import { isSquareFree } from '../is_square_free' describe('isSquareFree', () => { - test.each([1, 2, 3, 5, 7, 10, 26, 2*3, 3*5*7, 11*13*17*19])( - "%i is square free", + test.each([1, 2, 3, 5, 7, 10, 26, 2 * 3, 3 * 5 * 7, 11 * 13 * 17 * 19])( + '%i is square free', (input) => { - expect(isSquareFree(input)).toBe(true); - }); - test.each([20, 48, 2*7*7, 2*3*3, 5*5*7, 2*3*13*13*17, 4*4*4, 2*2, 3*3, 5*5, 100, 0])( - "%i is not square free", - (input) => { - expect(isSquareFree(input)).toBe(false); - }); -}); + expect(isSquareFree(input)).toBe(true) + } + ) + test.each([ + 20, + 48, + 2 * 7 * 7, + 2 * 3 * 3, + 5 * 5 * 7, + 2 * 3 * 13 * 13 * 17, + 4 * 4 * 4, + 2 * 2, + 3 * 3, + 5 * 5, + 100, + 0 + ])('%i is not square free', (input) => { + expect(isSquareFree(input)).toBe(false) + }) +}) diff --git a/maths/test/juggler_sequence.test.ts b/maths/test/juggler_sequence.test.ts index 038c7011..b0a9a737 100644 --- a/maths/test/juggler_sequence.test.ts +++ b/maths/test/juggler_sequence.test.ts @@ -1,12 +1,12 @@ -import { jugglerSequence } from '../juggler_sequence'; +import { jugglerSequence } from '../juggler_sequence' describe('jugglerSequence', () => { it.each([ [3, 3, 36], [3, 5, 2], [7, 3, 2], - [5, 1, 11], + [5, 1, 11] ])('%i at index %i should equal %i', (a, n, k) => { - expect(jugglerSequence(a, n)).toBe(k); - }); -}); + expect(jugglerSequence(a, n)).toBe(k) + }) +}) diff --git a/maths/test/lowest_common_multiple.test.ts b/maths/test/lowest_common_multiple.test.ts index 388dba28..1dd768e4 100644 --- a/maths/test/lowest_common_multiple.test.ts +++ b/maths/test/lowest_common_multiple.test.ts @@ -1,61 +1,70 @@ -import { binaryLCM, lowestCommonMultiple, naiveLCM } from "../lowest_common_multiple"; +import { + binaryLCM, + lowestCommonMultiple, + naiveLCM +} from '../lowest_common_multiple' -describe("naiveLCM", () => { - test.each([[[3, 4], 12], [[8, 6], 24], [[5, 8, 3], 120], [[0.8, 0.4], 0.8]])( - "of given two numbers is correct", - (nums, expected) => { - expect(naiveLCM(nums)).toBe(expected); - }, - ); +describe('naiveLCM', () => { + test.each([ + [[3, 4], 12], + [[8, 6], 24], + [[5, 8, 3], 120], + [[0.8, 0.4], 0.8] + ])('of given two numbers is correct', (nums, expected) => { + expect(naiveLCM(nums)).toBe(expected) + }) - test("only positive numbers should be accepted", () => { + test('only positive numbers should be accepted', () => { expect(() => naiveLCM([-2, -3])).toThrowError( - "numbers must be positive to determine lowest common multiple", - ); - }); + 'numbers must be positive to determine lowest common multiple' + ) + }) - test("at least one number must be passed in", () => { + test('at least one number must be passed in', () => { expect(() => naiveLCM([])).toThrowError( - "at least one number must be passed in", - ); - }); -}); - -describe("binaryLCM", () => { - test.each([[3, 4, 12], [8, 6, 24], [8, 16, 16]])( - "of given two numbers is correct", - (numa, numb, expected) => { - expect(binaryLCM(numa, numb)).toBe(expected); - }, - ); - - test("only natural numbers should be accepted", () => { - expect(() => binaryLCM(-2, -3)).toThrowError(); - expect(() => binaryLCM(2, -3)).toThrowError(); - expect(() => binaryLCM(-2, 3)).toThrowError(); - }); - - test("should throw when any of the inputs is not an int", () => { - expect(() => binaryLCM(1, 2.5)).toThrowError(); - expect(() => binaryLCM(1.5, 2)).toThrowError(); - }); -}); - -describe("lowestCommonMultiple", () => { - test.each([[[3, 4], 12], [[8, 6], 24], [[5, 8, 3], 120], [[8, 16], 16]])( - "of given two numbers is correct", - (nums, expected) => { - expect(lowestCommonMultiple(nums)).toBe(expected); - }, - ); - - test("only positive numbers should be accepted", () => { - expect(() => lowestCommonMultiple([-2, -3])).toThrowError(); - }); - - test("at least one number must be passed in", () => { + 'at least one number must be passed in' + ) + }) +}) + +describe('binaryLCM', () => { + test.each([ + [3, 4, 12], + [8, 6, 24], + [8, 16, 16] + ])('of given two numbers is correct', (numa, numb, expected) => { + expect(binaryLCM(numa, numb)).toBe(expected) + }) + + test('only natural numbers should be accepted', () => { + expect(() => binaryLCM(-2, -3)).toThrowError() + expect(() => binaryLCM(2, -3)).toThrowError() + expect(() => binaryLCM(-2, 3)).toThrowError() + }) + + test('should throw when any of the inputs is not an int', () => { + expect(() => binaryLCM(1, 2.5)).toThrowError() + expect(() => binaryLCM(1.5, 2)).toThrowError() + }) +}) + +describe('lowestCommonMultiple', () => { + test.each([ + [[3, 4], 12], + [[8, 6], 24], + [[5, 8, 3], 120], + [[8, 16], 16] + ])('of given two numbers is correct', (nums, expected) => { + expect(lowestCommonMultiple(nums)).toBe(expected) + }) + + test('only positive numbers should be accepted', () => { + expect(() => lowestCommonMultiple([-2, -3])).toThrowError() + }) + + test('at least one number must be passed in', () => { expect(() => lowestCommonMultiple([])).toThrowError( - "at least one number must be passed in", - ); - }); -}); + 'at least one number must be passed in' + ) + }) +}) diff --git a/maths/test/matrix_multiplication.test.ts b/maths/test/matrix_multiplication.test.ts index 4c869f2a..3571c0d1 100644 --- a/maths/test/matrix_multiplication.test.ts +++ b/maths/test/matrix_multiplication.test.ts @@ -1,4 +1,4 @@ -import { matrixMultiplication } from '../matrix_multiplication'; +import { matrixMultiplication } from '../matrix_multiplication' describe('Matrix-matrix multiplication', () => { it.each([ @@ -49,9 +49,7 @@ describe('Matrix-matrix multiplication', () => { [1, 2], [3, 4] ], - [ - [1, 2] - ], + [[1, 2]], null ], [ @@ -65,11 +63,11 @@ describe('Matrix-matrix multiplication', () => { [5, 6] ], null - ], + ] ])('Multiplying %j with %j should return %j', (matA, matB, expected) => { - expect(matrixMultiplication(matA, matB)).toEqual(expected); - }); -}); + expect(matrixMultiplication(matA, matB)).toEqual(expected) + }) +}) describe('Matrix-scalar multiplication', () => { it.each([ @@ -116,11 +114,11 @@ describe('Matrix-scalar multiplication', () => { [-3, -6], [-9, -12] ] - ], + ] ])('Multiplying %j with %i should return %j', (matA, scalar, expected) => { - expect(matrixMultiplication(matA, scalar)).toEqual(expected); - }); -}); + expect(matrixMultiplication(matA, scalar)).toEqual(expected) + }) +}) describe('Matrix-vector multiplication', () => { it.each([ @@ -163,8 +161,8 @@ describe('Matrix-vector multiplication', () => { ], [1, 2, 3], null - ], + ] ])('Multiplying %j with %j should return %j', (matA, vector, expected) => { - expect(matrixMultiplication(matA, vector)).toEqual(expected); - }); -}); + expect(matrixMultiplication(matA, vector)).toEqual(expected) + }) +}) diff --git a/maths/test/number_of_digits.test.ts b/maths/test/number_of_digits.test.ts index 7dcd4254..f3593fc3 100644 --- a/maths/test/number_of_digits.test.ts +++ b/maths/test/number_of_digits.test.ts @@ -1,19 +1,22 @@ -import { numberOfDigits } from "../number_of_digits"; +import { numberOfDigits } from '../number_of_digits' -describe("numberOfDigits", () => { +describe('numberOfDigits', () => { test.each([-890, -5.56, -7, 0, 0.73, 4.2, NaN, -Infinity, Infinity])( - "should throw an error for non natural number %d", + 'should throw an error for non natural number %d', (num) => { expect(() => numberOfDigits(num)).toThrowError( - "only natural numbers are supported", - ); - }, - ); + 'only natural numbers are supported' + ) + } + ) - test.each([[1, 1], [18, 2], [549, 3], [7293, 4], [1234567890, 10]])( - "of %i should be %i", - (num, expected) => { - expect(numberOfDigits(num)).toBe(expected); - }, - ); -}); + test.each([ + [1, 1], + [18, 2], + [549, 3], + [7293, 4], + [1234567890, 10] + ])('of %i should be %i', (num, expected) => { + expect(numberOfDigits(num)).toBe(expected) + }) +}) diff --git a/maths/test/pascals_triangle.test.ts b/maths/test/pascals_triangle.test.ts index 7091ce13..b7b16541 100644 --- a/maths/test/pascals_triangle.test.ts +++ b/maths/test/pascals_triangle.test.ts @@ -1,11 +1,11 @@ -import { pascalsTriangle } from "../pascals_triangle"; +import { pascalsTriangle } from '../pascals_triangle' describe('pascalsTriangle', () => { it.each([ [2, [1, 1]], [4, [1, 3, 3, 1]], - [6, [1, 5, 10, 10, 5, 1]], - ])('The %i th row should equal to %i', (n, expectation) => { - expect(pascalsTriangle(n)).toEqual(expectation); - }); -}); + [6, [1, 5, 10, 10, 5, 1]] + ])('The %i th row should equal to %i', (n, expectation) => { + expect(pascalsTriangle(n)).toEqual(expectation) + }) +}) diff --git a/maths/test/perfect_cube.test.ts b/maths/test/perfect_cube.test.ts index 731ec67f..103e5774 100644 --- a/maths/test/perfect_cube.test.ts +++ b/maths/test/perfect_cube.test.ts @@ -1,4 +1,4 @@ -import { perfectCube } from "../perfect_cube"; +import { perfectCube } from '../perfect_cube' describe('perfect cube tests', () => { it.each([ @@ -8,8 +8,8 @@ describe('perfect cube tests', () => { [12, false], [64, true], [151, false], - [125, true], + [125, true] ])('The return value of %i should be %s', (n, expectation) => { - expect(perfectCube(n)).toBe(expectation); - }); -}); + expect(perfectCube(n)).toBe(expectation) + }) +}) diff --git a/maths/test/perfect_numbers.test.ts b/maths/test/perfect_numbers.test.ts index 7d2e92c9..a09374c2 100644 --- a/maths/test/perfect_numbers.test.ts +++ b/maths/test/perfect_numbers.test.ts @@ -1,4 +1,4 @@ -import { isPerfectNumber } from "../perfect_number"; +import { isPerfectNumber } from '../perfect_number' describe('perfect Numbers tests', () => { it.each([ @@ -11,8 +11,8 @@ describe('perfect Numbers tests', () => { [100, false], [0, false], [-1, false], - [1.5, false], + [1.5, false] ])('The return value of %i should be %s', (n, expectation) => { - expect(isPerfectNumber(n)).toBe(expectation); - }); -}); + expect(isPerfectNumber(n)).toBe(expectation) + }) +}) diff --git a/maths/test/perfect_square.test.ts b/maths/test/perfect_square.test.ts index e0612c6d..a2b7ea46 100644 --- a/maths/test/perfect_square.test.ts +++ b/maths/test/perfect_square.test.ts @@ -1,9 +1,9 @@ -import { perfectSquare } from "../perfect_square"; +import { perfectSquare } from '../perfect_square' -test("Check perfect square", () => { - expect(perfectSquare(16)).toBe(true); - expect(perfectSquare(12)).toBe(false); - expect(perfectSquare(19)).toBe(false); - expect(perfectSquare(25)).toBe(true); - expect(perfectSquare(42)).toBe(false); -}); +test('Check perfect square', () => { + expect(perfectSquare(16)).toBe(true) + expect(perfectSquare(12)).toBe(false) + expect(perfectSquare(19)).toBe(false) + expect(perfectSquare(25)).toBe(true) + expect(perfectSquare(42)).toBe(false) +}) diff --git a/maths/test/prime_factorization.test.ts b/maths/test/prime_factorization.test.ts index 23eaff0b..66e9ab14 100644 --- a/maths/test/prime_factorization.test.ts +++ b/maths/test/prime_factorization.test.ts @@ -1,26 +1,43 @@ -import { factorize } from "../prime_factorization"; - +import { factorize } from '../prime_factorization' interface TestCase { - n: number; - expected: Map + n: number + expected: Map } const cases: TestCase[] = [ - {n: 4, expected: new Map([[2, 2]])}, - {n: 5, expected: new Map([[5, 1]])}, - {n: 7, expected: new Map([[7, 1]])}, - {n: 10, expected: new Map([[2, 1], [5, 1]])}, - {n: 999, expected: new Map([[3, 3], [37, 1]])}, - {n: 999999999999878, expected: new Map([[2, 1], [19, 1], [26315789473681, 1]])}, -]; - -describe("factorize", () => { + { n: 4, expected: new Map([[2, 2]]) }, + { n: 5, expected: new Map([[5, 1]]) }, + { n: 7, expected: new Map([[7, 1]]) }, + { + n: 10, + expected: new Map([ + [2, 1], + [5, 1] + ]) + }, + { + n: 999, + expected: new Map([ + [3, 3], + [37, 1] + ]) + }, + { + n: 999999999999878, + expected: new Map([ + [2, 1], + [19, 1], + [26315789473681, 1] + ]) + } +] - test.each(cases)( - "prime factorization of $n should be $expected", - ({n, expected}) => { - expect(factorize(n)).toEqual(expected); - }, - ); -}); +describe('factorize', () => { + test.each(cases)( + 'prime factorization of $n should be $expected', + ({ n, expected }) => { + expect(factorize(n)).toEqual(expected) + } + ) +}) diff --git a/maths/test/primes.test.ts b/maths/test/primes.test.ts index c67a2fd8..c4011956 100644 --- a/maths/test/primes.test.ts +++ b/maths/test/primes.test.ts @@ -1,13 +1,12 @@ -import {isPrime, primeGenerator, sieveOfEratosthenes} from "../primes"; - +import { isPrime, primeGenerator, sieveOfEratosthenes } from '../primes' describe(sieveOfEratosthenes, () => { test.each([-1, 0, 1, 2.123, 1337.80085])( - "should throw an error when given an invalid limit=%d", + 'should throw an error when given an invalid limit=%d', (invalidLimit) => { - expect(() => sieveOfEratosthenes(invalidLimit)).toThrow(); + expect(() => sieveOfEratosthenes(invalidLimit)).toThrow() } - ); + ) test.each([ [2, [2]], [3, [2, 3]], @@ -16,44 +15,48 @@ describe(sieveOfEratosthenes, () => { [6, [2, 3, 5]], [7, [2, 3, 5, 7]], [8, [2, 3, 5, 7]], - [9, [2, 3, 5, 7]], + [9, [2, 3, 5, 7]] ])( - "should return the expected list of primes for limit=%i", + 'should return the expected list of primes for limit=%i', (limit, expected) => { - expect(sieveOfEratosthenes(limit)).toEqual(expected); + expect(sieveOfEratosthenes(limit)).toEqual(expected) } - ); -}); + ) +}) describe(primeGenerator, () => { - it("should generate prime numbers", () => { - const primeGen = primeGenerator(); + it('should generate prime numbers', () => { + const primeGen = primeGenerator() for (let i = 0; i < 100; i++) { - const prime = primeGen.next().value; + const prime = primeGen.next().value if (prime === undefined) { - throw new Error("prime generator returned undefined"); + throw new Error('prime generator returned undefined') } - expect(isPrime(prime)).toBe(true); + expect(isPrime(prime)).toBe(true) } - }); -}); + }) +}) -describe("IsPrime", () => { - test.each([[1, false], [2, true], [3, true], [3 * 3, false], [13, true], [24, false]])( - "correct output for %i", - (nums, expected) => { - expect(isPrime(nums)).toBe(expected); - }, - ); +describe('IsPrime', () => { + test.each([ + [1, false], + [2, true], + [3, true], + [3 * 3, false], + [13, true], + [24, false] + ])('correct output for %i', (nums, expected) => { + expect(isPrime(nums)).toBe(expected) + }) test.each([-890, -5.56, -7, 0.73, 4.2, NaN, -Infinity, Infinity])( - "should throw an error for non natural number %d", + 'should throw an error for non natural number %d', (num) => { expect(() => isPrime(num)).toThrowError( - "only natural numbers are supported", - ); - }, - ); -}); + 'only natural numbers are supported' + ) + } + ) +}) diff --git a/maths/test/pronic_number.test.ts b/maths/test/pronic_number.test.ts index 9817eaa9..19476aa3 100644 --- a/maths/test/pronic_number.test.ts +++ b/maths/test/pronic_number.test.ts @@ -1,5 +1,11 @@ import { pronicNumber } from '../pronic_number' -test.each([[0, true], [10, false], [30, true], [69, false], [420, true]])('Pronic Number', (number, result) => { +test.each([ + [0, true], + [10, false], + [30, true], + [69, false], + [420, true] +])('Pronic Number', (number, result) => { expect(pronicNumber(number)).toBe(result) }) diff --git a/maths/test/radians_to_degrees.test.ts b/maths/test/radians_to_degrees.test.ts index 9ff8868f..557500d8 100644 --- a/maths/test/radians_to_degrees.test.ts +++ b/maths/test/radians_to_degrees.test.ts @@ -1,7 +1,7 @@ -import { radiansToDegrees } from '../radians_to_degrees'; - -test("RadiansToDegrees", () => { - expect(radiansToDegrees(0)).toBe(0); - expect(radiansToDegrees(0.7853981633974483)).toBe(45); - expect(radiansToDegrees(1.5707963267948966)).toBe(90); -}); \ No newline at end of file +import { radiansToDegrees } from '../radians_to_degrees' + +test('RadiansToDegrees', () => { + expect(radiansToDegrees(0)).toBe(0) + expect(radiansToDegrees(0.7853981633974483)).toBe(45) + expect(radiansToDegrees(1.5707963267948966)).toBe(90) +}) diff --git a/maths/test/sieve_of_eratosthenes.test.ts b/maths/test/sieve_of_eratosthenes.test.ts index 9670e063..c07582f0 100644 --- a/maths/test/sieve_of_eratosthenes.test.ts +++ b/maths/test/sieve_of_eratosthenes.test.ts @@ -1,20 +1,20 @@ -import { sieveOfEratosthenes } from "../sieve_of_eratosthenes"; +import { sieveOfEratosthenes } from '../sieve_of_eratosthenes' - -describe("Sieve of Eratosthenes", () => { +describe('Sieve of Eratosthenes', () => { test.each([-2, 0.1, -0.01, 2.2])( - "should throw a error for non natural number", + 'should throw a error for non natural number', (n) => { expect(() => sieveOfEratosthenes(n)).toThrow( - "Only natural numbers are supported" - ); - }, - ); + 'Only natural numbers are supported' + ) + } + ) - test.each([[5, [2, 3, 5]], [11, [2, 3, 5, 7, 11]], [30, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]]])( - "of %i should be %o", - (num, expected) => { - expect(sieveOfEratosthenes(num)).toStrictEqual(expected); - }, - ); -}); + test.each([ + [5, [2, 3, 5]], + [11, [2, 3, 5, 7, 11]], + [30, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]] + ])('of %i should be %o', (num, expected) => { + expect(sieveOfEratosthenes(num)).toStrictEqual(expected) + }) +}) diff --git a/maths/test/signum.test.ts b/maths/test/signum.test.ts index 93c8ff68..02ac4fa6 100644 --- a/maths/test/signum.test.ts +++ b/maths/test/signum.test.ts @@ -1,5 +1,10 @@ -import { signum } from "../signum"; +import { signum } from '../signum' -test.each([[10, 1], [0, 0], [-69, -1], [NaN, NaN]])("The sign of %i is %i", (num, expected) => { +test.each([ + [10, 1], + [0, 0], + [-69, -1], + [NaN, NaN] +])('The sign of %i is %i', (num, expected) => { expect(signum(num)).toBe(expected) }) diff --git a/maths/test/square_root.test.ts b/maths/test/square_root.test.ts index 366f867c..1c08cbf5 100644 --- a/maths/test/square_root.test.ts +++ b/maths/test/square_root.test.ts @@ -1,24 +1,24 @@ -import { squareRoot } from "../square_root"; +import { squareRoot } from '../square_root' -describe("squareRoot", () => { +describe('squareRoot', () => { test.each([-1, -10, -2.4])( - "should throw an error for negative numbers", + 'should throw an error for negative numbers', (n: number) => { - expect(() => squareRoot(n)).toThrow("number must be non-negative number"); + expect(() => squareRoot(n)).toThrow('number must be non-negative number') } - ); + ) test.each([0, 1, 4, 9, 16, 25])( - "should return correct rational square root value for %i", + 'should return correct rational square root value for %i', (n: number) => { - expect(squareRoot(n)).toBeCloseTo(Math.sqrt(n)); + expect(squareRoot(n)).toBeCloseTo(Math.sqrt(n)) } - ); + ) test.each([2, 15, 20, 40, 99, 10032])( - "should return correct irrational square root value %i", + 'should return correct irrational square root value %i', (n: number) => { - expect(squareRoot(n)).toBeCloseTo(Math.sqrt(n)); + expect(squareRoot(n)).toBeCloseTo(Math.sqrt(n)) } - ); -}); + ) +}) diff --git a/maths/test/ugly_numbers.test.ts b/maths/test/ugly_numbers.test.ts index 41f22cb5..cfd22141 100644 --- a/maths/test/ugly_numbers.test.ts +++ b/maths/test/ugly_numbers.test.ts @@ -1,6 +1,10 @@ -import { uglyNumbers } from '../ugly_numbers'; +import { uglyNumbers } from '../ugly_numbers' test('Ugly Numbers', () => { - const uglyNums = uglyNumbers(); - expect(Array(11).fill(undefined).map(() => uglyNums.next().value)).toEqual([1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15]); + const uglyNums = uglyNumbers() + expect( + Array(11) + .fill(undefined) + .map(() => uglyNums.next().value) + ).toEqual([1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15]) }) diff --git a/maths/test/zellers_congruence.test.ts b/maths/test/zellers_congruence.test.ts index 719969e0..0ea310b9 100644 --- a/maths/test/zellers_congruence.test.ts +++ b/maths/test/zellers_congruence.test.ts @@ -1,4 +1,4 @@ -import { Calendar, getWeekday } from "../zellers_congruence"; +import { Calendar, getWeekday } from '../zellers_congruence' describe("Zeller's congruence", () => { test.each([ @@ -19,13 +19,13 @@ describe("Zeller's congruence", () => { { year: 456, month: 3, day: 31, expected: 5 }, { year: 1850, month: 4, day: 1, expected: 1 }, { year: 2100, month: 12, day: 31, expected: 5 }, - { year: 3000, month: 12, day: 31, expected: 3 }, + { year: 3000, month: 12, day: 31, expected: 3 } ])( `The weekday of $year-$month-$day in the default calendar is $expected`, ({ year, month, day, expected }) => { - expect(getWeekday(year, month, day)).toEqual(expected); + expect(getWeekday(year, month, day)).toEqual(expected) } - ); + ) test.each([ { year: 1500, month: 1, day: 1, expected: 3 }, @@ -43,17 +43,17 @@ describe("Zeller's congruence", () => { { year: 1, month: 1, day: 1, expected: 6 }, { year: 23, month: 2, day: 28, expected: 0 }, { year: 456, month: 3, day: 31, expected: 6 }, - { year: 1582, month: 2, day: 1, expected: 4 }, + { year: 1582, month: 2, day: 1, expected: 4 } ])( `The weekday of $year-$month-$day in the Julian calendar is $expected`, ({ year, month, day, expected }) => { - expect(getWeekday(year, month, day, Calendar.Julian)).toEqual(expected); + expect(getWeekday(year, month, day, Calendar.Julian)).toEqual(expected) } - ); + ) test(`The default calendar is Gregorian`, () => { - expect(getWeekday(1, 1, 1)).toEqual(1); - }); + expect(getWeekday(1, 1, 1)).toEqual(1) + }) test.each([ { year: 1, month: 1, day: 1, expected: 1 }, @@ -62,51 +62,51 @@ describe("Zeller's congruence", () => { { year: 1850, month: 4, day: 1, expected: 1 }, { year: 2000, month: 1, day: 1, expected: 6 }, { year: 2100, month: 12, day: 31, expected: 5 }, - { year: 3000, month: 12, day: 31, expected: 3 }, + { year: 3000, month: 12, day: 31, expected: 3 } ])( `The weekday for $year-$month-$day in the default calendar matches getUTCDay`, ({ year, month, day }) => { // Convert to a string to avoid Date constructor mapping 1 to year 1901 - const dateString = `${year.toString().padStart(4, "0")}-${month + const dateString = `${year.toString().padStart(4, '0')}-${month .toString() - .padStart(2, "0")}-${day.toString().padStart(2, "0")}`; + .padStart(2, '0')}-${day.toString().padStart(2, '0')}` expect(getWeekday(year, month, day)).toEqual( new Date(dateString).getUTCDay() - ); + ) } - ); + ) test.each([ { year: 0, month: 1, day: 1 }, { year: -5, month: 1, day: 1 }, - { year: 12.2, month: 1, day: 1 }, + { year: 12.2, month: 1, day: 1 } ])(`Should throw an error for invalid year $year`, ({ year, month, day }) => { expect(() => getWeekday(year, month, day)).toThrow( - "Year must be an integer greater than 0" - ); - }); + 'Year must be an integer greater than 0' + ) + }) test.each([ { year: 2001, month: -5, day: 1 }, { year: 2001, month: 0, day: 1 }, { year: 2001, month: 13, day: 1 }, - { year: 2001, month: 9.3, day: 1 }, + { year: 2001, month: 9.3, day: 1 } ])( `Should throw an error for invalid month $month`, ({ year, month, day }) => { expect(() => getWeekday(year, month, day)).toThrow( - "Month must be an integer between 1 and 12" - ); + 'Month must be an integer between 1 and 12' + ) } - ); + ) test.each([ { year: 2001, month: 1, day: -5 }, { year: 2001, month: 1, day: 0 }, - { year: 2001, month: 1, day: 32 }, + { year: 2001, month: 1, day: 32 } ])(`Should throw an error for invalid day $day`, ({ year, month, day }) => { expect(() => getWeekday(year, month, day)).toThrow( - "Day must be an integer between 1 and 31" - ); - }); -}); + 'Day must be an integer between 1 and 31' + ) + }) +}) diff --git a/maths/ugly_numbers.ts b/maths/ugly_numbers.ts index 81414d84..52ee4c71 100644 --- a/maths/ugly_numbers.ts +++ b/maths/ugly_numbers.ts @@ -5,19 +5,21 @@ * They can be represented in the form 2^a * 3^b * 5*c. By convention, 1 is also considered to be * an ugly number. * The first few terms of the sequence are: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20... - * + * * For the provided n, the nth ugly number shall be computed. * @see [GeeksForGeeks](https://www.geeksforgeeks.org/ugly-numbers/) */ function* uglyNumbers(): Generator { yield 1 - let idx2 = 0, idx3 = 0, idx5 = 0 + let idx2 = 0, + idx3 = 0, + idx5 = 0 const uglyNums = [1] let nextx2: number, nextx3: number, nextx5: number, nextUglyNum: number - while(true) { + while (true) { nextx2 = uglyNums[idx2] * 2 nextx3 = uglyNums[idx3] * 3 nextx5 = uglyNums[idx5] * 5 @@ -25,10 +27,10 @@ function* uglyNumbers(): Generator { nextUglyNum = Math.min(nextx2, nextx3, nextx5) yield nextUglyNum - if(nextx2 === nextUglyNum) idx2++ - if(nextx3 === nextUglyNum) idx3++ - if(nextx5 === nextUglyNum) idx5++ - + if (nextx2 === nextUglyNum) idx2++ + if (nextx3 === nextUglyNum) idx3++ + if (nextx5 === nextUglyNum) idx5++ + uglyNums.push(nextUglyNum) } } diff --git a/maths/zellers_congruence.ts b/maths/zellers_congruence.ts index 76315eb2..8b320418 100644 --- a/maths/zellers_congruence.ts +++ b/maths/zellers_congruence.ts @@ -1,6 +1,6 @@ export enum Calendar { Gregorian, - Julian, + Julian } /** @@ -22,27 +22,27 @@ export const getWeekday = ( ): number => { // Input validation if (!Number.isInteger(year) || year < 1) { - throw new Error("Year must be an integer greater than 0"); + throw new Error('Year must be an integer greater than 0') } if (!Number.isInteger(month) || month < 1 || month > 12) { - throw new Error("Month must be an integer between 1 and 12"); + throw new Error('Month must be an integer between 1 and 12') } if (!Number.isInteger(day) || day < 1 || day > 31) { - throw new Error("Day must be an integer between 1 and 31"); + throw new Error('Day must be an integer between 1 and 31') } // Move January and February to the end of the previous year if (month < 3) { - month += 12; - year--; + month += 12 + year-- } - const century = Math.floor(year / 100); - year %= 100; + const century = Math.floor(year / 100) + year %= 100 - let weekday: number | undefined = undefined; + let weekday: number | undefined = undefined if (calendar === Calendar.Gregorian) { weekday = (day + @@ -51,7 +51,7 @@ export const getWeekday = ( Math.floor(year / 4) + Math.floor(century / 4) + 5 * century) % - 7; + 7 } else { weekday = (day + @@ -60,9 +60,9 @@ export const getWeekday = ( Math.floor(year / 4) + 5 + 6 * century) % - 7; + 7 } // Convert to Sunday being 0 - return (weekday + 6) % 7; -}; + return (weekday + 6) % 7 +} diff --git a/other/is_sorted_array.ts b/other/is_sorted_array.ts index e35ff2ef..25d20238 100644 --- a/other/is_sorted_array.ts +++ b/other/is_sorted_array.ts @@ -5,12 +5,12 @@ * @returns {boolean} - true if the array is sorted and false if it's not sorted * @example isSortedArray([1,2,3]) => true * @example isSortedArray([9,2,3]) => false -*/ + */ export function isSortedArray(arr: number[]): boolean { - for (let i = 0; i < arr.length - 1; i++) { - if (arr[i] >= arr[i + 1]) { - return false; - } - } - return true; + for (let i = 0; i < arr.length - 1; i++) { + if (arr[i] >= arr[i + 1]) { + return false + } + } + return true } diff --git a/other/parse_nested_brackets.ts b/other/parse_nested_brackets.ts index dce1ef37..6d373d27 100644 --- a/other/parse_nested_brackets.ts +++ b/other/parse_nested_brackets.ts @@ -16,32 +16,32 @@ '(ABBR)' ] */ - export const parseNestedBrackets = ( - text: string, - openBrackets = "<", - closingBrackets = ">" - ) => { - let array: string[] = []; // The array of the tags in this present floor. - let prFloor = 0; // The present floor. - let begin = 0, // The begin index of the tag. - end = 0; // The end index of the tag. - for (let i = 0; i < text.length; i++) { - if (text[i] === openBrackets) { - prFloor++; - if (prFloor === 1) begin = i; - } else if (text[i] === closingBrackets) { - if (prFloor === 1) { - end = i; - const tag = text.slice(begin + 1, end); - // push the tag in this present floor. - array.push(`${openBrackets}${tag}${closingBrackets}`); - // push the array of the tags in the next floor. - array = array.concat( - parseNestedBrackets(tag, openBrackets, closingBrackets) - ); - } - prFloor--; - } - } - return array; - }; +export const parseNestedBrackets = ( + text: string, + openBrackets = '<', + closingBrackets = '>' +) => { + let array: string[] = [] // The array of the tags in this present floor. + let prFloor = 0 // The present floor. + let begin = 0, // The begin index of the tag. + end = 0 // The end index of the tag. + for (let i = 0; i < text.length; i++) { + if (text[i] === openBrackets) { + prFloor++ + if (prFloor === 1) begin = i + } else if (text[i] === closingBrackets) { + if (prFloor === 1) { + end = i + const tag = text.slice(begin + 1, end) + // push the tag in this present floor. + array.push(`${openBrackets}${tag}${closingBrackets}`) + // push the array of the tags in the next floor. + array = array.concat( + parseNestedBrackets(tag, openBrackets, closingBrackets) + ) + } + prFloor-- + } + } + return array +} diff --git a/other/shuffle_array.ts b/other/shuffle_array.ts index 04a5b701..992145c2 100644 --- a/other/shuffle_array.ts +++ b/other/shuffle_array.ts @@ -1,8 +1,8 @@ export function shuffleArray(arr: number[]) { - for (let i = arr.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - const temp = arr[i]; - arr[i] = arr[j]; - arr[j] = temp; - } + for (let i = arr.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)) + const temp = arr[i] + arr[i] = arr[j] + arr[j] = temp + } } diff --git a/other/test/is_sorted_array.test.ts b/other/test/is_sorted_array.test.ts index 58a223b4..199b8121 100644 --- a/other/test/is_sorted_array.test.ts +++ b/other/test/is_sorted_array.test.ts @@ -1,11 +1,11 @@ -import { isSortedArray } from '../is_sorted_array'; +import { isSortedArray } from '../is_sorted_array' describe('isSortedArray', () => { - test.each([ - { arr: [100], expected: true }, - { arr: [9, 2, 3], expected: false }, - { arr: [1, 2, 3], expected: true }, - ])('The return value of ($arr) should be $expected', ({ arr, expected }) => { - expect(isSortedArray(arr)).toEqual(expected); - }); -}); + test.each([ + { arr: [100], expected: true }, + { arr: [9, 2, 3], expected: false }, + { arr: [1, 2, 3], expected: true } + ])('The return value of ($arr) should be $expected', ({ arr, expected }) => { + expect(isSortedArray(arr)).toEqual(expected) + }) +}) diff --git a/other/test/parse_nested_brackets.test.ts b/other/test/parse_nested_brackets.test.ts index 751e8651..15a4d45f 100644 --- a/other/test/parse_nested_brackets.test.ts +++ b/other/test/parse_nested_brackets.test.ts @@ -1,24 +1,24 @@ -import { parseNestedBrackets } from "../parse_nested_brackets"; +import { parseNestedBrackets } from '../parse_nested_brackets' -describe("parseNestedBrackets", () => { - it("should return an array of the tags", () => { - expect(parseNestedBrackets("
")).toEqual([ - "
", - "", - ]); - }); - it("should return an array of the tags (nested)", () => { +describe('parseNestedBrackets', () => { + it('should return an array of the tags', () => { + expect(parseNestedBrackets('
')).toEqual([ + '
', + '' + ]) + }) + it('should return an array of the tags (nested)', () => { expect( parseNestedBrackets( `THIS IS SAMPLE TEXT(MAIN hoge 0.1 fuga(ITEM fuga hoge)hoge(ITEM2 nogami(ABBR)))`, - "(", - ")" + '(', + ')' ) ).toEqual([ - "(MAIN hoge 0.1 fuga(ITEM fuga hoge)hoge(ITEM2 nogami(ABBR)))", - "(ITEM fuga hoge)", - "(ITEM2 nogami(ABBR))", - "(ABBR)", - ]); - }); -}); + '(MAIN hoge 0.1 fuga(ITEM fuga hoge)hoge(ITEM2 nogami(ABBR)))', + '(ITEM fuga hoge)', + '(ITEM2 nogami(ABBR))', + '(ABBR)' + ]) + }) +}) diff --git a/other/test/shuffle_array.test.ts b/other/test/shuffle_array.test.ts index a5ac836d..fcc4c4f6 100644 --- a/other/test/shuffle_array.test.ts +++ b/other/test/shuffle_array.test.ts @@ -1,25 +1,25 @@ -import { shuffleArray } from '../shuffle_array'; +import { shuffleArray } from '../shuffle_array' describe('shuffleArray', () => { - test.each([{ arr: [1, 2, 3] }, { arr: [1, 2, 3, 6, 78, 2] }])( - "The length of the array $arr does'nt change after shuffling the array", - ({ arr }) => { - const originalLength = arr.length; - shuffleArray(arr); - expect(arr.length).toEqual(originalLength); - } - ); + test.each([{ arr: [1, 2, 3] }, { arr: [1, 2, 3, 6, 78, 2] }])( + "The length of the array $arr does'nt change after shuffling the array", + ({ arr }) => { + const originalLength = arr.length + shuffleArray(arr) + expect(arr.length).toEqual(originalLength) + } + ) - test.each([{ arr: [1, 2, 3] }, { arr: [1, 2, 3, 6, 78, 2] }])( - 'The elements of the array $arr remain the same (possibly with different order) after shuffling the array', - ({ arr }) => { - const copyArray = Array.from(arr); - shuffleArray(arr); - expect( - arr.every((elem) => { - return copyArray.includes(elem); - }) - ).toEqual(true); - } - ); -}); + test.each([{ arr: [1, 2, 3] }, { arr: [1, 2, 3, 6, 78, 2] }])( + 'The elements of the array $arr remain the same (possibly with different order) after shuffling the array', + ({ arr }) => { + const copyArray = Array.from(arr) + shuffleArray(arr) + expect( + arr.every((elem) => { + return copyArray.includes(elem) + }) + ).toEqual(true) + } + ) +}) diff --git a/package-lock.json b/package-lock.json index e26490a2..ad263744 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6465 +1,6487 @@ { - "name": "typescript", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "typescript", - "version": "1.0.0", - "license": "MIT", - "devDependencies": { - "@types/jest": "^29.0.3", - "husky": "^8.0.1", - "jest": "^29.0.3", - "ts-jest": "^29.0.2", - "ts-node": "^10.9.1" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", - "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", - "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.1", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.19.0", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", - "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.19.1", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", - "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", - "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.1", - "@babel/types": "^7.19.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.3.tgz", - "integrity": "sha512-cGg0r+klVHSYnfE977S9wmpuQ9L+iYuYgL+5bPXiUlUynLLYunRxswEmhBzvrSKGof5AKiHuTTmUKAqRcDY9dg==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.0.3", - "jest-util": "^29.0.3", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.3.tgz", - "integrity": "sha512-1d0hLbOrM1qQE3eP3DtakeMbKTcXiXP3afWxqz103xPyddS2NhnNghS7MaXx1dcDt4/6p4nlhmeILo2ofgi8cQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.0.3", - "@jest/reporters": "^29.0.3", - "@jest/test-result": "^29.0.3", - "@jest/transform": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.0.0", - "jest-config": "^29.0.3", - "jest-haste-map": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.3", - "jest-resolve-dependencies": "^29.0.3", - "jest-runner": "^29.0.3", - "jest-runtime": "^29.0.3", - "jest-snapshot": "^29.0.3", - "jest-util": "^29.0.3", - "jest-validate": "^29.0.3", - "jest-watcher": "^29.0.3", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.3", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.3.tgz", - "integrity": "sha512-iKl272NKxYNQNqXMQandAIwjhQaGw5uJfGXduu8dS9llHi8jV2ChWrtOAVPnMbaaoDhnI3wgUGNDvZgHeEJQCA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "jest-mock": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.3.tgz", - "integrity": "sha512-6W7K+fsI23FQ01H/BWccPyDZFrnU9QlzDcKOjrNVU5L8yUORFAJJIpmyxWPW70+X624KUNqzZwPThPMX28aXEQ==", - "dev": true, - "dependencies": { - "expect": "^29.0.3", - "jest-snapshot": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.3.tgz", - "integrity": "sha512-i1xUkau7K/63MpdwiRqaxgZOjxYs4f0WMTGJnYwUKubsNRZSeQbLorS7+I4uXVF9KQ5r61BUPAUMZ7Lf66l64Q==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.3.tgz", - "integrity": "sha512-tmbUIo03x0TdtcZCESQ0oQSakPCpo7+s6+9mU19dd71MptkP4zCwoeZqna23//pgbhtT1Wq02VmA9Z9cNtvtCQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.3", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^29.0.3", - "jest-mock": "^29.0.3", - "jest-util": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.3.tgz", - "integrity": "sha512-YqGHT65rFY2siPIHHFjuCGUsbzRjdqkwbat+Of6DmYRg5shIXXrLdZoVE/+TJ9O1dsKsFmYhU58JvIbZRU1Z9w==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.3", - "@jest/expect": "^29.0.3", - "@jest/types": "^29.0.3", - "jest-mock": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.3.tgz", - "integrity": "sha512-3+QU3d4aiyOWfmk1obDerie4XNCaD5Xo1IlKNde2yGEi02WQD+ZQD0i5Hgqm1e73sMV7kw6pMlCnprtEwEVwxw==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.0.3", - "@jest/test-result": "^29.0.3", - "@jest/transform": "^29.0.3", - "@jest/types": "^29.0.3", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.0.3", - "jest-util": "^29.0.3", - "jest-worker": "^29.0.3", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", - "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.3.tgz", - "integrity": "sha512-vViVnQjCgTmbhDKEonKJPtcFe9G/CJO4/Np4XwYJah+lF2oI7KKeRp8t1dFvv44wN2NdbDb/qC6pi++Vpp0Dlg==", - "dev": true, - "dependencies": { - "@jest/console": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.3.tgz", - "integrity": "sha512-Hf4+xYSWZdxTNnhDykr8JBs0yBN/nxOXyUQWfotBUqqy0LF9vzcFB0jm/EDNZCx587znLWTIgxcokW7WeZMobQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.0.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.3", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.3.tgz", - "integrity": "sha512-C5ihFTRYaGDbi/xbRQRdbo5ddGtI4VSpmL6AIcZxdhwLbXMa7PcXxxqyI91vGOFHnn5aVM3WYnYKCHEqmLVGzg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.3", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.3", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.3", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.0.3.tgz", - "integrity": "sha512-coBJmOQvurXjN1Hh5PzF7cmsod0zLIOXpP8KD161mqNlroMhLcwpODiEzi7ZsRl5Z/AIuxpeNm8DCl43F4kz8A==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.24.43", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.43.tgz", - "integrity": "sha512-1orQTvtazZmsPeBroJjysvsOQCYV2yjWlebkSY38pl5vr2tdLjEJ+LoxITlGNZaH2RE19WlAwQMkH/7C14wLfw==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "node_modules/@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", - "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.0.3.tgz", - "integrity": "sha512-F6ukyCTwbfsEX5F2YmVYmM5TcTHy1q9P5rWlRbrk56KyMh3v9xRGUO3aa8+SkvMi0SHXtASJv1283enXimC0Og==", - "dev": true, - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", - "dev": true - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", - "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/babel-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.3.tgz", - "integrity": "sha512-ApPyHSOhS/sVzwUOQIWJmdvDhBsMG01HX9z7ogtkp1TToHGGUWFlnXJUIzCgKPSfiYLn3ibipCYzsKSURHEwLg==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.0.3", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.0.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", - "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", - "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.0.2", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001412", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001412.tgz", - "integrity": "sha512-+TeEIee1gS5bYOiuf+PS/kp2mrXic37Hl66VY6EAfxasIk5fELTktK2oOezYed12H8w7jt3s512PpulQidPjwA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", - "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", - "dev": true - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", - "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.264", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.264.tgz", - "integrity": "sha512-AZ6ZRkucHOQT8wke50MktxtmcWZr67kE17X/nAXFf62NIdMdgY6xfsaJD5Szoy84lnkuPWH+4tTNE3s2+bPCiw==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.3.tgz", - "integrity": "sha512-t8l5DTws3212VbmPL+tBFXhjRHLmctHB0oQbL8eUc6S7NzZtYUhycrFO9mkxA0ZUC6FAWdNi7JchJSkODtcu1Q==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.0.3", - "jest-get-type": "^29.0.0", - "jest-matcher-utils": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-util": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/husky": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz", - "integrity": "sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==", - "dev": true, - "bin": { - "husky": "lib/bin.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.3.tgz", - "integrity": "sha512-ElgUtJBLgXM1E8L6K1RW1T96R897YY/3lRYqq9uVcPWtP2AAl/nQ16IYDh/FzQOOQ12VEuLdcPU83mbhG2C3PQ==", - "dev": true, - "dependencies": { - "@jest/core": "^29.0.3", - "@jest/types": "^29.0.3", - "import-local": "^3.0.2", - "jest-cli": "^29.0.3" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", - "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.3.tgz", - "integrity": "sha512-QeGzagC6Hw5pP+df1+aoF8+FBSgkPmraC1UdkeunWh0jmrp7wC0Hr6umdUAOELBQmxtKAOMNC3KAdjmCds92Zg==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.3", - "@jest/expect": "^29.0.3", - "@jest/test-result": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.0.3", - "jest-matcher-utils": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-runtime": "^29.0.3", - "jest-snapshot": "^29.0.3", - "jest-util": "^29.0.3", - "p-limit": "^3.1.0", - "pretty-format": "^29.0.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.3.tgz", - "integrity": "sha512-aUy9Gd/Kut1z80eBzG10jAn6BgS3BoBbXyv+uXEqBJ8wnnuZ5RpNfARoskSrTIy1GY4a8f32YGuCMwibtkl9CQ==", - "dev": true, - "dependencies": { - "@jest/core": "^29.0.3", - "@jest/test-result": "^29.0.3", - "@jest/types": "^29.0.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.0.3", - "jest-util": "^29.0.3", - "jest-validate": "^29.0.3", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.3.tgz", - "integrity": "sha512-U5qkc82HHVYe3fNu2CRXLN4g761Na26rWKf7CjM8LlZB3In1jadEkZdMwsE37rd9RSPV0NfYaCjHdk/gu3v+Ew==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.0.3", - "@jest/types": "^29.0.3", - "babel-jest": "^29.0.3", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.0.3", - "jest-environment-node": "^29.0.3", - "jest-get-type": "^29.0.0", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.3", - "jest-runner": "^29.0.3", - "jest-util": "^29.0.3", - "jest-validate": "^29.0.3", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.0.3", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.3.tgz", - "integrity": "sha512-+X/AIF5G/vX9fWK+Db9bi9BQas7M9oBME7egU7psbn4jlszLFCu0dW63UgeE6cs/GANq4fLaT+8sGHQQ0eCUfg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.0.0", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", - "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.3.tgz", - "integrity": "sha512-wILhZfESURHHBNvPMJ0lZlYZrvOQJxAo3wNHi+ycr90V7M+uGR9Gh4+4a/BmaZF0XTyZsk4OiYEf3GJN7Ltqzg==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "jest-util": "^29.0.3", - "pretty-format": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.3.tgz", - "integrity": "sha512-cdZqRCnmIlTXC+9vtvmfiY/40Cj6s2T0czXuq1whvQdmpzAnj4sbqVYuZ4zFHk766xTTJ+Ij3uUqkk8KCfXoyg==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.3", - "@jest/fake-timers": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "jest-mock": "^29.0.3", - "jest-util": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", - "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.3.tgz", - "integrity": "sha512-uMqR99+GuBHo0RjRhOE4iA6LmsxEwRdgiIAQgMU/wdT2XebsLDz5obIwLZm/Psj+GwSEQhw9AfAVKGYbh2G55A==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.3", - "jest-worker": "^29.0.3", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.3.tgz", - "integrity": "sha512-YfW/G63dAuiuQ3QmQlh8hnqLDe25WFY3eQhuc/Ev1AGmkw5zREblTh7TCSKLoheyggu6G9gxO2hY8p9o6xbaRQ==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.3.tgz", - "integrity": "sha512-RsR1+cZ6p1hDV4GSCQTg+9qjeotQCgkaleIKLK7dm+U4V/H2bWedU3RAtLm8+mANzZ7eDV33dMar4pejd7047w==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.0.3", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.3.tgz", - "integrity": "sha512-7T8JiUTtDfppojosORAflABfLsLKMLkBHSWkjNQrjIltGoDzNGn7wEPOSfjqYAGTYME65esQzMJxGDjuLBKdOg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.0.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.3.tgz", - "integrity": "sha512-ort9pYowltbcrCVR43wdlqfAiFJXBx8l4uJDsD8U72LgBcetvEp+Qxj1W9ZYgMRoeAo+ov5cnAGF2B6+Oth+ww==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.3", - "@types/node": "*" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.3.tgz", - "integrity": "sha512-toVkia85Y/BPAjJasTC9zIPY6MmVXQPtrCk8SmiheC4MwVFE/CMFlOtMN6jrwPMC6TtNh8+sTMllasFeu1wMPg==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.3", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.0.3", - "jest-validate": "^29.0.3", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.3.tgz", - "integrity": "sha512-KzuBnXqNvbuCdoJpv8EanbIGObk7vUBNt/PwQPPx2aMhlv/jaXpUJsqWYRpP/0a50faMBY7WFFP8S3/CCzwfDw==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.0.0", - "jest-snapshot": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.3.tgz", - "integrity": "sha512-Usu6VlTOZlCZoNuh3b2Tv/yzDpKqtiNAetG9t3kJuHfUyVMNW7ipCCJOUojzKkjPoaN7Bl1f7Buu6PE0sGpQxw==", - "dev": true, - "dependencies": { - "@jest/console": "^29.0.3", - "@jest/environment": "^29.0.3", - "@jest/test-result": "^29.0.3", - "@jest/transform": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.0.0", - "jest-environment-node": "^29.0.3", - "jest-haste-map": "^29.0.3", - "jest-leak-detector": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-resolve": "^29.0.3", - "jest-runtime": "^29.0.3", - "jest-util": "^29.0.3", - "jest-watcher": "^29.0.3", - "jest-worker": "^29.0.3", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.3.tgz", - "integrity": "sha512-12gZXRQ7ozEeEHKTY45a+YLqzNDR/x4c//X6AqwKwKJPpWM8FY4vwn4VQJOcLRS3Nd1fWwgP7LU4SoynhuUMHQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.0.3", - "@jest/fake-timers": "^29.0.3", - "@jest/globals": "^29.0.3", - "@jest/source-map": "^29.0.0", - "@jest/test-result": "^29.0.3", - "@jest/transform": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-mock": "^29.0.3", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.3", - "jest-snapshot": "^29.0.3", - "jest-util": "^29.0.3", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.3.tgz", - "integrity": "sha512-52q6JChm04U3deq+mkQ7R/7uy7YyfVIrebMi6ZkBoDJ85yEjm/sJwdr1P0LOIEHmpyLlXrxy3QP0Zf5J2kj0ew==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.0.3", - "@jest/transform": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.0.3", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.0.3", - "jest-get-type": "^29.0.0", - "jest-haste-map": "^29.0.3", - "jest-matcher-utils": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-util": "^29.0.3", - "natural-compare": "^1.4.0", - "pretty-format": "^29.0.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-util": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.0.3.tgz", - "integrity": "sha512-Q0xaG3YRG8QiTC4R6fHjHQPaPpz9pJBEi0AeOE4mQh/FuWOijFjGXMMOfQEaU9i3z76cNR7FobZZUQnL6IyfdQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.3.tgz", - "integrity": "sha512-OebiqqT6lK8cbMPtrSoS3aZP4juID762lZvpf1u+smZnwTEBCBInan0GAIIhv36MxGaJvmq5uJm7dl5gVt+Zrw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.0.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "leven": "^3.1.0", - "pretty-format": "^29.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.3.tgz", - "integrity": "sha512-tQX9lU91A+9tyUQKUMp0Ns8xAcdhC9fo73eqA3LFxP2bSgiF49TNcc+vf3qgGYYK9qRjFpXW9+4RgF/mbxyOOw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^29.0.3", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.3.tgz", - "integrity": "sha512-Tl/YWUugQOjoTYwjKdfJWkSOfhufJHO5LhXTSZC3TRoQKO+fuXnZAdoXXBlpLXKGODBL3OvdUasfDD4PcMe6ng==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-format": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.3.tgz", - "integrity": "sha512-cHudsvQr1K5vNVLbvYF/nv3Qy/F/BcEKxGuIeMiVMRHxPOO1RxXooP8g/ZrwAp7Dx+KdMZoOc7NxLHhMrP2f9Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "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, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.2.tgz", - "integrity": "sha512-P03IUItnAjG6RkJXtjjD5pu0TryQFOwcb1YKmW63rO19V0UFqL3wiXZrmR5D7qYjI98btzIOAcYafLZ0GHAcQg==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", - "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "name": "typescript", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "typescript", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@types/jest": "^29.0.3", + "husky": "^8.0.1", + "jest": "^29.0.3", + "prettier": "^3.2.5", + "ts-jest": "^29.0.2", + "ts-node": "^10.9.1" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", + "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", + "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.0", + "@babel/helper-compilation-targets": "^7.19.1", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", + "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.19.0", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", + "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.19.1", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", + "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", + "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", + "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", + "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.19.1", + "@babel/types": "^7.19.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", + "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.3.tgz", + "integrity": "sha512-cGg0r+klVHSYnfE977S9wmpuQ9L+iYuYgL+5bPXiUlUynLLYunRxswEmhBzvrSKGof5AKiHuTTmUKAqRcDY9dg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.3.tgz", + "integrity": "sha512-1d0hLbOrM1qQE3eP3DtakeMbKTcXiXP3afWxqz103xPyddS2NhnNghS7MaXx1dcDt4/6p4nlhmeILo2ofgi8cQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.0.3", + "@jest/reporters": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.0.0", + "jest-config": "^29.0.3", + "jest-haste-map": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-resolve-dependencies": "^29.0.3", + "jest-runner": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "jest-watcher": "^29.0.3", + "micromatch": "^4.0.4", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.3.tgz", + "integrity": "sha512-iKl272NKxYNQNqXMQandAIwjhQaGw5uJfGXduu8dS9llHi8jV2ChWrtOAVPnMbaaoDhnI3wgUGNDvZgHeEJQCA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "jest-mock": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.3.tgz", + "integrity": "sha512-6W7K+fsI23FQ01H/BWccPyDZFrnU9QlzDcKOjrNVU5L8yUORFAJJIpmyxWPW70+X624KUNqzZwPThPMX28aXEQ==", + "dev": true, + "dependencies": { + "expect": "^29.0.3", + "jest-snapshot": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.3.tgz", + "integrity": "sha512-i1xUkau7K/63MpdwiRqaxgZOjxYs4f0WMTGJnYwUKubsNRZSeQbLorS7+I4uXVF9KQ5r61BUPAUMZ7Lf66l64Q==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.3.tgz", + "integrity": "sha512-tmbUIo03x0TdtcZCESQ0oQSakPCpo7+s6+9mU19dd71MptkP4zCwoeZqna23//pgbhtT1Wq02VmA9Z9cNtvtCQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^29.0.3", + "jest-mock": "^29.0.3", + "jest-util": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.3.tgz", + "integrity": "sha512-YqGHT65rFY2siPIHHFjuCGUsbzRjdqkwbat+Of6DmYRg5shIXXrLdZoVE/+TJ9O1dsKsFmYhU58JvIbZRU1Z9w==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.0.3", + "@jest/expect": "^29.0.3", + "@jest/types": "^29.0.3", + "jest-mock": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.3.tgz", + "integrity": "sha512-3+QU3d4aiyOWfmk1obDerie4XNCaD5Xo1IlKNde2yGEi02WQD+ZQD0i5Hgqm1e73sMV7kw6pMlCnprtEwEVwxw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "jest-worker": "^29.0.3", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", + "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.3.tgz", + "integrity": "sha512-vViVnQjCgTmbhDKEonKJPtcFe9G/CJO4/Np4XwYJah+lF2oI7KKeRp8t1dFvv44wN2NdbDb/qC6pi++Vpp0Dlg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.3.tgz", + "integrity": "sha512-Hf4+xYSWZdxTNnhDykr8JBs0yBN/nxOXyUQWfotBUqqy0LF9vzcFB0jm/EDNZCx587znLWTIgxcokW7WeZMobQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.0.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.3.tgz", + "integrity": "sha512-C5ihFTRYaGDbi/xbRQRdbo5ddGtI4VSpmL6AIcZxdhwLbXMa7PcXxxqyI91vGOFHnn5aVM3WYnYKCHEqmLVGzg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.0.3", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.0.3.tgz", + "integrity": "sha512-coBJmOQvurXjN1Hh5PzF7cmsod0zLIOXpP8KD161mqNlroMhLcwpODiEzi7ZsRl5Z/AIuxpeNm8DCl43F4kz8A==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.43", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.43.tgz", + "integrity": "sha512-1orQTvtazZmsPeBroJjysvsOQCYV2yjWlebkSY38pl5vr2tdLjEJ+LoxITlGNZaH2RE19WlAwQMkH/7C14wLfw==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", + "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.0.3.tgz", + "integrity": "sha512-F6ukyCTwbfsEX5F2YmVYmM5TcTHy1q9P5rWlRbrk56KyMh3v9xRGUO3aa8+SkvMi0SHXtASJv1283enXimC0Og==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/node": { + "version": "18.7.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", + "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/babel-jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.3.tgz", + "integrity": "sha512-ApPyHSOhS/sVzwUOQIWJmdvDhBsMG01HX9z7ogtkp1TToHGGUWFlnXJUIzCgKPSfiYLn3ibipCYzsKSURHEwLg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.0.3", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.0.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", + "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", + "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.0.2", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001412", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001412.tgz", + "integrity": "sha512-+TeEIee1gS5bYOiuf+PS/kp2mrXic37Hl66VY6EAfxasIk5fELTktK2oOezYed12H8w7jt3s512PpulQidPjwA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", + "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", + "dev": true + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } + } }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", - "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", - "dev": true - }, - "@babel/core": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", - "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.1", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - } - }, - "@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", - "dev": true, - "requires": { - "@babel/types": "^7.19.0", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", - "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.19.1", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "dev": true, - "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true - }, - "@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "dev": true, - "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", - "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - } - }, - "@babel/traverse": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", - "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.1", - "@babel/types": "^7.19.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } - } - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.3.tgz", - "integrity": "sha512-cGg0r+klVHSYnfE977S9wmpuQ9L+iYuYgL+5bPXiUlUynLLYunRxswEmhBzvrSKGof5AKiHuTTmUKAqRcDY9dg==", - "dev": true, - "requires": { - "@jest/types": "^29.0.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.0.3", - "jest-util": "^29.0.3", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.3.tgz", - "integrity": "sha512-1d0hLbOrM1qQE3eP3DtakeMbKTcXiXP3afWxqz103xPyddS2NhnNghS7MaXx1dcDt4/6p4nlhmeILo2ofgi8cQ==", - "dev": true, - "requires": { - "@jest/console": "^29.0.3", - "@jest/reporters": "^29.0.3", - "@jest/test-result": "^29.0.3", - "@jest/transform": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.0.0", - "jest-config": "^29.0.3", - "jest-haste-map": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.3", - "jest-resolve-dependencies": "^29.0.3", - "jest-runner": "^29.0.3", - "jest-runtime": "^29.0.3", - "jest-snapshot": "^29.0.3", - "jest-util": "^29.0.3", - "jest-validate": "^29.0.3", - "jest-watcher": "^29.0.3", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.3", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "@jest/environment": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.3.tgz", - "integrity": "sha512-iKl272NKxYNQNqXMQandAIwjhQaGw5uJfGXduu8dS9llHi8jV2ChWrtOAVPnMbaaoDhnI3wgUGNDvZgHeEJQCA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "jest-mock": "^29.0.3" - } - }, - "@jest/expect": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.3.tgz", - "integrity": "sha512-6W7K+fsI23FQ01H/BWccPyDZFrnU9QlzDcKOjrNVU5L8yUORFAJJIpmyxWPW70+X624KUNqzZwPThPMX28aXEQ==", - "dev": true, - "requires": { - "expect": "^29.0.3", - "jest-snapshot": "^29.0.3" - } - }, - "@jest/expect-utils": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.3.tgz", - "integrity": "sha512-i1xUkau7K/63MpdwiRqaxgZOjxYs4f0WMTGJnYwUKubsNRZSeQbLorS7+I4uXVF9KQ5r61BUPAUMZ7Lf66l64Q==", - "dev": true, - "requires": { - "jest-get-type": "^29.0.0" - } - }, - "@jest/fake-timers": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.3.tgz", - "integrity": "sha512-tmbUIo03x0TdtcZCESQ0oQSakPCpo7+s6+9mU19dd71MptkP4zCwoeZqna23//pgbhtT1Wq02VmA9Z9cNtvtCQ==", - "dev": true, - "requires": { - "@jest/types": "^29.0.3", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^29.0.3", - "jest-mock": "^29.0.3", - "jest-util": "^29.0.3" - } - }, - "@jest/globals": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.3.tgz", - "integrity": "sha512-YqGHT65rFY2siPIHHFjuCGUsbzRjdqkwbat+Of6DmYRg5shIXXrLdZoVE/+TJ9O1dsKsFmYhU58JvIbZRU1Z9w==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.3", - "@jest/expect": "^29.0.3", - "@jest/types": "^29.0.3", - "jest-mock": "^29.0.3" - } - }, - "@jest/reporters": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.3.tgz", - "integrity": "sha512-3+QU3d4aiyOWfmk1obDerie4XNCaD5Xo1IlKNde2yGEi02WQD+ZQD0i5Hgqm1e73sMV7kw6pMlCnprtEwEVwxw==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.0.3", - "@jest/test-result": "^29.0.3", - "@jest/transform": "^29.0.3", - "@jest/types": "^29.0.3", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.0.3", - "jest-util": "^29.0.3", - "jest-worker": "^29.0.3", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.1" - } - }, - "@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.24.1" - } - }, - "@jest/source-map": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", - "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.3.tgz", - "integrity": "sha512-vViVnQjCgTmbhDKEonKJPtcFe9G/CJO4/Np4XwYJah+lF2oI7KKeRp8t1dFvv44wN2NdbDb/qC6pi++Vpp0Dlg==", - "dev": true, - "requires": { - "@jest/console": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.3.tgz", - "integrity": "sha512-Hf4+xYSWZdxTNnhDykr8JBs0yBN/nxOXyUQWfotBUqqy0LF9vzcFB0jm/EDNZCx587znLWTIgxcokW7WeZMobQ==", - "dev": true, - "requires": { - "@jest/test-result": "^29.0.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.3", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.3.tgz", - "integrity": "sha512-C5ihFTRYaGDbi/xbRQRdbo5ddGtI4VSpmL6AIcZxdhwLbXMa7PcXxxqyI91vGOFHnn5aVM3WYnYKCHEqmLVGzg==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.0.3", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.3", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.3", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - } - }, - "@jest/types": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.0.3.tgz", - "integrity": "sha512-coBJmOQvurXjN1Hh5PzF7cmsod0zLIOXpP8KD161mqNlroMhLcwpODiEzi7ZsRl5Z/AIuxpeNm8DCl43F4kz8A==", - "dev": true, - "requires": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@sinclair/typebox": { - "version": "0.24.43", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.43.tgz", - "integrity": "sha512-1orQTvtazZmsPeBroJjysvsOQCYV2yjWlebkSY38pl5vr2tdLjEJ+LoxITlGNZaH2RE19WlAwQMkH/7C14wLfw==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", - "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.0.3.tgz", - "integrity": "sha512-F6ukyCTwbfsEX5F2YmVYmM5TcTHy1q9P5rWlRbrk56KyMh3v9xRGUO3aa8+SkvMi0SHXtASJv1283enXimC0Og==", - "dev": true, - "requires": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", + "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.264", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.264.tgz", + "integrity": "sha512-AZ6ZRkucHOQT8wke50MktxtmcWZr67kE17X/nAXFf62NIdMdgY6xfsaJD5Szoy84lnkuPWH+4tTNE3s2+bPCiw==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.3.tgz", + "integrity": "sha512-t8l5DTws3212VbmPL+tBFXhjRHLmctHB0oQbL8eUc6S7NzZtYUhycrFO9mkxA0ZUC6FAWdNi7JchJSkODtcu1Q==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/husky": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz", + "integrity": "sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.3.tgz", + "integrity": "sha512-ElgUtJBLgXM1E8L6K1RW1T96R897YY/3lRYqq9uVcPWtP2AAl/nQ16IYDh/FzQOOQ12VEuLdcPU83mbhG2C3PQ==", + "dev": true, + "dependencies": { + "@jest/core": "^29.0.3", + "@jest/types": "^29.0.3", + "import-local": "^3.0.2", + "jest-cli": "^29.0.3" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", + "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.3.tgz", + "integrity": "sha512-QeGzagC6Hw5pP+df1+aoF8+FBSgkPmraC1UdkeunWh0jmrp7wC0Hr6umdUAOELBQmxtKAOMNC3KAdjmCds92Zg==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.0.3", + "@jest/expect": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.0.3", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "p-limit": "^3.1.0", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.3.tgz", + "integrity": "sha512-aUy9Gd/Kut1z80eBzG10jAn6BgS3BoBbXyv+uXEqBJ8wnnuZ5RpNfARoskSrTIy1GY4a8f32YGuCMwibtkl9CQ==", + "dev": true, + "dependencies": { + "@jest/core": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.3.tgz", + "integrity": "sha512-U5qkc82HHVYe3fNu2CRXLN4g761Na26rWKf7CjM8LlZB3In1jadEkZdMwsE37rd9RSPV0NfYaCjHdk/gu3v+Ew==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.0.3", + "@jest/types": "^29.0.3", + "babel-jest": "^29.0.3", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.0.3", + "jest-environment-node": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-runner": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { "@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", - "dev": true - }, - "@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/yargs": { - "version": "17.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", - "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "babel-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.3.tgz", - "integrity": "sha512-ApPyHSOhS/sVzwUOQIWJmdvDhBsMG01HX9z7ogtkp1TToHGGUWFlnXJUIzCgKPSfiYLn3ibipCYzsKSURHEwLg==", - "dev": true, - "requires": { - "@jest/transform": "^29.0.3", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.0.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", - "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", - "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^29.0.2", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } + "optional": true }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.3.tgz", + "integrity": "sha512-+X/AIF5G/vX9fWK+Db9bi9BQas7M9oBME7egU7psbn4jlszLFCu0dW63UgeE6cs/GANq4fLaT+8sGHQQ0eCUfg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.0.0", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", + "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.3.tgz", + "integrity": "sha512-wILhZfESURHHBNvPMJ0lZlYZrvOQJxAo3wNHi+ycr90V7M+uGR9Gh4+4a/BmaZF0XTyZsk4OiYEf3GJN7Ltqzg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.0.0", + "jest-util": "^29.0.3", + "pretty-format": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.3.tgz", + "integrity": "sha512-cdZqRCnmIlTXC+9vtvmfiY/40Cj6s2T0czXuq1whvQdmpzAnj4sbqVYuZ4zFHk766xTTJ+Ij3uUqkk8KCfXoyg==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.0.3", + "@jest/fake-timers": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "jest-mock": "^29.0.3", + "jest-util": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", + "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.3.tgz", + "integrity": "sha512-uMqR99+GuBHo0RjRhOE4iA6LmsxEwRdgiIAQgMU/wdT2XebsLDz5obIwLZm/Psj+GwSEQhw9AfAVKGYbh2G55A==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.3", + "jest-worker": "^29.0.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.3.tgz", + "integrity": "sha512-YfW/G63dAuiuQ3QmQlh8hnqLDe25WFY3eQhuc/Ev1AGmkw5zREblTh7TCSKLoheyggu6G9gxO2hY8p9o6xbaRQ==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.3.tgz", + "integrity": "sha512-RsR1+cZ6p1hDV4GSCQTg+9qjeotQCgkaleIKLK7dm+U4V/H2bWedU3RAtLm8+mANzZ7eDV33dMar4pejd7047w==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.0.3", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.3.tgz", + "integrity": "sha512-7T8JiUTtDfppojosORAflABfLsLKMLkBHSWkjNQrjIltGoDzNGn7wEPOSfjqYAGTYME65esQzMJxGDjuLBKdOg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.0.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.3.tgz", + "integrity": "sha512-ort9pYowltbcrCVR43wdlqfAiFJXBx8l4uJDsD8U72LgBcetvEp+Qxj1W9ZYgMRoeAo+ov5cnAGF2B6+Oth+ww==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "@types/node": "*" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", + "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.3.tgz", + "integrity": "sha512-toVkia85Y/BPAjJasTC9zIPY6MmVXQPtrCk8SmiheC4MwVFE/CMFlOtMN6jrwPMC6TtNh8+sTMllasFeu1wMPg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.3.tgz", + "integrity": "sha512-KzuBnXqNvbuCdoJpv8EanbIGObk7vUBNt/PwQPPx2aMhlv/jaXpUJsqWYRpP/0a50faMBY7WFFP8S3/CCzwfDw==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.0.0", + "jest-snapshot": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.3.tgz", + "integrity": "sha512-Usu6VlTOZlCZoNuh3b2Tv/yzDpKqtiNAetG9t3kJuHfUyVMNW7ipCCJOUojzKkjPoaN7Bl1f7Buu6PE0sGpQxw==", + "dev": true, + "dependencies": { + "@jest/console": "^29.0.3", + "@jest/environment": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.0.0", + "jest-environment-node": "^29.0.3", + "jest-haste-map": "^29.0.3", + "jest-leak-detector": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-resolve": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-util": "^29.0.3", + "jest-watcher": "^29.0.3", + "jest-worker": "^29.0.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.3.tgz", + "integrity": "sha512-12gZXRQ7ozEeEHKTY45a+YLqzNDR/x4c//X6AqwKwKJPpWM8FY4vwn4VQJOcLRS3Nd1fWwgP7LU4SoynhuUMHQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.0.3", + "@jest/fake-timers": "^29.0.3", + "@jest/globals": "^29.0.3", + "@jest/source-map": "^29.0.0", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-mock": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.3.tgz", + "integrity": "sha512-52q6JChm04U3deq+mkQ7R/7uy7YyfVIrebMi6ZkBoDJ85yEjm/sJwdr1P0LOIEHmpyLlXrxy3QP0Zf5J2kj0ew==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.0.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-haste-map": "^29.0.3", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "natural-compare": "^1.4.0", + "pretty-format": "^29.0.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.0.3.tgz", + "integrity": "sha512-Q0xaG3YRG8QiTC4R6fHjHQPaPpz9pJBEi0AeOE4mQh/FuWOijFjGXMMOfQEaU9i3z76cNR7FobZZUQnL6IyfdQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.3.tgz", + "integrity": "sha512-OebiqqT6lK8cbMPtrSoS3aZP4juID762lZvpf1u+smZnwTEBCBInan0GAIIhv36MxGaJvmq5uJm7dl5gVt+Zrw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.0.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.0.0", + "leven": "^3.1.0", + "pretty-format": "^29.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.3.tgz", + "integrity": "sha512-tQX9lU91A+9tyUQKUMp0Ns8xAcdhC9fo73eqA3LFxP2bSgiF49TNcc+vf3qgGYYK9qRjFpXW9+4RgF/mbxyOOw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^29.0.3", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.3.tgz", + "integrity": "sha512-Tl/YWUugQOjoTYwjKdfJWkSOfhufJHO5LhXTSZC3TRoQKO+fuXnZAdoXXBlpLXKGODBL3OvdUasfDD4PcMe6ng==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.3.tgz", + "integrity": "sha512-cHudsvQr1K5vNVLbvYF/nv3Qy/F/BcEKxGuIeMiVMRHxPOO1RxXooP8g/ZrwAp7Dx+KdMZoOc7NxLHhMrP2f9Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-jest": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.2.tgz", + "integrity": "sha512-P03IUItnAjG6RkJXtjjD5pu0TryQFOwcb1YKmW63rO19V0UFqL3wiXZrmR5D7qYjI98btzIOAcYafLZ0GHAcQg==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "@jest/types": { + "optional": true }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true + "babel-jest": { + "optional": true }, - "caniuse-lite": { - "version": "1.0.30001412", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001412.tgz", - "integrity": "sha512-+TeEIee1gS5bYOiuf+PS/kp2mrXic37Hl66VY6EAfxasIk5fELTktK2oOezYed12H8w7jt3s512PpulQidPjwA==", - "dev": true + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", + "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", + "dev": true + }, + "@babel/core": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", + "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.0", + "@babel/helper-compilation-targets": "^7.19.1", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + } + }, + "@babel/generator": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", + "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "dev": true, + "requires": { + "@babel/types": "^7.19.0", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", + "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.19.1", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", + "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", + "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } }, "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "ci-info": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", - "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } }, "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } }, "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "diff-sequences": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", - "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.4.264", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.264.tgz", - "integrity": "sha512-AZ6ZRkucHOQT8wke50MktxtmcWZr67kE17X/nAXFf62NIdMdgY6xfsaJD5Szoy84lnkuPWH+4tTNE3s2+bPCiw==", - "dev": true - }, - "emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true - }, - "expect": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.3.tgz", - "integrity": "sha512-t8l5DTws3212VbmPL+tBFXhjRHLmctHB0oQbL8eUc6S7NzZtYUhycrFO9mkxA0ZUC6FAWdNi7JchJSkODtcu1Q==", - "dev": true, - "requires": { - "@jest/expect-utils": "^29.0.3", - "jest-get-type": "^29.0.0", - "jest-matcher-utils": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-util": "^29.0.3" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true }, "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "husky": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz", - "integrity": "sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==", - "dev": true - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "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 - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.3.tgz", - "integrity": "sha512-ElgUtJBLgXM1E8L6K1RW1T96R897YY/3lRYqq9uVcPWtP2AAl/nQ16IYDh/FzQOOQ12VEuLdcPU83mbhG2C3PQ==", - "dev": true, - "requires": { - "@jest/core": "^29.0.3", - "@jest/types": "^29.0.3", - "import-local": "^3.0.2", - "jest-cli": "^29.0.3" - } - }, - "jest-changed-files": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", - "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - } - }, - "jest-circus": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.3.tgz", - "integrity": "sha512-QeGzagC6Hw5pP+df1+aoF8+FBSgkPmraC1UdkeunWh0jmrp7wC0Hr6umdUAOELBQmxtKAOMNC3KAdjmCds92Zg==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.3", - "@jest/expect": "^29.0.3", - "@jest/test-result": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.0.3", - "jest-matcher-utils": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-runtime": "^29.0.3", - "jest-snapshot": "^29.0.3", - "jest-util": "^29.0.3", - "p-limit": "^3.1.0", - "pretty-format": "^29.0.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-cli": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.3.tgz", - "integrity": "sha512-aUy9Gd/Kut1z80eBzG10jAn6BgS3BoBbXyv+uXEqBJ8wnnuZ5RpNfARoskSrTIy1GY4a8f32YGuCMwibtkl9CQ==", - "dev": true, - "requires": { - "@jest/core": "^29.0.3", - "@jest/test-result": "^29.0.3", - "@jest/types": "^29.0.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.0.3", - "jest-util": "^29.0.3", - "jest-validate": "^29.0.3", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - } - }, - "jest-config": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.3.tgz", - "integrity": "sha512-U5qkc82HHVYe3fNu2CRXLN4g761Na26rWKf7CjM8LlZB3In1jadEkZdMwsE37rd9RSPV0NfYaCjHdk/gu3v+Ew==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.0.3", - "@jest/types": "^29.0.3", - "babel-jest": "^29.0.3", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.0.3", - "jest-environment-node": "^29.0.3", - "jest-get-type": "^29.0.0", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.3", - "jest-runner": "^29.0.3", - "jest-util": "^29.0.3", - "jest-validate": "^29.0.3", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.0.3", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - } - }, - "jest-diff": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.3.tgz", - "integrity": "sha512-+X/AIF5G/vX9fWK+Db9bi9BQas7M9oBME7egU7psbn4jlszLFCu0dW63UgeE6cs/GANq4fLaT+8sGHQQ0eCUfg==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.0.0", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.3" - } - }, - "jest-docblock": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", - "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.3.tgz", - "integrity": "sha512-wILhZfESURHHBNvPMJ0lZlYZrvOQJxAo3wNHi+ycr90V7M+uGR9Gh4+4a/BmaZF0XTyZsk4OiYEf3GJN7Ltqzg==", - "dev": true, - "requires": { - "@jest/types": "^29.0.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "jest-util": "^29.0.3", - "pretty-format": "^29.0.3" - } - }, - "jest-environment-node": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.3.tgz", - "integrity": "sha512-cdZqRCnmIlTXC+9vtvmfiY/40Cj6s2T0czXuq1whvQdmpzAnj4sbqVYuZ4zFHk766xTTJ+Ij3uUqkk8KCfXoyg==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.3", - "@jest/fake-timers": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "jest-mock": "^29.0.3", - "jest-util": "^29.0.3" - } - }, - "jest-get-type": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", - "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", - "dev": true - }, - "jest-haste-map": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.3.tgz", - "integrity": "sha512-uMqR99+GuBHo0RjRhOE4iA6LmsxEwRdgiIAQgMU/wdT2XebsLDz5obIwLZm/Psj+GwSEQhw9AfAVKGYbh2G55A==", - "dev": true, - "requires": { - "@jest/types": "^29.0.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.0.0", - "jest-util": "^29.0.3", - "jest-worker": "^29.0.3", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-leak-detector": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.3.tgz", - "integrity": "sha512-YfW/G63dAuiuQ3QmQlh8hnqLDe25WFY3eQhuc/Ev1AGmkw5zREblTh7TCSKLoheyggu6G9gxO2hY8p9o6xbaRQ==", - "dev": true, - "requires": { - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.3" - } - }, - "jest-matcher-utils": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.3.tgz", - "integrity": "sha512-RsR1+cZ6p1hDV4GSCQTg+9qjeotQCgkaleIKLK7dm+U4V/H2bWedU3RAtLm8+mANzZ7eDV33dMar4pejd7047w==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.0.3", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.0.3" - } - }, - "jest-message-util": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.3.tgz", - "integrity": "sha512-7T8JiUTtDfppojosORAflABfLsLKMLkBHSWkjNQrjIltGoDzNGn7wEPOSfjqYAGTYME65esQzMJxGDjuLBKdOg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.0.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.0.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.3.tgz", - "integrity": "sha512-ort9pYowltbcrCVR43wdlqfAiFJXBx8l4uJDsD8U72LgBcetvEp+Qxj1W9ZYgMRoeAo+ov5cnAGF2B6+Oth+ww==", - "dev": true, - "requires": { - "@jest/types": "^29.0.3", - "@types/node": "*" - } - }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", - "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", - "dev": true - }, - "jest-resolve": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.3.tgz", - "integrity": "sha512-toVkia85Y/BPAjJasTC9zIPY6MmVXQPtrCk8SmiheC4MwVFE/CMFlOtMN6jrwPMC6TtNh8+sTMllasFeu1wMPg==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.3", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.0.3", - "jest-validate": "^29.0.3", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - } - }, - "jest-resolve-dependencies": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.3.tgz", - "integrity": "sha512-KzuBnXqNvbuCdoJpv8EanbIGObk7vUBNt/PwQPPx2aMhlv/jaXpUJsqWYRpP/0a50faMBY7WFFP8S3/CCzwfDw==", - "dev": true, - "requires": { - "jest-regex-util": "^29.0.0", - "jest-snapshot": "^29.0.3" - } - }, - "jest-runner": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.3.tgz", - "integrity": "sha512-Usu6VlTOZlCZoNuh3b2Tv/yzDpKqtiNAetG9t3kJuHfUyVMNW7ipCCJOUojzKkjPoaN7Bl1f7Buu6PE0sGpQxw==", - "dev": true, - "requires": { - "@jest/console": "^29.0.3", - "@jest/environment": "^29.0.3", - "@jest/test-result": "^29.0.3", - "@jest/transform": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.0.0", - "jest-environment-node": "^29.0.3", - "jest-haste-map": "^29.0.3", - "jest-leak-detector": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-resolve": "^29.0.3", - "jest-runtime": "^29.0.3", - "jest-util": "^29.0.3", - "jest-watcher": "^29.0.3", - "jest-worker": "^29.0.3", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - } - }, - "jest-runtime": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.3.tgz", - "integrity": "sha512-12gZXRQ7ozEeEHKTY45a+YLqzNDR/x4c//X6AqwKwKJPpWM8FY4vwn4VQJOcLRS3Nd1fWwgP7LU4SoynhuUMHQ==", - "dev": true, - "requires": { - "@jest/environment": "^29.0.3", - "@jest/fake-timers": "^29.0.3", - "@jest/globals": "^29.0.3", - "@jest/source-map": "^29.0.0", - "@jest/test-result": "^29.0.3", - "@jest/transform": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-mock": "^29.0.3", - "jest-regex-util": "^29.0.0", - "jest-resolve": "^29.0.3", - "jest-snapshot": "^29.0.3", - "jest-util": "^29.0.3", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - } - }, - "jest-snapshot": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.3.tgz", - "integrity": "sha512-52q6JChm04U3deq+mkQ7R/7uy7YyfVIrebMi6ZkBoDJ85yEjm/sJwdr1P0LOIEHmpyLlXrxy3QP0Zf5J2kj0ew==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.0.3", - "@jest/transform": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.0.3", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.0.3", - "jest-get-type": "^29.0.0", - "jest-haste-map": "^29.0.3", - "jest-matcher-utils": "^29.0.3", - "jest-message-util": "^29.0.3", - "jest-util": "^29.0.3", - "natural-compare": "^1.4.0", - "pretty-format": "^29.0.3", - "semver": "^7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "jest-util": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.0.3.tgz", - "integrity": "sha512-Q0xaG3YRG8QiTC4R6fHjHQPaPpz9pJBEi0AeOE4mQh/FuWOijFjGXMMOfQEaU9i3z76cNR7FobZZUQnL6IyfdQ==", - "dev": true, - "requires": { - "@jest/types": "^29.0.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "jest-validate": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.3.tgz", - "integrity": "sha512-OebiqqT6lK8cbMPtrSoS3aZP4juID762lZvpf1u+smZnwTEBCBInan0GAIIhv36MxGaJvmq5uJm7dl5gVt+Zrw==", - "dev": true, - "requires": { - "@jest/types": "^29.0.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.0.0", - "leven": "^3.1.0", - "pretty-format": "^29.0.3" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.3.tgz", - "integrity": "sha512-tQX9lU91A+9tyUQKUMp0Ns8xAcdhC9fo73eqA3LFxP2bSgiF49TNcc+vf3qgGYYK9qRjFpXW9+4RgF/mbxyOOw==", - "dev": true, - "requires": { - "@jest/test-result": "^29.0.3", - "@jest/types": "^29.0.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^29.0.3", - "string-length": "^4.0.1" - } - }, - "jest-worker": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.3.tgz", - "integrity": "sha512-Tl/YWUugQOjoTYwjKdfJWkSOfhufJHO5LhXTSZC3TRoQKO+fuXnZAdoXXBlpLXKGODBL3OvdUasfDD4PcMe6ng==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - }, - "dependencies": { - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - } - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "pretty-format": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.3.tgz", - "integrity": "sha512-cHudsvQr1K5vNVLbvYF/nv3Qy/F/BcEKxGuIeMiVMRHxPOO1RxXooP8g/ZrwAp7Dx+KdMZoOc7NxLHhMrP2f9Q==", - "dev": true, - "requires": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", + "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@babel/traverse": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", + "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.19.1", + "@babel/types": "^7.19.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", + "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.0.3.tgz", + "integrity": "sha512-cGg0r+klVHSYnfE977S9wmpuQ9L+iYuYgL+5bPXiUlUynLLYunRxswEmhBzvrSKGof5AKiHuTTmUKAqRcDY9dg==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.0.3.tgz", + "integrity": "sha512-1d0hLbOrM1qQE3eP3DtakeMbKTcXiXP3afWxqz103xPyddS2NhnNghS7MaXx1dcDt4/6p4nlhmeILo2ofgi8cQ==", + "dev": true, + "requires": { + "@jest/console": "^29.0.3", + "@jest/reporters": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.0.0", + "jest-config": "^29.0.3", + "jest-haste-map": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-resolve-dependencies": "^29.0.3", + "jest-runner": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "jest-watcher": "^29.0.3", + "micromatch": "^4.0.4", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.0.3.tgz", + "integrity": "sha512-iKl272NKxYNQNqXMQandAIwjhQaGw5uJfGXduu8dS9llHi8jV2ChWrtOAVPnMbaaoDhnI3wgUGNDvZgHeEJQCA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "jest-mock": "^29.0.3" + } + }, + "@jest/expect": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.0.3.tgz", + "integrity": "sha512-6W7K+fsI23FQ01H/BWccPyDZFrnU9QlzDcKOjrNVU5L8yUORFAJJIpmyxWPW70+X624KUNqzZwPThPMX28aXEQ==", + "dev": true, + "requires": { + "expect": "^29.0.3", + "jest-snapshot": "^29.0.3" + } + }, + "@jest/expect-utils": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.0.3.tgz", + "integrity": "sha512-i1xUkau7K/63MpdwiRqaxgZOjxYs4f0WMTGJnYwUKubsNRZSeQbLorS7+I4uXVF9KQ5r61BUPAUMZ7Lf66l64Q==", + "dev": true, + "requires": { + "jest-get-type": "^29.0.0" + } + }, + "@jest/fake-timers": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.0.3.tgz", + "integrity": "sha512-tmbUIo03x0TdtcZCESQ0oQSakPCpo7+s6+9mU19dd71MptkP4zCwoeZqna23//pgbhtT1Wq02VmA9Z9cNtvtCQ==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^29.0.3", + "jest-mock": "^29.0.3", + "jest-util": "^29.0.3" + } + }, + "@jest/globals": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.0.3.tgz", + "integrity": "sha512-YqGHT65rFY2siPIHHFjuCGUsbzRjdqkwbat+Of6DmYRg5shIXXrLdZoVE/+TJ9O1dsKsFmYhU58JvIbZRU1Z9w==", + "dev": true, + "requires": { + "@jest/environment": "^29.0.3", + "@jest/expect": "^29.0.3", + "@jest/types": "^29.0.3", + "jest-mock": "^29.0.3" + } + }, + "@jest/reporters": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.0.3.tgz", + "integrity": "sha512-3+QU3d4aiyOWfmk1obDerie4XNCaD5Xo1IlKNde2yGEi02WQD+ZQD0i5Hgqm1e73sMV7kw6pMlCnprtEwEVwxw==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "jest-worker": "^29.0.3", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.1" + } + }, + "@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, + "@jest/source-map": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", + "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.0.3.tgz", + "integrity": "sha512-vViVnQjCgTmbhDKEonKJPtcFe9G/CJO4/Np4XwYJah+lF2oI7KKeRp8t1dFvv44wN2NdbDb/qC6pi++Vpp0Dlg==", + "dev": true, + "requires": { + "@jest/console": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.0.3.tgz", + "integrity": "sha512-Hf4+xYSWZdxTNnhDykr8JBs0yBN/nxOXyUQWfotBUqqy0LF9vzcFB0jm/EDNZCx587znLWTIgxcokW7WeZMobQ==", + "dev": true, + "requires": { + "@jest/test-result": "^29.0.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "slash": "^3.0.0" + } + }, + "@jest/transform": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.0.3.tgz", + "integrity": "sha512-C5ihFTRYaGDbi/xbRQRdbo5ddGtI4VSpmL6AIcZxdhwLbXMa7PcXxxqyI91vGOFHnn5aVM3WYnYKCHEqmLVGzg==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.0.3", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + } + }, + "@jest/types": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.0.3.tgz", + "integrity": "sha512-coBJmOQvurXjN1Hh5PzF7cmsod0zLIOXpP8KD161mqNlroMhLcwpODiEzi7ZsRl5Z/AIuxpeNm8DCl43F4kz8A==", + "dev": true, + "requires": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@sinclair/typebox": { + "version": "0.24.43", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.43.tgz", + "integrity": "sha512-1orQTvtazZmsPeBroJjysvsOQCYV2yjWlebkSY38pl5vr2tdLjEJ+LoxITlGNZaH2RE19WlAwQMkH/7C14wLfw==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", + "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.0.3.tgz", + "integrity": "sha512-F6ukyCTwbfsEX5F2YmVYmM5TcTHy1q9P5rWlRbrk56KyMh3v9xRGUO3aa8+SkvMi0SHXtASJv1283enXimC0Og==", + "dev": true, + "requires": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "@types/node": { + "version": "18.7.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", + "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", + "dev": true + }, + "@types/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "babel-jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.0.3.tgz", + "integrity": "sha512-ApPyHSOhS/sVzwUOQIWJmdvDhBsMG01HX9z7ogtkp1TToHGGUWFlnXJUIzCgKPSfiYLn3ibipCYzsKSURHEwLg==", + "dev": true, + "requires": { + "@jest/transform": "^29.0.3", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.0.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", + "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", + "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^29.0.2", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001412", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001412.tgz", + "integrity": "sha512-+TeEIee1gS5bYOiuf+PS/kp2mrXic37Hl66VY6EAfxasIk5fELTktK2oOezYed12H8w7jt3s512PpulQidPjwA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "ci-info": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", + "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "diff-sequences": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", + "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.4.264", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.264.tgz", + "integrity": "sha512-AZ6ZRkucHOQT8wke50MktxtmcWZr67kE17X/nAXFf62NIdMdgY6xfsaJD5Szoy84lnkuPWH+4tTNE3s2+bPCiw==", + "dev": true + }, + "emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true + }, + "expect": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.0.3.tgz", + "integrity": "sha512-t8l5DTws3212VbmPL+tBFXhjRHLmctHB0oQbL8eUc6S7NzZtYUhycrFO9mkxA0ZUC6FAWdNi7JchJSkODtcu1Q==", + "dev": true, + "requires": { + "@jest/expect-utils": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "husky": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz", + "integrity": "sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==", + "dev": true + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "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 + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.0.3.tgz", + "integrity": "sha512-ElgUtJBLgXM1E8L6K1RW1T96R897YY/3lRYqq9uVcPWtP2AAl/nQ16IYDh/FzQOOQ12VEuLdcPU83mbhG2C3PQ==", + "dev": true, + "requires": { + "@jest/core": "^29.0.3", + "@jest/types": "^29.0.3", + "import-local": "^3.0.2", + "jest-cli": "^29.0.3" + } + }, + "jest-changed-files": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", + "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", + "dev": true, + "requires": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + } + }, + "jest-circus": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.0.3.tgz", + "integrity": "sha512-QeGzagC6Hw5pP+df1+aoF8+FBSgkPmraC1UdkeunWh0jmrp7wC0Hr6umdUAOELBQmxtKAOMNC3KAdjmCds92Zg==", + "dev": true, + "requires": { + "@jest/environment": "^29.0.3", + "@jest/expect": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.0.3", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "p-limit": "^3.1.0", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-cli": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.0.3.tgz", + "integrity": "sha512-aUy9Gd/Kut1z80eBzG10jAn6BgS3BoBbXyv+uXEqBJ8wnnuZ5RpNfARoskSrTIy1GY4a8f32YGuCMwibtkl9CQ==", + "dev": true, + "requires": { + "@jest/core": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + } + }, + "jest-config": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.0.3.tgz", + "integrity": "sha512-U5qkc82HHVYe3fNu2CRXLN4g761Na26rWKf7CjM8LlZB3In1jadEkZdMwsE37rd9RSPV0NfYaCjHdk/gu3v+Ew==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.0.3", + "@jest/types": "^29.0.3", + "babel-jest": "^29.0.3", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.0.3", + "jest-environment-node": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-runner": "^29.0.3", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + } + }, + "jest-diff": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.0.3.tgz", + "integrity": "sha512-+X/AIF5G/vX9fWK+Db9bi9BQas7M9oBME7egU7psbn4jlszLFCu0dW63UgeE6cs/GANq4fLaT+8sGHQQ0eCUfg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.0.0", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + } + }, + "jest-docblock": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", + "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.0.3.tgz", + "integrity": "sha512-wILhZfESURHHBNvPMJ0lZlYZrvOQJxAo3wNHi+ycr90V7M+uGR9Gh4+4a/BmaZF0XTyZsk4OiYEf3GJN7Ltqzg==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.0.0", + "jest-util": "^29.0.3", + "pretty-format": "^29.0.3" + } + }, + "jest-environment-node": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.0.3.tgz", + "integrity": "sha512-cdZqRCnmIlTXC+9vtvmfiY/40Cj6s2T0czXuq1whvQdmpzAnj4sbqVYuZ4zFHk766xTTJ+Ij3uUqkk8KCfXoyg==", + "dev": true, + "requires": { + "@jest/environment": "^29.0.3", + "@jest/fake-timers": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "jest-mock": "^29.0.3", + "jest-util": "^29.0.3" + } + }, + "jest-get-type": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", + "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", + "dev": true + }, + "jest-haste-map": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.0.3.tgz", + "integrity": "sha512-uMqR99+GuBHo0RjRhOE4iA6LmsxEwRdgiIAQgMU/wdT2XebsLDz5obIwLZm/Psj+GwSEQhw9AfAVKGYbh2G55A==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.0.3", + "jest-worker": "^29.0.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-leak-detector": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.0.3.tgz", + "integrity": "sha512-YfW/G63dAuiuQ3QmQlh8hnqLDe25WFY3eQhuc/Ev1AGmkw5zREblTh7TCSKLoheyggu6G9gxO2hY8p9o6xbaRQ==", + "dev": true, + "requires": { + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + } + }, + "jest-matcher-utils": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.0.3.tgz", + "integrity": "sha512-RsR1+cZ6p1hDV4GSCQTg+9qjeotQCgkaleIKLK7dm+U4V/H2bWedU3RAtLm8+mANzZ7eDV33dMar4pejd7047w==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.0.3", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.0.3" + } + }, + "jest-message-util": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.0.3.tgz", + "integrity": "sha512-7T8JiUTtDfppojosORAflABfLsLKMLkBHSWkjNQrjIltGoDzNGn7wEPOSfjqYAGTYME65esQzMJxGDjuLBKdOg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.0.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.0.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.0.3.tgz", + "integrity": "sha512-ort9pYowltbcrCVR43wdlqfAiFJXBx8l4uJDsD8U72LgBcetvEp+Qxj1W9ZYgMRoeAo+ov5cnAGF2B6+Oth+ww==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", + "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", + "dev": true + }, + "jest-resolve": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.0.3.tgz", + "integrity": "sha512-toVkia85Y/BPAjJasTC9zIPY6MmVXQPtrCk8SmiheC4MwVFE/CMFlOtMN6jrwPMC6TtNh8+sTMllasFeu1wMPg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.0.3", + "jest-validate": "^29.0.3", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.3.tgz", + "integrity": "sha512-KzuBnXqNvbuCdoJpv8EanbIGObk7vUBNt/PwQPPx2aMhlv/jaXpUJsqWYRpP/0a50faMBY7WFFP8S3/CCzwfDw==", + "dev": true, + "requires": { + "jest-regex-util": "^29.0.0", + "jest-snapshot": "^29.0.3" + } + }, + "jest-runner": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.0.3.tgz", + "integrity": "sha512-Usu6VlTOZlCZoNuh3b2Tv/yzDpKqtiNAetG9t3kJuHfUyVMNW7ipCCJOUojzKkjPoaN7Bl1f7Buu6PE0sGpQxw==", + "dev": true, + "requires": { + "@jest/console": "^29.0.3", + "@jest/environment": "^29.0.3", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.0.0", + "jest-environment-node": "^29.0.3", + "jest-haste-map": "^29.0.3", + "jest-leak-detector": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-resolve": "^29.0.3", + "jest-runtime": "^29.0.3", + "jest-util": "^29.0.3", + "jest-watcher": "^29.0.3", + "jest-worker": "^29.0.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + } + }, + "jest-runtime": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.0.3.tgz", + "integrity": "sha512-12gZXRQ7ozEeEHKTY45a+YLqzNDR/x4c//X6AqwKwKJPpWM8FY4vwn4VQJOcLRS3Nd1fWwgP7LU4SoynhuUMHQ==", + "dev": true, + "requires": { + "@jest/environment": "^29.0.3", + "@jest/fake-timers": "^29.0.3", + "@jest/globals": "^29.0.3", + "@jest/source-map": "^29.0.0", + "@jest/test-result": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-mock": "^29.0.3", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.0.3", + "jest-snapshot": "^29.0.3", + "jest-util": "^29.0.3", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + } + }, + "jest-snapshot": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.0.3.tgz", + "integrity": "sha512-52q6JChm04U3deq+mkQ7R/7uy7YyfVIrebMi6ZkBoDJ85yEjm/sJwdr1P0LOIEHmpyLlXrxy3QP0Zf5J2kj0ew==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.0.3", + "@jest/transform": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.0.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.0.3", + "jest-get-type": "^29.0.0", + "jest-haste-map": "^29.0.3", + "jest-matcher-utils": "^29.0.3", + "jest-message-util": "^29.0.3", + "jest-util": "^29.0.3", + "natural-compare": "^1.4.0", + "pretty-format": "^29.0.3", + "semver": "^7.3.5" + }, + "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "jest-util": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.0.3.tgz", + "integrity": "sha512-Q0xaG3YRG8QiTC4R6fHjHQPaPpz9pJBEi0AeOE4mQh/FuWOijFjGXMMOfQEaU9i3z76cNR7FobZZUQnL6IyfdQ==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.0.3.tgz", + "integrity": "sha512-OebiqqT6lK8cbMPtrSoS3aZP4juID762lZvpf1u+smZnwTEBCBInan0GAIIhv36MxGaJvmq5uJm7dl5gVt+Zrw==", + "dev": true, + "requires": { + "@jest/types": "^29.0.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.0.0", + "leven": "^3.1.0", + "pretty-format": "^29.0.3" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.0.3.tgz", + "integrity": "sha512-tQX9lU91A+9tyUQKUMp0Ns8xAcdhC9fo73eqA3LFxP2bSgiF49TNcc+vf3qgGYYK9qRjFpXW9+4RgF/mbxyOOw==", + "dev": true, + "requires": { + "@jest/test-result": "^29.0.3", + "@jest/types": "^29.0.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^29.0.3", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.0.3.tgz", + "integrity": "sha512-Tl/YWUugQOjoTYwjKdfJWkSOfhufJHO5LhXTSZC3TRoQKO+fuXnZAdoXXBlpLXKGODBL3OvdUasfDD4PcMe6ng==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "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, - "requires": { - "is-number": "^7.0.0" - } - }, - "ts-jest": { - "version": "29.0.2", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.2.tgz", - "integrity": "sha512-P03IUItnAjG6RkJXtjjD5pu0TryQFOwcb1YKmW63rO19V0UFqL3wiXZrmR5D7qYjI98btzIOAcYafLZ0GHAcQg==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - }, - "dependencies": { - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - }, - "typescript": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", - "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", - "dev": true, - "peer": true - }, - "update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + } + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true + }, + "pretty-format": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.0.3.tgz", + "integrity": "sha512-cHudsvQr1K5vNVLbvYF/nv3Qy/F/BcEKxGuIeMiVMRHxPOO1RxXooP8g/ZrwAp7Dx+KdMZoOc7NxLHhMrP2f9Q==", + "dev": true, + "requires": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + } + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "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, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-jest": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.2.tgz", + "integrity": "sha512-P03IUItnAjG6RkJXtjjD5pu0TryQFOwcb1YKmW63rO19V0UFqL3wiXZrmR5D7qYjI98btzIOAcYafLZ0GHAcQg==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } + } + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "typescript": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "dev": true, + "peer": true + }, + "update-browserslist-db": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + } + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } + } } diff --git a/package.json b/package.json index b3a21669..b45ab4ea 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,23 @@ { - "name": "typescript", - "version": "1.0.0", - "type": "module", - "description": "A repository for All algorithms implemented in Typescript (for educational purposes only)", - "main": "", - "devDependencies": { - "@types/jest": "^29.0.3", - "husky": "^8.0.1", - "jest": "^29.0.3", - "ts-jest": "^29.0.2", - "ts-node": "^10.9.1" - }, - "scripts": { - "test": "jest --no-cache", - "style": "standard", - "prepare": "husky install" - }, - "author": "TheAlgorithms", - "license": "MIT" - } + "name": "typescript", + "version": "1.0.0", + "type": "module", + "description": "A repository for All algorithms implemented in Typescript (for educational purposes only)", + "main": "", + "devDependencies": { + "@types/jest": "^29.0.3", + "husky": "^8.0.1", + "jest": "^29.0.3", + "prettier": "^3.2.5", + "ts-jest": "^29.0.2", + "ts-node": "^10.9.1" + }, + "scripts": { + "test": "jest --no-cache", + "style": "npx prettier . --write", + "check-style": "npx prettier . --check", + "prepare": "husky install" + }, + "author": "TheAlgorithms", + "license": "MIT" +} diff --git a/search/binary_search.ts b/search/binary_search.ts index 760a2c50..39d380a4 100644 --- a/search/binary_search.ts +++ b/search/binary_search.ts @@ -1,11 +1,11 @@ /** * @function binarySearch - * @description binary search algorithm (iterative & recursive implementations) for a sorted array. - * + * @description binary search algorithm (iterative & recursive implementations) for a sorted array. + * * The algorithm searches for a specific value in a sorted array in logarithmic time. * It repeatedly halves the portion of the list that could contain the item, * until you've narrowed down the possible indices to just one. - * + * * @param {number[]} array - sorted list of numbers * @param {number} target - target number to search for * @return {number} - index of the target number in the list, or -1 if not found @@ -14,45 +14,51 @@ * @example binarySearch([4,5,6], 2) => -1 */ -export const binarySearchIterative = (array: number[], target: number): number => { - if (array.length === 0) return -1; - - // declare pointers for the start, middle and end indices - let start = 0, - end = array.length - 1, - middle = (start + end) >> 1; - - // ensure the target is within the bounds of the array - if (target < array[start] || target > array[end]) return -1; - - while (array[middle] !== target && start <= end) { - // if the target is less than the middle value, move the end pointer to be middle -1 to narrow the search space - // otherwise, move the start pointer to be middle + 1 - if (target < array[middle]) - end = middle - 1; - else - start = middle + 1; - // redeclare the middle index when the search window changes - middle = (start + end) >> 1; - } - // return the middle index if it is equal to target - return array[middle] === target ? middle : -1; +export const binarySearchIterative = ( + array: number[], + target: number +): number => { + if (array.length === 0) return -1 + + // declare pointers for the start, middle and end indices + let start = 0, + end = array.length - 1, + middle = (start + end) >> 1 + + // ensure the target is within the bounds of the array + if (target < array[start] || target > array[end]) return -1 + + while (array[middle] !== target && start <= end) { + // if the target is less than the middle value, move the end pointer to be middle -1 to narrow the search space + // otherwise, move the start pointer to be middle + 1 + if (target < array[middle]) end = middle - 1 + else start = middle + 1 + // redeclare the middle index when the search window changes + middle = (start + end) >> 1 + } + // return the middle index if it is equal to target + return array[middle] === target ? middle : -1 } -export const binarySearchRecursive = (array: number[], target: number, start = 0, end = array.length - 1): number => { - if (array.length === 0) return -1; +export const binarySearchRecursive = ( + array: number[], + target: number, + start = 0, + end = array.length - 1 +): number => { + if (array.length === 0) return -1 - // ensure the target is within the bounds of the array - if (target < array[start] || target > array[end]) return -1; + // ensure the target is within the bounds of the array + if (target < array[start] || target > array[end]) return -1 - const middle = (start + end) >> 1; + const middle = (start + end) >> 1 - if (array[middle] === target) return middle; // target found - if (start > end) return -1; // target not found + if (array[middle] === target) return middle // target found + if (start > end) return -1 // target not found - // if the target is less than the middle value, move the end pointer to be middle -1 to narrow the search space - // otherwise, move the start pointer to be middle + 1 - return target < array[middle] - ? binarySearchRecursive(array, target, start, middle - 1) - : binarySearchRecursive(array, target, middle + 1, end); -} \ No newline at end of file + // if the target is less than the middle value, move the end pointer to be middle -1 to narrow the search space + // otherwise, move the start pointer to be middle + 1 + return target < array[middle] + ? binarySearchRecursive(array, target, start, middle - 1) + : binarySearchRecursive(array, target, middle + 1, end) +} diff --git a/search/interpolation_search.ts b/search/interpolation_search.ts index 61942782..8ee1e043 100644 --- a/search/interpolation_search.ts +++ b/search/interpolation_search.ts @@ -9,41 +9,47 @@ * @see https://en.wikipedia.org/wiki/Interpolation_search * @example interpolationSearch([1, 3, 5, 7, 9, 11], 1) => 0 */ -export const interpolationSearch = (array: number[], target: number): number => { - let lowIndex: number = 0; - let highIndex: number = array.length - 1; - let currentValue: number = array[lowIndex]; - let pos: number = 0; +export const interpolationSearch = ( + array: number[], + target: number +): number => { + let lowIndex: number = 0 + let highIndex: number = array.length - 1 + let currentValue: number = array[lowIndex] + let pos: number = 0 while (lowIndex <= highIndex) { - const lowValue: number = array[lowIndex]; - const highValue: number = array[highIndex]; + const lowValue: number = array[lowIndex] + const highValue: number = array[highIndex] if (lowValue === highValue) { if (array[lowIndex] === target) { - return lowIndex; + return lowIndex } - break; + break } - pos = Math.round(lowIndex + (target-lowValue)*(highIndex-lowIndex) / (highValue-lowValue)); + pos = Math.round( + lowIndex + + ((target - lowValue) * (highIndex - lowIndex)) / (highValue - lowValue) + ) if (pos < 0 || pos >= array.length) { - break; + break } - currentValue = array[pos]; + currentValue = array[pos] if (target === currentValue) { - return pos; + return pos } if (target > currentValue) { - lowIndex = pos + 1; + lowIndex = pos + 1 } else { - highIndex = pos - 1; + highIndex = pos - 1 } } - return -1; -} \ No newline at end of file + return -1 +} diff --git a/search/jump_search.ts b/search/jump_search.ts index e79061d8..9707dbf3 100644 --- a/search/jump_search.ts +++ b/search/jump_search.ts @@ -1,47 +1,46 @@ -/** - * @function jumpSearch - * @description Jump search algorithm for a sorted array. - * - * Jump search is a searching algorithm for sorted arrays that checks elements - * by jumping ahead by fixed steps. The optimal step size is the square root of the array length. - * - * The algorithm works as follows: - * 1.Start from the first element and jump by step size until finding an element that is greater than or equal to the target value. - * 2.Go back one step and perform a linear search from there until finding the target value or reaching the end of the subarray. - * 3.If the target value is found, return its index. Otherwise, return -1 to indicate that it is not in the array. - * - * @param {number[]} array - sorted list of numbers - * @param {number} target - target number to search for - * @return {number} - index of the target number in the list, or -1 if not found - * @see [JumpSearch](https://www.geeksforgeeks.org/jump-search/) - * @example jumpSearch([1,2,3], 2) => 1 - * @example jumpSearch([4,5,6], 2) => -1 - */ - -export const jumpSearch = (array: number[], target: number): number => { - if (array.length === 0) return -1; - - // declare pointers for the current and next indexes and step size - let currentIdx: number = 0, - stepSize: number = Math.floor(Math.sqrt(array.length)), - nextIdx: number = stepSize; - - while (array[nextIdx - 1] < target) { - currentIdx = nextIdx; - nextIdx += stepSize; - - if (nextIdx > array.length) { - nextIdx = array.length; - break; - } - } - - for (let index = currentIdx; index < nextIdx; index++) { - if(array[index] == target) - { - return index; - } - } - - return -1; -} \ No newline at end of file +/** + * @function jumpSearch + * @description Jump search algorithm for a sorted array. + * + * Jump search is a searching algorithm for sorted arrays that checks elements + * by jumping ahead by fixed steps. The optimal step size is the square root of the array length. + * + * The algorithm works as follows: + * 1.Start from the first element and jump by step size until finding an element that is greater than or equal to the target value. + * 2.Go back one step and perform a linear search from there until finding the target value or reaching the end of the subarray. + * 3.If the target value is found, return its index. Otherwise, return -1 to indicate that it is not in the array. + * + * @param {number[]} array - sorted list of numbers + * @param {number} target - target number to search for + * @return {number} - index of the target number in the list, or -1 if not found + * @see [JumpSearch](https://www.geeksforgeeks.org/jump-search/) + * @example jumpSearch([1,2,3], 2) => 1 + * @example jumpSearch([4,5,6], 2) => -1 + */ + +export const jumpSearch = (array: number[], target: number): number => { + if (array.length === 0) return -1 + + // declare pointers for the current and next indexes and step size + let currentIdx: number = 0, + stepSize: number = Math.floor(Math.sqrt(array.length)), + nextIdx: number = stepSize + + while (array[nextIdx - 1] < target) { + currentIdx = nextIdx + nextIdx += stepSize + + if (nextIdx > array.length) { + nextIdx = array.length + break + } + } + + for (let index = currentIdx; index < nextIdx; index++) { + if (array[index] == target) { + return index + } + } + + return -1 +} diff --git a/search/linear_search.ts b/search/linear_search.ts index ae03288a..83a84205 100644 --- a/search/linear_search.ts +++ b/search/linear_search.ts @@ -1,8 +1,8 @@ /** * @function linearSearch - * @description linear search is the simplest search possible in a array - * it has a linear cost, if the value is present in the array, then the index of the first occurence will be returned - * if it's not present, the return it will be -1 + * @description linear search is the simplest search possible in a array + * it has a linear cost, if the value is present in the array, then the index of the first occurence will be returned + * if it's not present, the return it will be -1 * @param {number[]} array - list of numbers * @param {number} target - target number to search for * @return {number} - index of the target number in the list, or -1 if not found @@ -12,7 +12,7 @@ */ export const linearSearch = (array: any[], target: any): number => { for (let i = 0; i < array.length; i++) { - if (array[i] === target) return i; + if (array[i] === target) return i } - return -1; -} \ No newline at end of file + return -1 +} diff --git a/search/sentinel_search.ts b/search/sentinel_search.ts index 3a9052a2..bbafdad5 100644 --- a/search/sentinel_search.ts +++ b/search/sentinel_search.ts @@ -1,13 +1,13 @@ /** * @function sentinelSearch - * @description Sentinel search algorithm for array. - * - * Sentinel linear search is a variation of the standard linear search algorithm used to - * find a target value in an array or list. The basic idea behind this algorithm is to add a + * @description Sentinel search algorithm for array. + * + * Sentinel linear search is a variation of the standard linear search algorithm used to + * find a target value in an array or list. The basic idea behind this algorithm is to add a * sentinel value at the end of the array which is equal to the target value we are looking for. - * This helps to avoid checking the array boundary condition during each iteration of the loop, + * This helps to avoid checking the array boundary condition during each iteration of the loop, * as the sentinel value acts as a stopper for the loop. - * + * * @param {number[]} array - sorted list of numbers * @param {number} target - target number to search for * @return {number|null} - index of the target number in the list, or null if not found @@ -22,21 +22,23 @@ * Auxiliary Space: O(1) */ -export const sentinelSearch = (array: number[], target: number): number|null => { - const arrayLength = array.length - if (arrayLength === 0) return null; +export const sentinelSearch = ( + array: number[], + target: number +): number | null => { + const arrayLength = array.length + if (arrayLength === 0) return null - // Element to be searched is placed at the last index - const last = array[arrayLength-1] - array[arrayLength-1] = target + // Element to be searched is placed at the last index + const last = array[arrayLength - 1] + array[arrayLength - 1] = target - let index: number = 0 - while (array[index] !== target) index += 1 + let index: number = 0 + while (array[index] !== target) index += 1 - // Put the last element back - array[arrayLength-1] = last - - if ((index < arrayLength - 1) || (array[arrayLength - 1] === target)) - return index - return null -} \ No newline at end of file + // Put the last element back + array[arrayLength - 1] = last + + if (index < arrayLength - 1 || array[arrayLength - 1] === target) return index + return null +} diff --git a/search/test/binary_search.test.ts b/search/test/binary_search.test.ts index 0e218a13..6ebd12d9 100644 --- a/search/test/binary_search.test.ts +++ b/search/test/binary_search.test.ts @@ -1,34 +1,37 @@ -import { binarySearchIterative, binarySearchRecursive } from "../binary_search"; +import { binarySearchIterative, binarySearchRecursive } from '../binary_search' -describe("BinarySearch", () => { - const testArray: number[] = [1,2,3,4]; - type FunctionsArray = { (array: number[], index: number): number }[]; - const functions: FunctionsArray = [binarySearchIterative, binarySearchRecursive]; +describe('BinarySearch', () => { + const testArray: number[] = [1, 2, 3, 4] + type FunctionsArray = { (array: number[], index: number): number }[] + const functions: FunctionsArray = [ + binarySearchIterative, + binarySearchRecursive + ] - for (const func of functions) { - it("should be defined", () => { - expect(func(testArray, 2)).toBeDefined(); - }); - it("should return a number", () => { - expect(typeof func(testArray, 2)).toBe("number"); - }); - it("should return -1 if the target is not found in the array", () => { - expect(func(testArray, 5)).toBe(-1); - }); - it("should return -1 if there are no elements in the array", () => { - expect(func([], 5)).toBe(-1); - }); - it("should return the index of the target if it is found in the array", () => { - expect(func(testArray, 2)).toBe(1); - }); - it("should return a correct index of target when the array contains duplicate values", () => { - expect(func([1,2,2,3,3,3,4], 2)).toBe(1); - }); - it("should return the first index when the target is the first item in the array", () => { - expect(func(testArray, 1)).toBe(0); - }); - it("should return the last index when the target is the last item in the array", () => { - expect(func(testArray, 4)).toBe(3); - }); - } -}); \ No newline at end of file + for (const func of functions) { + it('should be defined', () => { + expect(func(testArray, 2)).toBeDefined() + }) + it('should return a number', () => { + expect(typeof func(testArray, 2)).toBe('number') + }) + it('should return -1 if the target is not found in the array', () => { + expect(func(testArray, 5)).toBe(-1) + }) + it('should return -1 if there are no elements in the array', () => { + expect(func([], 5)).toBe(-1) + }) + it('should return the index of the target if it is found in the array', () => { + expect(func(testArray, 2)).toBe(1) + }) + it('should return a correct index of target when the array contains duplicate values', () => { + expect(func([1, 2, 2, 3, 3, 3, 4], 2)).toBe(1) + }) + it('should return the first index when the target is the first item in the array', () => { + expect(func(testArray, 1)).toBe(0) + }) + it('should return the last index when the target is the last item in the array', () => { + expect(func(testArray, 4)).toBe(3) + }) + } +}) diff --git a/search/test/interpolation_search.test.ts b/search/test/interpolation_search.test.ts index 6cc6e4e2..d8a96f63 100644 --- a/search/test/interpolation_search.test.ts +++ b/search/test/interpolation_search.test.ts @@ -1,15 +1,22 @@ -import { interpolationSearch } from "../interpolation_search"; +import { interpolationSearch } from '../interpolation_search' -describe("Interpolation search", () => { +describe('Interpolation search', () => { test.each([ [[1, 3, 5, 7, 9, 11], 1, 0], - [[1, 3, 7, 10, 14, 15, 16, 18, 20, 21, 22, 23, 25, 33, 35, 42, 45, 47, 50, 52], 33, 13], + [ + [ + 1, 3, 7, 10, 14, 15, 16, 18, 20, 21, 22, 23, 25, 33, 35, 42, 45, 47, 50, + 52 + ], + 33, + 13 + ], [[0, 45, 67, 70, 89, 129, 150, 308], 308, 7], [[0, 45, 67, 70, 89, 129, 150, 308], 190, -1] ])( - "of %o, searching for %o, expected %i", + 'of %o, searching for %o, expected %i', (array: any[], target: any, index: number) => { expect(interpolationSearch(array, target)).toStrictEqual(index) - }, - ); -}); + } + ) +}) diff --git a/search/test/jump_search.test.ts b/search/test/jump_search.test.ts index 3687ccec..3f24d261 100644 --- a/search/test/jump_search.test.ts +++ b/search/test/jump_search.test.ts @@ -1,23 +1,23 @@ -import { jumpSearch } from "../jump_search"; - -describe("Jump search", () => { - test.each([ - [[], 1, -1], - [[1, 2, 3, 4, 5], 4, 3], - [[1, 3, 5, 8, 9], 4, -1], - [[1, 3, 5, 8], 8, 3], - [[1, 3, 5, 8], 9, -1], - [[1, 3, 5, 8], 7, -1], - [[1, 3, 5, 8, 10], 10, 4], - [[1, 3, 5, 8, 10], 11, -1], - [[1, 3, 5, 8, 10], 9, -1], - [[5], 5, 0], - [[5], 100, -1], - [[], 100, -1], - ])( - "of %o , searching for %o, expected %i", - (array: any[], target: any, index: number) => { - expect(jumpSearch(array, target)).toStrictEqual(index) - }, - ); -}); +import { jumpSearch } from '../jump_search' + +describe('Jump search', () => { + test.each([ + [[], 1, -1], + [[1, 2, 3, 4, 5], 4, 3], + [[1, 3, 5, 8, 9], 4, -1], + [[1, 3, 5, 8], 8, 3], + [[1, 3, 5, 8], 9, -1], + [[1, 3, 5, 8], 7, -1], + [[1, 3, 5, 8, 10], 10, 4], + [[1, 3, 5, 8, 10], 11, -1], + [[1, 3, 5, 8, 10], 9, -1], + [[5], 5, 0], + [[5], 100, -1], + [[], 100, -1] + ])( + 'of %o , searching for %o, expected %i', + (array: any[], target: any, index: number) => { + expect(jumpSearch(array, target)).toStrictEqual(index) + } + ) +}) diff --git a/search/test/linear_search.test.ts b/search/test/linear_search.test.ts index b0ab6605..02fe4644 100644 --- a/search/test/linear_search.test.ts +++ b/search/test/linear_search.test.ts @@ -1,14 +1,14 @@ -import { linearSearch } from "../linear_search"; +import { linearSearch } from '../linear_search' -describe("Linear search", () => { +describe('Linear search', () => { test.each([ [['o', 'b', 'c'], 'c', 2], [[1, 2, 3, 4, 5], 4, 3], [['s', 't', 'r', 'i', 'n', 'g'], 'a', -1] ])( - "of %o , searching for %o, expected %i", + 'of %o , searching for %o, expected %i', (array: any[], target: any, index: number) => { expect(linearSearch(array, target)).toStrictEqual(index) - }, - ); -}); + } + ) +}) diff --git a/search/test/sentinel_search.test.ts b/search/test/sentinel_search.test.ts index 910aa254..6de62f84 100644 --- a/search/test/sentinel_search.test.ts +++ b/search/test/sentinel_search.test.ts @@ -1,16 +1,16 @@ -import { sentinelSearch } from "../sentinel_search"; +import { sentinelSearch } from '../sentinel_search' -describe("Sentinel search", () => { +describe('Sentinel search', () => { test.each([ [['o', 'b', 'c'], 'c', 2], [[1, 2, 3, 4, 5], 4, 3], [['s', 't', 'r', 'i', 'n', 'g'], 'a', null], - [['1','2','3'],'1',0], - [['4','e','6','10'],4,null] + [['1', '2', '3'], '1', 0], + [['4', 'e', '6', '10'], 4, null] ])( - "of %o , searching for %o, expected %i", - (array: any[], target: any, index: number|null) => { + 'of %o , searching for %o, expected %i', + (array: any[], target: any, index: number | null) => { expect(sentinelSearch(array, target)).toStrictEqual(index) - }, - ); -}); \ No newline at end of file + } + ) +}) diff --git a/sorts/bogo_sort.ts b/sorts/bogo_sort.ts index b2231d28..ffe840c5 100644 --- a/sorts/bogo_sort.ts +++ b/sorts/bogo_sort.ts @@ -1,5 +1,5 @@ -import { isSortedArray } from '../other/is_sorted_array'; -import { shuffleArray } from '../other/shuffle_array'; +import { isSortedArray } from '../other/is_sorted_array' +import { shuffleArray } from '../other/shuffle_array' /** * @function bogoSort @@ -22,8 +22,8 @@ import { shuffleArray } from '../other/shuffle_array'; * @example bogoSort([8, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 8] */ export function bogoSort(arr: number[]): number[] { - while (!isSortedArray(arr)) { - shuffleArray(arr); - } - return arr; + while (!isSortedArray(arr)) { + shuffleArray(arr) + } + return arr } diff --git a/sorts/bubble_sort.ts b/sorts/bubble_sort.ts index 3086051e..5ab1f853 100644 --- a/sorts/bubble_sort.ts +++ b/sorts/bubble_sort.ts @@ -1,32 +1,33 @@ -/** - * @function bubbleSort +/** + * @function bubbleSort * @description Bubble sort algorithm is simple and easy. In bubble sort every pair of adjacent value is compared and swap if the first value is greater than the second one. By this with every iteration the greatest value goes to the right side making it ascending order.This algorithm is not suitable for large data sets as its average and worst-case time complexity is quite high. - * @Complexity_Analysis - * Space complexity - O(1) - * Time complexity  + * @Complexity_Analysis + * Space complexity - O(1) + * Time complexity *      Best case   -   O(n^2) - * The best case occurs when an array is already sorted. + * The best case occurs when an array is already sorted. *      Worst case  -   O(n^2) * The worst case occurs when an array is reverse sorted. *      Average case -  O(n^2) * The average case occurs when an array is reverse sorted. * - * @param {number[]} arr - The input array - * @return {number[]} - The sorted array. - * @see [Bubble Sort](https://www.freecodecamp.org/news/bubble-sort) - * @example bubbleSort([8, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 8] + * @param {number[]} arr - The input array + * @return {number[]} - The sorted array. + * @see [Bubble Sort](https://www.freecodecamp.org/news/bubble-sort) + * @example bubbleSort([8, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 8] */ export const bubbleSort = (arr: number[]): number[] => { - - for (let i = 0; i < arr.length; i++) { - for (let j = 0; j < arr.length-1; j++) { //iterating till the 2nd last element of array - if (arr[j] > arr[j+1]) { //current indexed number > next indexed number - const temp: number = arr[j]; //swapping two numbers - arr[j] = arr[j+1]; - arr[j+1] = temp; + for (let i = 0; i < arr.length; i++) { + for (let j = 0; j < arr.length - 1; j++) { + //iterating till the 2nd last element of array + if (arr[j] > arr[j + 1]) { + //current indexed number > next indexed number + const temp: number = arr[j] //swapping two numbers + arr[j] = arr[j + 1] + arr[j + 1] = temp } } } - return arr; -}; + return arr +} diff --git a/sorts/counting_sort.ts b/sorts/counting_sort.ts index 61ecbfbd..cedad89f 100644 --- a/sorts/counting_sort.ts +++ b/sorts/counting_sort.ts @@ -7,24 +7,22 @@ * const array = [3, 0, 2, 5, 4, 1] * countingSort(array, 0, 5) */ - + export const countingSort = (inputArr: number[], min: number, max: number) => { - const sortedArr = [] - - const count = new Array(max - min + 1).fill(0) + const sortedArr = [] + + const count = new Array(max - min + 1).fill(0) - for (let i = 0; i < inputArr.length; i++) - count[inputArr[i] - min]++ + for (let i = 0; i < inputArr.length; i++) count[inputArr[i] - min]++ - count[0] -= 1 - - for (let i = 1; i < count.length; i++) - count[i] += count[i - 1] + count[0] -= 1 - for (let i = inputArr.length - 1; i >= 0; i--) { - sortedArr[count[inputArr[i] - min]] = inputArr[i] - count[inputArr[i] - min]-- - } + for (let i = 1; i < count.length; i++) count[i] += count[i - 1] - return sortedArr + for (let i = inputArr.length - 1; i >= 0; i--) { + sortedArr[count[inputArr[i] - min]] = inputArr[i] + count[inputArr[i] - min]-- } + + return sortedArr +} diff --git a/sorts/cycle_sort.ts b/sorts/cycle_sort.ts index a43f8873..30da5790 100644 --- a/sorts/cycle_sort.ts +++ b/sorts/cycle_sort.ts @@ -1,63 +1,68 @@ -/** - * @function cycleSort - * @description Cycle sort is an in-place, unstable sorting algorithm, a comparison sort that is theoretically optimal in terms of the total number of writes to the original array, unlike any other in-place sorting algorithm. It is based on the idea that the permutation to be sorted can be factored into cycles, which can individually be rotated to give a sorted result. - * @param {number[]}array - The input array - * @return {number[]} - The sorted array. - * @see [CycleSort] https://en.wikipedia.org/wiki/Cycle_sort - * @example cycleSort([8, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 8] - */ - -export const cycleSort = (array: number[]) => { - for (let i: number = 0; i < array.length - 1; i++) { - MoveCycle(array, i); - } - return array; -}; - -function MoveCycle(array: number[], startIndex: number) : void { - - let currentItem: number = array[startIndex]; - let nextChangeIndex: number = startIndex + CountSmallerItems(array, startIndex, currentItem); - if(nextChangeIndex == startIndex) - { - return; - } - - nextChangeIndex = SkipDuplicates(array, nextChangeIndex, currentItem); - - let tmp: number = array[nextChangeIndex]; - array[nextChangeIndex] = currentItem; - currentItem = tmp; - - while (nextChangeIndex != startIndex) - { - nextChangeIndex = startIndex + CountSmallerItems(array, startIndex, currentItem); - nextChangeIndex = SkipDuplicates(array, nextChangeIndex, currentItem); - - tmp = array[nextChangeIndex]; - array[nextChangeIndex] = currentItem; - currentItem = tmp; - } -} - -function CountSmallerItems(array: number[], startIndex: number, currentItem: number) : number{ - let elementsCount: number = 0; - - for (let i: number = startIndex + 1; i < array.length; i++) { - if(currentItem > array[i]) - { - elementsCount++; - } - } - - return elementsCount; -} - -function SkipDuplicates(array: number[], currentPosition: number, currentItem: number): number { - while (array[currentPosition] == currentItem) { - currentPosition++; - } - - return currentPosition; -} - +/** + * @function cycleSort + * @description Cycle sort is an in-place, unstable sorting algorithm, a comparison sort that is theoretically optimal in terms of the total number of writes to the original array, unlike any other in-place sorting algorithm. It is based on the idea that the permutation to be sorted can be factored into cycles, which can individually be rotated to give a sorted result. + * @param {number[]}array - The input array + * @return {number[]} - The sorted array. + * @see [CycleSort] https://en.wikipedia.org/wiki/Cycle_sort + * @example cycleSort([8, 3, 5, 1, 4, 2]) = [1, 2, 3, 4, 5, 8] + */ + +export const cycleSort = (array: number[]) => { + for (let i: number = 0; i < array.length - 1; i++) { + MoveCycle(array, i) + } + return array +} + +function MoveCycle(array: number[], startIndex: number): void { + let currentItem: number = array[startIndex] + let nextChangeIndex: number = + startIndex + CountSmallerItems(array, startIndex, currentItem) + if (nextChangeIndex == startIndex) { + return + } + + nextChangeIndex = SkipDuplicates(array, nextChangeIndex, currentItem) + + let tmp: number = array[nextChangeIndex] + array[nextChangeIndex] = currentItem + currentItem = tmp + + while (nextChangeIndex != startIndex) { + nextChangeIndex = + startIndex + CountSmallerItems(array, startIndex, currentItem) + nextChangeIndex = SkipDuplicates(array, nextChangeIndex, currentItem) + + tmp = array[nextChangeIndex] + array[nextChangeIndex] = currentItem + currentItem = tmp + } +} + +function CountSmallerItems( + array: number[], + startIndex: number, + currentItem: number +): number { + let elementsCount: number = 0 + + for (let i: number = startIndex + 1; i < array.length; i++) { + if (currentItem > array[i]) { + elementsCount++ + } + } + + return elementsCount +} + +function SkipDuplicates( + array: number[], + currentPosition: number, + currentItem: number +): number { + while (array[currentPosition] == currentItem) { + currentPosition++ + } + + return currentPosition +} diff --git a/sorts/gnome_sort.ts b/sorts/gnome_sort.ts index adfbf28b..7b77a8fb 100644 --- a/sorts/gnome_sort.ts +++ b/sorts/gnome_sort.ts @@ -9,18 +9,18 @@ export const gnomeSort = (arr: number[]): number[] => { if (arr.length <= 1) { - return arr; + return arr } - let i: number = 1; + let i: number = 1 while (i < arr.length) { if (arr[i - 1] <= arr[i]) { - i++; //increment index if sub-array[0:i] already sorted + i++ //increment index if sub-array[0:i] already sorted } else { - [arr[i], arr[i - 1]] = [arr[i - 1], arr[i]]; //swapping two numbers - i = Math.max(1, i - 1); //go back to the previous index to check the swapped number + ;[arr[i], arr[i - 1]] = [arr[i - 1], arr[i]] //swapping two numbers + i = Math.max(1, i - 1) //go back to the previous index to check the swapped number } } - return arr; -}; + return arr +} diff --git a/sorts/heap_sort.ts b/sorts/heap_sort.ts index e5541a77..2f96b005 100644 --- a/sorts/heap_sort.ts +++ b/sorts/heap_sort.ts @@ -13,49 +13,48 @@ // Function to perform the Heap Sort export const HeapSort = (arr: number[]): number[] => { + buildMaxHeap(arr) - buildMaxHeap(arr); + for (let i = arr.length - 1; i > 0; i--) { + swap(arr, 0, i) + heapify(arr, 0, i) + } - for (let i = arr.length - 1; i > 0; i--) { - swap(arr, 0, i); - heapify(arr, 0, i); - } - - return arr; -}; + return arr +} // Function to build a max-heap from an array function buildMaxHeap(arr: number[]): void { - const n = arr.length; + const n = arr.length - for (let i = Math.floor(n / 2) - 1; i >= 0; i--) { - heapify(arr, i, n); - } + for (let i = Math.floor(n / 2) - 1; i >= 0; i--) { + heapify(arr, i, n) + } } // Function to heapify a subtree rooted at a given index function heapify(arr: number[], index: number, size: number): void { - let largest = index; - const left = 2 * index + 1; - const right = 2 * index + 2; - - if (left < size && arr[left] > arr[largest]) { - largest = left; - } - - if (right < size && arr[right] > arr[largest]) { - largest = right; - } - - if (largest !== index) { - swap(arr, index, largest); - heapify(arr, largest, size); - } + let largest = index + const left = 2 * index + 1 + const right = 2 * index + 2 + + if (left < size && arr[left] > arr[largest]) { + largest = left + } + + if (right < size && arr[right] > arr[largest]) { + largest = right + } + + if (largest !== index) { + swap(arr, index, largest) + heapify(arr, largest, size) + } } // Function to swap two elements in an array function swap(arr: number[], i: number, j: number): void { - const temp = arr[i]; - arr[i] = arr[j]; - arr[j] = temp; + const temp = arr[i] + arr[i] = arr[j] + arr[j] = temp } diff --git a/sorts/insertion_sort.ts b/sorts/insertion_sort.ts index 1b01578c..e48451d7 100644 --- a/sorts/insertion_sort.ts +++ b/sorts/insertion_sort.ts @@ -9,14 +9,14 @@ export const insertionSort = (arr: number[]): number[] => { for (let i = 1; i < arr.length; i++) { - const temp = arr[i]; - let j = i - 1; + const temp = arr[i] + let j = i - 1 while (j >= 0 && arr[j] > temp) { - arr[j + 1] = arr[j]; - j--; + arr[j + 1] = arr[j] + j-- } - arr[j + 1] = temp; + arr[j + 1] = temp } - return arr; -}; + return arr +} diff --git a/sorts/quick_select.ts b/sorts/quick_select.ts index 91d03bfc..927d3393 100644 --- a/sorts/quick_select.ts +++ b/sorts/quick_select.ts @@ -1,4 +1,4 @@ -import {partition} from "./quick_sort"; +import { partition } from './quick_sort' /** * @function QuickSelect * @description is an algorithm based on the QuickSort approach that selects the kth smallest element from an array @@ -11,30 +11,30 @@ import {partition} from "./quick_sort"; */ export const QuickSelect = ( - array: number[], - k: number, - left: number = 0, - right: number = array.length - 1 -):number => { - if(k < 0 || k >= array.length) { - throw new Error('k is out of bounds'); - } - if (left === right) { - // If the list contains only one element, return that element - return array[left]; - } + array: number[], + k: number, + left: number = 0, + right: number = array.length - 1 +): number => { + if (k < 0 || k >= array.length) { + throw new Error('k is out of bounds') + } + if (left === right) { + // If the list contains only one element, return that element + return array[left] + } - // Partition the array - const pivotIndex = partition(array, left, right); + // Partition the array + const pivotIndex = partition(array, left, right) - // The pivot is in its final sorted position - if (k === pivotIndex) { - return array[k]; - } else if (k < pivotIndex) { - // If k is less than the pivot index, look left - return QuickSelect(array, k, left, pivotIndex - 1); - } else { - // If k is greater than the pivot index, look right - return QuickSelect(array, k, pivotIndex + 1, right); - } -}; + // The pivot is in its final sorted position + if (k === pivotIndex) { + return array[k] + } else if (k < pivotIndex) { + // If k is less than the pivot index, look left + return QuickSelect(array, k, left, pivotIndex - 1) + } else { + // If k is greater than the pivot index, look right + return QuickSelect(array, k, pivotIndex + 1, right) + } +} diff --git a/sorts/quick_sort.ts b/sorts/quick_sort.ts index 90d03266..b5e45e17 100644 --- a/sorts/quick_sort.ts +++ b/sorts/quick_sort.ts @@ -10,24 +10,24 @@ export const partition = ( left: number = 0, right: number = array.length - 1 ) => { - const pivotIndex = choosePivot(left,right); - const pivot = array[pivotIndex]; - [array[pivotIndex], array[right]] = [array[right], array[pivotIndex]]; - let i = left - 1; - let j = right; + const pivotIndex = choosePivot(left, right) + const pivot = array[pivotIndex] + ;[array[pivotIndex], array[right]] = [array[right], array[pivotIndex]] + let i = left - 1 + let j = right while (i < j) { while (array[++i] < pivot); while (array[--j] > pivot); if (i < j) { - [array[i], array[j]] = [array[j], array[i]]; + ;[array[i], array[j]] = [array[j], array[i]] } } - [array[right], array[i]] = [array[i], array[right]]; - return i; -}; + ;[array[right], array[i]] = [array[i], array[right]] + return i +} /** * @function choosePivot @@ -36,12 +36,9 @@ export const partition = ( * @param {number} right - The right index of the subarray. * @returns {number} - The index of the chosen pivot element. */ -const choosePivot = ( - left: number, - right: number -): number => { - return Math.floor(Math.random() * (right - left + 1)) + left; -}; +const choosePivot = (left: number, right: number): number => { + return Math.floor(Math.random() * (right - left + 1)) + left +} /** * Quicksort implementation @@ -52,7 +49,7 @@ const choosePivot = ( * @returns {number[]} * @complexity_analysis * Space complexity - O(nlogn) - * Time complexity + * Time complexity * Best case - O(nlogn) * When pivot element lies in the middle of the list * Worst case - O(n^2) @@ -67,16 +64,16 @@ export const QuickSort = ( right: number = array.length - 1 ) => { if (array.length > 1) { - const index = partition(array, left, right); + const index = partition(array, left, right) if (left < index - 1) { - QuickSort(array, left, index - 1); + QuickSort(array, left, index - 1) } if (index + 1 < right) { - QuickSort(array, index + 1, right); + QuickSort(array, index + 1, right) } } - return array; -}; + return array +} diff --git a/sorts/selection_sort.ts b/sorts/selection_sort.ts index bd4cfb6d..a09a35fa 100644 --- a/sorts/selection_sort.ts +++ b/sorts/selection_sort.ts @@ -19,15 +19,15 @@ export const selectionSort = (items: number[]) => { for (let i = 0; i < items.length; i++) { - let min = i; + let min = i for (let j = i + 1; j < items.length; j++) { if (items[j] < items[min]) { - min = j; + min = j } } if (i !== min) { - [items[i], items[min]] = [items[min], items[i]]; + ;[items[i], items[min]] = [items[min], items[i]] } } - return items; -}; + return items +} diff --git a/sorts/shell_sort.ts b/sorts/shell_sort.ts index f9012ee6..4b1061ba 100644 --- a/sorts/shell_sort.ts +++ b/sorts/shell_sort.ts @@ -14,18 +14,18 @@ * @example shellSort([4, 1, 8, 10, 3, 2, 5, 0, 7, 6, 9]) = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] */ export function shellSort(arr: T[]): Array { - // start with the biggest gap, reduce gap twice on each step - for (let gap = arr.length >> 1; gap > 0; gap >>= 1) { - for (let i = gap; i < arr.length; i++) { - const temp = arr[i]; - let j = i; // index for compared element on the left side - // shift larger elements down - while (j >= gap && arr[j - gap] > temp) { - arr[j] = arr[j - gap]; - j -= gap; - } - arr[j] = temp; // place i-th element at appropriate position - } + // start with the biggest gap, reduce gap twice on each step + for (let gap = arr.length >> 1; gap > 0; gap >>= 1) { + for (let i = gap; i < arr.length; i++) { + const temp = arr[i] + let j = i // index for compared element on the left side + // shift larger elements down + while (j >= gap && arr[j - gap] > temp) { + arr[j] = arr[j - gap] + j -= gap + } + arr[j] = temp // place i-th element at appropriate position } - return arr; + } + return arr } diff --git a/sorts/swap_sort.ts b/sorts/swap_sort.ts index 722c33b5..98d408b5 100644 --- a/sorts/swap_sort.ts +++ b/sorts/swap_sort.ts @@ -1,33 +1,32 @@ /** * @author : dev-madhurendra - * @description + * @description * Swap Sort is an algorithm to find the number of swaps required to sort an array. * @param {number[]} inputArr - Array of numbers * @return {number} - Number of swaps required to sort the array. * @see */ -export const minSwapsToSort = (inputArr: number[]): number => { - const sortedArray = inputArr.slice() - - sortedArray.sort() +export const minSwapsToSort = (inputArr: number[]): number => { + const sortedArray = inputArr.slice() - const indexMap = new Map(); + sortedArray.sort() - for (let i = 0; i < inputArr.length; i++) - indexMap.set(inputArr[i],i); + const indexMap = new Map() - let swaps = 0 - for (let i = 0; i < inputArr.length; i++) { - if (inputArr[i] !== sortedArray[i]) { - const temp = inputArr[i] - inputArr[i] = inputArr[indexMap.get(sortedArray[i])] - inputArr[indexMap.get(sortedArray[i])] = temp - indexMap.set(temp,indexMap.get(sortedArray[i])) - indexMap.set(sortedArray[i],1) - swaps++ - } + for (let i = 0; i < inputArr.length; i++) indexMap.set(inputArr[i], i) + + let swaps = 0 + for (let i = 0; i < inputArr.length; i++) { + if (inputArr[i] !== sortedArray[i]) { + const temp = inputArr[i] + inputArr[i] = inputArr[indexMap.get(sortedArray[i])] + inputArr[indexMap.get(sortedArray[i])] = temp + indexMap.set(temp, indexMap.get(sortedArray[i])) + indexMap.set(sortedArray[i], 1) + swaps++ } + } - return swaps + return swaps } diff --git a/sorts/test/bogo_sort.test.ts b/sorts/test/bogo_sort.test.ts index 81e11ae9..61d40045 100644 --- a/sorts/test/bogo_sort.test.ts +++ b/sorts/test/bogo_sort.test.ts @@ -1,15 +1,15 @@ -import { bogoSort } from '../bogo_sort'; +import { bogoSort } from '../bogo_sort' describe('BogoSort', () => { - test.each([ - { arr: [1], expectedResult: [1] }, - { arr: [2, 1], expectedResult: [1, 2] }, - { arr: [3, 1, 2], expectedResult: [1, 2, 3] }, - { arr: [3, 4, 1, 2], expectedResult: [1, 2, 3, 4] }, - ])( - 'The return value of $arr should be $expectedResult', - ({ arr, expectedResult }) => { - expect(bogoSort(arr)).toStrictEqual(expectedResult); - } - ); -}); + test.each([ + { arr: [1], expectedResult: [1] }, + { arr: [2, 1], expectedResult: [1, 2] }, + { arr: [3, 1, 2], expectedResult: [1, 2, 3] }, + { arr: [3, 4, 1, 2], expectedResult: [1, 2, 3, 4] } + ])( + 'The return value of $arr should be $expectedResult', + ({ arr, expectedResult }) => { + expect(bogoSort(arr)).toStrictEqual(expectedResult) + } + ) +}) diff --git a/sorts/test/bubble_sort.test.ts b/sorts/test/bubble_sort.test.ts index 29e11f94..334b9cb1 100644 --- a/sorts/test/bubble_sort.test.ts +++ b/sorts/test/bubble_sort.test.ts @@ -1,15 +1,17 @@ -import {bubbleSort} from "../bubble_sort" +import { bubbleSort } from '../bubble_sort' -describe("BubbleSort", () => { -  it("should return the correct value for average case", () => { -    expect(bubbleSort([8, 3, 5, 1, 4, 2])).toStrictEqual([1, 2, 3, 4, 5, 8]); -  }); - -  it("should return the correct value for worst case", () => { -    expect(bubbleSort([9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]); -   }); - -  it("should return the correct value for best case", () => { -    expect(bubbleSort([1, 2, 3, 4, 5, 8])).toStrictEqual([1, 2, 3, 4, 5, 8]); -   }); -}); \ No newline at end of file +describe('BubbleSort', () => { + it('should return the correct value for average case', () => { + expect(bubbleSort([8, 3, 5, 1, 4, 2])).toStrictEqual([1, 2, 3, 4, 5, 8]) + }) + + it('should return the correct value for worst case', () => { + expect(bubbleSort([9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9 + ]) + }) + + it('should return the correct value for best case', () => { + expect(bubbleSort([1, 2, 3, 4, 5, 8])).toStrictEqual([1, 2, 3, 4, 5, 8]) + }) +}) diff --git a/sorts/test/counting_sort.test.ts b/sorts/test/counting_sort.test.ts index 1f8d409f..68cd3d21 100644 --- a/sorts/test/counting_sort.test.ts +++ b/sorts/test/counting_sort.test.ts @@ -1,28 +1,28 @@ -import { countingSort } from "../counting_sort"; +import { countingSort } from '../counting_sort' const testCases = [ [ [3, 0, 2, 5, 4, 1], - [0, 1, 2, 3, 4, 5], + [0, 1, 2, 3, 4, 5] ], [ [6, 4, 2, 1, 3, 5], - [1, 2, 3, 4, 5, 6], + [1, 2, 3, 4, 5, 6] ], [ [11, 14, 12, 15, 16, 13], - [11, 12, 13, 14, 15, 16], + [11, 12, 13, 14, 15, 16] ], [ [13, 18, 2, 15, 43, 11], - [2, 11, 13, 15, 18, 43], - ], -]; + [2, 11, 13, 15, 18, 43] + ] +] it.each(testCases)( 'The countingSort of the array %p is %p', (input, expected) => { - const res = countingSort(input, Math.min(...input), Math.max(...input)); - expect(res).toEqual(expected); + const res = countingSort(input, Math.min(...input), Math.max(...input)) + expect(res).toEqual(expected) } -); +) diff --git a/sorts/test/cycle_sort.test.ts b/sorts/test/cycle_sort.test.ts index 08772456..4f3d1d7f 100644 --- a/sorts/test/cycle_sort.test.ts +++ b/sorts/test/cycle_sort.test.ts @@ -1,15 +1,21 @@ -import { cycleSort } from "../cycle_sort"; - -describe("Cycle Sort", () => { - it("should return the correct value for average case", () => { - expect(cycleSort([1, 4, 2, 5, 9, 6, 3, 8, 10, 7])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); - - it("should return the correct value for worst case", () => { - expect(cycleSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); - - it("should return the correct value for best case", () => { - expect(cycleSort([1, 4, 2, 9, 5, 7, 3, 8, 10, 6])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); - }); \ No newline at end of file +import { cycleSort } from '../cycle_sort' + +describe('Cycle Sort', () => { + it('should return the correct value for average case', () => { + expect(cycleSort([1, 4, 2, 5, 9, 6, 3, 8, 10, 7])).toStrictEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) + + it('should return the correct value for worst case', () => { + expect(cycleSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) + + it('should return the correct value for best case', () => { + expect(cycleSort([1, 4, 2, 9, 5, 7, 3, 8, 10, 6])).toStrictEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) +}) diff --git a/sorts/test/gnome_sort.test.ts b/sorts/test/gnome_sort.test.ts index d5a6ac1c..203d02ff 100644 --- a/sorts/test/gnome_sort.test.ts +++ b/sorts/test/gnome_sort.test.ts @@ -1,4 +1,4 @@ -import { gnomeSort } from '../gnome_sort'; +import { gnomeSort } from '../gnome_sort' describe('Testing Gnome sort', () => { const testCases: number[][] = [ @@ -7,15 +7,15 @@ describe('Testing Gnome sort', () => { [8, 3, 5, 9, 1, 7, 4, 2, 6], [9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 2, 3, 4, 5, 6, 7, 8, 9], - [1, 1, 1, 1, 1, 1, 1, 1, 1], - ]; + [1, 1, 1, 1, 1, 1, 1, 1, 1] + ] test.each(testCases)( 'should return the correct value for test case: %#', (...arr: number[]) => { expect(gnomeSort([...arr])).toStrictEqual( [...arr].sort((a: number, b: number) => a - b) - ); + ) } - ); -}); + ) +}) diff --git a/sorts/test/heap_sort.test.ts b/sorts/test/heap_sort.test.ts index 3463a91d..d5768d69 100644 --- a/sorts/test/heap_sort.test.ts +++ b/sorts/test/heap_sort.test.ts @@ -1,15 +1,21 @@ -import { HeapSort } from "../heap_sort"; +import { HeapSort } from '../heap_sort' -describe("Heap Sort", () => { - it("should return the correct value for average case", () => { - expect(HeapSort([1, 4, 2, 5, 9, 6, 3, 8, 10, 7])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); - - it("should return the correct value for worst case", () => { - expect(HeapSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); - - it("should return the correct value for best case", () => { - expect(HeapSort([1, 4, 2, 9, 5, 7, 3, 8, 10, 6])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); - }); \ No newline at end of file +describe('Heap Sort', () => { + it('should return the correct value for average case', () => { + expect(HeapSort([1, 4, 2, 5, 9, 6, 3, 8, 10, 7])).toStrictEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) + + it('should return the correct value for worst case', () => { + expect(HeapSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) + + it('should return the correct value for best case', () => { + expect(HeapSort([1, 4, 2, 9, 5, 7, 3, 8, 10, 6])).toStrictEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) +}) diff --git a/sorts/test/insertion_sort.test.ts b/sorts/test/insertion_sort.test.ts index e90c9e41..526f6da4 100644 --- a/sorts/test/insertion_sort.test.ts +++ b/sorts/test/insertion_sort.test.ts @@ -1,15 +1,17 @@ -import { insertionSort } from "../insertion_sort"; +import { insertionSort } from '../insertion_sort' -describe("Insertion Sort", () => { - it("should return the correct value for average case", () => { - expect(insertionSort([8, 3, 5, 1, 4, 2])).toStrictEqual([1, 2, 3, 4, 5, 8]); - }); +describe('Insertion Sort', () => { + it('should return the correct value for average case', () => { + expect(insertionSort([8, 3, 5, 1, 4, 2])).toStrictEqual([1, 2, 3, 4, 5, 8]) + }) - it("should return the correct value for worst case", () => { - expect(insertionSort([9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]); - }); + it('should return the correct value for worst case', () => { + expect(insertionSort([9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9 + ]) + }) - it("should return the correct value for best case", () => { - expect(insertionSort([1, 2, 3, 4, 5, 8])).toStrictEqual([1, 2, 3, 4, 5, 8]); - }); -}); + it('should return the correct value for best case', () => { + expect(insertionSort([1, 2, 3, 4, 5, 8])).toStrictEqual([1, 2, 3, 4, 5, 8]) + }) +}) diff --git a/sorts/test/merge_sort.test.ts b/sorts/test/merge_sort.test.ts index cc21b628..5ae9203f 100644 --- a/sorts/test/merge_sort.test.ts +++ b/sorts/test/merge_sort.test.ts @@ -1,7 +1,7 @@ -import { mergeSort } from "../merge_sort" +import { mergeSort } from '../merge_sort' -describe("Merge Sort", () => { - it("generating array with variable length and comparing with sorted array", () => { +describe('Merge Sort', () => { + it('generating array with variable length and comparing with sorted array', () => { const arrLenArr = [10, 200, 40000] arrLenArr.forEach((arrLen: number) => { diff --git a/sorts/test/quick_select.test.ts b/sorts/test/quick_select.test.ts index 885ed5e1..66eb7733 100644 --- a/sorts/test/quick_select.test.ts +++ b/sorts/test/quick_select.test.ts @@ -1,29 +1,29 @@ -import { QuickSelect } from "../quick_select"; +import { QuickSelect } from '../quick_select' describe('QuickSelect', () => { - test('should return the kth smallest element in an array', () => { - const array = [8, 3, 5, 1, 4, 2]; - expect(QuickSelect(array, 0)).toBe(1); - expect(QuickSelect(array, 1)).toBe(2); - expect(QuickSelect(array, 2)).toBe(3); - expect(QuickSelect(array, 3)).toBe(4); - expect(QuickSelect(array, 4)).toBe(5); - expect(QuickSelect(array, 5)).toBe(8); - }); + test('should return the kth smallest element in an array', () => { + const array = [8, 3, 5, 1, 4, 2] + expect(QuickSelect(array, 0)).toBe(1) + expect(QuickSelect(array, 1)).toBe(2) + expect(QuickSelect(array, 2)).toBe(3) + expect(QuickSelect(array, 3)).toBe(4) + expect(QuickSelect(array, 4)).toBe(5) + expect(QuickSelect(array, 5)).toBe(8) + }) - test('should work with arrays of size 1', () => { - const array = [4]; - expect(QuickSelect(array, 0)).toBe(4); - }); + test('should work with arrays of size 1', () => { + const array = [4] + expect(QuickSelect(array, 0)).toBe(4) + }) - test('should work with large arrays', () => { - const array = Array.from({length: 1000}, (_, i) => i + 1); - expect(QuickSelect(array, 499)).toBe(500); - }); + test('should work with large arrays', () => { + const array = Array.from({ length: 1000 }, (_, i) => i + 1) + expect(QuickSelect(array, 499)).toBe(500) + }) - test('should throw error when k is out of bounds', () => { - const array = [8, 3, 5, 1, 4, 2]; - expect(() => QuickSelect(array, -1)).toThrow(); - expect(() => QuickSelect(array, 6)).toThrow(); - }); -}); + test('should throw error when k is out of bounds', () => { + const array = [8, 3, 5, 1, 4, 2] + expect(() => QuickSelect(array, -1)).toThrow() + expect(() => QuickSelect(array, 6)).toThrow() + }) +}) diff --git a/sorts/test/quick_sort.test.ts b/sorts/test/quick_sort.test.ts index aa4e1167..63b0e420 100644 --- a/sorts/test/quick_sort.test.ts +++ b/sorts/test/quick_sort.test.ts @@ -1,15 +1,21 @@ -import { QuickSort } from "../quick_sort"; +import { QuickSort } from '../quick_sort' -describe("Quick Sort", () => { - it("should return the correct value for average case", () => { - expect(QuickSort([1, 4, 2, 5, 9, 6, 3, 8, 10, 7])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); - - it("should return the correct value for worst case", () => { - expect(QuickSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); - - it("should return the correct value for best case", () => { - expect(QuickSort([1, 4, 2, 9, 5, 7, 3, 8, 10, 6])).toStrictEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); - }); \ No newline at end of file +describe('Quick Sort', () => { + it('should return the correct value for average case', () => { + expect(QuickSort([1, 4, 2, 5, 9, 6, 3, 8, 10, 7])).toStrictEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) + + it('should return the correct value for worst case', () => { + expect(QuickSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])).toStrictEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) + + it('should return the correct value for best case', () => { + expect(QuickSort([1, 4, 2, 9, 5, 7, 3, 8, 10, 6])).toStrictEqual([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) +}) diff --git a/sorts/test/selection_sort.test.ts b/sorts/test/selection_sort.test.ts index 9ed5a322..955cf6ac 100644 --- a/sorts/test/selection_sort.test.ts +++ b/sorts/test/selection_sort.test.ts @@ -1,21 +1,21 @@ -import { selectionSort } from "../selection_sort"; +import { selectionSort } from '../selection_sort' -describe("Testing Selection sort", () => { - const testCases: number[][] = []; +describe('Testing Selection sort', () => { + const testCases: number[][] = [] for (let i = 0; i < 10; i++) { - const arr = []; + const arr = [] for (let j = 0; j < 100; j++) { - arr.push(Math.floor(Math.random() * 100)); + arr.push(Math.floor(Math.random() * 100)) } - testCases.push(arr); + testCases.push(arr) } test.each(testCases)( - "should return the correct value for test case: %#", + 'should return the correct value for test case: %#', (...arr: number[]) => { expect(selectionSort([...arr])).toStrictEqual( [...arr].sort((a: number, b: number) => a - b) - ); + ) } - ); -}); + ) +}) diff --git a/sorts/test/shell_sort.test.ts b/sorts/test/shell_sort.test.ts index 695050f4..ced19428 100644 --- a/sorts/test/shell_sort.test.ts +++ b/sorts/test/shell_sort.test.ts @@ -1,15 +1,21 @@ -import { shellSort } from "../shell_sort"; +import { shellSort } from '../shell_sort' -describe("Shell Sort", () => { - it("should return the correct value for average case", () => { - expect(shellSort([4, 1, 8, 10, 3, 2, 5, 0, 7, 6, 9])).toStrictEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); +describe('Shell Sort', () => { + it('should return the correct value for average case', () => { + expect(shellSort([4, 1, 8, 10, 3, 2, 5, 0, 7, 6, 9])).toStrictEqual([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) - it("should return the correct value for worst case", () => { - expect(shellSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0])).toStrictEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); + it('should return the correct value for worst case', () => { + expect(shellSort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0])).toStrictEqual([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) - it("should return the correct value for best case", () => { - expect(shellSort([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])).toStrictEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - }); -}); \ No newline at end of file + it('should return the correct value for best case', () => { + expect(shellSort([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])).toStrictEqual([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + ]) + }) +}) diff --git a/sorts/test/swap_sort.test.ts b/sorts/test/swap_sort.test.ts index 5221f57b..13998711 100644 --- a/sorts/test/swap_sort.test.ts +++ b/sorts/test/swap_sort.test.ts @@ -1,15 +1,14 @@ -import { minSwapsToSort } from "../swap_sort"; +import { minSwapsToSort } from '../swap_sort' describe('SwapSort', () => { - it.each([ - { input: [], expected: 0 }, - { input: [1, 2, 3, 4, 5, 6], expected: 0 }, - { input: [7, 6, 2, 5, 11, 0], expected: 2 }, - { input: [3, 3, 2, 1, 0], expected: 2 }, - { input: [3, 0, 2, 1, 9, 8, 7, 6], expected: 4 }, - { input: [1, 0, 14, 0, 8, 6, 8], expected: 3 }, - ])('should work for given input', ({ input, expected }) => { - expect(minSwapsToSort(input)).toEqual(expected); - }); - }); - \ No newline at end of file + it.each([ + { input: [], expected: 0 }, + { input: [1, 2, 3, 4, 5, 6], expected: 0 }, + { input: [7, 6, 2, 5, 11, 0], expected: 2 }, + { input: [3, 3, 2, 1, 0], expected: 2 }, + { input: [3, 0, 2, 1, 9, 8, 7, 6], expected: 4 }, + { input: [1, 0, 14, 0, 8, 6, 8], expected: 3 } + ])('should work for given input', ({ input, expected }) => { + expect(minSwapsToSort(input)).toEqual(expected) + }) +}) diff --git a/sorts/test/tree_sort.test.ts b/sorts/test/tree_sort.test.ts index 07cbca56..4c7b9cfc 100644 --- a/sorts/test/tree_sort.test.ts +++ b/sorts/test/tree_sort.test.ts @@ -1,4 +1,4 @@ -import { treeSort } from "../tree_sort"; +import { treeSort } from '../tree_sort' describe('TreeSort (numbers)', () => { it.each([ @@ -6,28 +6,42 @@ describe('TreeSort (numbers)', () => { { input: [1, 18, 3, 4, -5, 6], expected: [-5, 1, 3, 4, 6, 18] }, { input: [7, 6, 2, 5.2, 11, 0], expected: [0, 2, 5.2, 6, 7, 11] }, { input: [3, 3, -2, 1, 0], expected: [-2, 0, 1, 3, 3] }, - { input: [3, 0, -2.4, 1, 9, 8, -7, 6], expected: [-7, -2.4, 0, 1, 3, 6, 8, 9] }, - { input: [1, 0, -14, 0, 8.6, 6, 8], expected: [-14, 0, 0, 1, 6, 8, 8.6] }, + { + input: [3, 0, -2.4, 1, 9, 8, -7, 6], + expected: [-7, -2.4, 0, 1, 3, 6, 8, 9] + }, + { input: [1, 0, -14, 0, 8.6, 6, 8], expected: [-14, 0, 0, 1, 6, 8, 8.6] } ])('should work for given input', ({ input, expected }) => { - expect(treeSort(input)).toEqual(expected); - }); -}); + expect(treeSort(input)).toEqual(expected) + }) +}) describe('TreeSort (strings)', () => { it.each([ - { input: ["e","egr","sse","aas", "as","abs"], expected: ["aas","abs","as","e","egr","sse"] }, + { + input: ['e', 'egr', 'sse', 'aas', 'as', 'abs'], + expected: ['aas', 'abs', 'as', 'e', 'egr', 'sse'] + } ])('should work for given input', ({ input, expected }) => { - expect(treeSort(input)).toEqual(expected); - }); -}); - + expect(treeSort(input)).toEqual(expected) + }) +}) + describe('TreeSort (dates)', () => { it.each([ - { input: [new Date("2019-01-16"),new Date("2019-01-01"),new Date("2022-05-20")], expected: [new Date("2019-01-01"),new Date("2019-01-16"),new Date("2022-05-20")] }, + { + input: [ + new Date('2019-01-16'), + new Date('2019-01-01'), + new Date('2022-05-20') + ], + expected: [ + new Date('2019-01-01'), + new Date('2019-01-16'), + new Date('2022-05-20') + ] + } ])('should work for given input', ({ input, expected }) => { - expect(treeSort(input)).toEqual(expected); - }); -}); - - - \ No newline at end of file + expect(treeSort(input)).toEqual(expected) + }) +}) diff --git a/sorts/tree_sort.ts b/sorts/tree_sort.ts index e4369e52..26f74e27 100644 --- a/sorts/tree_sort.ts +++ b/sorts/tree_sort.ts @@ -7,12 +7,12 @@ * @see */ -import { BinarySearchTree } from "../data_structures/tree/binary_search_tree"; +import { BinarySearchTree } from '../data_structures/tree/binary_search_tree' export const treeSort = (arr: T[]): T[] => { - const searchTree = new BinarySearchTree(); + const searchTree = new BinarySearchTree() for (const item of arr) { - searchTree.insert(item); + searchTree.insert(item) } - return searchTree.inOrderTraversal(); -}; + return searchTree.inOrderTraversal() +} diff --git a/tsconfig.json b/tsconfig.json index 3b8b39aa..806623b8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,20 +1,19 @@ { "compilerOptions": { - /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, /* Modules */ - "module": "CommonJS", /* Specify what module code is generated. */ - + "module": "CommonJS" /* Specify what module code is generated. */, + /* Interop Constraints */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - "strictFunctionTypes": true, /* Visit https://aka.ms/tsconfig to read more about this file */ /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */, + "strictFunctionTypes": true /* Visit https://aka.ms/tsconfig to read more about this file */ /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */, + "skipLibCheck": true /* Skip type checking all .d.ts files. */ } } From b4062be2abcea61f989cabbb971ea82ad5edff5e Mon Sep 17 00:00:00 2001 From: SOZEL <80200848+TruongNhanNguyen@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:38:06 +0700 Subject: [PATCH 098/107] Refactor 0-1 Knapsack Implementation (#236) * ref: improve code readability, maintainabiity and edge case handling - Correctly throws an error if the length of the `weights` and `values` arrays are not equal - Use camelCase consistently through the codebase - Add type annotations to the function params and return types - Adding comments within the loops to clarify the logic - Ensure the function handles edge cases appropriately, such as when capacity is 0 or when weights and values arrays are empty * chore(docs): rewrite function docstring * style: format code using prettier --- dynamic_programming/knapsack.ts | 70 ++++++++++++++++----------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/dynamic_programming/knapsack.ts b/dynamic_programming/knapsack.ts index 853e50ab..0bc51012 100644 --- a/dynamic_programming/knapsack.ts +++ b/dynamic_programming/knapsack.ts @@ -1,56 +1,54 @@ /** - * @function knapsack - * @description Given weights and values of n (numberOfItems) items, put these items in a knapsack of capacity to get the maximum total value in the knapsack. In other words, given two integer arrays values[0..n-1] and weights[0..n-1] which represent values and weights associated with n items respectively. Also given an integer capacity which represents knapsack capacity, find out the maximum value subset of values[] such that sum of the weights of this subset is smaller than or equal to capacity. You cannot break an item, either pick the complete item or don’t pick it (0-1 property). - * @Complexity_Analysis - * Space complexity - O(1) - * Time complexity (independent of input) : O(numberOfItems * capacity) - * - * @return maximum value subset of values[] such that sum of the weights of this subset is smaller than or equal to capacity. - * @see [Knapsack](https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/) - * @example knapsack(3, 8, [3, 4, 5], [30, 50, 60]) = 90 + * Solves the 0-1 Knapsack Problem. + * @param capacity Knapsack capacity + * @param weights Array of item weights + * @param values Array of item values + * @returns Maximum value subset such that sum of the weights of this subset is smaller than or equal to capacity + * @throws If weights and values arrays have different lengths + * @see [Knapsack](https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/) + * @example knapsack(3, [3, 4, 5], [30, 50, 60]) // Output: 90 */ + export const knapsack = ( capacity: number, weights: number[], values: number[] -) => { - if (weights.length != values.length) { +): number => { + if (weights.length !== values.length) { throw new Error( - 'weights and values arrays should have same number of elements' + 'Weights and values arrays should have the same number of elements' ) } - const numberOfItems = weights.length + const numberOfItems: number = weights.length - // Declaring a data structure to store calculated states/values + // Initializing a 2D array to store calculated states/values const dp: number[][] = new Array(numberOfItems + 1) - - for (let i = 0; i < dp.length; i++) { - // Placing an array at each index of dp to make it a 2d matrix - dp[i] = new Array(capacity + 1) - } + .fill(0) + .map(() => new Array(capacity + 1).fill(0)) // Loop traversing each state of dp - for (let i = 0; i < numberOfItems; i++) { - for (let j = 0; j <= capacity; j++) { - if (i == 0) { - if (j >= weights[i]) { - // grab the first item if it's weight is less than remaining weight (j) - dp[i][j] = values[i] - } else { - // if weight[i] is more than remaining weight (j) leave it - dp[i][j] = 0 - } - } else if (j < weights[i]) { - // if weight of current item (weights[i]) is more than remaining weight (j), leave the current item and just carry on previous items - dp[i][j] = dp[i - 1][j] + for (let itemIndex = 1; itemIndex <= numberOfItems; itemIndex++) { + const weight = weights[itemIndex - 1] + const value = values[itemIndex - 1] + for ( + let currentCapacity = 1; + currentCapacity <= capacity; + currentCapacity++ + ) { + if (weight <= currentCapacity) { + // Select the maximum value of including the current item or excluding it + dp[itemIndex][currentCapacity] = Math.max( + value + dp[itemIndex - 1][currentCapacity - weight], + dp[itemIndex - 1][currentCapacity] + ) } else { - // select the maximum of (if current weight is collected thus adding it's value) and (if current weight is not collected thus not adding it's value) - dp[i][j] = Math.max(dp[i - 1][j - weights[i]] + values[i], dp[i - 1][j]) + // If the current item's weight exceeds the current capacity, exclude it + dp[itemIndex][currentCapacity] = dp[itemIndex - 1][currentCapacity] } } } - // Return the final maximized value at last position of dp matrix - return dp[numberOfItems - 1][capacity] + // Return the final maximized value at the last position of the dp matrix + return dp[numberOfItems][capacity] } From e1f635a7a19f1d28954eb60e4bfd7de5beffbc46 Mon Sep 17 00:00:00 2001 From: SOZEL <80200848+TruongNhanNguyen@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:14:05 +0700 Subject: [PATCH 099/107] ref: update `Heap` implementation (#237) - Improved comments for clarity and correctness. - Used default parameter values where applicable for better readability. - Consistently used `void` return type for functions without a return value. - Ensured consistent use of semicolons for statement termination. - Made minor adjustments to ensure consistency in naming and coding style. --- data_structures/heap/heap.ts | 56 ++++++++++++++---------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/data_structures/heap/heap.ts b/data_structures/heap/heap.ts index 100ce1b3..65ce9f0b 100644 --- a/data_structures/heap/heap.ts +++ b/data_structures/heap/heap.ts @@ -3,14 +3,12 @@ * In a complete binary tree each level is filled before lower levels are added * Each level is filled from left to right * - * In a (min|max) heap the value of every node is (less|greater) than that if its children + * In a (min|max) heap the value of every node is (less|greater) than that of its children * - * The heap if often implemented using an array structure. + * The heap is often implemented using an array structure. * In the array implementation, the relationship between a parent index and its two children * are ((parentindex * 2) + 1) and ((parentindex * 2) + 2) - * */ - export abstract class Heap { protected heap: T[] // A comparison function. Returns true if a should be the parent of b. @@ -23,17 +21,16 @@ export abstract class Heap { /** * Compares the value at parentIndex with the value at childIndex - * In a maxHeap the value at parentIndex should be larger than the value at childIndex - * In a minHeap the value at parentIndex should be smaller than the value at childIndex - * + * In a maxHeap, the value at parentIndex should be larger than the value at childIndex + * In a minHeap, the value at parentIndex should be smaller than the value at childIndex */ - private isRightlyPlaced(childIndex: number, parentIndex: number) { + private isRightlyPlaced(childIndex: number, parentIndex: number): boolean { return this.compare(this.heap[parentIndex], this.heap[childIndex]) } /** - * In a maxHeap the index with the larger value is returned - * In a minHeap the index with the smaller value is returned + * In a maxHeap, the index with the larger value is returned + * In a minHeap, the index with the smaller value is returned */ private getChildIndexToSwap( leftChildIndex: number, @@ -68,11 +65,11 @@ export abstract class Heap { return this.size() === 0 } - protected swap(a: number, b: number) { + protected swap(a: number, b: number): void { ;[this.heap[a], this.heap[b]] = [this.heap[b], this.heap[a]] } - protected bubbleUp(index = this.size() - 1): void { + protected bubbleUp(index: number = this.size() - 1): void { let parentIndex while (index > 0) { @@ -111,7 +108,7 @@ export abstract class Heap { } public check(): void { - return this._check() + this._check() } private _check(index: number = 0): void { @@ -122,14 +119,16 @@ export abstract class Heap { if ( this.heap[leftChildIndex] && !this.isRightlyPlaced(leftChildIndex, index) - ) + ) { throw new Error('Heap does not adhere to heap invariant') + } if ( this.heap[rightChildIndex] && !this.isRightlyPlaced(rightChildIndex, index) - ) + ) { throw new Error('Heap does not adhere to heap invariant') + } this._check(leftChildIndex) this._check(rightChildIndex) @@ -137,26 +136,17 @@ export abstract class Heap { } export class MinHeap extends Heap { - constructor( - compare = (a: T, b: T) => { - return a < b - } - ) { + constructor(compare: (a: T, b: T) => boolean = (a: T, b: T) => a < b) { super(compare) } } export class MaxHeap extends Heap { - constructor( - compare = (a: T, b: T) => { - return a > b - } - ) { + constructor(compare: (a: T, b: T) => boolean = (a: T, b: T) => a > b) { super(compare) } } -// Priority queue that supports increasePriority() in O(log(n)). The limitation is that there can only be a single element for each key, and the max number or keys must be specified at heap construction. Most of the functions are wrappers around MinHeap functions and update the keys array. export class PriorityQueue extends MinHeap { // Maps from the n'th node to its index within the heap. private keys: number[] @@ -166,29 +156,27 @@ export class PriorityQueue extends MinHeap { constructor( keys_index: (a: T) => number, num_keys: number, - compare = (a: T, b: T) => { - return a < b - } + compare: (a: T, b: T) => boolean = (a: T, b: T) => a < b ) { super(compare) this.keys = Array(num_keys).fill(-1) this.keys_index = keys_index } - protected swap(a: number, b: number) { + protected swap(a: number, b: number): void { const akey = this.keys_index(this.heap[a]) const bkey = this.keys_index(this.heap[b]) ;[this.keys[akey], this.keys[bkey]] = [this.keys[bkey], this.keys[akey]] super.swap(a, b) } - public insert(value: T) { + public insert(value: T): void { this.keys[this.keys_index(value)] = this.size() super.insert(value) } public extract(): T { - // Unmark the the highest priority element and set key to zero for the last element in the heap. + // Unmark the highest priority element and set key to zero for the last element in the heap. this.keys[this.keys_index(this.heap[0])] = -1 if (this.size() > 1) { this.keys[this.keys_index(this.heap[this.size() - 1])] = 0 @@ -196,8 +184,8 @@ export class PriorityQueue extends MinHeap { return super.extract() } - public increasePriority(idx: number, value: T) { - if (this.keys[idx] == -1) { + public increasePriority(idx: number, value: T): void { + if (this.keys[idx] === -1) { // If the key does not exist, insert the value. this.insert(value) return From 59984eef0047e9a888ef0be2d2a751fce32d58d5 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Wed, 24 Apr 2024 21:41:51 +0200 Subject: [PATCH 100/107] Add codecov badge (#225) * Update DIRECTORY.md * docs: add codecov badge --------- Co-authored-by: autoprettier --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5412c60a..5836b72f 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ TypeScript Repository of TheAlgorithms, which implements various algorithms and [![TypeScript Banner][banner]](DIRECTORY.md) + [![codecov](https://codecov.io/gh/TheAlgorithms/TypeScript/graph/badge.svg?token=Z51PSAC1FD)](https://codecov.io/gh/TheAlgorithms/TypeScript) [![Contributions Welcome][welcome]](CONTRIBUTING.md) [![Discord chat][chat]][discord-server] From a08a1226b6a0d186954d16712d252b0a2a04faf0 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Sat, 25 May 2024 13:04:50 +0200 Subject: [PATCH 101/107] style: fix some eslint warnings (#240) * style: mark `stepSize` as `const` * style: fix some `eslint` warnings --- graph/dijkstra.ts | 4 ++-- search/jump_search.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/graph/dijkstra.ts b/graph/dijkstra.ts index 7804a592..1ad76fa0 100644 --- a/graph/dijkstra.ts +++ b/graph/dijkstra.ts @@ -1,4 +1,4 @@ -import { MinHeap, PriorityQueue } from '../data_structures/heap/heap' +import { PriorityQueue } from '../data_structures/heap/heap' /** * @function dijkstra * @description Compute the shortest path from a source node to all other nodes. The input graph is in adjacency list form. It is a multidimensional array of edges. graph[i] holds the edges for the i'th node. Each edge is a 2-tuple where the 0'th item is the destination node, and the 1'th item is the edge weight. @@ -32,7 +32,7 @@ export const dijkstra = ( distances[start] = 0 while (priorityQueue.size() > 0) { - const [node, _] = priorityQueue.extract() + const node = priorityQueue.extract()[0] graph[node].forEach(([child, weight]) => { const new_distance = distances[node] + weight if (new_distance < distances[child]) { diff --git a/search/jump_search.ts b/search/jump_search.ts index 9707dbf3..e54aa196 100644 --- a/search/jump_search.ts +++ b/search/jump_search.ts @@ -22,8 +22,8 @@ export const jumpSearch = (array: number[], target: number): number => { if (array.length === 0) return -1 // declare pointers for the current and next indexes and step size + const stepSize: number = Math.floor(Math.sqrt(array.length)) let currentIdx: number = 0, - stepSize: number = Math.floor(Math.sqrt(array.length)), nextIdx: number = stepSize while (array[nextIdx - 1] < target) { From 8c8a0ecf2de803390983876e48d62455bd3f51ec Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Thu, 6 Jun 2024 04:44:45 +0200 Subject: [PATCH 102/107] style: use `for-of` (#241) --- dynamic_programming/coin_change.ts | 10 +++++----- graph/prim.ts | 3 +-- sorts/counting_sort.ts | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/dynamic_programming/coin_change.ts b/dynamic_programming/coin_change.ts index 0734fb9a..2e9e7b0d 100644 --- a/dynamic_programming/coin_change.ts +++ b/dynamic_programming/coin_change.ts @@ -17,12 +17,12 @@ export const coinChange = (money: number, coins: number[]): CoinChange => { minCoins[0] = 0 // Fill in the DP table - for (let i = 0; i < coins.length; i++) { + for (const coin of coins) { for (let j = 0; j <= money; j++) { - if (j >= coins[i]) { - if (minCoins[j] > 1 + minCoins[j - coins[i]]) { - minCoins[j] = 1 + minCoins[j - coins[i]] - lastCoin[j] = coins[i] + if (j >= coin) { + if (minCoins[j] > 1 + minCoins[j - coin]) { + minCoins[j] = 1 + minCoins[j - coin] + lastCoin[j] = coin } } } diff --git a/graph/prim.ts b/graph/prim.ts index 3261c633..b3f565c7 100644 --- a/graph/prim.ts +++ b/graph/prim.ts @@ -51,8 +51,7 @@ const add_children = ( priorityQueue: PriorityQueue, node: number ) => { - for (let i = 0; i < graph[node].length; ++i) { - const out_edge = graph[node][i] + for (const out_edge of graph[node]) { // By increasing the priority, we ensure we only add each vertex to the queue one time, and the queue will be at most size V. priorityQueue.increasePriority( out_edge[0], diff --git a/sorts/counting_sort.ts b/sorts/counting_sort.ts index cedad89f..49e76232 100644 --- a/sorts/counting_sort.ts +++ b/sorts/counting_sort.ts @@ -13,7 +13,7 @@ export const countingSort = (inputArr: number[], min: number, max: number) => { const count = new Array(max - min + 1).fill(0) - for (let i = 0; i < inputArr.length; i++) count[inputArr[i] - min]++ + for (const element of inputArr) count[element - min]++ count[0] -= 1 From d42b9623626eea39372bfcfa051a11cffbc49a1d Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Sat, 8 Jun 2024 12:50:47 +0200 Subject: [PATCH 103/107] style: lint `tries.ts` (#242) * style: resolve `consistent-indexed-object-style` * style: remove redundant constructor * style: resolve `non-inferrable-types` --- data_structures/tries/tries.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/data_structures/tries/tries.ts b/data_structures/tries/tries.ts index 78dc1432..2ec99c94 100644 --- a/data_structures/tries/tries.ts +++ b/data_structures/tries/tries.ts @@ -5,12 +5,12 @@ class TrieNode { /** * An object that stores child nodes for each character in the alphabet. */ - children: { [key: string]: TrieNode } = {} + children: Record = {} /** * Indicates whether the node represents the end of a word. */ - isWord: boolean = false + isWord = false } /** @@ -22,11 +22,6 @@ export class Trie { */ root: TrieNode = new TrieNode() - /** - * Creates a new Trie instance. - */ - constructor() {} - /** * Inserts a word into the Trie. * @@ -51,7 +46,7 @@ export class Trie { * If false, the method returns true only if an exact match is found. * @returns True if the word (or prefix) is found in the Trie; otherwise, false. */ - public find(word: string, isPrefixMatch: boolean = false): boolean { + public find(word: string, isPrefixMatch = false): boolean { return this.searchNode(this.root, word, isPrefixMatch) } From 869135a83629d6df9f3e0050f9d1449046e30966 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Tue, 11 Jun 2024 22:09:30 +0200 Subject: [PATCH 104/107] style: use `T[]` instead of `Array` (#243) --- sorts/shell_sort.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sorts/shell_sort.ts b/sorts/shell_sort.ts index 4b1061ba..1a409659 100644 --- a/sorts/shell_sort.ts +++ b/sorts/shell_sort.ts @@ -9,11 +9,11 @@ * Average case - O(n log(n)^2) * * @param {T[]} arr - The input array - * @return {Array} - The sorted array. + * @return {T[]} - The sorted array. * @see [Shell Sort] (https://www.geeksforgeeks.org/shellsort/) * @example shellSort([4, 1, 8, 10, 3, 2, 5, 0, 7, 6, 9]) = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] */ -export function shellSort(arr: T[]): Array { +export function shellSort(arr: T[]): T[] { // start with the biggest gap, reduce gap twice on each step for (let gap = arr.length >> 1; gap > 0; gap >>= 1) { for (let i = gap; i < arr.length; i++) { From e6d916e7bb80a43750fe5f6bbf92cefa9612ead2 Mon Sep 17 00:00:00 2001 From: Federico Fiaschi Date: Sun, 4 Aug 2024 07:50:19 +0200 Subject: [PATCH 105/107] feat: add fibonaccisearch algorithm (#244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add fibonaccisearch algorithm * test: add test for fibonacci search algorithm * fix: changed variable names and function return * remove redundant @function * fix tests * fix type * fix formatting --------- Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> Co-authored-by: Lars Mueller --- search/fibonacci_search.ts | 57 ++++++++++++++++++++++++++++ search/test/fibonacci_search.test.ts | 18 +++++++++ 2 files changed, 75 insertions(+) create mode 100644 search/fibonacci_search.ts create mode 100644 search/test/fibonacci_search.test.ts diff --git a/search/fibonacci_search.ts b/search/fibonacci_search.ts new file mode 100644 index 00000000..b0125277 --- /dev/null +++ b/search/fibonacci_search.ts @@ -0,0 +1,57 @@ +/** + * @description Fibonacci search algorithm for a sorted array. + * + * The algorithm searches for a specific value in a sorted array using Fibonacci numbers + * to divide the array into smaller subarrays. This algorithm is useful for large arrays where + * the cost of accessing elements is high. + * + * @param {number[]} array - sorted list of numbers + * @param {number} target - target number to search for + * @return {number | null} - index of the target number in the list, or null if not found + * @see [FibonacciSearch](https://www.geeksforgeeks.org/fibonacci-search/) + * @example fibonacciSearch([1,2,3], 2) => 1 + * @example fibonacciSearch([4,5,6], 2) => null + */ + +export const fibonacciSearch = ( + array: number[], + target: number +): number | null => { + const arrayLength = array.length + let a = 0 // (n-2)'th Fibonacci No. + let b = 1 // (n-1)'th Fibonacci No. + let c = a + b // n'th Fibonacci + + while (c < arrayLength) { + a = b + b = c + c = a + b + } + + let offset = -1 + + while (c > 1) { + let i = Math.min(offset + a, arrayLength - 1) + + if (array[i] < target) { + c = b + b = a + a = c - b + offset = i + } else if (array[i] > target) { + c = a + b = b - a + a = c - b + } else { + // Element found then return index + return i + } + } + + if (b && array[offset + 1] === target) { + return offset + 1 + } + + // Element not found then return null + return null +} diff --git a/search/test/fibonacci_search.test.ts b/search/test/fibonacci_search.test.ts new file mode 100644 index 00000000..5b2b54b7 --- /dev/null +++ b/search/test/fibonacci_search.test.ts @@ -0,0 +1,18 @@ +import { fibonacciSearch } from '../fibonacci_search' + +describe('Fibonacci search', () => { + test.each([ + [[1, 2, 3], 2, 1], + [[4, 5, 6], 2, null], + [[10, 22, 35, 40, 45, 50, 80, 82, 85, 90, 100], 85, 8], + [[], 1, null], + [[1], 1, 0], + [[1, 3, 5, 7, 9, 11, 13], 11, 5], + [[1, 3, 5, 7, 9, 11, 13], 8, null] + ])( + 'of %o, searching for %o, expected %i', + (array: number[], target: number, expected: number | null) => { + expect(fibonacciSearch(array, target)).toBe(expected) + } + ) +}) From 44127b253941c06c93e2815bd8a8e222373328a7 Mon Sep 17 00:00:00 2001 From: Federico Fiaschi Date: Mon, 5 Aug 2024 17:44:53 +0200 Subject: [PATCH 106/107] Exponential search (#247) * feat: add exponential search * test: add test for exponential search * fix : prettier fix * fix: added parameters to iterative binary search * fix: prettier fix #2 * fix: modified the return on binary search and related tests --- search/binary_search.ts | 32 ++++++++++----------- search/exponential_search.ts | 40 ++++++++++++++++++++++++++ search/test/binary_search.test.ts | 16 ++++++----- search/test/exponential_search.test.ts | 19 ++++++++++++ 4 files changed, 84 insertions(+), 23 deletions(-) create mode 100644 search/exponential_search.ts create mode 100644 search/test/exponential_search.test.ts diff --git a/search/binary_search.ts b/search/binary_search.ts index 39d380a4..cf86f39a 100644 --- a/search/binary_search.ts +++ b/search/binary_search.ts @@ -8,25 +8,25 @@ * * @param {number[]} array - sorted list of numbers * @param {number} target - target number to search for - * @return {number} - index of the target number in the list, or -1 if not found + * @return {number} - index of the target number in the list, or null if not found * @see [BinarySearch](https://www.geeksforgeeks.org/binary-search/) * @example binarySearch([1,2,3], 2) => 1 - * @example binarySearch([4,5,6], 2) => -1 + * @example binarySearch([4,5,6], 2) => null */ export const binarySearchIterative = ( array: number[], - target: number -): number => { - if (array.length === 0) return -1 - - // declare pointers for the start, middle and end indices - let start = 0, - end = array.length - 1, - middle = (start + end) >> 1 + target: number, + start: number = 0, + end: number = array.length - 1 +): number | null => { + if (array.length === 0) return null // ensure the target is within the bounds of the array - if (target < array[start] || target > array[end]) return -1 + if (target < array[start] || target > array[end]) return null + + // declare pointers for the middle index + let middle = (start + end) >> 1 while (array[middle] !== target && start <= end) { // if the target is less than the middle value, move the end pointer to be middle -1 to narrow the search space @@ -37,7 +37,7 @@ export const binarySearchIterative = ( middle = (start + end) >> 1 } // return the middle index if it is equal to target - return array[middle] === target ? middle : -1 + return array[middle] === target ? middle : null } export const binarySearchRecursive = ( @@ -45,16 +45,16 @@ export const binarySearchRecursive = ( target: number, start = 0, end = array.length - 1 -): number => { - if (array.length === 0) return -1 +): number | null => { + if (array.length === 0) return null // ensure the target is within the bounds of the array - if (target < array[start] || target > array[end]) return -1 + if (target < array[start] || target > array[end]) return null const middle = (start + end) >> 1 if (array[middle] === target) return middle // target found - if (start > end) return -1 // target not found + if (start > end) return null // target not found // if the target is less than the middle value, move the end pointer to be middle -1 to narrow the search space // otherwise, move the start pointer to be middle + 1 diff --git a/search/exponential_search.ts b/search/exponential_search.ts new file mode 100644 index 00000000..4a8eba47 --- /dev/null +++ b/search/exponential_search.ts @@ -0,0 +1,40 @@ +import { binarySearchIterative } from './binary_search' + +/** + * @description Exponential search algorithm for a sorted array. + * + * The algorithm searches for a specific value in a sorted array by first finding a range + * where the value may be present and then performing a binary search within that range. + * + * Compared with binary search, exponential search can be more convenient and advantageous + * in cases where the element to be searched is closer to the beginning of the array, + * thus avoiding several comparisons that would make the search more verbose. + * + * @param {number[]} array - sorted list of numbers + * @param {number} x - target number to search for + * @return {number | null} - index of the target number in the list, or null if not found + * @see [ExponentialSearch](https://www.geeksforgeeks.org/exponential-search/) + * @example exponentialSearch([1, 2, 3, 4, 5], 3) => 2 + * @example exponentialSearch([10, 20, 30, 40, 50], 35) => null + */ + +export const exponentialSearch = ( + array: number[], + x: number +): number | null => { + const arrayLength = array.length + if (arrayLength === 0) return null + + if (array[0] === x) return 0 + + let i = 1 + while (i < arrayLength && array[i] <= x) { + i = i * 2 + } + + const start = Math.floor(i / 2) + const end = Math.min(i, arrayLength - 1) + const result = binarySearchIterative(array, x, start, end) + + return result +} diff --git a/search/test/binary_search.test.ts b/search/test/binary_search.test.ts index 6ebd12d9..13b13251 100644 --- a/search/test/binary_search.test.ts +++ b/search/test/binary_search.test.ts @@ -2,7 +2,7 @@ import { binarySearchIterative, binarySearchRecursive } from '../binary_search' describe('BinarySearch', () => { const testArray: number[] = [1, 2, 3, 4] - type FunctionsArray = { (array: number[], index: number): number }[] + type FunctionsArray = { (array: number[], index: number): number | null }[] const functions: FunctionsArray = [ binarySearchIterative, binarySearchRecursive @@ -12,14 +12,16 @@ describe('BinarySearch', () => { it('should be defined', () => { expect(func(testArray, 2)).toBeDefined() }) - it('should return a number', () => { - expect(typeof func(testArray, 2)).toBe('number') + it('should return a number or null', () => { + expect( + typeof func(testArray, 2) === 'number' || func(testArray, 2) === null + ).toBe(true) }) - it('should return -1 if the target is not found in the array', () => { - expect(func(testArray, 5)).toBe(-1) + it('should return null if the target is not found in the array', () => { + expect(func(testArray, 5)).toBe(null) }) - it('should return -1 if there are no elements in the array', () => { - expect(func([], 5)).toBe(-1) + it('should return null if there are no elements in the array', () => { + expect(func([], 5)).toBe(null) }) it('should return the index of the target if it is found in the array', () => { expect(func(testArray, 2)).toBe(1) diff --git a/search/test/exponential_search.test.ts b/search/test/exponential_search.test.ts new file mode 100644 index 00000000..80f6a07f --- /dev/null +++ b/search/test/exponential_search.test.ts @@ -0,0 +1,19 @@ +import { exponentialSearch } from '../exponential_search' + +describe('Exponential search', () => { + test.each([ + [[1, 2, 3, 4, 5], 3, 2], + [[10, 20, 30, 40, 50], 35, null], + [[10, 20, 30, 40, 50], 10, 0], + [[10, 20, 30, 40, 50], 50, 4], + [[10, 20, 30, 40, 50], 60, null], + [[], 10, null], + [[1, 2, 3, 4, 5], 1, 0], + [[1, 2, 3, 4, 5], 5, 4] + ])( + 'of %o, searching for %o, expected %i', + (array: number[], target: number, expected: number | null) => { + expect(exponentialSearch(array, target)).toBe(expected) + } + ) +}) From 19b4ced86c99815f142d4a46a028f55487b8038a Mon Sep 17 00:00:00 2001 From: Aadish Jain <121042282+mapcrafter2048@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:51:48 +0530 Subject: [PATCH 107/107] Added the implementation of the Edmond Karp algorithm along with test cases (#252) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added the implementation for bijection method binary to decimal and euler method * Added the implementation of the edmondkarp along with tests * Update graph/edmondkarp.ts Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> * Update edmondkarp.ts * Update graph/edmondkarp.ts Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> * Implement the furhter changes to make the algorithm more refined * Updated the test cases Updated the test cases * Updated the code and rewrite some functions Updated the code and rewrite some functions * Implement the optimal stack queue implementation in the edmond karp algorithm * removed the bisection_method.ts, decimal_convert.ts, euler_method.ts * Revert changes to package.json and package-lock.json --------- Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- graph/edmonds_karp.ts | 97 +++++++++++++++++++++++++++++++++ graph/test/edmonds_karp.test.ts | 82 ++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 graph/edmonds_karp.ts create mode 100644 graph/test/edmonds_karp.test.ts diff --git a/graph/edmonds_karp.ts b/graph/edmonds_karp.ts new file mode 100644 index 00000000..fb781a42 --- /dev/null +++ b/graph/edmonds_karp.ts @@ -0,0 +1,97 @@ +import { StackQueue } from '../data_structures/queue/stack_queue' + +/** + * @function edmondsKarp + * @description Compute the maximum flow from a source node to a sink node using the Edmonds-Karp algorithm. + * @Complexity_Analysis + * Time complexity: O(V * E^2) where V is the number of vertices and E is the number of edges. + * Space Complexity: O(E) due to residual graph representation. + * @param {[number, number][][]} graph - The graph in adjacency list form. + * @param {number} source - The source node. + * @param {number} sink - The sink node. + * @return {number} - The maximum flow from the source node to the sink node. + * @see https://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm + */ +export default function edmondsKarp( + graph: [number, number][][], + source: number, + sink: number +): number { + const n = graph.length + + // Initialize residual graph + const residualGraph: [number, number][][] = Array.from( + { length: n }, + () => [] + ) + + // Build residual graph from the original graph + for (let u = 0; u < n; u++) { + for (const [v, cap] of graph[u]) { + if (cap > 0) { + residualGraph[u].push([v, cap]) // Forward edge + residualGraph[v].push([u, 0]) // Reverse edge with 0 capacity + } + } + } + + const findAugmentingPath = (parent: (number | null)[]): number => { + const visited = Array(n).fill(false) + const queue = new StackQueue() + queue.enqueue(source) + visited[source] = true + parent[source] = null + + while (queue.length() > 0) { + const u = queue.dequeue() + for (const [v, cap] of residualGraph[u]) { + if (!visited[v] && cap > 0) { + parent[v] = u + visited[v] = true + if (v === sink) { + // Return the bottleneck capacity along the path + let pathFlow = Infinity + let current = v + while (parent[current] !== null) { + const prev = parent[current]! + const edgeCap = residualGraph[prev].find( + ([node]) => node === current + )![1] + pathFlow = Math.min(pathFlow, edgeCap) + current = prev + } + return pathFlow + } + queue.enqueue(v) + } + } + } + return 0 + } + + let maxFlow = 0 + const parent = Array(n).fill(null) + + while (true) { + const pathFlow = findAugmentingPath(parent) + if (pathFlow === 0) break // No augmenting path found + + // Update the capacities and reverse capacities in the residual graph + let v = sink + while (parent[v] !== null) { + const u = parent[v]! + // Update capacity of the forward edge + const forwardEdge = residualGraph[u].find(([node]) => node === v)! + forwardEdge[1] -= pathFlow + // Update capacity of the reverse edge + const reverseEdge = residualGraph[v].find(([node]) => node === u)! + reverseEdge[1] += pathFlow + + v = u + } + + maxFlow += pathFlow + } + + return maxFlow +} diff --git a/graph/test/edmonds_karp.test.ts b/graph/test/edmonds_karp.test.ts new file mode 100644 index 00000000..22711ab9 --- /dev/null +++ b/graph/test/edmonds_karp.test.ts @@ -0,0 +1,82 @@ +import edmondsKarp from '../edmonds_karp' + +describe('Edmonds-Karp Algorithm', () => { + it('should find the maximum flow in a simple graph', () => { + const graph: [number, number][][] = [ + [ + [1, 3], + [2, 2] + ], // Node 0: Edges to node 1 (capacity 3), and node 2 (capacity 2) + [[3, 2]], // Node 1: Edge to node 3 (capacity 2) + [[3, 3]], // Node 2: Edge to node 3 (capacity 3) + [] // Node 3: No outgoing edges + ] + const source = 0 + const sink = 3 + const maxFlow = edmondsKarp(graph, source, sink) + expect(maxFlow).toBe(4) + }) + + it('should find the maximum flow in a more complex graph', () => { + const graph: [number, number][][] = [ + [ + [1, 10], + [2, 10] + ], // Node 0: Edges to node 1 and node 2 (both capacity 10) + [ + [3, 4], + [4, 8] + ], // Node 1: Edges to node 3 (capacity 4), and node 4 (capacity 8) + [[4, 9]], // Node 2: Edge to node 4 (capacity 9) + [[5, 10]], // Node 3: Edge to node 5 (capacity 10) + [[5, 10]], // Node 4: Edge to node 5 (capacity 10) + [] // Node 5: No outgoing edges (sink) + ] + const source = 0 + const sink = 5 + const maxFlow = edmondsKarp(graph, source, sink) + expect(maxFlow).toBe(14) + }) + + it('should return 0 when there is no path from source to sink', () => { + const graph: [number, number][][] = [ + [], // Node 0: No outgoing edges + [], // Node 1: No outgoing edges + [] // Node 2: No outgoing edges (sink) + ] + const source = 0 + const sink = 2 + const maxFlow = edmondsKarp(graph, source, sink) + expect(maxFlow).toBe(0) + }) + + it('should handle graphs with no edges', () => { + const graph: [number, number][][] = [ + [], // Node 0: No outgoing edges + [], // Node 1: No outgoing edges + [] // Node 2: No outgoing edges + ] + const source = 0 + const sink = 2 + const maxFlow = edmondsKarp(graph, source, sink) + expect(maxFlow).toBe(0) + }) + + it('should handle graphs with self-loops', () => { + const graph: [number, number][][] = [ + [ + [0, 10], + [1, 10] + ], // Node 0: Self-loop with capacity 10, and edge to node 1 (capacity 10) + [ + [1, 10], + [2, 10] + ], // Node 1: Self-loop and edge to node 2 + [] // Node 2: No outgoing edges (sink) + ] + const source = 0 + const sink = 2 + const maxFlow = edmondsKarp(graph, source, sink) + expect(maxFlow).toBe(10) + }) +})