From c3cc796723c636f71a9a27b2f08b4dfdac7ecbb2 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 10:16:33 +0100 Subject: [PATCH 001/127] refactor: update formatAs12HourClock function to improve time parsing and period handling --- format-clock-edge-cases/timeConverter.js | 31 ++++++++++++++++++------ 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index 310c07bd9..5c54f88ed 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -1,11 +1,28 @@ -function formatAs12HourClock(time) { +// function formatAs12HourClock(time) { - const hours = Number(time.slice(0, 2)); +// const hours = Number(time.slice(0, 2)); - if (hours > 12) { - return `${hours - 12}:00 pm`; +// if (hours > 12) { +// return `${hours - 12}:00 pm`; +// } +// return `${time} am`; +// } + +// export {formatAs12HourClock}; + +function formatAs12HourClock(time){ + const [hourPart, minutePart] = time.split(":"); + const hours = Number(hourPart); + + let period; + if(hours < 12){ + period = "am"; + } else { + period = "pm"; } - return `${time} am`; -} -export {formatAs12HourClock}; + let displayHour = hours % 12; + if(displayHour === 0){ + displayHour = 12; + } +} From b03e0fbd6025ddf479c53fda059c6782d01a865a Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 10:43:31 +0100 Subject: [PATCH 002/127] refactor: update test syntax to use arrow functions for consistency --- format-clock-edge-cases/timeConverter.test.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index 88f2af094..87ebf6f0d 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -2,10 +2,13 @@ import {formatAs12HourClock} from "./timeConverter.js"; import assert from "node:assert"; import test from "node:test"; -test("correctly convert time after 12:00", function(){ +test("correctly convert time after 12:00", () => { assert.equal(formatAs12HourClock("23:00"), "11:00 pm"); }); -test("can correctly convert morning time", function() { +test("can correctly convert morning time", () => { assert.equal(formatAs12HourClock("08:00"), "08:00 am"); }); +test("converts a single-digit morning hour and drops leading zero", () => { + assert.equal(formatAs12HourClock("08:00"), "8:00am"); +}) \ No newline at end of file From 05e8ef311bd3e4cd59181cb6001f96f960649d76 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 10:44:14 +0100 Subject: [PATCH 003/127] fix: ensure formatAs12HourClock function exports correctly --- format-clock-edge-cases/timeConverter.js | 1 + 1 file changed, 1 insertion(+) diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index 5c54f88ed..cfc15cf0d 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -26,3 +26,4 @@ function formatAs12HourClock(time){ displayHour = 12; } } +export {formatAs12HourClock}; From 1544b3863f7bc83092b1a3779f123901ddae1f13 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 10:47:01 +0100 Subject: [PATCH 004/127] test: add test case for converting midnight time --- format-clock-edge-cases/timeConverter.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index 87ebf6f0d..958577764 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -11,4 +11,7 @@ test("can correctly convert morning time", () => { }); test("converts a single-digit morning hour and drops leading zero", () => { assert.equal(formatAs12HourClock("08:00"), "8:00am"); +}) +test("converts correctly to midnight", () => { + assert.equal(formatAs12HourClock("00:00"), "12:00am"); }) \ No newline at end of file From 8230a0e18ffb9f272d44bd8d3022cb0648cfb923 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 12:08:19 +0100 Subject: [PATCH 005/127] refactor: improve time conversion logic and enhance test cases for clarity --- format-clock-edge-cases/timeConverter.test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index 958577764..526b54add 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -12,6 +12,9 @@ test("can correctly convert morning time", () => { test("converts a single-digit morning hour and drops leading zero", () => { assert.equal(formatAs12HourClock("08:00"), "8:00am"); }) -test("converts correctly to midnight", () => { +test("converts exactly to midnight", () => { assert.equal(formatAs12HourClock("00:00"), "12:00am"); +}) +test("converts time just after midnight", () => { + assert.equal(formatAs12HourClock("00:30"), "12:30am"); }) \ No newline at end of file From ead95df8677dafc76d86a95af0136c91a71aa890 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 12:08:43 +0100 Subject: [PATCH 006/127] fix: correct return statement in formatAs12HourClock function for accurate time formatting --- format-clock-edge-cases/timeConverter.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index cfc15cf0d..8c790c71e 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -25,5 +25,7 @@ function formatAs12HourClock(time){ if(displayHour === 0){ displayHour = 12; } + return `${displayHour}:${minutePart} ${period}` } export {formatAs12HourClock}; +console.log(formatAs12HourClock("24:00")) From 19e10f50ad39a1576e23461bad31f26c6d514ab2 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 12:10:41 +0100 Subject: [PATCH 007/127] test: add test case for converting the last minute before noon --- format-clock-edge-cases/timeConverter.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index 526b54add..1439f3645 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -17,4 +17,7 @@ test("converts exactly to midnight", () => { }) test("converts time just after midnight", () => { assert.equal(formatAs12HourClock("00:30"), "12:30am"); +}) +test("converts the last minute before noon", () => { + assert.equal(formatAs12HourClock("11:59"), "11:59am"); }) \ No newline at end of file From 15938a2f6f3dba6ac81a0574486468eeedf2f395 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 12:17:57 +0100 Subject: [PATCH 008/127] test: add test case for converting exact noon to pm --- format-clock-edge-cases/timeConverter.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index 1439f3645..d17001510 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -20,4 +20,7 @@ test("converts time just after midnight", () => { }) test("converts the last minute before noon", () => { assert.equal(formatAs12HourClock("11:59"), "11:59am"); +}) +test("converts exact noon to pm", () => { + assert.equal(formatAs12HourClock("12:00"), "12:00pm"); }) \ No newline at end of file From 8acdeaac7b1ecf042a74ecbac66df04d501780de Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 12:24:44 +0100 Subject: [PATCH 009/127] test: add test case for converting time just after noon --- format-clock-edge-cases/timeConverter.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index d17001510..e6de2a0ae 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -23,4 +23,7 @@ test("converts the last minute before noon", () => { }) test("converts exact noon to pm", () => { assert.equal(formatAs12HourClock("12:00"), "12:00pm"); +}) +test("convert time just after noon", () => { + assert.equal(formatAs12HourClock("12:30"), "12:30pm"); }) \ No newline at end of file From a7d1115808deaf5f887c330cd6b91d9ab1327965 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 12:31:15 +0100 Subject: [PATCH 010/127] fix: add missing newline at end of timeConverter.test.js --- format-clock-edge-cases/timeConverter.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index e6de2a0ae..5c77479ae 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -26,4 +26,4 @@ test("converts exact noon to pm", () => { }) test("convert time just after noon", () => { assert.equal(formatAs12HourClock("12:30"), "12:30pm"); -}) \ No newline at end of file +}) From ee8f85b58e813844d51c47595bfbdfc698cd94f3 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 14:13:43 +0100 Subject: [PATCH 011/127] fix: remove space before am/pm in time formatting and clean up test cases --- format-clock-edge-cases/timeConverter.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index 5c77479ae..35f0353f3 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -3,12 +3,9 @@ import assert from "node:assert"; import test from "node:test"; test("correctly convert time after 12:00", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00 pm"); + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); }); -test("can correctly convert morning time", () => { - assert.equal(formatAs12HourClock("08:00"), "08:00 am"); -}); test("converts a single-digit morning hour and drops leading zero", () => { assert.equal(formatAs12HourClock("08:00"), "8:00am"); }) @@ -27,3 +24,6 @@ test("converts exact noon to pm", () => { test("convert time just after noon", () => { assert.equal(formatAs12HourClock("12:30"), "12:30pm"); }) +test("converts the first afternoon hour", () => { + assert.equal(formatAs12HourClock("13:00"), "1:30pm"); +}) \ No newline at end of file From f93cd35b0045c49fcd1009cf6b44e0d6bdf86104 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 14:13:53 +0100 Subject: [PATCH 012/127] fix: remove space before period in time formatting --- format-clock-edge-cases/timeConverter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index 8c790c71e..2838957f9 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -25,7 +25,7 @@ function formatAs12HourClock(time){ if(displayHour === 0){ displayHour = 12; } - return `${displayHour}:${minutePart} ${period}` + return `${displayHour}:${minutePart}${period}`; } export {formatAs12HourClock}; console.log(formatAs12HourClock("24:00")) From 59863c5e7088f6732b3ef324778de64c1f8a6e9d Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 14:15:29 +0100 Subject: [PATCH 013/127] test: add test case for converting late evening hour --- format-clock-edge-cases/timeConverter.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index 35f0353f3..3e85ff048 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -26,4 +26,7 @@ test("convert time just after noon", () => { }) test("converts the first afternoon hour", () => { assert.equal(formatAs12HourClock("13:00"), "1:30pm"); +}) +test("converts late evening hour", () => { + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); }) \ No newline at end of file From c6ed571c83cfb10cf15f19c3a8f1e55ce0b9e62e Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 14:18:46 +0100 Subject: [PATCH 014/127] test: add test case for converting last minute of the day --- format-clock-edge-cases/timeConverter.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index 3e85ff048..e35005af7 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -29,4 +29,7 @@ test("converts the first afternoon hour", () => { }) test("converts late evening hour", () => { assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}) +test("converts last minute of the day", () => { + assert.equal(formatAs12HourClock("23:59"), "11:59pm"); }) \ No newline at end of file From ced1c53a2856d38caa69fe7991ffe0447aa69f6a Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 14:21:23 +0100 Subject: [PATCH 015/127] fix: correct expected output for first afternoon hour test case --- format-clock-edge-cases/timeConverter.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index e35005af7..95e2dbb63 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -25,7 +25,7 @@ test("convert time just after noon", () => { assert.equal(formatAs12HourClock("12:30"), "12:30pm"); }) test("converts the first afternoon hour", () => { - assert.equal(formatAs12HourClock("13:00"), "1:30pm"); + assert.equal(formatAs12HourClock("13:00"), "1:00pm"); }) test("converts late evening hour", () => { assert.equal(formatAs12HourClock("23:00"), "11:00pm"); From 9f0876ffc3e682040df0d6091c22839210580481 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 14:27:19 +0100 Subject: [PATCH 016/127] test: add test case for preserving minutes with leading zero --- format-clock-edge-cases/timeConverter.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index 95e2dbb63..dde4dfa88 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -32,4 +32,7 @@ test("converts late evening hour", () => { }) test("converts last minute of the day", () => { assert.equal(formatAs12HourClock("23:59"), "11:59pm"); +}) +test("preserves minutes with leading zero", () => { + assert.equal(formatAs12HourClock("09:05"), "9:05am"); }) \ No newline at end of file From 03c860be74f1e4f038572dc3980050112046c4b1 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 14:27:33 +0100 Subject: [PATCH 017/127] test: update console log to test formatting for 8:00 AM --- format-clock-edge-cases/timeConverter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index 2838957f9..40878c68b 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -28,4 +28,4 @@ function formatAs12HourClock(time){ return `${displayHour}:${minutePart}${period}`; } export {formatAs12HourClock}; -console.log(formatAs12HourClock("24:00")) +console.log(formatAs12HourClock("08:00")) From 42d563c84ef7e1dcf86cab68f30941cf2a71ade8 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 14:29:00 +0100 Subject: [PATCH 018/127] test: add test case for preserving non-zero minutes --- format-clock-edge-cases/timeConverter.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index dde4dfa88..ac64852b1 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -35,4 +35,7 @@ test("converts last minute of the day", () => { }) test("preserves minutes with leading zero", () => { assert.equal(formatAs12HourClock("09:05"), "9:05am"); +}) +test("preserves non-zero minutes", () => { + assert.equal(formatAs12HourClock("14:45"), "2:45pm"); }) \ No newline at end of file From 91ccb0c1655a452efe960dc0a75650fb536d6fa5 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sat, 3 Oct 2026 14:30:09 +0100 Subject: [PATCH 019/127] test: update console log to test formatting for 8:40 AM --- format-clock-edge-cases/timeConverter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index 40878c68b..d941da6e8 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -28,4 +28,4 @@ function formatAs12HourClock(time){ return `${displayHour}:${minutePart}${period}`; } export {formatAs12HourClock}; -console.log(formatAs12HourClock("08:00")) +console.log(formatAs12HourClock("08:40")) From 472364d3f324bd4b18bbaa78fb5c97722fd6a67c Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sun, 4 Oct 2026 20:15:21 +0100 Subject: [PATCH 020/127] Remove commented-out code from time formatting function --- format-clock-edge-cases/timeConverter.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index d941da6e8..f1b5ec631 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -1,15 +1,3 @@ -// function formatAs12HourClock(time) { - -// const hours = Number(time.slice(0, 2)); - -// if (hours > 12) { -// return `${hours - 12}:00 pm`; -// } -// return `${time} am`; -// } - -// export {formatAs12HourClock}; - function formatAs12HourClock(time){ const [hourPart, minutePart] = time.split(":"); const hours = Number(hourPart); From 5b48a96d3f7f884310efe101d4d0a8ed424c055e Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sun, 4 Oct 2026 20:20:48 +0100 Subject: [PATCH 021/127] Remove console log from time formatting function --- format-clock-edge-cases/timeConverter.js | 1 - 1 file changed, 1 deletion(-) diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index f1b5ec631..897565f28 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -16,4 +16,3 @@ function formatAs12HourClock(time){ return `${displayHour}:${minutePart}${period}`; } export {formatAs12HourClock}; -console.log(formatAs12HourClock("08:40")) From 8a740151f986648e6da5fce04705d20d0e61d51d Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sun, 4 Oct 2026 20:26:11 +0100 Subject: [PATCH 022/127] Add jsconfig.json for TypeScript configuration --- jsconfig.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 jsconfig.json diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 000000000..ce3653908 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Bundler", + "target": "ES2024", + "jsx": "react-jsx", + "allowImportingTsExtensions": true, + "checkJs": undefined, + "experimentalDecorators": false, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strict": true + }, + "exclude": [ + "node_modules", + "**/node_modules/*" + ] +} \ No newline at end of file From 27919c8ba64b659942665e79d3a9c1873fd0cf08 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Sun, 4 Oct 2026 20:43:28 +0100 Subject: [PATCH 023/127] Format code and improve readability --- .prettierrc | 1 - format-clock-edge-cases/timeConverter.js | 2 +- format-clock-edge-cases/timeConverter.test.js | 48 +++++++++---------- .../3-get-card-value.test.js | 6 ++- .../3-get-card-value.test.js | 1 - package.json | 5 +- practice-tdd/count.js | 2 +- .../password-validator.test.js | 15 +++--- 8 files changed, 42 insertions(+), 38 deletions(-) diff --git a/.prettierrc b/.prettierrc index 59bb3b44f..2e7e49095 100644 --- a/.prettierrc +++ b/.prettierrc @@ -4,7 +4,6 @@ "embeddedLanguageFormatting": "auto", "htmlWhitespaceSensitivity": "css", "insertPragma": false, - "jsxBracketSameLine": false, "jsxSingleQuote": false, "printWidth": 80, "proseWrap": "preserve", diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index 897565f28..389d4fad8 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -5,7 +5,7 @@ function formatAs12HourClock(time){ let period; if(hours < 12){ period = "am"; - } else { + }else{ period = "pm"; } diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index ac64852b1..bc3a9a933 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -1,41 +1,41 @@ -import {formatAs12HourClock} from "./timeConverter.js"; +import { formatAs12HourClock } from "./timeConverter.js"; import assert from "node:assert"; import test from "node:test"; test("correctly convert time after 12:00", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); }); test("converts a single-digit morning hour and drops leading zero", () => { - assert.equal(formatAs12HourClock("08:00"), "8:00am"); -}) + assert.equal(formatAs12HourClock("08:00"), "8:00am"); +}); test("converts exactly to midnight", () => { - assert.equal(formatAs12HourClock("00:00"), "12:00am"); -}) + assert.equal(formatAs12HourClock("00:00"), "12:00am"); +}); test("converts time just after midnight", () => { - assert.equal(formatAs12HourClock("00:30"), "12:30am"); -}) + assert.equal(formatAs12HourClock("00:30"), "12:30am"); +}); test("converts the last minute before noon", () => { - assert.equal(formatAs12HourClock("11:59"), "11:59am"); -}) + assert.equal(formatAs12HourClock("11:59"), "11:59am"); +}); test("converts exact noon to pm", () => { - assert.equal(formatAs12HourClock("12:00"), "12:00pm"); -}) + assert.equal(formatAs12HourClock("12:00"), "12:00pm"); +}); test("convert time just after noon", () => { - assert.equal(formatAs12HourClock("12:30"), "12:30pm"); -}) + assert.equal(formatAs12HourClock("12:30"), "12:30pm"); +}); test("converts the first afternoon hour", () => { - assert.equal(formatAs12HourClock("13:00"), "1:00pm"); -}) + assert.equal(formatAs12HourClock("13:00"), "1:00pm"); +}); test("converts late evening hour", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}) + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}); test("converts last minute of the day", () => { - assert.equal(formatAs12HourClock("23:59"), "11:59pm"); -}) + assert.equal(formatAs12HourClock("23:59"), "11:59pm"); +}); test("preserves minutes with leading zero", () => { - assert.equal(formatAs12HourClock("09:05"), "9:05am"); -}) + assert.equal(formatAs12HourClock("09:05"), "9:05am"); +}); test("preserves non-zero minutes", () => { - assert.equal(formatAs12HourClock("14:45"), "2:45pm"); -}) \ No newline at end of file + assert.equal(formatAs12HourClock("14:45"), "2:45pm"); +}); diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index f5092d9b1..273197c9d 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -10,7 +10,11 @@ test("Valid single-digit card", () => { }); test("Arbitrary non-card string", () => { - assert.throws(() => getCardValue("invalid"), /Expected a number followed by a suit, but got "invalid"/, "Expected clear error"); + assert.throws( + () => getCardValue("invalid"), + /Expected a number followed by a suit, but got "invalid"/, + "Expected clear error" + ); }); // TODO: What other invalid card cases can you think of? diff --git a/implement-and-rewrite-tests/rewrite-tests-with-jest/3-get-card-value.test.js b/implement-and-rewrite-tests/rewrite-tests-with-jest/3-get-card-value.test.js index a6de5a82a..b5619e5e0 100644 --- a/implement-and-rewrite-tests/rewrite-tests-with-jest/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/rewrite-tests-with-jest/3-get-card-value.test.js @@ -15,4 +15,3 @@ test(`Should return 11 when given an ace card`, () => { // To learn how to test whether a function throws an error as expected in Jest, // please refer to the Jest documentation: // https://jestjs.io/docs/expect#tothrowerror - diff --git a/package.json b/package.json index 6ae16268c..96cf0230d 100644 --- a/package.json +++ b/package.json @@ -12,5 +12,8 @@ "license": "ISC", "dependencies": { "jest": "^29.7.0" + }, + "devDependencies": { + "prettier": "^3.9.9" } -} \ No newline at end of file +} diff --git a/practice-tdd/count.js b/practice-tdd/count.js index 5518c5712..1a099f60f 100644 --- a/practice-tdd/count.js +++ b/practice-tdd/count.js @@ -1,3 +1,3 @@ export function countChar(stringOfCharacters, findCharacter) { - return 5 + return 5; } diff --git a/sprint-3-stretch-exercises/password-validator.test.js b/sprint-3-stretch-exercises/password-validator.test.js index 2a58a0fb6..52f4b75e5 100644 --- a/sprint-3-stretch-exercises/password-validator.test.js +++ b/sprint-3-stretch-exercises/password-validator.test.js @@ -16,11 +16,10 @@ You must breakdown this problem in order to solve it. Find one test case first a */ import { isValidPassword } from "./password-validator.js"; test("password has at least 5 characters", () => { - // Arrange - const password = "12345"; - // Act - const result = isValidPassword(password); - // Assert - expect(result).toEqual(true); -} -); \ No newline at end of file + // Arrange + const password = "12345"; + // Act + const result = isValidPassword(password); + // Assert + expect(result).toEqual(true); +}); From fa688b11bc5fa9f281234745ef39327ea4522a6c Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Mon, 5 Oct 2026 01:24:56 +0100 Subject: [PATCH 024/127] Simplify period determination and improve formatting --- format-clock-edge-cases/timeConverter.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index 389d4fad8..13f488faf 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -1,18 +1,13 @@ -function formatAs12HourClock(time){ +function formatAs12HourClock(time) { const [hourPart, minutePart] = time.split(":"); const hours = Number(hourPart); - let period; - if(hours < 12){ - period = "am"; - }else{ - period = "pm"; - } + const period = hours < 12 ? "am" : "pm"; let displayHour = hours % 12; - if(displayHour === 0){ + if (displayHour === 0) { displayHour = 12; - } + } return `${displayHour}:${minutePart}${period}`; } -export {formatAs12HourClock}; +export { formatAs12HourClock }; From 5d58269403e74f6454241f735a2cc8cb218107df Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Mon, 5 Oct 2026 01:29:25 +0100 Subject: [PATCH 025/127] Refactor display hour calculation for 12-hour clock format --- format-clock-edge-cases/timeConverter.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index 13f488faf..f4a24c094 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -4,10 +4,7 @@ function formatAs12HourClock(time) { const period = hours < 12 ? "am" : "pm"; - let displayHour = hours % 12; - if (displayHour === 0) { - displayHour = 12; - } + const displayHour = hours % 12 || 12; return `${displayHour}:${minutePart}${period}`; } export { formatAs12HourClock }; From f9fac2a6e43f79e5c6af324f4f1913e19a3e107f Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Mon, 5 Oct 2026 02:03:20 +0100 Subject: [PATCH 026/127] Remove jsconfig.json and clean up package.json by deleting devDependencies --- .prettierrc | 1 + jsconfig.json | 18 ------------------ package.json | 5 +---- 3 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 jsconfig.json diff --git a/.prettierrc b/.prettierrc index 2e7e49095..59bb3b44f 100644 --- a/.prettierrc +++ b/.prettierrc @@ -4,6 +4,7 @@ "embeddedLanguageFormatting": "auto", "htmlWhitespaceSensitivity": "css", "insertPragma": false, + "jsxBracketSameLine": false, "jsxSingleQuote": false, "printWidth": 80, "proseWrap": "preserve", diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index ce3653908..000000000 --- a/jsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "module": "ESNext", - "moduleResolution": "Bundler", - "target": "ES2024", - "jsx": "react-jsx", - "allowImportingTsExtensions": true, - "checkJs": undefined, - "experimentalDecorators": false, - "strictNullChecks": true, - "strictFunctionTypes": true, - "strict": true - }, - "exclude": [ - "node_modules", - "**/node_modules/*" - ] -} \ No newline at end of file diff --git a/package.json b/package.json index 96cf0230d..6ae16268c 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,5 @@ "license": "ISC", "dependencies": { "jest": "^29.7.0" - }, - "devDependencies": { - "prettier": "^3.9.9" } -} +} \ No newline at end of file From aba07711c3bd9b30a047b9cace71a3b0073e6b40 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Mon, 5 Oct 2026 02:16:02 +0100 Subject: [PATCH 027/127] Refactor folders to match main --- .../3-get-card-value.test.js | 6 +----- .../3-get-card-value.test.js | 1 + practice-tdd/count.js | 2 +- .../password-validator.test.js | 15 ++++++++------- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index 273197c9d..f5092d9b1 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -10,11 +10,7 @@ test("Valid single-digit card", () => { }); test("Arbitrary non-card string", () => { - assert.throws( - () => getCardValue("invalid"), - /Expected a number followed by a suit, but got "invalid"/, - "Expected clear error" - ); + assert.throws(() => getCardValue("invalid"), /Expected a number followed by a suit, but got "invalid"/, "Expected clear error"); }); // TODO: What other invalid card cases can you think of? diff --git a/implement-and-rewrite-tests/rewrite-tests-with-jest/3-get-card-value.test.js b/implement-and-rewrite-tests/rewrite-tests-with-jest/3-get-card-value.test.js index b5619e5e0..a6de5a82a 100644 --- a/implement-and-rewrite-tests/rewrite-tests-with-jest/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/rewrite-tests-with-jest/3-get-card-value.test.js @@ -15,3 +15,4 @@ test(`Should return 11 when given an ace card`, () => { // To learn how to test whether a function throws an error as expected in Jest, // please refer to the Jest documentation: // https://jestjs.io/docs/expect#tothrowerror + diff --git a/practice-tdd/count.js b/practice-tdd/count.js index 1a099f60f..5518c5712 100644 --- a/practice-tdd/count.js +++ b/practice-tdd/count.js @@ -1,3 +1,3 @@ export function countChar(stringOfCharacters, findCharacter) { - return 5; + return 5 } diff --git a/sprint-3-stretch-exercises/password-validator.test.js b/sprint-3-stretch-exercises/password-validator.test.js index 52f4b75e5..2a58a0fb6 100644 --- a/sprint-3-stretch-exercises/password-validator.test.js +++ b/sprint-3-stretch-exercises/password-validator.test.js @@ -16,10 +16,11 @@ You must breakdown this problem in order to solve it. Find one test case first a */ import { isValidPassword } from "./password-validator.js"; test("password has at least 5 characters", () => { - // Arrange - const password = "12345"; - // Act - const result = isValidPassword(password); - // Assert - expect(result).toEqual(true); -}); + // Arrange + const password = "12345"; + // Act + const result = isValidPassword(password); + // Assert + expect(result).toEqual(true); +} +); \ No newline at end of file From dc991743f54beb83f7609dc97d36084b823477a5 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:01:30 +0100 Subject: [PATCH 028/127] Add test case for classifying acute angles --- .../implement-tests-with-node-test/1-get-angle-type.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js index cf50f6cad..73e6768ab 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js @@ -10,3 +10,7 @@ test("Classifies right angles", () => { const right = getAngleType(90); assert.equal(right, "Right angle"); }); + +test("Classifies acute angles", () => { + assert.equal(getAngleType(45), "Acute angle"); +}); From ca9a48e1af0e8cb2a2c919b762f7141b80f79172 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:06:53 +0100 Subject: [PATCH 029/127] Add test case for classifying acute angles at 1 degree --- .../implement-tests-with-node-test/1-get-angle-type.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js index 73e6768ab..4a29c1e3e 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js @@ -13,4 +13,5 @@ test("Classifies right angles", () => { test("Classifies acute angles", () => { assert.equal(getAngleType(45), "Acute angle"); + assert.equal(getAngleType(1), "Acute angle"); }); From e9127ddcedd07adadad688d17479c0c89571204a Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:08:19 +0100 Subject: [PATCH 030/127] Add test case for classifying acute angles at 89 degrees --- .../implement-tests-with-node-test/1-get-angle-type.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js index 4a29c1e3e..ae51c8860 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js @@ -14,4 +14,5 @@ test("Classifies right angles", () => { test("Classifies acute angles", () => { assert.equal(getAngleType(45), "Acute angle"); assert.equal(getAngleType(1), "Acute angle"); + assert.equal(getAngleType(89), "Acute angle"); }); From 965d13c542dd0efc34985b0f3abe2e0acd9a35a6 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:15:02 +0100 Subject: [PATCH 031/127] Implement angle classification function for acute and right angles --- implement-and-rewrite-tests/implement/1-get-angle-type.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/1-get-angle-type.js b/implement-and-rewrite-tests/implement/1-get-angle-type.js index 8a6fba050..a1f61e961 100644 --- a/implement-and-rewrite-tests/implement/1-get-angle-type.js +++ b/implement-and-rewrite-tests/implement/1-get-angle-type.js @@ -17,5 +17,9 @@ // execute the code to ensure all tests pass. export function getAngleType(angle) { - // TODO: Implement this function + if(angle > 0 && angle < 90) { + return "Acute angle"; + } else if(angle === 90) { + return "RIght angle"; + } } From f95598e030fcb1490e76c885b29ffe77bdd9f964 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:18:28 +0100 Subject: [PATCH 032/127] Add test cases for classifying obtuse angles --- .../implement-tests-with-node-test/1-get-angle-type.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js index ae51c8860..b84a5ba10 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js @@ -16,3 +16,9 @@ test("Classifies acute angles", () => { assert.equal(getAngleType(1), "Acute angle"); assert.equal(getAngleType(89), "Acute angle"); }); + +test("Classifies obtuse angles", () => { + assert.equal(getAngleType(91), "Obtuse angle"); + assert.equal(getAngleType(135), "Obtuse angle"); + assert.equal(getAngleType(179), "Obtuse angle"); +}) From 727a787a5a67afe942d52e5f485331a0108d2752 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:22:41 +0100 Subject: [PATCH 033/127] add angle classification logic for obtuse angles --- implement-and-rewrite-tests/implement/1-get-angle-type.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/implement-and-rewrite-tests/implement/1-get-angle-type.js b/implement-and-rewrite-tests/implement/1-get-angle-type.js index a1f61e961..02e244185 100644 --- a/implement-and-rewrite-tests/implement/1-get-angle-type.js +++ b/implement-and-rewrite-tests/implement/1-get-angle-type.js @@ -21,5 +21,8 @@ export function getAngleType(angle) { return "Acute angle"; } else if(angle === 90) { return "RIght angle"; + } else if(angle > 90 && angle < 180){ + return "Obtuse angle"; } } +console.log(getAngleType(179)) From fc10ee87c43065fc7b56cdea2b2b135db506d402 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:24:28 +0100 Subject: [PATCH 034/127] Add test case for classifying straight angles --- .../implement-tests-with-node-test/1-get-angle-type.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js index b84a5ba10..a8cffee50 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js @@ -21,4 +21,8 @@ test("Classifies obtuse angles", () => { assert.equal(getAngleType(91), "Obtuse angle"); assert.equal(getAngleType(135), "Obtuse angle"); assert.equal(getAngleType(179), "Obtuse angle"); +}); + +test("Classifies straight angles", () => { + assert.equal(getAngleType(180), "Straight angle"); }) From a54dbf349587c65e833386d9d300c2b24d861088 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:26:26 +0100 Subject: [PATCH 035/127] add angle classification logic for straight angle --- implement-and-rewrite-tests/implement/1-get-angle-type.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/1-get-angle-type.js b/implement-and-rewrite-tests/implement/1-get-angle-type.js index 02e244185..64537d704 100644 --- a/implement-and-rewrite-tests/implement/1-get-angle-type.js +++ b/implement-and-rewrite-tests/implement/1-get-angle-type.js @@ -23,6 +23,7 @@ export function getAngleType(angle) { return "RIght angle"; } else if(angle > 90 && angle < 180){ return "Obtuse angle"; + } else if(angle === 180) { + return "Straight angle" } } -console.log(getAngleType(179)) From 59841f30ead6140c9f3acf67d8e2c9b695a81889 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:29:20 +0100 Subject: [PATCH 036/127] Add test cases for classifying reflex angles --- .../implement-tests-with-node-test/1-get-angle-type.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js index a8cffee50..0fcbeebc0 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js @@ -25,4 +25,10 @@ test("Classifies obtuse angles", () => { test("Classifies straight angles", () => { assert.equal(getAngleType(180), "Straight angle"); +}); + +test("Classifies reflex angles", () => { + assert.equal(getAngleType(181), "Reflex angle"); + assert.equal(getAngleType(270), "Reflex angle"); + assert.equal(getAngleType(359), "Reflex angle"); }) From 985fc65c666644e05a74678a4f2c995fd6cd8fc9 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:31:21 +0100 Subject: [PATCH 037/127] add angle classification logic for reflex angle --- implement-and-rewrite-tests/implement/1-get-angle-type.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/implement-and-rewrite-tests/implement/1-get-angle-type.js b/implement-and-rewrite-tests/implement/1-get-angle-type.js index 64537d704..cb203635f 100644 --- a/implement-and-rewrite-tests/implement/1-get-angle-type.js +++ b/implement-and-rewrite-tests/implement/1-get-angle-type.js @@ -25,5 +25,7 @@ export function getAngleType(angle) { return "Obtuse angle"; } else if(angle === 180) { return "Straight angle" + } else if (angle < 180 && angle < 360){ + return "Reflex angle"; } } From e34c68016796013fcf4e84c5ef692fe50af10ac4 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:34:58 +0100 Subject: [PATCH 038/127] Add test cases for classifying invalid angles --- .../1-get-angle-type.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js index 0fcbeebc0..32d473387 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js @@ -31,4 +31,11 @@ test("Classifies reflex angles", () => { assert.equal(getAngleType(181), "Reflex angle"); assert.equal(getAngleType(270), "Reflex angle"); assert.equal(getAngleType(359), "Reflex angle"); +}); + +test("Classifies invalid angles", () => { + assert.equal(getAngleType(0), "Invalid angle"); + assert.equal(getAngleType(360), "Invalid angle"); + assert.equal(getAngleType(400), "Invalid angle"); + assert.equal(getAngleType(-5), "Invalid angle"); }) From d04480383929a2db6995bbc3b7bd630cbcc673c6 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:36:29 +0100 Subject: [PATCH 039/127] Fix logic for invalid angle classification --- implement-and-rewrite-tests/implement/1-get-angle-type.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/implement-and-rewrite-tests/implement/1-get-angle-type.js b/implement-and-rewrite-tests/implement/1-get-angle-type.js index cb203635f..98057979d 100644 --- a/implement-and-rewrite-tests/implement/1-get-angle-type.js +++ b/implement-and-rewrite-tests/implement/1-get-angle-type.js @@ -27,5 +27,7 @@ export function getAngleType(angle) { return "Straight angle" } else if (angle < 180 && angle < 360){ return "Reflex angle"; + } else { + return "Invalid angle"; } } From dcbaa8af9542a205c6ef0be1b5ad7448e955f7f2 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:43:45 +0100 Subject: [PATCH 040/127] Fix typo in angle classification for right angle --- implement-and-rewrite-tests/implement/1-get-angle-type.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/1-get-angle-type.js b/implement-and-rewrite-tests/implement/1-get-angle-type.js index 98057979d..a746f0d32 100644 --- a/implement-and-rewrite-tests/implement/1-get-angle-type.js +++ b/implement-and-rewrite-tests/implement/1-get-angle-type.js @@ -20,7 +20,7 @@ export function getAngleType(angle) { if(angle > 0 && angle < 90) { return "Acute angle"; } else if(angle === 90) { - return "RIght angle"; + return "Right angle"; } else if(angle > 90 && angle < 180){ return "Obtuse angle"; } else if(angle === 180) { From cafa444e61f56f57f010bc4dee0559298c9da991 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 18:44:11 +0100 Subject: [PATCH 041/127] Fix logic for reflex angle classification --- implement-and-rewrite-tests/implement/1-get-angle-type.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/1-get-angle-type.js b/implement-and-rewrite-tests/implement/1-get-angle-type.js index a746f0d32..4ff290d94 100644 --- a/implement-and-rewrite-tests/implement/1-get-angle-type.js +++ b/implement-and-rewrite-tests/implement/1-get-angle-type.js @@ -25,7 +25,7 @@ export function getAngleType(angle) { return "Obtuse angle"; } else if(angle === 180) { return "Straight angle" - } else if (angle < 180 && angle < 360){ + } else if (angle > 180 && angle < 360){ return "Reflex angle"; } else { return "Invalid angle"; From c864dae50e5242ebd81b33f9c02a1d2ef75bd13c Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:19:42 +0100 Subject: [PATCH 042/127] Implement isProperFraction function to evaluate proper fractions --- .../implement/2-is-proper-fraction.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/2-is-proper-fraction.js b/implement-and-rewrite-tests/implement/2-is-proper-fraction.js index f983800f0..f836922e4 100644 --- a/implement-and-rewrite-tests/implement/2-is-proper-fraction.js +++ b/implement-and-rewrite-tests/implement/2-is-proper-fraction.js @@ -14,5 +14,9 @@ // execute the code to ensure all tests pass. export function isProperFraction(numerator, denominator) { - // TODO: Implement this function + if(Math.abs(numerator) < Math.abs(denominator)){ + return "true"; + } else { + return "false"; + } } From 25a95f7af9a8ce00d59b28f278f1dea832c2adc1 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:25:08 +0100 Subject: [PATCH 043/127] Fix return values in isProperFraction function to boolean type and update test cases --- .../2-is-proper-fraction.test.js | 2 +- implement-and-rewrite-tests/implement/2-is-proper-fraction.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index a29084605..19768d74d 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -7,6 +7,6 @@ import { isProperFraction } from "../implement/2-is-proper-fraction.js"; // What combinations of numerators and denominators should you test? test("Basic proper fraction", () => { - // Example: 1/2 is a proper fraction assert.equal(isProperFraction(1, 2), true); + assert.equal(isProperFraction(0, 5), true); }); diff --git a/implement-and-rewrite-tests/implement/2-is-proper-fraction.js b/implement-and-rewrite-tests/implement/2-is-proper-fraction.js index f836922e4..f56b51bf3 100644 --- a/implement-and-rewrite-tests/implement/2-is-proper-fraction.js +++ b/implement-and-rewrite-tests/implement/2-is-proper-fraction.js @@ -15,8 +15,8 @@ export function isProperFraction(numerator, denominator) { if(Math.abs(numerator) < Math.abs(denominator)){ - return "true"; + return true; } else { - return "false"; + return false; } } From a494567f59b40a86b9d353fafca6d07fc8f18e45 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:26:20 +0100 Subject: [PATCH 044/127] Add test case for negative numerator in isProperFraction function --- .../implement-tests-with-node-test/2-is-proper-fraction.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index 19768d74d..8ed3b6085 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -9,4 +9,5 @@ import { isProperFraction } from "../implement/2-is-proper-fraction.js"; test("Basic proper fraction", () => { assert.equal(isProperFraction(1, 2), true); assert.equal(isProperFraction(0, 5), true); + assert.equal(isProperFraction(-1, 2), true); }); From f9957fb65b1dec3c65f519a4d513379708a4c723 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:27:20 +0100 Subject: [PATCH 045/127] Add test case for negative denominator in isProperFraction function --- .../implement-tests-with-node-test/2-is-proper-fraction.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index 8ed3b6085..2de4b9e7e 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -10,4 +10,5 @@ test("Basic proper fraction", () => { assert.equal(isProperFraction(1, 2), true); assert.equal(isProperFraction(0, 5), true); assert.equal(isProperFraction(-1, 2), true); + assert.equal(isProperFraction(1, -2), true); }); From 8ad8453a94a8a2e94a9b9ebc64b119ce3fc6a9e1 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:28:01 +0100 Subject: [PATCH 046/127] Add test case for negative numerator and denominator in isProperFraction function --- .../implement-tests-with-node-test/2-is-proper-fraction.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index 2de4b9e7e..b659206a0 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -11,4 +11,5 @@ test("Basic proper fraction", () => { assert.equal(isProperFraction(0, 5), true); assert.equal(isProperFraction(-1, 2), true); assert.equal(isProperFraction(1, -2), true); + assert.equal(isProperFraction(-1, -2), true); }); From 583322972db28c74cc66f15e80217d85cf05ed8f Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:34:04 +0100 Subject: [PATCH 047/127] Add test case for improper fractions in isProperFraction function --- .../implement-tests-with-node-test/2-is-proper-fraction.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index b659206a0..3bdf052f0 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -12,4 +12,5 @@ test("Basic proper fraction", () => { assert.equal(isProperFraction(-1, 2), true); assert.equal(isProperFraction(1, -2), true); assert.equal(isProperFraction(-1, -2), true); + assert.equal(isProperFraction(5, 2), false) }); From 6735c73e4f96cf6a1b5a9344fd71a391a77c2d54 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:36:11 +0100 Subject: [PATCH 048/127] Add test case for basic improper fraction in isProperFraction function --- .../2-is-proper-fraction.test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index 3bdf052f0..141b9eb9e 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -12,5 +12,8 @@ test("Basic proper fraction", () => { assert.equal(isProperFraction(-1, 2), true); assert.equal(isProperFraction(1, -2), true); assert.equal(isProperFraction(-1, -2), true); - assert.equal(isProperFraction(5, 2), false) }); + +test("Basic improper fraction", () => { + assert.equal(isProperFraction(5, 2), false); +}) From e2cac11765b4f92801390df2f6ed7e49df1496d3 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:37:08 +0100 Subject: [PATCH 049/127] Add test case for equal numerator and denominator in isProperFraction function --- .../implement-tests-with-node-test/2-is-proper-fraction.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index 141b9eb9e..cfe005a50 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -16,4 +16,5 @@ test("Basic proper fraction", () => { test("Basic improper fraction", () => { assert.equal(isProperFraction(5, 2), false); + assert.equal(isProperFraction(3, 3), false); }) From ebfa5cc764a7de5ae5fc6c6f50629db003f3c319 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:37:46 +0100 Subject: [PATCH 050/127] Add test case for zero denominator in isProperFraction function --- .../implement-tests-with-node-test/2-is-proper-fraction.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index cfe005a50..8a1ff3b9a 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -17,4 +17,5 @@ test("Basic proper fraction", () => { test("Basic improper fraction", () => { assert.equal(isProperFraction(5, 2), false); assert.equal(isProperFraction(3, 3), false); + assert.equal(isProperFraction(5, 0), false); }) From 157c520a338274d8624ae6218080e16c92a14d2a Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:41:02 +0100 Subject: [PATCH 051/127] Add test case for negative numerator in isProperFraction function --- .../implement-tests-with-node-test/2-is-proper-fraction.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index 8a1ff3b9a..5a9c76b0b 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -18,4 +18,5 @@ test("Basic improper fraction", () => { assert.equal(isProperFraction(5, 2), false); assert.equal(isProperFraction(3, 3), false); assert.equal(isProperFraction(5, 0), false); + assert.equal(isProperFraction(-5, 2), false); }) From 68c550109dcd0ea661277b7d5e9e3162271bcd1b Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:42:31 +0100 Subject: [PATCH 052/127] Add test case for negative denominator in isProperFraction function --- .../implement-tests-with-node-test/2-is-proper-fraction.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index 5a9c76b0b..4bcade9e8 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -19,4 +19,5 @@ test("Basic improper fraction", () => { assert.equal(isProperFraction(3, 3), false); assert.equal(isProperFraction(5, 0), false); assert.equal(isProperFraction(-5, 2), false); + assert.equal(isProperFraction(5, -2), false); }) From 7df31abc110e9fd3bb19039762f84adcce5be548 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 19:43:23 +0100 Subject: [PATCH 053/127] Add test case for negative numerator and denominator in isProperFraction function --- .../2-is-proper-fraction.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index 4bcade9e8..75ebbe7fd 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -20,4 +20,5 @@ test("Basic improper fraction", () => { assert.equal(isProperFraction(5, 0), false); assert.equal(isProperFraction(-5, 2), false); assert.equal(isProperFraction(5, -2), false); -}) + assert.equal(isProperFraction(-5, -2), false); +}); From 39c47a261598baf362d3bdaefedec06ef81d9fdf Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:21:59 +0100 Subject: [PATCH 054/127] Implement valid suits array in getCardValue function --- implement-and-rewrite-tests/implement/3-get-card-value.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 9614ab1ee..df96c5d00 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -24,5 +24,5 @@ // execute the code to ensure all tests pass. export function getCardValue(card) { - // TODO: Implement this function + const validSuits = [u2660", "\u2665", "\u2666", "\u2663"];; } From ecd96e6674114f166da6b0197812ac7ddfa552e1 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:22:34 +0100 Subject: [PATCH 055/127] Fix syntax error in validSuits array in getCardValue function --- implement-and-rewrite-tests/implement/3-get-card-value.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index df96c5d00..460987121 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -24,5 +24,5 @@ // execute the code to ensure all tests pass. export function getCardValue(card) { - const validSuits = [u2660", "\u2665", "\u2666", "\u2663"];; + const validSuits = ["u2660", "\u2665", "\u2666", "\u2663"]; } From 7efe47c845e22ffd64d761944dc80cf9a8527825 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:23:44 +0100 Subject: [PATCH 056/127] Add numberRanks array to getCardValue function --- implement-and-rewrite-tests/implement/3-get-card-value.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 460987121..96250952f 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -25,4 +25,5 @@ export function getCardValue(card) { const validSuits = ["u2660", "\u2665", "\u2666", "\u2663"]; + const numberRanks = ["2", "3", "4", "5", "6", "7", "8", "9", "10"]; } From f85638bd72660875be38062d1ac9881328aafbe0 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:24:39 +0100 Subject: [PATCH 057/127] Add faceRanks array to getCardValue function --- implement-and-rewrite-tests/implement/3-get-card-value.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 96250952f..64187f0b4 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -26,4 +26,5 @@ export function getCardValue(card) { const validSuits = ["u2660", "\u2665", "\u2666", "\u2663"]; const numberRanks = ["2", "3", "4", "5", "6", "7", "8", "9", "10"]; + const faceRanks = ["J", "Q", "K"]; } From d37ed99913844304a820fbfccecb135bd65020e3 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:26:08 +0100 Subject: [PATCH 058/127] Add faceRanks array to getCardValue function --- implement-and-rewrite-tests/implement/3-get-card-value.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 64187f0b4..1a4c9bf6d 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -27,4 +27,5 @@ export function getCardValue(card) { const validSuits = ["u2660", "\u2665", "\u2666", "\u2663"]; const numberRanks = ["2", "3", "4", "5", "6", "7", "8", "9", "10"]; const faceRanks = ["J", "Q", "K"]; + } From e1ddceb06cff3f4e54aa7e332c55a22c1907347a Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:27:41 +0100 Subject: [PATCH 059/127] Add error handling for invalid card format in getCardValue function --- implement-and-rewrite-tests/implement/3-get-card-value.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 1a4c9bf6d..31b3e6a82 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -28,4 +28,6 @@ export function getCardValue(card) { const numberRanks = ["2", "3", "4", "5", "6", "7", "8", "9", "10"]; const faceRanks = ["J", "Q", "K"]; + const error = new Error(`Expected a number followed by a suit, but got "${card}"`); + } From fcf852fca863451f0a2142ee423d2f6546b1f575 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:31:21 +0100 Subject: [PATCH 060/127] add initial validation for card input in getCardValue function --- implement-and-rewrite-tests/implement/3-get-card-value.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 31b3e6a82..5fde174a3 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -24,10 +24,15 @@ // execute the code to ensure all tests pass. export function getCardValue(card) { - const validSuits = ["u2660", "\u2665", "\u2666", "\u2663"]; + const validSuits = ["\u2660", "\u2665", "\u2666", "\u2663"]; const numberRanks = ["2", "3", "4", "5", "6", "7", "8", "9", "10"]; const faceRanks = ["J", "Q", "K"]; const error = new Error(`Expected a number followed by a suit, but got "${card}"`); + if(typeof card !== "string" || card.length < 2){ + throw error; + } + + } From c1b599d653901c5ed10e00823a54871262f9e0cb Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:34:02 +0100 Subject: [PATCH 061/127] Add suit and rank extraction with validation in getCardValue function --- implement-and-rewrite-tests/implement/3-get-card-value.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 5fde174a3..fe2c5aabd 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -34,5 +34,11 @@ export function getCardValue(card) { throw error; } + const suit = card.slice(-1); + const rank = card.slice(0, -1); + + if(!validSuits.includes(suit)){ + throw error; + } } From 7567f280c2c0ecde9f5be914bc954d73bcc49015 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:36:28 +0100 Subject: [PATCH 062/127] Implement handling for Ace rank in getCardValue function --- implement-and-rewrite-tests/implement/3-get-card-value.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index fe2c5aabd..d832c5b8b 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -40,5 +40,9 @@ export function getCardValue(card) { if(!validSuits.includes(suit)){ throw error; } + if(rank === "A") { + return 11; + } + } From 93b333afd4aba85b91e74bb29b762bd54f77ec77 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:39:33 +0100 Subject: [PATCH 063/127] implement handling for faceRanks to return 10 for face cards --- implement-and-rewrite-tests/implement/3-get-card-value.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index d832c5b8b..08a0cf016 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -43,6 +43,8 @@ export function getCardValue(card) { if(rank === "A") { return 11; } - + if(faceRanks.includes(rank)){ + return 10; + } } From 1348019dcec8b6bc9b413ad951c75f6f37d42d3f Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:41:28 +0100 Subject: [PATCH 064/127] Refactor getCardValue function to ensure proper handling of number ranks and maintain error throwing for invalid inputs --- implement-and-rewrite-tests/implement/3-get-card-value.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 08a0cf016..7aff141b7 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -46,5 +46,8 @@ export function getCardValue(card) { if(faceRanks.includes(rank)){ return 10; } - + if(numberRanks.includes(rank)){ + return Number(rank); + } + throw error; } From e7cfd7bb9ad8bb4b22f89f6487240901d198fe50 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:45:52 +0100 Subject: [PATCH 065/127] Fix suit representation in getCardValue function to use Unicode characters for consistency --- implement-and-rewrite-tests/implement/3-get-card-value.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 7aff141b7..a666b2b85 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -24,7 +24,7 @@ // execute the code to ensure all tests pass. export function getCardValue(card) { - const validSuits = ["\u2660", "\u2665", "\u2666", "\u2663"]; + const validSuits = ["♠", "♥", "♦", "♣"]; const numberRanks = ["2", "3", "4", "5", "6", "7", "8", "9", "10"]; const faceRanks = ["J", "Q", "K"]; @@ -51,3 +51,5 @@ export function getCardValue(card) { } throw error; } + +console.log(getCardValue("A♦")) From cd4dc167731920ef7f089f20f1d6e845a00e1714 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:47:35 +0100 Subject: [PATCH 066/127] Comment out console log statement for getCardValue function --- implement-and-rewrite-tests/implement/3-get-card-value.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index a666b2b85..1b68bf598 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -52,4 +52,4 @@ export function getCardValue(card) { throw error; } -console.log(getCardValue("A♦")) +// console.log(getCardValue("A♦")); From d60f2bd3e3eac7966552faee2261d63570bc4007 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 20:49:52 +0100 Subject: [PATCH 067/127] Add test case for Ace card value --- .../implement-tests-with-node-test/3-get-card-value.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index f5092d9b1..7ae4d5c79 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -9,6 +9,10 @@ test("Valid single-digit card", () => { assert.equal(getCardValue("9♠"), 9); }); +test("Ace returns 11", () => { + assert.equal(getCardValue("A♠"), 11); +}); + test("Arbitrary non-card string", () => { assert.throws(() => getCardValue("invalid"), /Expected a number followed by a suit, but got "invalid"/, "Expected clear error"); }); From f38db7ff37303e279f109aba1545c16f6abe7c62 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 21:18:18 +0100 Subject: [PATCH 068/127] Add test cases for face cards to ensure they return a value of 10 --- .../implement-tests-with-node-test/3-get-card-value.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index 7ae4d5c79..7feb7345a 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -13,6 +13,12 @@ test("Ace returns 11", () => { assert.equal(getCardValue("A♠"), 11); }); +test("Face cards return 10", () => { + assert.equal(getCardValue("J♣"), 10); + assert.equal(getCardValue("Q♦"), 10); + assert.equal(getCardValue("K♥"), 10); +}) + test("Arbitrary non-card string", () => { assert.throws(() => getCardValue("invalid"), /Expected a number followed by a suit, but got "invalid"/, "Expected clear error"); }); From c25755ded5a1e5274f7133cb60a12904bdb50b96 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 21:30:05 +0100 Subject: [PATCH 069/127] Add test case for number cards 2 to 10 to verify correct value returns --- .../implement-tests-with-node-test/3-get-card-value.test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index 7feb7345a..bec6f17b0 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -19,6 +19,11 @@ test("Face cards return 10", () => { assert.equal(getCardValue("K♥"), 10); }) +test("Number cards 2 to 10 return their numbers", () => { + for(let n = 2; n <= 10; n++){ + assert.equal(getCardValue(`${n}♦`), n) + } +}) test("Arbitrary non-card string", () => { assert.throws(() => getCardValue("invalid"), /Expected a number followed by a suit, but got "invalid"/, "Expected clear error"); }); From f3c9bdad2f47cfcf75c94bb45df482002d7f6c75 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 21:30:41 +0100 Subject: [PATCH 070/127] Fix formatting in number card test for consistency --- .../implement-tests-with-node-test/3-get-card-value.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index bec6f17b0..6be212480 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -20,10 +20,10 @@ test("Face cards return 10", () => { }) test("Number cards 2 to 10 return their numbers", () => { - for(let n = 2; n <= 10; n++){ - assert.equal(getCardValue(`${n}♦`), n) + for(let n = 2; n <= 10; n++) { + assert.equal(getCardValue(`${n}♦`), n); } -}) +}); test("Arbitrary non-card string", () => { assert.throws(() => getCardValue("invalid"), /Expected a number followed by a suit, but got "invalid"/, "Expected clear error"); }); From 84f32b87874fc72d52e540639dee41d514c9f8dc Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 21:36:19 +0100 Subject: [PATCH 071/127] Add test for valid double-digit '10' card to ensure correct value returns --- .../implement-tests-with-node-test/3-get-card-value.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index 6be212480..d7216d1e4 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -24,6 +24,10 @@ test("Number cards 2 to 10 return their numbers", () => { assert.equal(getCardValue(`${n}♦`), n); } }); + +test("Only valid double-digit '10' card", () => { + assert.equal(getCardValue("10♥"), 10); +}) test("Arbitrary non-card string", () => { assert.throws(() => getCardValue("invalid"), /Expected a number followed by a suit, but got "invalid"/, "Expected clear error"); }); From ea302ed3c6d93775e7f1e2aa05b26f83a4569d3a Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 21:48:42 +0100 Subject: [PATCH 072/127] Add tests to ensure all four suits are accepted --- .../3-get-card-value.test.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index d7216d1e4..f6b2099dc 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -27,7 +27,14 @@ test("Number cards 2 to 10 return their numbers", () => { test("Only valid double-digit '10' card", () => { assert.equal(getCardValue("10♥"), 10); -}) +}); + +test("Accepts all four suits", () => { + for (const suit of ["♠", "♥", "♦", "♣"]){ + assert.equal(getCardValue(`5${suit}`), 5); + } +}); + test("Arbitrary non-card string", () => { assert.throws(() => getCardValue("invalid"), /Expected a number followed by a suit, but got "invalid"/, "Expected clear error"); }); From 78d0ff4a0019d872dc0ab37ea0a60c241a298d7c Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 22:01:38 +0100 Subject: [PATCH 073/127] Add test for missing suit to validate error handling --- .../implement-tests-with-node-test/3-get-card-value.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index f6b2099dc..ab2384ab7 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -40,3 +40,7 @@ test("Arbitrary non-card string", () => { }); // TODO: What other invalid card cases can you think of? +test("Missing suit", () => { + assert.equal(getCardValue("7"), /Expected a number followed by a suit/); + assert.equal(getCardValue("A"), /Expected a number followed by a result/); +}); \ No newline at end of file From 6635d24700881b3b5089eda35de4bb4c5b2bd8b8 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 22:19:24 +0100 Subject: [PATCH 074/127] Add test for missing ranks to validate error handling --- .../implement-tests-with-node-test/3-get-card-value.test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index ab2384ab7..7a79f935e 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -43,4 +43,8 @@ test("Arbitrary non-card string", () => { test("Missing suit", () => { assert.equal(getCardValue("7"), /Expected a number followed by a suit/); assert.equal(getCardValue("A"), /Expected a number followed by a result/); -}); \ No newline at end of file +}); + +test("Missing ranks", () => { + assert.equal(() => getCardValue("♥"), /Expected a number followed by a suit/); +}) \ No newline at end of file From 700c2b9b5a721edfd879fe0c872c7da7edbce358 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 22:23:56 +0100 Subject: [PATCH 075/127] Fix tests for missing suit and ranks to ensure proper error handling --- .../implement-tests-with-node-test/3-get-card-value.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index 7a79f935e..b7dd4cc9f 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -41,10 +41,10 @@ test("Arbitrary non-card string", () => { // TODO: What other invalid card cases can you think of? test("Missing suit", () => { - assert.equal(getCardValue("7"), /Expected a number followed by a suit/); - assert.equal(getCardValue("A"), /Expected a number followed by a result/); + assert.throws(() => getCardValue("7"), /Expected a number followed by a suit/); + assert.throws(() => getCardValue("A"), /Expected a number followed by a suit/); }); test("Missing ranks", () => { - assert.equal(() => getCardValue("♥"), /Expected a number followed by a suit/); + assert.throws(() => getCardValue("♥"), /Expected a number followed by a suit/); }) \ No newline at end of file From c06b70179d48f44d2defd4688618567734cfa458 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 22:25:53 +0100 Subject: [PATCH 076/127] Add test for empty strings to validate error handling --- .../implement-tests-with-node-test/3-get-card-value.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index b7dd4cc9f..963e9398d 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -47,4 +47,8 @@ test("Missing suit", () => { test("Missing ranks", () => { assert.throws(() => getCardValue("♥"), /Expected a number followed by a suit/); +}); + +test("Empty strings", () => { + assert.throws(() => getCardValue(""), /Expected a number followed by a suit/); }) \ No newline at end of file From bc54e01c7895665e97f05df58ee2cfa22688dd10 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 22:32:13 +0100 Subject: [PATCH 077/127] Add test for out-of-range number ranks to validate error handling --- .../3-get-card-value.test.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index 963e9398d..80fcf901b 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -51,4 +51,10 @@ test("Missing ranks", () => { test("Empty strings", () => { assert.throws(() => getCardValue(""), /Expected a number followed by a suit/); -}) \ No newline at end of file +}); + +test("Out-of-range number ranks", () => { + for (const OOR of ["0♥", "1♠", "11♦", "100♣"]) { + assert.throws(() => getCardValue(OOR), /Expected a number followed by a suit/); + } +}); \ No newline at end of file From 47797b5489e4bc66ba4d154f2705d1cc6e00e5d9 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 22:44:20 +0100 Subject: [PATCH 078/127] Add test for unknown suit to validate error handling --- .../3-get-card-value.test.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index 80fcf901b..874584bc0 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -57,4 +57,9 @@ test("Out-of-range number ranks", () => { for (const OOR of ["0♥", "1♠", "11♦", "100♣"]) { assert.throws(() => getCardValue(OOR), /Expected a number followed by a suit/); } -}); \ No newline at end of file +}); + +test("Unknown suit", () => { + assert.throws(() => getCardValue("A❤"), /Expected a number followed by a suit/); + assert.throws(() => getCardValue("AV"), /Expected a number followed by a suit/); +}) \ No newline at end of file From a6231b0801467acc4766704296d495b482756797 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 22:57:06 +0100 Subject: [PATCH 079/127] Add test for lowercase ranks to validate error handling --- .../implement-tests-with-node-test/3-get-card-value.test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index 874584bc0..2797d81d6 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -62,4 +62,9 @@ test("Out-of-range number ranks", () => { test("Unknown suit", () => { assert.throws(() => getCardValue("A❤"), /Expected a number followed by a suit/); assert.throws(() => getCardValue("AV"), /Expected a number followed by a suit/); +}); + +test("Lowercase ranks", () => { + assert.throws(() => getCardValue("a♦"), /Expected a number followed by a suit/); + assert.throws(() => getCardValue("k♥"), /Expected a number followed by a suit/); }) \ No newline at end of file From 20e286aa6fc18db320c2204fc4997e8b60ce38e7 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 22:59:01 +0100 Subject: [PATCH 080/127] Add test for suit before rank to validate error handling --- .../implement-tests-with-node-test/3-get-card-value.test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index 2797d81d6..b5293b8b8 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -67,4 +67,8 @@ test("Unknown suit", () => { test("Lowercase ranks", () => { assert.throws(() => getCardValue("a♦"), /Expected a number followed by a suit/); assert.throws(() => getCardValue("k♥"), /Expected a number followed by a suit/); -}) \ No newline at end of file +}); + +test("Suit before rank", () => { + assert.throws(() => getCardValue("♣A"), /Expected a number followed by a suit/); +}); \ No newline at end of file From d91a6cbc7917c128e91ba811168e85fb3f402d60 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 23:19:04 +0100 Subject: [PATCH 081/127] Add tests for extra characters, spaces, and non-string inputs to validate error handling --- .../3-get-card-value.test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index b5293b8b8..765ccd34d 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -71,4 +71,15 @@ test("Lowercase ranks", () => { test("Suit before rank", () => { assert.throws(() => getCardValue("♣A"), /Expected a number followed by a suit/); +}); + +test("Extra characters or spaces", () => { + for (const ExS of [" A♦", "A♦ ", "A♦♦", "A ♦"]){ + assert.throws(() => getCardValue(ExS), /Expected a number followed by a suit/); + } +}); + +test("Non-string input", () => { + assert.throws(() => getCardValue(undefined), /Expected a number followed by a suit/); + assert.throws(() => getCardValue(5), /Expected a number followed by a suit/); }); \ No newline at end of file From 2052992f641685a63050f40b99e8410ab631a27b Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 23:20:46 +0100 Subject: [PATCH 082/127] Remove commented-out console log for getCardValue function --- implement-and-rewrite-tests/implement/3-get-card-value.js | 1 - 1 file changed, 1 deletion(-) diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 1b68bf598..05a47f6d2 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -52,4 +52,3 @@ export function getCardValue(card) { throw error; } -// console.log(getCardValue("A♦")); From e021e17f90c2d327596574148afebabaaaf072b4 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 23:48:53 +0100 Subject: [PATCH 083/127] Remove formatAs12HourClock function and its tests due to refactoring --- format-clock-edge-cases/README.md | 15 ------- format-clock-edge-cases/timeConverter.js | 10 ----- format-clock-edge-cases/timeConverter.test.js | 41 ------------------- 3 files changed, 66 deletions(-) delete mode 100644 format-clock-edge-cases/README.md delete mode 100644 format-clock-edge-cases/timeConverter.js delete mode 100644 format-clock-edge-cases/timeConverter.test.js diff --git a/format-clock-edge-cases/README.md b/format-clock-edge-cases/README.md deleted file mode 100644 index 8a43a9e96..000000000 --- a/format-clock-edge-cases/README.md +++ /dev/null @@ -1,15 +0,0 @@ -In your prep, you looked this `formatAs12HourClock` function: - -```js -function formatAs12HourClock(time) { - - const hours = Number(time.slice(0, 2)); - - if (hours > 12) { - return `${hours - 12}:00 pm`; - } - return `${time} am`; -} -``` - -It still has bugs. Think of as many edge-cases as you can with this code. Write tests for all of them, and fix this code so that it works correctly for all valid inputs. You don't need to worry about invalid inputs (e.g. `"25:00"`). diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js deleted file mode 100644 index f4a24c094..000000000 --- a/format-clock-edge-cases/timeConverter.js +++ /dev/null @@ -1,10 +0,0 @@ -function formatAs12HourClock(time) { - const [hourPart, minutePart] = time.split(":"); - const hours = Number(hourPart); - - const period = hours < 12 ? "am" : "pm"; - - const displayHour = hours % 12 || 12; - return `${displayHour}:${minutePart}${period}`; -} -export { formatAs12HourClock }; diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js deleted file mode 100644 index bc3a9a933..000000000 --- a/format-clock-edge-cases/timeConverter.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import { formatAs12HourClock } from "./timeConverter.js"; -import assert from "node:assert"; -import test from "node:test"; - -test("correctly convert time after 12:00", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}); - -test("converts a single-digit morning hour and drops leading zero", () => { - assert.equal(formatAs12HourClock("08:00"), "8:00am"); -}); -test("converts exactly to midnight", () => { - assert.equal(formatAs12HourClock("00:00"), "12:00am"); -}); -test("converts time just after midnight", () => { - assert.equal(formatAs12HourClock("00:30"), "12:30am"); -}); -test("converts the last minute before noon", () => { - assert.equal(formatAs12HourClock("11:59"), "11:59am"); -}); -test("converts exact noon to pm", () => { - assert.equal(formatAs12HourClock("12:00"), "12:00pm"); -}); -test("convert time just after noon", () => { - assert.equal(formatAs12HourClock("12:30"), "12:30pm"); -}); -test("converts the first afternoon hour", () => { - assert.equal(formatAs12HourClock("13:00"), "1:00pm"); -}); -test("converts late evening hour", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}); -test("converts last minute of the day", () => { - assert.equal(formatAs12HourClock("23:59"), "11:59pm"); -}); -test("preserves minutes with leading zero", () => { - assert.equal(formatAs12HourClock("09:05"), "9:05am"); -}); -test("preserves non-zero minutes", () => { - assert.equal(formatAs12HourClock("14:45"), "2:45pm"); -}); From 5c7ee795abcb5ed86094f5cac52f6e9626d59798 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 23:49:24 +0100 Subject: [PATCH 084/127] Add formatAs12HourClock function and corresponding tests for time conversion --- format-clock-edge-cases/README.md | 15 +++++++ format-clock-edge-cases/timeConverter.js | 10 +++++ format-clock-edge-cases/timeConverter.test.js | 41 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 format-clock-edge-cases/README.md create mode 100644 format-clock-edge-cases/timeConverter.js create mode 100644 format-clock-edge-cases/timeConverter.test.js diff --git a/format-clock-edge-cases/README.md b/format-clock-edge-cases/README.md new file mode 100644 index 000000000..8a43a9e96 --- /dev/null +++ b/format-clock-edge-cases/README.md @@ -0,0 +1,15 @@ +In your prep, you looked this `formatAs12HourClock` function: + +```js +function formatAs12HourClock(time) { + + const hours = Number(time.slice(0, 2)); + + if (hours > 12) { + return `${hours - 12}:00 pm`; + } + return `${time} am`; +} +``` + +It still has bugs. Think of as many edge-cases as you can with this code. Write tests for all of them, and fix this code so that it works correctly for all valid inputs. You don't need to worry about invalid inputs (e.g. `"25:00"`). diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js new file mode 100644 index 000000000..f4a24c094 --- /dev/null +++ b/format-clock-edge-cases/timeConverter.js @@ -0,0 +1,10 @@ +function formatAs12HourClock(time) { + const [hourPart, minutePart] = time.split(":"); + const hours = Number(hourPart); + + const period = hours < 12 ? "am" : "pm"; + + const displayHour = hours % 12 || 12; + return `${displayHour}:${minutePart}${period}`; +} +export { formatAs12HourClock }; diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js new file mode 100644 index 000000000..bc3a9a933 --- /dev/null +++ b/format-clock-edge-cases/timeConverter.test.js @@ -0,0 +1,41 @@ +import { formatAs12HourClock } from "./timeConverter.js"; +import assert from "node:assert"; +import test from "node:test"; + +test("correctly convert time after 12:00", () => { + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}); + +test("converts a single-digit morning hour and drops leading zero", () => { + assert.equal(formatAs12HourClock("08:00"), "8:00am"); +}); +test("converts exactly to midnight", () => { + assert.equal(formatAs12HourClock("00:00"), "12:00am"); +}); +test("converts time just after midnight", () => { + assert.equal(formatAs12HourClock("00:30"), "12:30am"); +}); +test("converts the last minute before noon", () => { + assert.equal(formatAs12HourClock("11:59"), "11:59am"); +}); +test("converts exact noon to pm", () => { + assert.equal(formatAs12HourClock("12:00"), "12:00pm"); +}); +test("convert time just after noon", () => { + assert.equal(formatAs12HourClock("12:30"), "12:30pm"); +}); +test("converts the first afternoon hour", () => { + assert.equal(formatAs12HourClock("13:00"), "1:00pm"); +}); +test("converts late evening hour", () => { + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}); +test("converts last minute of the day", () => { + assert.equal(formatAs12HourClock("23:59"), "11:59pm"); +}); +test("preserves minutes with leading zero", () => { + assert.equal(formatAs12HourClock("09:05"), "9:05am"); +}); +test("preserves non-zero minutes", () => { + assert.equal(formatAs12HourClock("14:45"), "2:45pm"); +}); From 1c195d74408b74006b8616826d58f3effbb8c41b Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Thu, 8 Oct 2026 23:52:23 +0100 Subject: [PATCH 085/127] Remove formatAs12HourClock function and its tests due to refactoring --- format-clock-edge-cases/README.md | 15 ------- format-clock-edge-cases/timeConverter.js | 10 ----- format-clock-edge-cases/timeConverter.test.js | 41 ------------------- 3 files changed, 66 deletions(-) delete mode 100644 format-clock-edge-cases/README.md delete mode 100644 format-clock-edge-cases/timeConverter.js delete mode 100644 format-clock-edge-cases/timeConverter.test.js diff --git a/format-clock-edge-cases/README.md b/format-clock-edge-cases/README.md deleted file mode 100644 index 8a43a9e96..000000000 --- a/format-clock-edge-cases/README.md +++ /dev/null @@ -1,15 +0,0 @@ -In your prep, you looked this `formatAs12HourClock` function: - -```js -function formatAs12HourClock(time) { - - const hours = Number(time.slice(0, 2)); - - if (hours > 12) { - return `${hours - 12}:00 pm`; - } - return `${time} am`; -} -``` - -It still has bugs. Think of as many edge-cases as you can with this code. Write tests for all of them, and fix this code so that it works correctly for all valid inputs. You don't need to worry about invalid inputs (e.g. `"25:00"`). diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js deleted file mode 100644 index f4a24c094..000000000 --- a/format-clock-edge-cases/timeConverter.js +++ /dev/null @@ -1,10 +0,0 @@ -function formatAs12HourClock(time) { - const [hourPart, minutePart] = time.split(":"); - const hours = Number(hourPart); - - const period = hours < 12 ? "am" : "pm"; - - const displayHour = hours % 12 || 12; - return `${displayHour}:${minutePart}${period}`; -} -export { formatAs12HourClock }; diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js deleted file mode 100644 index bc3a9a933..000000000 --- a/format-clock-edge-cases/timeConverter.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import { formatAs12HourClock } from "./timeConverter.js"; -import assert from "node:assert"; -import test from "node:test"; - -test("correctly convert time after 12:00", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}); - -test("converts a single-digit morning hour and drops leading zero", () => { - assert.equal(formatAs12HourClock("08:00"), "8:00am"); -}); -test("converts exactly to midnight", () => { - assert.equal(formatAs12HourClock("00:00"), "12:00am"); -}); -test("converts time just after midnight", () => { - assert.equal(formatAs12HourClock("00:30"), "12:30am"); -}); -test("converts the last minute before noon", () => { - assert.equal(formatAs12HourClock("11:59"), "11:59am"); -}); -test("converts exact noon to pm", () => { - assert.equal(formatAs12HourClock("12:00"), "12:00pm"); -}); -test("convert time just after noon", () => { - assert.equal(formatAs12HourClock("12:30"), "12:30pm"); -}); -test("converts the first afternoon hour", () => { - assert.equal(formatAs12HourClock("13:00"), "1:00pm"); -}); -test("converts late evening hour", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}); -test("converts last minute of the day", () => { - assert.equal(formatAs12HourClock("23:59"), "11:59pm"); -}); -test("preserves minutes with leading zero", () => { - assert.equal(formatAs12HourClock("09:05"), "9:05am"); -}); -test("preserves non-zero minutes", () => { - assert.equal(formatAs12HourClock("14:45"), "2:45pm"); -}); From 7a4a0c7539fcd0ea9d3ce81b1f81034e1461bf21 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 00:09:44 +0100 Subject: [PATCH 086/127] Implement formatAs12HourClock function with comprehensive tests for time conversion --- format-clock-edge-cases/README.md | 15 +++++++ format-clock-edge-cases/timeConverter.js | 31 ++++++++++++++ format-clock-edge-cases/timeConverter.test.js | 41 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 format-clock-edge-cases/README.md create mode 100644 format-clock-edge-cases/timeConverter.js create mode 100644 format-clock-edge-cases/timeConverter.test.js diff --git a/format-clock-edge-cases/README.md b/format-clock-edge-cases/README.md new file mode 100644 index 000000000..8a43a9e96 --- /dev/null +++ b/format-clock-edge-cases/README.md @@ -0,0 +1,15 @@ +In your prep, you looked this `formatAs12HourClock` function: + +```js +function formatAs12HourClock(time) { + + const hours = Number(time.slice(0, 2)); + + if (hours > 12) { + return `${hours - 12}:00 pm`; + } + return `${time} am`; +} +``` + +It still has bugs. Think of as many edge-cases as you can with this code. Write tests for all of them, and fix this code so that it works correctly for all valid inputs. You don't need to worry about invalid inputs (e.g. `"25:00"`). diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js new file mode 100644 index 000000000..d941da6e8 --- /dev/null +++ b/format-clock-edge-cases/timeConverter.js @@ -0,0 +1,31 @@ +// function formatAs12HourClock(time) { + +// const hours = Number(time.slice(0, 2)); + +// if (hours > 12) { +// return `${hours - 12}:00 pm`; +// } +// return `${time} am`; +// } + +// export {formatAs12HourClock}; + +function formatAs12HourClock(time){ + const [hourPart, minutePart] = time.split(":"); + const hours = Number(hourPart); + + let period; + if(hours < 12){ + period = "am"; + } else { + period = "pm"; + } + + let displayHour = hours % 12; + if(displayHour === 0){ + displayHour = 12; + } + return `${displayHour}:${minutePart}${period}`; +} +export {formatAs12HourClock}; +console.log(formatAs12HourClock("08:40")) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js new file mode 100644 index 000000000..ac64852b1 --- /dev/null +++ b/format-clock-edge-cases/timeConverter.test.js @@ -0,0 +1,41 @@ +import {formatAs12HourClock} from "./timeConverter.js"; +import assert from "node:assert"; +import test from "node:test"; + +test("correctly convert time after 12:00", () => { + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}); + +test("converts a single-digit morning hour and drops leading zero", () => { + assert.equal(formatAs12HourClock("08:00"), "8:00am"); +}) +test("converts exactly to midnight", () => { + assert.equal(formatAs12HourClock("00:00"), "12:00am"); +}) +test("converts time just after midnight", () => { + assert.equal(formatAs12HourClock("00:30"), "12:30am"); +}) +test("converts the last minute before noon", () => { + assert.equal(formatAs12HourClock("11:59"), "11:59am"); +}) +test("converts exact noon to pm", () => { + assert.equal(formatAs12HourClock("12:00"), "12:00pm"); +}) +test("convert time just after noon", () => { + assert.equal(formatAs12HourClock("12:30"), "12:30pm"); +}) +test("converts the first afternoon hour", () => { + assert.equal(formatAs12HourClock("13:00"), "1:00pm"); +}) +test("converts late evening hour", () => { + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}) +test("converts last minute of the day", () => { + assert.equal(formatAs12HourClock("23:59"), "11:59pm"); +}) +test("preserves minutes with leading zero", () => { + assert.equal(formatAs12HourClock("09:05"), "9:05am"); +}) +test("preserves non-zero minutes", () => { + assert.equal(formatAs12HourClock("14:45"), "2:45pm"); +}) \ No newline at end of file From e313bdcccb580e9fe35eea247b27da738226a379 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 00:15:28 +0100 Subject: [PATCH 087/127] Remove formatAs12HourClock function and its tests due to refactoring --- format-clock-edge-cases/README.md | 15 ------- format-clock-edge-cases/timeConverter.js | 31 -------------- format-clock-edge-cases/timeConverter.test.js | 41 ------------------- 3 files changed, 87 deletions(-) delete mode 100644 format-clock-edge-cases/README.md delete mode 100644 format-clock-edge-cases/timeConverter.js delete mode 100644 format-clock-edge-cases/timeConverter.test.js diff --git a/format-clock-edge-cases/README.md b/format-clock-edge-cases/README.md deleted file mode 100644 index 8a43a9e96..000000000 --- a/format-clock-edge-cases/README.md +++ /dev/null @@ -1,15 +0,0 @@ -In your prep, you looked this `formatAs12HourClock` function: - -```js -function formatAs12HourClock(time) { - - const hours = Number(time.slice(0, 2)); - - if (hours > 12) { - return `${hours - 12}:00 pm`; - } - return `${time} am`; -} -``` - -It still has bugs. Think of as many edge-cases as you can with this code. Write tests for all of them, and fix this code so that it works correctly for all valid inputs. You don't need to worry about invalid inputs (e.g. `"25:00"`). diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js deleted file mode 100644 index d941da6e8..000000000 --- a/format-clock-edge-cases/timeConverter.js +++ /dev/null @@ -1,31 +0,0 @@ -// function formatAs12HourClock(time) { - -// const hours = Number(time.slice(0, 2)); - -// if (hours > 12) { -// return `${hours - 12}:00 pm`; -// } -// return `${time} am`; -// } - -// export {formatAs12HourClock}; - -function formatAs12HourClock(time){ - const [hourPart, minutePart] = time.split(":"); - const hours = Number(hourPart); - - let period; - if(hours < 12){ - period = "am"; - } else { - period = "pm"; - } - - let displayHour = hours % 12; - if(displayHour === 0){ - displayHour = 12; - } - return `${displayHour}:${minutePart}${period}`; -} -export {formatAs12HourClock}; -console.log(formatAs12HourClock("08:40")) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js deleted file mode 100644 index ac64852b1..000000000 --- a/format-clock-edge-cases/timeConverter.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import {formatAs12HourClock} from "./timeConverter.js"; -import assert from "node:assert"; -import test from "node:test"; - -test("correctly convert time after 12:00", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}); - -test("converts a single-digit morning hour and drops leading zero", () => { - assert.equal(formatAs12HourClock("08:00"), "8:00am"); -}) -test("converts exactly to midnight", () => { - assert.equal(formatAs12HourClock("00:00"), "12:00am"); -}) -test("converts time just after midnight", () => { - assert.equal(formatAs12HourClock("00:30"), "12:30am"); -}) -test("converts the last minute before noon", () => { - assert.equal(formatAs12HourClock("11:59"), "11:59am"); -}) -test("converts exact noon to pm", () => { - assert.equal(formatAs12HourClock("12:00"), "12:00pm"); -}) -test("convert time just after noon", () => { - assert.equal(formatAs12HourClock("12:30"), "12:30pm"); -}) -test("converts the first afternoon hour", () => { - assert.equal(formatAs12HourClock("13:00"), "1:00pm"); -}) -test("converts late evening hour", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}) -test("converts last minute of the day", () => { - assert.equal(formatAs12HourClock("23:59"), "11:59pm"); -}) -test("preserves minutes with leading zero", () => { - assert.equal(formatAs12HourClock("09:05"), "9:05am"); -}) -test("preserves non-zero minutes", () => { - assert.equal(formatAs12HourClock("14:45"), "2:45pm"); -}) \ No newline at end of file From c6ae2f73bdb8783fe33e8997fb289011cca3a3d0 Mon Sep 17 00:00:00 2001 From: Moses777 Date: Fri, 9 Oct 2026 00:18:43 +0100 Subject: [PATCH 088/127] Delete format-clock-edge-cases/timeConverter.js --- format-clock-edge-cases/timeConverter.js | 31 ------------------------ 1 file changed, 31 deletions(-) delete mode 100644 format-clock-edge-cases/timeConverter.js diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js deleted file mode 100644 index d941da6e8..000000000 --- a/format-clock-edge-cases/timeConverter.js +++ /dev/null @@ -1,31 +0,0 @@ -// function formatAs12HourClock(time) { - -// const hours = Number(time.slice(0, 2)); - -// if (hours > 12) { -// return `${hours - 12}:00 pm`; -// } -// return `${time} am`; -// } - -// export {formatAs12HourClock}; - -function formatAs12HourClock(time){ - const [hourPart, minutePart] = time.split(":"); - const hours = Number(hourPart); - - let period; - if(hours < 12){ - period = "am"; - } else { - period = "pm"; - } - - let displayHour = hours % 12; - if(displayHour === 0){ - displayHour = 12; - } - return `${displayHour}:${minutePart}${period}`; -} -export {formatAs12HourClock}; -console.log(formatAs12HourClock("08:40")) From 32535c774fb332672d03d9d6c5f1d152c478b47c Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 00:22:30 +0100 Subject: [PATCH 089/127] Add formatAs12HourClock function and comprehensive tests for edge cases --- format-clock-edge-cases/README.md | 15 +++++++ format-clock-edge-cases/timeConverter.js | 31 ++++++++++++++ format-clock-edge-cases/timeConverter.test.js | 41 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 format-clock-edge-cases/README.md create mode 100644 format-clock-edge-cases/timeConverter.js create mode 100644 format-clock-edge-cases/timeConverter.test.js diff --git a/format-clock-edge-cases/README.md b/format-clock-edge-cases/README.md new file mode 100644 index 000000000..8a43a9e96 --- /dev/null +++ b/format-clock-edge-cases/README.md @@ -0,0 +1,15 @@ +In your prep, you looked this `formatAs12HourClock` function: + +```js +function formatAs12HourClock(time) { + + const hours = Number(time.slice(0, 2)); + + if (hours > 12) { + return `${hours - 12}:00 pm`; + } + return `${time} am`; +} +``` + +It still has bugs. Think of as many edge-cases as you can with this code. Write tests for all of them, and fix this code so that it works correctly for all valid inputs. You don't need to worry about invalid inputs (e.g. `"25:00"`). diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js new file mode 100644 index 000000000..d941da6e8 --- /dev/null +++ b/format-clock-edge-cases/timeConverter.js @@ -0,0 +1,31 @@ +// function formatAs12HourClock(time) { + +// const hours = Number(time.slice(0, 2)); + +// if (hours > 12) { +// return `${hours - 12}:00 pm`; +// } +// return `${time} am`; +// } + +// export {formatAs12HourClock}; + +function formatAs12HourClock(time){ + const [hourPart, minutePart] = time.split(":"); + const hours = Number(hourPart); + + let period; + if(hours < 12){ + period = "am"; + } else { + period = "pm"; + } + + let displayHour = hours % 12; + if(displayHour === 0){ + displayHour = 12; + } + return `${displayHour}:${minutePart}${period}`; +} +export {formatAs12HourClock}; +console.log(formatAs12HourClock("08:40")) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js new file mode 100644 index 000000000..ac64852b1 --- /dev/null +++ b/format-clock-edge-cases/timeConverter.test.js @@ -0,0 +1,41 @@ +import {formatAs12HourClock} from "./timeConverter.js"; +import assert from "node:assert"; +import test from "node:test"; + +test("correctly convert time after 12:00", () => { + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}); + +test("converts a single-digit morning hour and drops leading zero", () => { + assert.equal(formatAs12HourClock("08:00"), "8:00am"); +}) +test("converts exactly to midnight", () => { + assert.equal(formatAs12HourClock("00:00"), "12:00am"); +}) +test("converts time just after midnight", () => { + assert.equal(formatAs12HourClock("00:30"), "12:30am"); +}) +test("converts the last minute before noon", () => { + assert.equal(formatAs12HourClock("11:59"), "11:59am"); +}) +test("converts exact noon to pm", () => { + assert.equal(formatAs12HourClock("12:00"), "12:00pm"); +}) +test("convert time just after noon", () => { + assert.equal(formatAs12HourClock("12:30"), "12:30pm"); +}) +test("converts the first afternoon hour", () => { + assert.equal(formatAs12HourClock("13:00"), "1:00pm"); +}) +test("converts late evening hour", () => { + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}) +test("converts last minute of the day", () => { + assert.equal(formatAs12HourClock("23:59"), "11:59pm"); +}) +test("preserves minutes with leading zero", () => { + assert.equal(formatAs12HourClock("09:05"), "9:05am"); +}) +test("preserves non-zero minutes", () => { + assert.equal(formatAs12HourClock("14:45"), "2:45pm"); +}) \ No newline at end of file From 46a0c2e163d9deca4d7c49f5aedbba180f78894e Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 00:30:41 +0100 Subject: [PATCH 090/127] Complete Sprint 3 implement and rewrite exercises --- .../1-get-angle-type.test.js | 29 ++++++++ .../2-is-proper-fraction.test.js | 14 +++- .../3-get-card-value.test.js | 69 +++++++++++++++++++ .../implement/1-get-angle-type.js | 14 +++- .../implement/2-is-proper-fraction.js | 6 +- .../implement/3-get-card-value.js | 28 +++++++- 6 files changed, 156 insertions(+), 4 deletions(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js index cf50f6cad..32d473387 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js @@ -10,3 +10,32 @@ test("Classifies right angles", () => { const right = getAngleType(90); assert.equal(right, "Right angle"); }); + +test("Classifies acute angles", () => { + assert.equal(getAngleType(45), "Acute angle"); + assert.equal(getAngleType(1), "Acute angle"); + assert.equal(getAngleType(89), "Acute angle"); +}); + +test("Classifies obtuse angles", () => { + assert.equal(getAngleType(91), "Obtuse angle"); + assert.equal(getAngleType(135), "Obtuse angle"); + assert.equal(getAngleType(179), "Obtuse angle"); +}); + +test("Classifies straight angles", () => { + assert.equal(getAngleType(180), "Straight angle"); +}); + +test("Classifies reflex angles", () => { + assert.equal(getAngleType(181), "Reflex angle"); + assert.equal(getAngleType(270), "Reflex angle"); + assert.equal(getAngleType(359), "Reflex angle"); +}); + +test("Classifies invalid angles", () => { + assert.equal(getAngleType(0), "Invalid angle"); + assert.equal(getAngleType(360), "Invalid angle"); + assert.equal(getAngleType(400), "Invalid angle"); + assert.equal(getAngleType(-5), "Invalid angle"); +}) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index a29084605..75ebbe7fd 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -7,6 +7,18 @@ import { isProperFraction } from "../implement/2-is-proper-fraction.js"; // What combinations of numerators and denominators should you test? test("Basic proper fraction", () => { - // Example: 1/2 is a proper fraction assert.equal(isProperFraction(1, 2), true); + assert.equal(isProperFraction(0, 5), true); + assert.equal(isProperFraction(-1, 2), true); + assert.equal(isProperFraction(1, -2), true); + assert.equal(isProperFraction(-1, -2), true); +}); + +test("Basic improper fraction", () => { + assert.equal(isProperFraction(5, 2), false); + assert.equal(isProperFraction(3, 3), false); + assert.equal(isProperFraction(5, 0), false); + assert.equal(isProperFraction(-5, 2), false); + assert.equal(isProperFraction(5, -2), false); + assert.equal(isProperFraction(-5, -2), false); }); diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index f5092d9b1..765ccd34d 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -9,8 +9,77 @@ test("Valid single-digit card", () => { assert.equal(getCardValue("9♠"), 9); }); +test("Ace returns 11", () => { + assert.equal(getCardValue("A♠"), 11); +}); + +test("Face cards return 10", () => { + assert.equal(getCardValue("J♣"), 10); + assert.equal(getCardValue("Q♦"), 10); + assert.equal(getCardValue("K♥"), 10); +}) + +test("Number cards 2 to 10 return their numbers", () => { + for(let n = 2; n <= 10; n++) { + assert.equal(getCardValue(`${n}♦`), n); + } +}); + +test("Only valid double-digit '10' card", () => { + assert.equal(getCardValue("10♥"), 10); +}); + +test("Accepts all four suits", () => { + for (const suit of ["♠", "♥", "♦", "♣"]){ + assert.equal(getCardValue(`5${suit}`), 5); + } +}); + test("Arbitrary non-card string", () => { assert.throws(() => getCardValue("invalid"), /Expected a number followed by a suit, but got "invalid"/, "Expected clear error"); }); // TODO: What other invalid card cases can you think of? +test("Missing suit", () => { + assert.throws(() => getCardValue("7"), /Expected a number followed by a suit/); + assert.throws(() => getCardValue("A"), /Expected a number followed by a suit/); +}); + +test("Missing ranks", () => { + assert.throws(() => getCardValue("♥"), /Expected a number followed by a suit/); +}); + +test("Empty strings", () => { + assert.throws(() => getCardValue(""), /Expected a number followed by a suit/); +}); + +test("Out-of-range number ranks", () => { + for (const OOR of ["0♥", "1♠", "11♦", "100♣"]) { + assert.throws(() => getCardValue(OOR), /Expected a number followed by a suit/); + } +}); + +test("Unknown suit", () => { + assert.throws(() => getCardValue("A❤"), /Expected a number followed by a suit/); + assert.throws(() => getCardValue("AV"), /Expected a number followed by a suit/); +}); + +test("Lowercase ranks", () => { + assert.throws(() => getCardValue("a♦"), /Expected a number followed by a suit/); + assert.throws(() => getCardValue("k♥"), /Expected a number followed by a suit/); +}); + +test("Suit before rank", () => { + assert.throws(() => getCardValue("♣A"), /Expected a number followed by a suit/); +}); + +test("Extra characters or spaces", () => { + for (const ExS of [" A♦", "A♦ ", "A♦♦", "A ♦"]){ + assert.throws(() => getCardValue(ExS), /Expected a number followed by a suit/); + } +}); + +test("Non-string input", () => { + assert.throws(() => getCardValue(undefined), /Expected a number followed by a suit/); + assert.throws(() => getCardValue(5), /Expected a number followed by a suit/); +}); \ No newline at end of file diff --git a/implement-and-rewrite-tests/implement/1-get-angle-type.js b/implement-and-rewrite-tests/implement/1-get-angle-type.js index 8a6fba050..4ff290d94 100644 --- a/implement-and-rewrite-tests/implement/1-get-angle-type.js +++ b/implement-and-rewrite-tests/implement/1-get-angle-type.js @@ -17,5 +17,17 @@ // execute the code to ensure all tests pass. export function getAngleType(angle) { - // TODO: Implement this function + if(angle > 0 && angle < 90) { + return "Acute angle"; + } else if(angle === 90) { + return "Right angle"; + } else if(angle > 90 && angle < 180){ + return "Obtuse angle"; + } else if(angle === 180) { + return "Straight angle" + } else if (angle > 180 && angle < 360){ + return "Reflex angle"; + } else { + return "Invalid angle"; + } } diff --git a/implement-and-rewrite-tests/implement/2-is-proper-fraction.js b/implement-and-rewrite-tests/implement/2-is-proper-fraction.js index f983800f0..f56b51bf3 100644 --- a/implement-and-rewrite-tests/implement/2-is-proper-fraction.js +++ b/implement-and-rewrite-tests/implement/2-is-proper-fraction.js @@ -14,5 +14,9 @@ // execute the code to ensure all tests pass. export function isProperFraction(numerator, denominator) { - // TODO: Implement this function + if(Math.abs(numerator) < Math.abs(denominator)){ + return true; + } else { + return false; + } } diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 9614ab1ee..05a47f6d2 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -24,5 +24,31 @@ // execute the code to ensure all tests pass. export function getCardValue(card) { - // TODO: Implement this function + const validSuits = ["♠", "♥", "♦", "♣"]; + const numberRanks = ["2", "3", "4", "5", "6", "7", "8", "9", "10"]; + const faceRanks = ["J", "Q", "K"]; + + const error = new Error(`Expected a number followed by a suit, but got "${card}"`); + + if(typeof card !== "string" || card.length < 2){ + throw error; + } + + const suit = card.slice(-1); + const rank = card.slice(0, -1); + + if(!validSuits.includes(suit)){ + throw error; + } + if(rank === "A") { + return 11; + } + if(faceRanks.includes(rank)){ + return 10; + } + if(numberRanks.includes(rank)){ + return Number(rank); + } + throw error; } + From 072555ca480349b5fcfde7266a3ad02451002274 Mon Sep 17 00:00:00 2001 From: Moses777 Date: Fri, 9 Oct 2026 00:50:38 +0100 Subject: [PATCH 091/127] Delete format-clock-edge-cases/timeConverter.test.js --- format-clock-edge-cases/timeConverter.test.js | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 format-clock-edge-cases/timeConverter.test.js diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js deleted file mode 100644 index ac64852b1..000000000 --- a/format-clock-edge-cases/timeConverter.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import {formatAs12HourClock} from "./timeConverter.js"; -import assert from "node:assert"; -import test from "node:test"; - -test("correctly convert time after 12:00", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}); - -test("converts a single-digit morning hour and drops leading zero", () => { - assert.equal(formatAs12HourClock("08:00"), "8:00am"); -}) -test("converts exactly to midnight", () => { - assert.equal(formatAs12HourClock("00:00"), "12:00am"); -}) -test("converts time just after midnight", () => { - assert.equal(formatAs12HourClock("00:30"), "12:30am"); -}) -test("converts the last minute before noon", () => { - assert.equal(formatAs12HourClock("11:59"), "11:59am"); -}) -test("converts exact noon to pm", () => { - assert.equal(formatAs12HourClock("12:00"), "12:00pm"); -}) -test("convert time just after noon", () => { - assert.equal(formatAs12HourClock("12:30"), "12:30pm"); -}) -test("converts the first afternoon hour", () => { - assert.equal(formatAs12HourClock("13:00"), "1:00pm"); -}) -test("converts late evening hour", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}) -test("converts last minute of the day", () => { - assert.equal(formatAs12HourClock("23:59"), "11:59pm"); -}) -test("preserves minutes with leading zero", () => { - assert.equal(formatAs12HourClock("09:05"), "9:05am"); -}) -test("preserves non-zero minutes", () => { - assert.equal(formatAs12HourClock("14:45"), "2:45pm"); -}) \ No newline at end of file From 6bba53a7947145968b40776a9c5fb34a5a9d833c Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 00:57:25 +0100 Subject: [PATCH 092/127] Exclude format-clock-edge-cases from PR --- format-clock-edge-cases/timeConverter.js | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 format-clock-edge-cases/timeConverter.js diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js new file mode 100644 index 000000000..d941da6e8 --- /dev/null +++ b/format-clock-edge-cases/timeConverter.js @@ -0,0 +1,31 @@ +// function formatAs12HourClock(time) { + +// const hours = Number(time.slice(0, 2)); + +// if (hours > 12) { +// return `${hours - 12}:00 pm`; +// } +// return `${time} am`; +// } + +// export {formatAs12HourClock}; + +function formatAs12HourClock(time){ + const [hourPart, minutePart] = time.split(":"); + const hours = Number(hourPart); + + let period; + if(hours < 12){ + period = "am"; + } else { + period = "pm"; + } + + let displayHour = hours % 12; + if(displayHour === 0){ + displayHour = 12; + } + return `${displayHour}:${minutePart}${period}`; +} +export {formatAs12HourClock}; +console.log(formatAs12HourClock("08:40")) From d11f6347a9a2ea22a619039aebad56913f5790f8 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 01:00:12 +0100 Subject: [PATCH 093/127] Add unit tests for time conversion in timeConverter.js --- format-clock-edge-cases/timeConverter.test.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 format-clock-edge-cases/timeConverter.test.js diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js new file mode 100644 index 000000000..ac64852b1 --- /dev/null +++ b/format-clock-edge-cases/timeConverter.test.js @@ -0,0 +1,41 @@ +import {formatAs12HourClock} from "./timeConverter.js"; +import assert from "node:assert"; +import test from "node:test"; + +test("correctly convert time after 12:00", () => { + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}); + +test("converts a single-digit morning hour and drops leading zero", () => { + assert.equal(formatAs12HourClock("08:00"), "8:00am"); +}) +test("converts exactly to midnight", () => { + assert.equal(formatAs12HourClock("00:00"), "12:00am"); +}) +test("converts time just after midnight", () => { + assert.equal(formatAs12HourClock("00:30"), "12:30am"); +}) +test("converts the last minute before noon", () => { + assert.equal(formatAs12HourClock("11:59"), "11:59am"); +}) +test("converts exact noon to pm", () => { + assert.equal(formatAs12HourClock("12:00"), "12:00pm"); +}) +test("convert time just after noon", () => { + assert.equal(formatAs12HourClock("12:30"), "12:30pm"); +}) +test("converts the first afternoon hour", () => { + assert.equal(formatAs12HourClock("13:00"), "1:00pm"); +}) +test("converts late evening hour", () => { + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}) +test("converts last minute of the day", () => { + assert.equal(formatAs12HourClock("23:59"), "11:59pm"); +}) +test("preserves minutes with leading zero", () => { + assert.equal(formatAs12HourClock("09:05"), "9:05am"); +}) +test("preserves non-zero minutes", () => { + assert.equal(formatAs12HourClock("14:45"), "2:45pm"); +}) \ No newline at end of file From 94742395f1e398c0f7a9a33075a6763d029597ae Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 01:31:22 +0100 Subject: [PATCH 094/127] Remove formatAs12HourClock function and associated tests --- format-clock-edge-cases/README.md | 15 ------- format-clock-edge-cases/timeConverter.js | 31 -------------- format-clock-edge-cases/timeConverter.test.js | 41 ------------------- 3 files changed, 87 deletions(-) delete mode 100644 format-clock-edge-cases/README.md delete mode 100644 format-clock-edge-cases/timeConverter.js delete mode 100644 format-clock-edge-cases/timeConverter.test.js diff --git a/format-clock-edge-cases/README.md b/format-clock-edge-cases/README.md deleted file mode 100644 index 8a43a9e96..000000000 --- a/format-clock-edge-cases/README.md +++ /dev/null @@ -1,15 +0,0 @@ -In your prep, you looked this `formatAs12HourClock` function: - -```js -function formatAs12HourClock(time) { - - const hours = Number(time.slice(0, 2)); - - if (hours > 12) { - return `${hours - 12}:00 pm`; - } - return `${time} am`; -} -``` - -It still has bugs. Think of as many edge-cases as you can with this code. Write tests for all of them, and fix this code so that it works correctly for all valid inputs. You don't need to worry about invalid inputs (e.g. `"25:00"`). diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js deleted file mode 100644 index d941da6e8..000000000 --- a/format-clock-edge-cases/timeConverter.js +++ /dev/null @@ -1,31 +0,0 @@ -// function formatAs12HourClock(time) { - -// const hours = Number(time.slice(0, 2)); - -// if (hours > 12) { -// return `${hours - 12}:00 pm`; -// } -// return `${time} am`; -// } - -// export {formatAs12HourClock}; - -function formatAs12HourClock(time){ - const [hourPart, minutePart] = time.split(":"); - const hours = Number(hourPart); - - let period; - if(hours < 12){ - period = "am"; - } else { - period = "pm"; - } - - let displayHour = hours % 12; - if(displayHour === 0){ - displayHour = 12; - } - return `${displayHour}:${minutePart}${period}`; -} -export {formatAs12HourClock}; -console.log(formatAs12HourClock("08:40")) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js deleted file mode 100644 index ac64852b1..000000000 --- a/format-clock-edge-cases/timeConverter.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import {formatAs12HourClock} from "./timeConverter.js"; -import assert from "node:assert"; -import test from "node:test"; - -test("correctly convert time after 12:00", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}); - -test("converts a single-digit morning hour and drops leading zero", () => { - assert.equal(formatAs12HourClock("08:00"), "8:00am"); -}) -test("converts exactly to midnight", () => { - assert.equal(formatAs12HourClock("00:00"), "12:00am"); -}) -test("converts time just after midnight", () => { - assert.equal(formatAs12HourClock("00:30"), "12:30am"); -}) -test("converts the last minute before noon", () => { - assert.equal(formatAs12HourClock("11:59"), "11:59am"); -}) -test("converts exact noon to pm", () => { - assert.equal(formatAs12HourClock("12:00"), "12:00pm"); -}) -test("convert time just after noon", () => { - assert.equal(formatAs12HourClock("12:30"), "12:30pm"); -}) -test("converts the first afternoon hour", () => { - assert.equal(formatAs12HourClock("13:00"), "1:00pm"); -}) -test("converts late evening hour", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}) -test("converts last minute of the day", () => { - assert.equal(formatAs12HourClock("23:59"), "11:59pm"); -}) -test("preserves minutes with leading zero", () => { - assert.equal(formatAs12HourClock("09:05"), "9:05am"); -}) -test("preserves non-zero minutes", () => { - assert.equal(formatAs12HourClock("14:45"), "2:45pm"); -}) \ No newline at end of file From 4a91c034fb63ebd8a6fd99b629ea64cd8fbf383b Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 01:32:51 +0100 Subject: [PATCH 095/127] Remove formatAs12HourClock function and associated tests --- format-clock-edge-cases/README.md | 15 ------- format-clock-edge-cases/timeConverter.js | 31 -------------- format-clock-edge-cases/timeConverter.test.js | 41 ------------------- 3 files changed, 87 deletions(-) delete mode 100644 format-clock-edge-cases/README.md delete mode 100644 format-clock-edge-cases/timeConverter.js delete mode 100644 format-clock-edge-cases/timeConverter.test.js diff --git a/format-clock-edge-cases/README.md b/format-clock-edge-cases/README.md deleted file mode 100644 index 8a43a9e96..000000000 --- a/format-clock-edge-cases/README.md +++ /dev/null @@ -1,15 +0,0 @@ -In your prep, you looked this `formatAs12HourClock` function: - -```js -function formatAs12HourClock(time) { - - const hours = Number(time.slice(0, 2)); - - if (hours > 12) { - return `${hours - 12}:00 pm`; - } - return `${time} am`; -} -``` - -It still has bugs. Think of as many edge-cases as you can with this code. Write tests for all of them, and fix this code so that it works correctly for all valid inputs. You don't need to worry about invalid inputs (e.g. `"25:00"`). diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js deleted file mode 100644 index d941da6e8..000000000 --- a/format-clock-edge-cases/timeConverter.js +++ /dev/null @@ -1,31 +0,0 @@ -// function formatAs12HourClock(time) { - -// const hours = Number(time.slice(0, 2)); - -// if (hours > 12) { -// return `${hours - 12}:00 pm`; -// } -// return `${time} am`; -// } - -// export {formatAs12HourClock}; - -function formatAs12HourClock(time){ - const [hourPart, minutePart] = time.split(":"); - const hours = Number(hourPart); - - let period; - if(hours < 12){ - period = "am"; - } else { - period = "pm"; - } - - let displayHour = hours % 12; - if(displayHour === 0){ - displayHour = 12; - } - return `${displayHour}:${minutePart}${period}`; -} -export {formatAs12HourClock}; -console.log(formatAs12HourClock("08:40")) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js deleted file mode 100644 index ac64852b1..000000000 --- a/format-clock-edge-cases/timeConverter.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import {formatAs12HourClock} from "./timeConverter.js"; -import assert from "node:assert"; -import test from "node:test"; - -test("correctly convert time after 12:00", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}); - -test("converts a single-digit morning hour and drops leading zero", () => { - assert.equal(formatAs12HourClock("08:00"), "8:00am"); -}) -test("converts exactly to midnight", () => { - assert.equal(formatAs12HourClock("00:00"), "12:00am"); -}) -test("converts time just after midnight", () => { - assert.equal(formatAs12HourClock("00:30"), "12:30am"); -}) -test("converts the last minute before noon", () => { - assert.equal(formatAs12HourClock("11:59"), "11:59am"); -}) -test("converts exact noon to pm", () => { - assert.equal(formatAs12HourClock("12:00"), "12:00pm"); -}) -test("convert time just after noon", () => { - assert.equal(formatAs12HourClock("12:30"), "12:30pm"); -}) -test("converts the first afternoon hour", () => { - assert.equal(formatAs12HourClock("13:00"), "1:00pm"); -}) -test("converts late evening hour", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}) -test("converts last minute of the day", () => { - assert.equal(formatAs12HourClock("23:59"), "11:59pm"); -}) -test("preserves minutes with leading zero", () => { - assert.equal(formatAs12HourClock("09:05"), "9:05am"); -}) -test("preserves non-zero minutes", () => { - assert.equal(formatAs12HourClock("14:45"), "2:45pm"); -}) \ No newline at end of file From a8d45ee98bbd2d541e15a99ce36d5a00c0c226ed Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 01:37:55 +0100 Subject: [PATCH 096/127] Add unit tests for time conversion in timeConverter.js --- format-clock-edge-cases/README.md | 15 ------------ format-clock-edge-cases/timeConverter.js | 31 ------------------------ 2 files changed, 46 deletions(-) delete mode 100644 format-clock-edge-cases/README.md delete mode 100644 format-clock-edge-cases/timeConverter.js diff --git a/format-clock-edge-cases/README.md b/format-clock-edge-cases/README.md deleted file mode 100644 index 8a43a9e96..000000000 --- a/format-clock-edge-cases/README.md +++ /dev/null @@ -1,15 +0,0 @@ -In your prep, you looked this `formatAs12HourClock` function: - -```js -function formatAs12HourClock(time) { - - const hours = Number(time.slice(0, 2)); - - if (hours > 12) { - return `${hours - 12}:00 pm`; - } - return `${time} am`; -} -``` - -It still has bugs. Think of as many edge-cases as you can with this code. Write tests for all of them, and fix this code so that it works correctly for all valid inputs. You don't need to worry about invalid inputs (e.g. `"25:00"`). diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js deleted file mode 100644 index d941da6e8..000000000 --- a/format-clock-edge-cases/timeConverter.js +++ /dev/null @@ -1,31 +0,0 @@ -// function formatAs12HourClock(time) { - -// const hours = Number(time.slice(0, 2)); - -// if (hours > 12) { -// return `${hours - 12}:00 pm`; -// } -// return `${time} am`; -// } - -// export {formatAs12HourClock}; - -function formatAs12HourClock(time){ - const [hourPart, minutePart] = time.split(":"); - const hours = Number(hourPart); - - let period; - if(hours < 12){ - period = "am"; - } else { - period = "pm"; - } - - let displayHour = hours % 12; - if(displayHour === 0){ - displayHour = 12; - } - return `${displayHour}:${minutePart}${period}`; -} -export {formatAs12HourClock}; -console.log(formatAs12HourClock("08:40")) From e817ed0f7c13481f28e54c6165e816b382858cce Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 01:44:15 +0100 Subject: [PATCH 097/127] Implement formatAs12HourClock function and add comprehensive unit tests --- format-clock-edge-cases/README.md | 15 +++++++ format-clock-edge-cases/timeConverter.js | 31 ++++++++++++++ format-clock-edge-cases/timeConverter.test.js | 41 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 format-clock-edge-cases/README.md create mode 100644 format-clock-edge-cases/timeConverter.js create mode 100644 format-clock-edge-cases/timeConverter.test.js diff --git a/format-clock-edge-cases/README.md b/format-clock-edge-cases/README.md new file mode 100644 index 000000000..8a43a9e96 --- /dev/null +++ b/format-clock-edge-cases/README.md @@ -0,0 +1,15 @@ +In your prep, you looked this `formatAs12HourClock` function: + +```js +function formatAs12HourClock(time) { + + const hours = Number(time.slice(0, 2)); + + if (hours > 12) { + return `${hours - 12}:00 pm`; + } + return `${time} am`; +} +``` + +It still has bugs. Think of as many edge-cases as you can with this code. Write tests for all of them, and fix this code so that it works correctly for all valid inputs. You don't need to worry about invalid inputs (e.g. `"25:00"`). diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js new file mode 100644 index 000000000..d941da6e8 --- /dev/null +++ b/format-clock-edge-cases/timeConverter.js @@ -0,0 +1,31 @@ +// function formatAs12HourClock(time) { + +// const hours = Number(time.slice(0, 2)); + +// if (hours > 12) { +// return `${hours - 12}:00 pm`; +// } +// return `${time} am`; +// } + +// export {formatAs12HourClock}; + +function formatAs12HourClock(time){ + const [hourPart, minutePart] = time.split(":"); + const hours = Number(hourPart); + + let period; + if(hours < 12){ + period = "am"; + } else { + period = "pm"; + } + + let displayHour = hours % 12; + if(displayHour === 0){ + displayHour = 12; + } + return `${displayHour}:${minutePart}${period}`; +} +export {formatAs12HourClock}; +console.log(formatAs12HourClock("08:40")) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js new file mode 100644 index 000000000..ac64852b1 --- /dev/null +++ b/format-clock-edge-cases/timeConverter.test.js @@ -0,0 +1,41 @@ +import {formatAs12HourClock} from "./timeConverter.js"; +import assert from "node:assert"; +import test from "node:test"; + +test("correctly convert time after 12:00", () => { + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}); + +test("converts a single-digit morning hour and drops leading zero", () => { + assert.equal(formatAs12HourClock("08:00"), "8:00am"); +}) +test("converts exactly to midnight", () => { + assert.equal(formatAs12HourClock("00:00"), "12:00am"); +}) +test("converts time just after midnight", () => { + assert.equal(formatAs12HourClock("00:30"), "12:30am"); +}) +test("converts the last minute before noon", () => { + assert.equal(formatAs12HourClock("11:59"), "11:59am"); +}) +test("converts exact noon to pm", () => { + assert.equal(formatAs12HourClock("12:00"), "12:00pm"); +}) +test("convert time just after noon", () => { + assert.equal(formatAs12HourClock("12:30"), "12:30pm"); +}) +test("converts the first afternoon hour", () => { + assert.equal(formatAs12HourClock("13:00"), "1:00pm"); +}) +test("converts late evening hour", () => { + assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +}) +test("converts last minute of the day", () => { + assert.equal(formatAs12HourClock("23:59"), "11:59pm"); +}) +test("preserves minutes with leading zero", () => { + assert.equal(formatAs12HourClock("09:05"), "9:05am"); +}) +test("preserves non-zero minutes", () => { + assert.equal(formatAs12HourClock("14:45"), "2:45pm"); +}) \ No newline at end of file From d5895355956cad03a416c260a8b1c0b648e4bfb5 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 01:52:09 +0100 Subject: [PATCH 098/127] Revert unrelated format-clock-edge-cases changes --- format-clock-edge-cases/timeConverter.js | 32 +++------------ format-clock-edge-cases/timeConverter.test.js | 40 +++---------------- 2 files changed, 11 insertions(+), 61 deletions(-) diff --git a/format-clock-edge-cases/timeConverter.js b/format-clock-edge-cases/timeConverter.js index d941da6e8..310c07bd9 100644 --- a/format-clock-edge-cases/timeConverter.js +++ b/format-clock-edge-cases/timeConverter.js @@ -1,31 +1,11 @@ -// function formatAs12HourClock(time) { +function formatAs12HourClock(time) { -// const hours = Number(time.slice(0, 2)); + const hours = Number(time.slice(0, 2)); -// if (hours > 12) { -// return `${hours - 12}:00 pm`; -// } -// return `${time} am`; -// } - -// export {formatAs12HourClock}; - -function formatAs12HourClock(time){ - const [hourPart, minutePart] = time.split(":"); - const hours = Number(hourPart); - - let period; - if(hours < 12){ - period = "am"; - } else { - period = "pm"; + if (hours > 12) { + return `${hours - 12}:00 pm`; } - - let displayHour = hours % 12; - if(displayHour === 0){ - displayHour = 12; - } - return `${displayHour}:${minutePart}${period}`; + return `${time} am`; } + export {formatAs12HourClock}; -console.log(formatAs12HourClock("08:40")) diff --git a/format-clock-edge-cases/timeConverter.test.js b/format-clock-edge-cases/timeConverter.test.js index ac64852b1..88f2af094 100644 --- a/format-clock-edge-cases/timeConverter.test.js +++ b/format-clock-edge-cases/timeConverter.test.js @@ -2,40 +2,10 @@ import {formatAs12HourClock} from "./timeConverter.js"; import assert from "node:assert"; import test from "node:test"; -test("correctly convert time after 12:00", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); +test("correctly convert time after 12:00", function(){ + assert.equal(formatAs12HourClock("23:00"), "11:00 pm"); }); -test("converts a single-digit morning hour and drops leading zero", () => { - assert.equal(formatAs12HourClock("08:00"), "8:00am"); -}) -test("converts exactly to midnight", () => { - assert.equal(formatAs12HourClock("00:00"), "12:00am"); -}) -test("converts time just after midnight", () => { - assert.equal(formatAs12HourClock("00:30"), "12:30am"); -}) -test("converts the last minute before noon", () => { - assert.equal(formatAs12HourClock("11:59"), "11:59am"); -}) -test("converts exact noon to pm", () => { - assert.equal(formatAs12HourClock("12:00"), "12:00pm"); -}) -test("convert time just after noon", () => { - assert.equal(formatAs12HourClock("12:30"), "12:30pm"); -}) -test("converts the first afternoon hour", () => { - assert.equal(formatAs12HourClock("13:00"), "1:00pm"); -}) -test("converts late evening hour", () => { - assert.equal(formatAs12HourClock("23:00"), "11:00pm"); -}) -test("converts last minute of the day", () => { - assert.equal(formatAs12HourClock("23:59"), "11:59pm"); -}) -test("preserves minutes with leading zero", () => { - assert.equal(formatAs12HourClock("09:05"), "9:05am"); -}) -test("preserves non-zero minutes", () => { - assert.equal(formatAs12HourClock("14:45"), "2:45pm"); -}) \ No newline at end of file +test("can correctly convert morning time", function() { + assert.equal(formatAs12HourClock("08:00"), "08:00 am"); +}); From 1cb5d4874d4bf5bf0890f701160b8c196474aad1 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 02:34:19 +0100 Subject: [PATCH 099/127] Fix countChar function to correctly count occurrences of a character in a string --- practice-tdd/count.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/practice-tdd/count.js b/practice-tdd/count.js index 5518c5712..3bc9653bd 100644 --- a/practice-tdd/count.js +++ b/practice-tdd/count.js @@ -1,3 +1,10 @@ export function countChar(stringOfCharacters, findCharacter) { - return 5 + let count = 0; + + for (let i = 0; i < stringOfCharacters.length; i++){ + if(stringOfCharacters[1] === findCharacter){ + count++ + } + } + return count; } From a8ffa73f12111863940d3b224ca25837b709be13 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 02:41:36 +0100 Subject: [PATCH 100/127] Add missing imports for test framework in count.test.js --- practice-tdd/count.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/practice-tdd/count.test.js b/practice-tdd/count.test.js index cb3aaae59..216bc8525 100644 --- a/practice-tdd/count.test.js +++ b/practice-tdd/count.test.js @@ -1,5 +1,7 @@ // implement a function countChar that counts the number of times a character occurs in a string import { countChar } from "./count.js"; +import { test } from "node:test"; +import assert from "node:assert/strict"; // Given a string `str` and a single character `char` to search for, // When the countChar function is called with these inputs, // Then it should: From 26aa530023ff0f7a6072b86de616e24c2d76425f Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 02:42:42 +0100 Subject: [PATCH 101/127] Replace expect with assert in countChar test for consistency --- practice-tdd/count.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/practice-tdd/count.test.js b/practice-tdd/count.test.js index 216bc8525..fd004b4a1 100644 --- a/practice-tdd/count.test.js +++ b/practice-tdd/count.test.js @@ -16,7 +16,7 @@ test("should count multiple occurrences of a character", () => { const str = "aaaaa"; const char = "a"; const count = countChar(str, char); - expect(count).toEqual(5); + assert.equal(count, 5); }); // Scenario: No Occurrences From 588a65f97164a1f62dca244d595c27c19afd73d7 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 02:45:18 +0100 Subject: [PATCH 102/127] Add test case to verify countChar returns 0 for non-existent character --- practice-tdd/count.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/practice-tdd/count.test.js b/practice-tdd/count.test.js index fd004b4a1..c2ea99891 100644 --- a/practice-tdd/count.test.js +++ b/practice-tdd/count.test.js @@ -24,3 +24,10 @@ test("should count multiple occurrences of a character", () => { // And a character `char` that does not exist within `str`. // When the function is called with these inputs, // Then it should return 0, indicating that no occurrences of `char` were found. + +test("should return 0 when the character does not occur", () => { + const str = "moses"; + const char = "z"; + const count = countChar(str, char); + assert.equal(count, 0); +}) From 09fa9f94791d61fe74000ed5668d2f1a03c3e584 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 03:31:30 +0100 Subject: [PATCH 103/127] chore: add package.json for practice-tdd with Jest as dev dependency --- practice-tdd/package-lock.json | 4203 ++++++++++++++++++++++++++++++++ practice-tdd/package.json | 16 + 2 files changed, 4219 insertions(+) create mode 100644 practice-tdd/package-lock.json create mode 100644 practice-tdd/package.json diff --git a/practice-tdd/package-lock.json b/practice-tdd/package-lock.json new file mode 100644 index 000000000..08693290c --- /dev/null +++ b/practice-tdd/package-lock.json @@ -0,0 +1,4203 @@ +{ + "name": "practice-tdd", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "practice-tdd", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "jest": "^30.5.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.10.tgz", + "integrity": "sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.29.8" + }, + "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-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "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-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "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.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "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-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "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-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.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.10.tgz", + "integrity": "sha512-B3lYAs2nkKskbgQ1nfy8Ma9ao9Q1rntTAQHrzzyDuj+TSO+X3le6PfWwqDvodsb+OumE10eMFfuMCTQSQ5iuIQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.9", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "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/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.4.0.tgz", + "integrity": "sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "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.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.5.2.tgz", + "integrity": "sha512-e8sQC4pCMHPBrPX7Hk8TJr+DM5dkUnImSTNag8SEWFAFAF6xIz4AJvCKapnrdHnZxep4bxw4PhG+ZbimYBMyKw==", + "dev": true, + "dependencies": { + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.5.1", + "jest-util": "30.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/core": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.5.2.tgz", + "integrity": "sha512-/jqvFWoJF7LV1a6AUpYMbMm+2yIYsHJfR474H0SCzr9k8tnO/jl9wRg6zSG6lxgf6EozNlCG4amFzWsbZSvvZA==", + "dev": true, + "dependencies": { + "@jest/console": "30.5.2", + "@jest/pattern": "30.5.0", + "@jest/reporters": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/transform": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.5.1", + "jest-config": "30.5.2", + "jest-haste-map": "30.5.1", + "jest-message-util": "30.5.1", + "jest-regex-util": "30.5.0", + "jest-resolve": "30.5.1", + "jest-resolve-dependencies": "30.5.2", + "jest-runner": "30.5.2", + "jest-runtime": "30.5.2", + "jest-snapshot": "30.5.2", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", + "jest-watcher": "30.5.2", + "pretty-format": "30.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.5.0.tgz", + "integrity": "sha512-OsqBjHXCn8cadasoAZBP6nWYvMsRhpMzGXTpxJ5aO04NlbdhIz+FVe3q49l0AwVhsz/cEmIpBes6gAFl1/dWQg==", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.5.2.tgz", + "integrity": "sha512-nwFPOUMbmsjNNRCpnJpB9HbSZu4C07wDDds++5j+j1MezzPLxMPDdbdUVjr2o4RULDOValnDd70taPFI1EtxAg==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "jest-mock": "30.5.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.5.2.tgz", + "integrity": "sha512-2E+1Pg6jJxbRjLNLpciC71iri/3qsKJL222/aXJEFwC0VdUSvfS+JZQQLEVjUYYc8t8pQu2MGE3cF2+bNTYRsg==", + "dev": true, + "dependencies": { + "expect": "30.5.2", + "jest-snapshot": "30.5.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.5.2.tgz", + "integrity": "sha512-d/HOLSrJUlBIl6n3LzOa7cjW3xdePm5H5gQw2lixZ/0h157l9sw3mLblzFqnPcTbhDzhRQdBOX3A3KcG73nm5Q==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.5.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.5.2.tgz", + "integrity": "sha512-GKk0h0tKT5SpDPxDhPg3r9mm5s8/YCBzVNMOGdRiQXwUiMsjU10mVPlMaQstH6/cu50vOb8N9oQUMETHuwwxKw==", + "dev": true, + "dependencies": { + "@jest/types": "30.5.1", + "@sinonjs/fake-timers": "^15.4.0", + "@types/node": "*", + "jest-message-util": "30.5.1", + "jest-mock": "30.5.2", + "jest-util": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.5.0.tgz", + "integrity": "sha512-9/2VUPitAjmBzbvDvqrxmvB7BzWsBW0WmkkojX1ODuxX1NLGxx9gfaZpHB0z8DtJ9uhGNmZG/VXBhf8uO0OV8Q==", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.5.2.tgz", + "integrity": "sha512-62zfS+dL+M5aTNHXCNLyqD+j4oqxTIzDYrZbpqMP8Yn+gvlAGyzC6BSPNb1ZmFOakV1RtFYX/O3FCQXSWmQdgg==", + "dev": true, + "dependencies": { + "@jest/environment": "30.5.2", + "@jest/expect": "30.5.2", + "@jest/types": "30.5.1", + "jest-mock": "30.5.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.5.0.tgz", + "integrity": "sha512-HdNQYSdRTEBNrginaqzQtTjG0HRMfrra/z6Ok7uL3S87vSlarIVohEsJsSj5edu3MiHoHjAkvPROz5ZjoKai+w==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.5.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/@jest/react-is-19": { + "name": "react-is", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.0.tgz", + "integrity": "sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==", + "dev": true + }, + "node_modules/@jest/reporters": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.5.2.tgz", + "integrity": "sha512-ev6E9iG73twQcfAfoTnviuYkr3yOrYbzAtMFCimv2fxHXPIp9PBt2u1wNMt0aYWgl8FPwIcS8oqRJg6alnht4Q==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/transform": "30.5.2", + "@jest/types": "30.5.1", + "@jridgewell/trace-mapping": "^0.3.31", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^13.0.6", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.5.1", + "jest-util": "30.5.1", + "jest-worker": "30.5.1", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.5.1.tgz", + "integrity": "sha512-V3wnxNtiVmw5PPVg433Cn3VdXnsOeu/ofLw3KC04Bn2y1wIlU5kozXQn48rhrgj/02LrCVtntTEF1yBha0XSUw==", + "dev": true, + "dependencies": { + "@jest/types": "30.5.1", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.5.2.tgz", + "integrity": "sha512-c5CehvkbfHX6yyNg7bMn2ylqlp9AHXuZ/3hPH/Lh5bxD/vefd/lV9HBjMqXef9yQNqkdwyZvkLSVSwB38hy8Qw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "callsites": "^3.1.0", + "convert-source-map": "^2.0.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.5.2.tgz", + "integrity": "sha512-eO6YU5rsLfs60ne694e0IAmRgeBnoA8mu0nlxXDbl/1j5km0o2vO9/VbbUIKIH+WRKKEI+ELgwraRGn2Lhep8g==", + "dev": true, + "dependencies": { + "@jest/console": "30.5.2", + "@jest/types": "30.5.1", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.5.2.tgz", + "integrity": "sha512-bmij8jZyYAC47ExT2GeP7PcrlwSNS+Bp3KeRuBH88gpcxqDv6fljN8PemS4J/lLZ79xb6mpaennQTTq0zUAVVg==", + "dev": true, + "dependencies": { + "@jest/test-result": "30.5.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.5.2.tgz", + "integrity": "sha512-LBGwmaE886C41jDZ65eqR1YbXM7642MK3ZhTowZd5+xDlrDLuf4ePuDdDmVSvcr8NTVJ3MqxLkMbUCzuigUaoQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.5.1", + "@jridgewell/trace-mapping": "^0.3.31", + "babel-plugin-istanbul": "^8.0.0", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.5.1", + "jest-regex-util": "30.5.0", + "jest-util": "30.5.1", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.1.tgz", + "integrity": "sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==", + "dev": true, + "dependencies": { + "@jest/pattern": "30.5.0", + "@jest/schemas": "30.5.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.5.tgz", + "integrity": "sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA==", + "dev": true, + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", + "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.6.0", + "@parcel/watcher-darwin-arm64": "2.6.0", + "@parcel/watcher-darwin-x64": "2.6.0", + "@parcel/watcher-freebsd-x64": "2.6.0", + "@parcel/watcher-linux-arm-glibc": "2.6.0", + "@parcel/watcher-linux-arm-musl": "2.6.0", + "@parcel/watcher-linux-arm64-glibc": "2.6.0", + "@parcel/watcher-linux-arm64-musl": "2.6.0", + "@parcel/watcher-linux-x64-glibc": "2.6.0", + "@parcel/watcher-linux-x64-musl": "2.6.0", + "@parcel/watcher-win32-arm64": "2.6.0", + "@parcel/watcher-win32-x64": "2.6.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", + "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", + "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", + "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", + "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", + "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", + "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", + "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", + "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", + "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", + "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", + "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", + "dev": true, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz", + "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "26.6.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.4.tgz", + "integrity": "sha512-ldVPDCzj7fsaGZrLB0NuHuTvJcsNasysBAqMolr/cgxrLd1xbqxIr3XJiPnHHJUCxj5sNF1vnRj9aWnrVh5Jcg==", + "dev": true, + "dependencies": { + "undici-types": "~8.9.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", + "dev": true + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", + "cpu": [ + "wasm32" + ], + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "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.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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": "30.5.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.5.2.tgz", + "integrity": "sha512-ES8WeJ2fNWPEDunyAtUfJ12nHyaWUloCHdkfK2oW5uSoQSUmjNKdWiGaXJITJwvFEWoD/evHEg/QoCXAvLaQqQ==", + "dev": true, + "dependencies": { + "@jest/transform": "30.5.2", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^8.0.0", + "babel-preset-jest": "30.5.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-8.0.0.tgz", + "integrity": "sha512-18wCskrN3DgbuBmp1gr7LBGT8xdz5xhQQqFvFhVxbkl8VBCrMKQ2YtqBWtUal1Zrc1HTuX0011+Brjw78TCFkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^7.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.5.0.tgz", + "integrity": "sha512-gtGo1B+u14jrZQv6TdSWIWkTqclboo7Qn+dFAGUOIuXLFuJKAdg3U5MIWzZnW4vfUb4dX9skmAMiby86e/SF4A==", + "dev": true, + "dependencies": { + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@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-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.5.0.tgz", + "integrity": "sha512-ZGPn5ClP4lBDpuOK8W1yQIOy359HmbnZv3suucAlIe+SEE9yDsxV4S2PjSbH2Vc97U+WmzYD7vw3kr8NsQ/i6w==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "30.5.0", + "babel-preset-current-node-syntax": "^1.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.1 || ^8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.28", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.28.tgz", + "integrity": "sha512-br0LOmjJqr6Rt4AEkadbcNf67Zpo7EPwKsWbjnRrJIa1QYFHQBqM4C7F2WTbV8ahTEcg1Eo+Y0aWjjORInYFyA==", + "dev": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.3.tgz", + "integrity": "sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "baseline-browser-mapping": "^2.11.26", + "caniuse-lite": "^1.0.30001813", + "electron-to-chromium": "^1.5.439", + "node-releases": "^2.0.57", + "update-browserslist-db": "^1.3.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "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/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.30001815", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001815.tgz", + "integrity": "sha512-uDybUEyfgbyJJ93J1vikTylBX31AkdVYeVPeffMQpf8XN7hSfr0oZOn4VFOIMNvtU5+rHvC5Udg2TgtJKHm23Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "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": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.3.0.tgz", + "integrity": "sha512-lmNyBzi6iYiqyrExTctfmjd8tInx+dHu9PBomTfH5RXS53c27JMFJgzNv5TyAnm3PgGf+MLy0+Ws41/HlVxdKQ==", + "dev": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "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/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "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.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.452", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.452.tgz", + "integrity": "sha512-cVvk1YBSj6571VmV6hdJTqj94Y79xSu8cj6Y9t6ae4Y4431z8/7EJFvu3rVp90xhfuv9BpPKUmaLfTo4+FOGBg==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "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.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "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-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.5.2.tgz", + "integrity": "sha512-0LNuMvs8/5mRYhnCR4k+lGV7fqPMs6Bnksda4S3zsCUmdxBpAn4zU4NNzXdq1pMKe/H4W5t/zVIDSJ/H3e0vDA==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "30.5.2", + "@jest/get-type": "30.5.0", + "jest-matcher-utils": "30.5.2", + "jest-message-util": "30.5.1", + "jest-mock": "30.5.2", + "jest-util": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.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/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "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/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "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/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "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/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-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.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.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.5.2.tgz", + "integrity": "sha512-3gnpdBIza8ijCl3iMV9ChE3hSt1+46865qqod863gQtJr1DixOkAU5DoGbi3u+XlRcw++BhZQMu/y4xBdHBvSQ==", + "dev": true, + "dependencies": { + "@jest/core": "30.5.2", + "@jest/types": "30.5.1", + "import-local": "^3.2.0", + "jest-cli": "30.5.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.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": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.5.1.tgz", + "integrity": "sha512-0+bvMM/ENhDI29Z8q1r4HxiDIi4G5tnBmSw4esfPQoj9q8Nik7KIyuxHkTVnnniJQf05SxpGaKDQ+4h28ynGPg==", + "dev": true, + "dependencies": { + "execa": "^5.1.1", + "jest-util": "30.5.1", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-circus": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.5.2.tgz", + "integrity": "sha512-vffFgjs5JSJ9q4ds1vNW3klKYPJfYfIY61LT/zaZgvTeASJOWZUt8LBfHgIcV4rwxlPBLl/ePBGccHEclS4PlQ==", + "dev": true, + "dependencies": { + "@jest/environment": "30.5.2", + "@jest/expect": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.5.2", + "jest-matcher-utils": "30.5.2", + "jest-message-util": "30.5.1", + "jest-runtime": "30.5.2", + "jest-snapshot": "30.5.2", + "jest-util": "30.5.1", + "p-limit": "^3.1.0", + "pretty-format": "30.5.1", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-cli": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.5.2.tgz", + "integrity": "sha512-YYYxUUVjFgPvgEleKNKMaYGIFgR3l3832Cl0kRL/oCiDZ03v7wImUtquHl2OOBCCNgprjZgBN5bczS/JklPBDg==", + "dev": true, + "dependencies": { + "@jest/core": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/types": "30.5.1", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.5.2", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.5.2.tgz", + "integrity": "sha512-U6221OZekabePvGcGPf4raIBKMvYQWFHvhobDJRojOYaFMj2HaGytAdknjDhYc6JTz2fdHW9+6k0wWUDaNeOFQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.5.0", + "@jest/pattern": "30.5.0", + "@jest/test-sequencer": "30.5.2", + "@jest/types": "30.5.1", + "babel-jest": "30.5.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^13.0.6", + "graceful-fs": "^4.2.11", + "jest-circus": "30.5.2", + "jest-docblock": "30.5.0", + "jest-environment-node": "30.5.2", + "jest-regex-util": "30.5.0", + "jest-resolve": "30.5.1", + "jest-runner": "30.5.2", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", + "parse-json": "^5.2.0", + "pretty-format": "30.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.5.2.tgz", + "integrity": "sha512-rBtHnI6BWTiWj3lM7fOLVfChx7R9B0u9VV3PRHawKs79x6ZjW1QoSrKenaigNGWlvhtoi2BqvDbABDie+Os3xQ==", + "dev": true, + "dependencies": { + "@jest/diff-sequences": "30.5.0", + "@jest/get-type": "30.5.0", + "chalk": "^4.1.2", + "pretty-format": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.5.0.tgz", + "integrity": "sha512-NwDqcxtoZi33RhuW+zJS/RVA3rmheQ8BnwpYZuc/Eruaz6seQb7+aoCeDZu/3X7W2XmD8DbSo9Pn72DbKsBFYw==", + "dev": true, + "dependencies": { + "detect-newline": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-each": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.5.2.tgz", + "integrity": "sha512-GRrW+7fmmgmkvyfEBqc1QFdWnF1Ex5yG6Y6AWL4TTxnkWlKIT98dsKh3P3UuWm6v4XsQwVE6DEzXIPMzWJ3ZbA==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.5.0", + "@jest/types": "30.5.1", + "chalk": "^4.1.2", + "jest-regex-util": "30.5.0", + "jest-util": "30.5.1", + "pretty-format": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.5.2.tgz", + "integrity": "sha512-Ciz4KgTGIbojxSKpuFImgWJj5EyqfE8xMq9NxWmOXnQywHHS03H9Mv+vaCB29J5pr3JBrY27WbRV18rBdjh8Dg==", + "dev": true, + "dependencies": { + "@jest/environment": "30.5.2", + "@jest/fake-timers": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "jest-mock": "30.5.2", + "jest-util": "30.5.1", + "jest-validate": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.5.1.tgz", + "integrity": "sha512-VIFgt67jW480YDxKfEv9IYQKrFpYt7bOCMn3VsnjK7AK9qo7p6acpnA1DHwsVOULE3dTaYew/6JaTD/d0VDHoQ==", + "dev": true, + "dependencies": { + "@jest/types": "30.5.1", + "@parcel/watcher": "^2.6.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "fdir": "^6.5.0", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.5.0", + "jest-util": "30.5.1", + "jest-worker": "30.5.1", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-leak-detector": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.5.1.tgz", + "integrity": "sha512-gt4GT2aWgEoCNTcBe4rqS74xTIUJxi+UD9SNSu9aOk5LmTEd6fS5KSTmAKAfitCCktQHNN+upUuL6EkBfFbMDQ==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.5.0", + "pretty-format": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.5.2.tgz", + "integrity": "sha512-lFkB365PTIHOhPzwrb9T6gvlDnPpOZ7/c3ewOKKB7bzztqjVrtlyRL2MkyfJXpyY2u2SKw001JKrTx14fBUFcQ==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.5.0", + "chalk": "^4.1.2", + "jest-diff": "30.5.2", + "pretty-format": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.5.1.tgz", + "integrity": "sha512-UdQlLdd9wL/Ys7xRErckqwD6wPlSZYueosSWuHc1r2ztGLwlgPvtSJq2+BPEgaEY13WLvfFbmhTj8pba0Sd1jg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.5.1", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-util": "30.5.1", + "picomatch": "^4.0.3", + "pretty-format": "30.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.5.2.tgz", + "integrity": "sha512-KTHb37Fhj8xY8qPFvTFaFJHcdsumQp+ExsUlgoX232Agmc706gagBs53+CYvulV7MVQo9AgXOUxsqzzVBoJlrA==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "jest-util": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-regex-util": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.5.0.tgz", + "integrity": "sha512-Mg0WK7A6xRHLSA1udJ8y9f3lM0uUhFTBnLKzwPmqB9AylvpleJ6BLemR8K9dK27DY+cesDryoA7yLZCAHsPG1A==", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.5.1.tgz", + "integrity": "sha512-wprhLejRtwN6h8ZgaqC0eYjGJ1uMdGPT/+b3eFncbG4NWuuP9QL+vWwRinu9waw7hkOLcpMJGVJAMgBwsPssMQ==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.5.1", + "jest-util": "30.5.1", + "jest-validate": "30.5.1", + "slash": "^3.0.0", + "unrs-resolver": "^1.12.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.5.2.tgz", + "integrity": "sha512-GMI0DP5enX9Z2qW2zFy1bOkrCfWAOPRJQ7qHt0pdfrxBPsgWxglMPrRSK2TX/wRWYxcPRSLFg3Z88qPOzHx7FQ==", + "dev": true, + "dependencies": { + "jest-regex-util": "30.5.0", + "jest-snapshot": "30.5.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.5.2.tgz", + "integrity": "sha512-/B6px7hiiNhVSRwuv9AGn0nawYvwsHeQZ3ItTd5Gp2diFd0EOKaWVeWqcbw3L88vx1GfpCKjQkxWItZCTl11Rw==", + "dev": true, + "dependencies": { + "@jest/console": "30.5.2", + "@jest/environment": "30.5.2", + "@jest/source-map": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/transform": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.5.0", + "jest-environment-node": "30.5.2", + "jest-haste-map": "30.5.1", + "jest-leak-detector": "30.5.1", + "jest-message-util": "30.5.1", + "jest-resolve": "30.5.1", + "jest-runtime": "30.5.2", + "jest-util": "30.5.1", + "jest-watcher": "30.5.2", + "jest-worker": "30.5.1", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.5.2.tgz", + "integrity": "sha512-0paUAHBlheai10A3XSy9Xh+YBG0IROy+/qzcDPzQ/nbbXrznQzeWy5qniICWK6d3W3scaRQCVAbXdcK0ibBq4w==", + "dev": true, + "dependencies": { + "@jest/environment": "30.5.2", + "@jest/fake-timers": "30.5.2", + "@jest/globals": "30.5.2", + "@jest/source-map": "30.5.2", + "@jest/test-result": "30.5.2", + "@jest/transform": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.2.0", + "collect-v8-coverage": "^1.0.2", + "es-module-lexer": "^2.1.0", + "glob": "^13.0.6", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.5.1", + "jest-message-util": "30.5.1", + "jest-mock": "30.5.2", + "jest-regex-util": "30.5.0", + "jest-resolve": "30.5.1", + "jest-snapshot": "30.5.2", + "jest-util": "30.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.5.2.tgz", + "integrity": "sha512-jKIdes25AnAH73dOCi2qE6J6vHJ6L2vyBS11M89kT50DVJcLTf2AOjvcc+2vVaN8lUbY5v2R83aqXo3Ro9fqYA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.5.2", + "@jest/get-type": "30.5.0", + "@jest/snapshot-utils": "30.5.1", + "@jest/transform": "30.5.2", + "@jest/types": "30.5.1", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.5.2", + "graceful-fs": "^4.2.11", + "jest-diff": "30.5.2", + "jest-matcher-utils": "30.5.2", + "jest-message-util": "30.5.1", + "jest-util": "30.5.1", + "pretty-format": "30.5.1", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.1.tgz", + "integrity": "sha512-yKuxmNy2rSbTXw+3SIPanJo+nV4/BS1p26v44IYBFMsswSQySfMMcPHErnOncda7i9HEz0q605rIhSTBVgrZTg==", + "dev": true, + "dependencies": { + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-validate": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.5.1.tgz", + "integrity": "sha512-i/buJ56wTpxihE93hQYNMfdOThS87+HGvLZzZJmU4xggPcdTYQq051iwALLCHp3q+SkCGH+EFejQZz5EbBSkkg==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.5.0", + "@jest/types": "30.5.1", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.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": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.5.2.tgz", + "integrity": "sha512-rqRgg4R11GA9m1UsEZwQeixHsgZReCn6TOHAHtIH33yXrIvoX0OGPA20Yzzjkz7X40fZvcRSxEpQppYPcWzmcQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.5.1", + "string-length": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.5.1.tgz", + "integrity": "sha512-Cbxh5v7AoLuFRmFJSM4/aHdQ68rjXvUWr716EE0Dh3I7T+T/3FgFKhOERGXHcU2Meftq9+9zxPM3TSNyI9D+HA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.5.1", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.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.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "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/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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/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": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "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-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "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.58", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.58.tgz", + "integrity": "sha512-BdiKAgbfRlvfMq/XzO/AF9NPmaA8a+YpLAyAFTVFBj3gARrAIfWvNq7Q7NE4se3KgFu0KkrvQMxTS0XVnsGzHg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "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/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/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, + "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-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-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "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": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", + "dev": true, + "dependencies": { + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.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/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "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-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/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "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/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/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.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "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/string-width-cjs": { + "name": "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-ansi-cjs": { + "name": "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/synckit": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", + "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.3.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/test-exclude": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.2.tgz", + "integrity": "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^10.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/test-exclude/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/test-exclude/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/test-exclude/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "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/undici-types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "dev": true + }, + "node_modules/unrs-resolver": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "napi-postinstall": "^0.3.4" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.4.tgz", + "integrity": "sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "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/wrap-ansi-cjs": { + "name": "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/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "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.1.1" + }, + "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/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" + } + } + } +} diff --git a/practice-tdd/package.json b/practice-tdd/package.json new file mode 100644 index 000000000..33a2da651 --- /dev/null +++ b/practice-tdd/package.json @@ -0,0 +1,16 @@ +{ + "name": "practice-tdd", + "version": "1.0.0", + "description": "In this section you'll practice this key skill of building up your program test first.", + "main": "count.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "module", + "devDependencies": { + "jest": "^30.5.2" + } +} From 0953a6fd1dfb98a39439ebf4464e02ee4626a0ff Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 03:38:02 +0100 Subject: [PATCH 104/127] Fix getOrdinalNumber function to return correct ordinal suffix and update test script to use Jest --- practice-tdd/get-ordinal-number.js | 8 +++++++- practice-tdd/package.json | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/practice-tdd/get-ordinal-number.js b/practice-tdd/get-ordinal-number.js index 5c6291f5e..66bb30b5e 100644 --- a/practice-tdd/get-ordinal-number.js +++ b/practice-tdd/get-ordinal-number.js @@ -1,3 +1,9 @@ export function getOrdinalNumber(num) { - return "1st"; + const getlastDigit = num % 10; + + if (getlastDigit === 1) { + return `${num}st`; + } + return `${num}th`; } +console.log(getOrdinalNumber(224)) \ No newline at end of file diff --git a/practice-tdd/package.json b/practice-tdd/package.json index 33a2da651..46fcc0f47 100644 --- a/practice-tdd/package.json +++ b/practice-tdd/package.json @@ -4,7 +4,7 @@ "description": "In this section you'll practice this key skill of building up your program test first.", "main": "count.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "jest" }, "keywords": [], "author": "", From 21d320584347d336b04256c5ebf020c3a68e434b Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 03:42:08 +0100 Subject: [PATCH 105/127] Fix getOrdinalNumber function to handle special case for 11th correctly --- practice-tdd/get-ordinal-number.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/practice-tdd/get-ordinal-number.js b/practice-tdd/get-ordinal-number.js index 66bb30b5e..be29304ee 100644 --- a/practice-tdd/get-ordinal-number.js +++ b/practice-tdd/get-ordinal-number.js @@ -1,9 +1,12 @@ export function getOrdinalNumber(num) { const getlastDigit = num % 10; + const getlastTwoDigit = num % 100; if (getlastDigit === 1) { return `${num}st`; } - return `${num}th`; + if (getlastTwoDigit === 11) { + return `${num}th`; + } } console.log(getOrdinalNumber(224)) \ No newline at end of file From 1766da88e8547c16927eb947fcdb568a616697a2 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 03:47:30 +0100 Subject: [PATCH 106/127] Refactor getOrdinalNumber function to check for 11th and improve readability --- practice-tdd/get-ordinal-number.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/practice-tdd/get-ordinal-number.js b/practice-tdd/get-ordinal-number.js index be29304ee..8fc3c363f 100644 --- a/practice-tdd/get-ordinal-number.js +++ b/practice-tdd/get-ordinal-number.js @@ -2,11 +2,13 @@ export function getOrdinalNumber(num) { const getlastDigit = num % 10; const getlastTwoDigit = num % 100; + if (getlastTwoDigit === 11) { + return `${num}th`; + } if (getlastDigit === 1) { return `${num}st`; } - if (getlastTwoDigit === 11) { return `${num}th`; - } + } -console.log(getOrdinalNumber(224)) \ No newline at end of file +console.log(getOrdinalNumber(121)) \ No newline at end of file From 39419df929e8152e05a6e580dae4ec24fd960d2e Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 04:04:20 +0100 Subject: [PATCH 107/127] Add @types/jest as a dev dependency and update compiler options --- practice-tdd/package-lock.json | 11 +++++++++++ practice-tdd/package.json | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/practice-tdd/package-lock.json b/practice-tdd/package-lock.json index 08693290c..d192035a4 100644 --- a/practice-tdd/package-lock.json +++ b/practice-tdd/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { + "@types/jest": "^30.0.0", "jest": "^30.5.2" } }, @@ -1424,6 +1425,16 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, "node_modules/@types/node": { "version": "26.6.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.4.tgz", diff --git a/practice-tdd/package.json b/practice-tdd/package.json index 46fcc0f47..99da3c5cb 100644 --- a/practice-tdd/package.json +++ b/practice-tdd/package.json @@ -11,6 +11,13 @@ "license": "ISC", "type": "module", "devDependencies": { + "@types/jest": "^30.0.0", "jest": "^30.5.2" + }, + "compilerOptions": { + "types": [ + "jest", + "node" + ] } } From 6182d670c2de5891947b59f8d86f5a7bccd38067 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 04:07:04 +0100 Subject: [PATCH 108/127] Update test script in package.json to use experimental VM modules for Jest --- practice-tdd/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/practice-tdd/package.json b/practice-tdd/package.json index 99da3c5cb..213d5cd4b 100644 --- a/practice-tdd/package.json +++ b/practice-tdd/package.json @@ -4,7 +4,7 @@ "description": "In this section you'll practice this key skill of building up your program test first.", "main": "count.js", "scripts": { - "test": "jest" + "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js" }, "keywords": [], "author": "", From 281f041563160ae6030ae1d0217990b8b52aa1d7 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 04:17:36 +0100 Subject: [PATCH 109/127] Add test cases for numbers ending with 2 in getOrdinalNumber function --- practice-tdd/get-ordinal-number.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/practice-tdd/get-ordinal-number.test.js b/practice-tdd/get-ordinal-number.test.js index e23174a18..849a73bfe 100644 --- a/practice-tdd/get-ordinal-number.test.js +++ b/practice-tdd/get-ordinal-number.test.js @@ -18,3 +18,9 @@ test("should append 'st' for numbers ending with 1, except those ending with 11" expect(getOrdinalNumber(21)).toEqual("21st"); expect(getOrdinalNumber(131)).toEqual("131st"); }); + +test("should append 'nd' for numbers ending with 2, except those ending with 12", () => { + expect(getOrdinalNumber(2)).toEqual("2nd"); + expect(getOrdinalNumber(22)).toEqual("22nd"); + expect(getOrdinalNumber(122)).toEqual("122nd"); +}) From e6d3f809b9a40356133c3114c3c6cb6c15a5efe8 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 04:23:07 +0100 Subject: [PATCH 110/127] Fix getOrdinalNumber function to correctly handle numbers ending with 2 --- practice-tdd/get-ordinal-number.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/practice-tdd/get-ordinal-number.js b/practice-tdd/get-ordinal-number.js index 8fc3c363f..b64cd3661 100644 --- a/practice-tdd/get-ordinal-number.js +++ b/practice-tdd/get-ordinal-number.js @@ -7,6 +7,9 @@ export function getOrdinalNumber(num) { } if (getlastDigit === 1) { return `${num}st`; + } + if (getlastDigit === 2) { + return `${num}nd`; } return `${num}th`; From ca98356bafdd8875682b90aa09fea7be2e2f8c16 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 04:27:18 +0100 Subject: [PATCH 111/127] Add test cases for numbers ending with 3 in getOrdinalNumber function --- practice-tdd/get-ordinal-number.js | 1 - practice-tdd/get-ordinal-number.test.js | 8 +++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/practice-tdd/get-ordinal-number.js b/practice-tdd/get-ordinal-number.js index b64cd3661..c34165eb9 100644 --- a/practice-tdd/get-ordinal-number.js +++ b/practice-tdd/get-ordinal-number.js @@ -14,4 +14,3 @@ export function getOrdinalNumber(num) { return `${num}th`; } -console.log(getOrdinalNumber(121)) \ No newline at end of file diff --git a/practice-tdd/get-ordinal-number.test.js b/practice-tdd/get-ordinal-number.test.js index 849a73bfe..4b6a785eb 100644 --- a/practice-tdd/get-ordinal-number.test.js +++ b/practice-tdd/get-ordinal-number.test.js @@ -23,4 +23,10 @@ test("should append 'nd' for numbers ending with 2, except those ending with 12" expect(getOrdinalNumber(2)).toEqual("2nd"); expect(getOrdinalNumber(22)).toEqual("22nd"); expect(getOrdinalNumber(122)).toEqual("122nd"); -}) +}); + +test("should append 'rd' for numbers ending with 3, except those ending with 13", () => { + expect(getOrdinalNumber(3)).toEqual("3rd"); + expect(getOrdinalNumber(23)).toEqual("23rd"); + expect(getOrdinalNumber(133)).toEqual("133rd"); +}); From e430ece026f2dbea200ce971faa22257858bad1f Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 04:29:40 +0100 Subject: [PATCH 112/127] Fix getOrdinalNumber function to correctly handle numbers ending with 3 --- practice-tdd/get-ordinal-number.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/practice-tdd/get-ordinal-number.js b/practice-tdd/get-ordinal-number.js index c34165eb9..a0a280115 100644 --- a/practice-tdd/get-ordinal-number.js +++ b/practice-tdd/get-ordinal-number.js @@ -10,6 +10,9 @@ export function getOrdinalNumber(num) { } if (getlastDigit === 2) { return `${num}nd`; + } + if (getlastDigit === 3) { + return `${num}rd`; } return `${num}th`; From 4abd0e74400d959ce4e050ba3b8344dd3b2fc716 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 04:33:51 +0100 Subject: [PATCH 113/127] Add test cases for numbers ending with 11, 12, and 13 in getOrdinalNumber function --- practice-tdd/get-ordinal-number.test.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/practice-tdd/get-ordinal-number.test.js b/practice-tdd/get-ordinal-number.test.js index 4b6a785eb..146417ff7 100644 --- a/practice-tdd/get-ordinal-number.test.js +++ b/practice-tdd/get-ordinal-number.test.js @@ -30,3 +30,12 @@ test("should append 'rd' for numbers ending with 3, except those ending with 13" expect(getOrdinalNumber(23)).toEqual("23rd"); expect(getOrdinalNumber(133)).toEqual("133rd"); }); + +test("should append 'th' for numbers ending with 11,12 or 13", () => { + expect(getOrdinalNumber(11)).toEqual("11th"); + expect(getOrdinalNumber(12)).toEqual("12th"); + expect(getOrdinalNumber(13)).toEqual("13th"); + expect(getOrdinalNumber(111)).toEqual("111th"); + expect(getOrdinalNumber(112)).toEqual("112th"); + expect(getOrdinalNumber(113)).toEqual("113th"); +}) From 5f7b13965a7f38b023d34c5cca75e0f78ba83373 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 04:35:02 +0100 Subject: [PATCH 114/127] Fix getOrdinalNumber function to correctly handle numbers ending with 12 and 13 --- practice-tdd/get-ordinal-number.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/practice-tdd/get-ordinal-number.js b/practice-tdd/get-ordinal-number.js index a0a280115..2322bf8be 100644 --- a/practice-tdd/get-ordinal-number.js +++ b/practice-tdd/get-ordinal-number.js @@ -2,7 +2,7 @@ export function getOrdinalNumber(num) { const getlastDigit = num % 10; const getlastTwoDigit = num % 100; - if (getlastTwoDigit === 11) { + if (getlastTwoDigit === 11 || getlastTwoDigit === 12 || getlastTwoDigit === 13) { return `${num}th`; } if (getlastDigit === 1) { From 75a8087632d55726836966496f2235d82a536a97 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 04:39:25 +0100 Subject: [PATCH 115/127] Add test cases for numbers ending with 4, 10, 20, and 100 in getOrdinalNumber function --- practice-tdd/get-ordinal-number.test.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/practice-tdd/get-ordinal-number.test.js b/practice-tdd/get-ordinal-number.test.js index 146417ff7..1189de477 100644 --- a/practice-tdd/get-ordinal-number.test.js +++ b/practice-tdd/get-ordinal-number.test.js @@ -38,4 +38,11 @@ test("should append 'th' for numbers ending with 11,12 or 13", () => { expect(getOrdinalNumber(111)).toEqual("111th"); expect(getOrdinalNumber(112)).toEqual("112th"); expect(getOrdinalNumber(113)).toEqual("113th"); -}) +}); + +test("should append 'th' for all other nnumbers", () => { + expect(getOrdinalNumber(4)).toEqual("4th"); + expect(getOrdinalNumber(10)).toEqual("10th"); + expect(getOrdinalNumber(20)).toEqual("20th"); + expect(getOrdinalNumber(100)).toEqual("100th"); +}); From 9717056d03697f99fce7a1091f1fd0534d0972a8 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 05:00:55 +0100 Subject: [PATCH 116/127] Refactor repeatStr function to accept parameters for string and count --- practice-tdd/repeat-str.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/practice-tdd/repeat-str.js b/practice-tdd/repeat-str.js index af273f3b0..c73758fc0 100644 --- a/practice-tdd/repeat-str.js +++ b/practice-tdd/repeat-str.js @@ -1,4 +1,4 @@ -export function repeatStr() { +export function repeatStr(str, count) { // Your implementation of this function must *not* call String.prototype.repeat (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat). // The goal is to re-implement that function, not to use it. return "hellohellohello"; From 677819c35126a00c6505c44a89bf891b8ef7ea6e Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 05:10:15 +0100 Subject: [PATCH 117/127] Refactor repeatStr function to correctly handle count parameter and prevent negative values --- practice-tdd/repeat-str.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/practice-tdd/repeat-str.js b/practice-tdd/repeat-str.js index c73758fc0..823760e51 100644 --- a/practice-tdd/repeat-str.js +++ b/practice-tdd/repeat-str.js @@ -1,5 +1,16 @@ export function repeatStr(str, count) { // Your implementation of this function must *not* call String.prototype.repeat (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat). // The goal is to re-implement that function, not to use it. + + let result = ""; + result = result + str; + result = result + str; + result = result + str; + + for (let i = 0; i < count; i++){ + if(count < 0){ + throw new Error("count must not be negative"); + } + } return "hellohellohello"; } From d5bb21aa034d902dbb7727100e6fae31d47e98b2 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 05:14:49 +0100 Subject: [PATCH 118/127] Add test case for repeating string 1 time --- practice-tdd/repeat-str.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/practice-tdd/repeat-str.test.js b/practice-tdd/repeat-str.test.js index 8a7036102..f225025d4 100644 --- a/practice-tdd/repeat-str.test.js +++ b/practice-tdd/repeat-str.test.js @@ -20,6 +20,12 @@ test("should repeat the string count times", () => { // Given a target string `str` and a `count` equal to 1, // When the repeatStr function is called with these inputs, // Then it should return the original `str` without repetition. +test("should repeat the string 1 time", () => { + const str = "moses"; + const count = 1; + const repeatedStr = repeatStr(str, count); + expect(repeatedStr).toEqual("moses"); +}); // Case: Handle count of 0: // Given a target string `str` and a `count` equal to 0, From 99c6335015d02695e1e71364ae7a05d8751891a8 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 05:26:49 +0100 Subject: [PATCH 119/127] Refactor repeatStr function to remove redundant string concatenation and ensure negative count check is performed at the start --- practice-tdd/repeat-str.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/practice-tdd/repeat-str.js b/practice-tdd/repeat-str.js index 823760e51..696df0304 100644 --- a/practice-tdd/repeat-str.js +++ b/practice-tdd/repeat-str.js @@ -2,15 +2,14 @@ export function repeatStr(str, count) { // Your implementation of this function must *not* call String.prototype.repeat (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat). // The goal is to re-implement that function, not to use it. + if(count < 0){ + throw new Error("count must not be negative"); + } + let result = ""; - result = result + str; - result = result + str; - result = result + str; for (let i = 0; i < count; i++){ - if(count < 0){ - throw new Error("count must not be negative"); - } + result = result + str; } - return "hellohellohello"; + return result; } From b7807571dbc80608621bcc7e87431e6c80540892 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 05:29:43 +0100 Subject: [PATCH 120/127] Fix test case for repeating string 1 time and ensure correct handling of count of 0 --- practice-tdd/repeat-str.test.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/practice-tdd/repeat-str.test.js b/practice-tdd/repeat-str.test.js index f225025d4..1d6e31fa2 100644 --- a/practice-tdd/repeat-str.test.js +++ b/practice-tdd/repeat-str.test.js @@ -21,16 +21,22 @@ test("should repeat the string count times", () => { // When the repeatStr function is called with these inputs, // Then it should return the original `str` without repetition. test("should repeat the string 1 time", () => { - const str = "moses"; + const str = "hello"; const count = 1; const repeatedStr = repeatStr(str, count); - expect(repeatedStr).toEqual("moses"); + expect(repeatedStr).toEqual("hello"); }); // Case: Handle count of 0: // Given a target string `str` and a `count` equal to 0, // When the repeatStr function is called with these inputs, // Then it should return an empty string. +test("should return empty string for count of 0", () => { + const str = "hello"; + const count = 0; + const repeatedStr = repeatStr(str, count); + expect(repeatedStr).toEqual(""); +}) // Case: Handle negative count: // Given a target string `str` and a negative integer `count`, From 64be7a797d61f383b2d9f6d91b563be7b5f65dea Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 05:40:19 +0100 Subject: [PATCH 121/127] Add test case to ensure error is thrown for negative count in repeatStr function --- practice-tdd/repeat-str.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/practice-tdd/repeat-str.test.js b/practice-tdd/repeat-str.test.js index 1d6e31fa2..5bd943253 100644 --- a/practice-tdd/repeat-str.test.js +++ b/practice-tdd/repeat-str.test.js @@ -42,3 +42,6 @@ test("should return empty string for count of 0", () => { // Given a target string `str` and a negative integer `count`, // When the repeatStr function is called with these inputs, // Then it should throw an error, as negative counts are not valid. +test("should throw an error for negative count", () => { + expect(() => repeatStr("hello", -1)).toThrow(); +}) \ No newline at end of file From 41a3faadf06a3949416706bf42513a54764bc3b9 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 05:40:54 +0100 Subject: [PATCH 122/127] Fix syntax error in test cases by adding missing closing braces --- practice-tdd/repeat-str.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/practice-tdd/repeat-str.test.js b/practice-tdd/repeat-str.test.js index 5bd943253..7a5161546 100644 --- a/practice-tdd/repeat-str.test.js +++ b/practice-tdd/repeat-str.test.js @@ -36,7 +36,7 @@ test("should return empty string for count of 0", () => { const count = 0; const repeatedStr = repeatStr(str, count); expect(repeatedStr).toEqual(""); -}) +}); // Case: Handle negative count: // Given a target string `str` and a negative integer `count`, @@ -44,4 +44,4 @@ test("should return empty string for count of 0", () => { // Then it should throw an error, as negative counts are not valid. test("should throw an error for negative count", () => { expect(() => repeatStr("hello", -1)).toThrow(); -}) \ No newline at end of file +}); \ No newline at end of file From 56fa3781ca7c8b7ba32b1d904e8f5e948bfdc85b Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 05:51:15 +0100 Subject: [PATCH 123/127] Revert unrelated implement-and-rewrite-tests changes --- .../1-get-angle-type.test.js | 29 -------- .../2-is-proper-fraction.test.js | 14 +--- .../3-get-card-value.test.js | 69 ------------------- .../implement/1-get-angle-type.js | 14 +--- .../implement/2-is-proper-fraction.js | 6 +- .../implement/3-get-card-value.js | 28 +------- 6 files changed, 4 insertions(+), 156 deletions(-) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js index 32d473387..cf50f6cad 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/1-get-angle-type.test.js @@ -10,32 +10,3 @@ test("Classifies right angles", () => { const right = getAngleType(90); assert.equal(right, "Right angle"); }); - -test("Classifies acute angles", () => { - assert.equal(getAngleType(45), "Acute angle"); - assert.equal(getAngleType(1), "Acute angle"); - assert.equal(getAngleType(89), "Acute angle"); -}); - -test("Classifies obtuse angles", () => { - assert.equal(getAngleType(91), "Obtuse angle"); - assert.equal(getAngleType(135), "Obtuse angle"); - assert.equal(getAngleType(179), "Obtuse angle"); -}); - -test("Classifies straight angles", () => { - assert.equal(getAngleType(180), "Straight angle"); -}); - -test("Classifies reflex angles", () => { - assert.equal(getAngleType(181), "Reflex angle"); - assert.equal(getAngleType(270), "Reflex angle"); - assert.equal(getAngleType(359), "Reflex angle"); -}); - -test("Classifies invalid angles", () => { - assert.equal(getAngleType(0), "Invalid angle"); - assert.equal(getAngleType(360), "Invalid angle"); - assert.equal(getAngleType(400), "Invalid angle"); - assert.equal(getAngleType(-5), "Invalid angle"); -}) diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js index 75ebbe7fd..a29084605 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/2-is-proper-fraction.test.js @@ -7,18 +7,6 @@ import { isProperFraction } from "../implement/2-is-proper-fraction.js"; // What combinations of numerators and denominators should you test? test("Basic proper fraction", () => { + // Example: 1/2 is a proper fraction assert.equal(isProperFraction(1, 2), true); - assert.equal(isProperFraction(0, 5), true); - assert.equal(isProperFraction(-1, 2), true); - assert.equal(isProperFraction(1, -2), true); - assert.equal(isProperFraction(-1, -2), true); -}); - -test("Basic improper fraction", () => { - assert.equal(isProperFraction(5, 2), false); - assert.equal(isProperFraction(3, 3), false); - assert.equal(isProperFraction(5, 0), false); - assert.equal(isProperFraction(-5, 2), false); - assert.equal(isProperFraction(5, -2), false); - assert.equal(isProperFraction(-5, -2), false); }); diff --git a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js index 765ccd34d..f5092d9b1 100644 --- a/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js +++ b/implement-and-rewrite-tests/implement-tests-with-node-test/3-get-card-value.test.js @@ -9,77 +9,8 @@ test("Valid single-digit card", () => { assert.equal(getCardValue("9♠"), 9); }); -test("Ace returns 11", () => { - assert.equal(getCardValue("A♠"), 11); -}); - -test("Face cards return 10", () => { - assert.equal(getCardValue("J♣"), 10); - assert.equal(getCardValue("Q♦"), 10); - assert.equal(getCardValue("K♥"), 10); -}) - -test("Number cards 2 to 10 return their numbers", () => { - for(let n = 2; n <= 10; n++) { - assert.equal(getCardValue(`${n}♦`), n); - } -}); - -test("Only valid double-digit '10' card", () => { - assert.equal(getCardValue("10♥"), 10); -}); - -test("Accepts all four suits", () => { - for (const suit of ["♠", "♥", "♦", "♣"]){ - assert.equal(getCardValue(`5${suit}`), 5); - } -}); - test("Arbitrary non-card string", () => { assert.throws(() => getCardValue("invalid"), /Expected a number followed by a suit, but got "invalid"/, "Expected clear error"); }); // TODO: What other invalid card cases can you think of? -test("Missing suit", () => { - assert.throws(() => getCardValue("7"), /Expected a number followed by a suit/); - assert.throws(() => getCardValue("A"), /Expected a number followed by a suit/); -}); - -test("Missing ranks", () => { - assert.throws(() => getCardValue("♥"), /Expected a number followed by a suit/); -}); - -test("Empty strings", () => { - assert.throws(() => getCardValue(""), /Expected a number followed by a suit/); -}); - -test("Out-of-range number ranks", () => { - for (const OOR of ["0♥", "1♠", "11♦", "100♣"]) { - assert.throws(() => getCardValue(OOR), /Expected a number followed by a suit/); - } -}); - -test("Unknown suit", () => { - assert.throws(() => getCardValue("A❤"), /Expected a number followed by a suit/); - assert.throws(() => getCardValue("AV"), /Expected a number followed by a suit/); -}); - -test("Lowercase ranks", () => { - assert.throws(() => getCardValue("a♦"), /Expected a number followed by a suit/); - assert.throws(() => getCardValue("k♥"), /Expected a number followed by a suit/); -}); - -test("Suit before rank", () => { - assert.throws(() => getCardValue("♣A"), /Expected a number followed by a suit/); -}); - -test("Extra characters or spaces", () => { - for (const ExS of [" A♦", "A♦ ", "A♦♦", "A ♦"]){ - assert.throws(() => getCardValue(ExS), /Expected a number followed by a suit/); - } -}); - -test("Non-string input", () => { - assert.throws(() => getCardValue(undefined), /Expected a number followed by a suit/); - assert.throws(() => getCardValue(5), /Expected a number followed by a suit/); -}); \ No newline at end of file diff --git a/implement-and-rewrite-tests/implement/1-get-angle-type.js b/implement-and-rewrite-tests/implement/1-get-angle-type.js index 4ff290d94..8a6fba050 100644 --- a/implement-and-rewrite-tests/implement/1-get-angle-type.js +++ b/implement-and-rewrite-tests/implement/1-get-angle-type.js @@ -17,17 +17,5 @@ // execute the code to ensure all tests pass. export function getAngleType(angle) { - if(angle > 0 && angle < 90) { - return "Acute angle"; - } else if(angle === 90) { - return "Right angle"; - } else if(angle > 90 && angle < 180){ - return "Obtuse angle"; - } else if(angle === 180) { - return "Straight angle" - } else if (angle > 180 && angle < 360){ - return "Reflex angle"; - } else { - return "Invalid angle"; - } + // TODO: Implement this function } diff --git a/implement-and-rewrite-tests/implement/2-is-proper-fraction.js b/implement-and-rewrite-tests/implement/2-is-proper-fraction.js index f56b51bf3..f983800f0 100644 --- a/implement-and-rewrite-tests/implement/2-is-proper-fraction.js +++ b/implement-and-rewrite-tests/implement/2-is-proper-fraction.js @@ -14,9 +14,5 @@ // execute the code to ensure all tests pass. export function isProperFraction(numerator, denominator) { - if(Math.abs(numerator) < Math.abs(denominator)){ - return true; - } else { - return false; - } + // TODO: Implement this function } diff --git a/implement-and-rewrite-tests/implement/3-get-card-value.js b/implement-and-rewrite-tests/implement/3-get-card-value.js index 05a47f6d2..9614ab1ee 100644 --- a/implement-and-rewrite-tests/implement/3-get-card-value.js +++ b/implement-and-rewrite-tests/implement/3-get-card-value.js @@ -24,31 +24,5 @@ // execute the code to ensure all tests pass. export function getCardValue(card) { - const validSuits = ["♠", "♥", "♦", "♣"]; - const numberRanks = ["2", "3", "4", "5", "6", "7", "8", "9", "10"]; - const faceRanks = ["J", "Q", "K"]; - - const error = new Error(`Expected a number followed by a suit, but got "${card}"`); - - if(typeof card !== "string" || card.length < 2){ - throw error; - } - - const suit = card.slice(-1); - const rank = card.slice(0, -1); - - if(!validSuits.includes(suit)){ - throw error; - } - if(rank === "A") { - return 11; - } - if(faceRanks.includes(rank)){ - return 10; - } - if(numberRanks.includes(rank)){ - return Number(rank); - } - throw error; + // TODO: Implement this function } - From 9370f27eb880c8f161fb138b42cd77c4306e1b61 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 22:19:33 +0100 Subject: [PATCH 124/127] Fix variable naming for clarity in getOrdinalNumber function --- practice-tdd/get-ordinal-number.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/practice-tdd/get-ordinal-number.js b/practice-tdd/get-ordinal-number.js index 2322bf8be..e4028a937 100644 --- a/practice-tdd/get-ordinal-number.js +++ b/practice-tdd/get-ordinal-number.js @@ -1,17 +1,17 @@ export function getOrdinalNumber(num) { - const getlastDigit = num % 10; - const getlastTwoDigit = num % 100; + const lastDigit = num % 10; + const lastTwoDigit = num % 100; - if (getlastTwoDigit === 11 || getlastTwoDigit === 12 || getlastTwoDigit === 13) { + if (lastTwoDigit === 11 || lastTwoDigit === 12 || lastTwoDigit === 13) { return `${num}th`; } - if (getlastDigit === 1) { + if (lastDigit === 1) { return `${num}st`; } - if (getlastDigit === 2) { + if (lastDigit === 2) { return `${num}nd`; } - if (getlastDigit === 3) { + if (lastDigit === 3) { return `${num}rd`; } return `${num}th`; From 389c799abc29335e7b54fd2adbe7c68542a75aec Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 22:33:12 +0100 Subject: [PATCH 125/127] Add test case for handling empty string in repeatStr function --- practice-tdd/repeat-str.test.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/practice-tdd/repeat-str.test.js b/practice-tdd/repeat-str.test.js index 7a5161546..07e9c9cbc 100644 --- a/practice-tdd/repeat-str.test.js +++ b/practice-tdd/repeat-str.test.js @@ -44,4 +44,15 @@ test("should return empty string for count of 0", () => { // Then it should throw an error, as negative counts are not valid. test("should throw an error for negative count", () => { expect(() => repeatStr("hello", -1)).toThrow(); -}); \ No newline at end of file +}); + +// Case: Handling special strings: Empty string +// Giving a target empty string `str` and a positive integer `count`, +// When the repeatStr function is called with these inputs, +// Then it should return an empty string. +test("should return an empty string when repeating an empty string", () => { + const str = ""; + const count = 5; + const repeatedStr = repeatStr(str, count); + expect(repeatedStr).toEqual(""); +}) \ No newline at end of file From 639dda6197c849ddb3c2c00d9a4107c42205d60b Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 22:36:25 +0100 Subject: [PATCH 126/127] Add test case to ensure error is thrown for negative count with empty string --- practice-tdd/repeat-str.test.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/practice-tdd/repeat-str.test.js b/practice-tdd/repeat-str.test.js index 07e9c9cbc..dfe49a9f6 100644 --- a/practice-tdd/repeat-str.test.js +++ b/practice-tdd/repeat-str.test.js @@ -55,4 +55,12 @@ test("should return an empty string when repeating an empty string", () => { const count = 5; const repeatedStr = repeatStr(str, count); expect(repeatedStr).toEqual(""); -}) \ No newline at end of file +}); + +// Case: Handling special strings: Empty string +// Giving a target empty string `str` and a negative integer `count`, +// When the repeatStr function is called with these inputs, +// Then it should throw an error. +test("should throw error for negative count even with an empty string", () => { + expect(() => repeatStr("", -1)).toThrow(); +}); \ No newline at end of file From 4a915c371ce6887524d49b24d951cc11d872ea49 Mon Sep 17 00:00:00 2001 From: Precious Moses Date: Fri, 9 Oct 2026 22:45:19 +0100 Subject: [PATCH 127/127] Add test case for repeating a string of symbols in repeatStr function --- practice-tdd/repeat-str.test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/practice-tdd/repeat-str.test.js b/practice-tdd/repeat-str.test.js index dfe49a9f6..722a7c8c6 100644 --- a/practice-tdd/repeat-str.test.js +++ b/practice-tdd/repeat-str.test.js @@ -63,4 +63,15 @@ test("should return an empty string when repeating an empty string", () => { // Then it should throw an error. test("should throw error for negative count even with an empty string", () => { expect(() => repeatStr("", -1)).toThrow(); +}); + +// Case: Handling special strings: symbols +// Giving a target empty string `str` and a positive integer `count`, +// When the repeatStr function is called with these inputs, +// Then it should return a string of symbols repeated `count` times. +test("should repeat a string made of symbols", () => { + const str = "@$$#@!!!!"; + const count = 3; + const repeatedStr = repeatStr(str, count); + expect(repeatedStr).toEqual("@$$#@!!!!@$$#@!!!!@$$#@!!!!") }); \ No newline at end of file