From f650582f6175be9d785cb755f3dd34d6944f8f91 Mon Sep 17 00:00:00 2001 From: suhyun113 <163711629+suhyun113@users.noreply.github.com> Date: Mon, 20 Oct 2025 19:41:25 +0900 Subject: [PATCH 01/10] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=ED=95=A0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 13420b29..1ef1e79f 100644 --- a/README.md +++ b/README.md @@ -1 +1,56 @@ -# javascript-calculator-precourse \ No newline at end of file +# javascript-calculator-precourse +# 1주차 - 문자열 덧셈 계산기 + +## ⚙️ 간단한 프로젝트 실행 흐름 +1. 안내 문구를 출력한다. +2. 사용자 입력을 수신한다. +3. 입력 문자열을 parser로 넘겨 숫자 배열로 변환한다. +4. 숫자 배열을 validator로 검증한다. +5. 검증 통과 배열을 calculator로 합산한다. +6. 합산 결과를 지정된 포맷으로 출력한다. +7. 프로세스를 종료한다. + + +## 🔧 구현할 기능 목록 +> **🌟 TDD 기반 구현 계획** +1. test 코드 작성 +2. npm test -> 실패 +3. 코드 구현 +4. npm test -> 통과 + + +### 1. parser (문자열 -> 숫자 배열 반환) +- [ ] parser 테스트 코드 작성 + - [ ] 빈 문자열 입력 시 `[]` 반환 테스트 + - [ ] `"1,2:3"` -> `[1,2,3]` 테스트 + - [ ] `"//;\n1;2;3"` -> `[1,2,3]` 테스트 + - [ ] `"//|\n1|2:3"` -> `[1,2,3]` 테스트 + + +- [ ] 기본 구분자(, :) 분리 및 숫자 배열 변환 +- [ ] 커스텀 구분자 지정(문자열 앞부분의 "//", "\n") + +### 2. validator (숫자 배열 유효성 검사) +- [ ] validator 테스트 코드 작성 + - [ ] 숫자 배열 -> 통과 테스트 + - [ ] 숫자가 아닌 값 발생 오류 테스트(NaN 체크) + - [ ] 양수가 아닌 값 발생 오류 테스트 +- [ ] 숫자가 아닌 값이 포함된 경우 검증 +- [ ] 양수가 아닌 값인 경우 검증 + +### 3. calculator (합산) +- [ ] calculator 테스트 코드 작성 + - [ ] 빈 배열 입력 시 `0` 반환 테스트 + - [ ] `[1,2,3]` -> `6` 반환 테스트 +- [ ] 빈 배열 합산 시 0 반환 +- [ ] 그 외 숫자 배열 합산 + +### 4. App.js (전체 통합 테스트) +- [ ] `App.js` 통합 테스트 코드 작성 + - [ ] 입력/출력 + - [ ] `"1,2:3"` 입력 -> `"결과 : 6"` 출력 테스트 + - [ ] `"//;\n1;2;3"` 입력 -> `"결과 : 6"` 출력 테스트 + - [ ] `"1,a,3"` 입력 -> `[ERROR] 숫자가 아닌 값이 포함되어 있습니다.` 출력 테스트 + +- [ ] 모든 모듈 연동 +- [ ] `App.run()` 실행 로직 완성 \ No newline at end of file From 73135817f37046bdc39c58139c538c2e4dc0ff3a Mon Sep 17 00:00:00 2001 From: suhyun113 <163711629+suhyun113@users.noreply.github.com> Date: Mon, 20 Oct 2025 20:27:24 +0900 Subject: [PATCH 02/10] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=ED=95=A0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 1ef1e79f..13c4f393 100644 --- a/README.md +++ b/README.md @@ -12,45 +12,20 @@ ## 🔧 구현할 기능 목록 -> **🌟 TDD 기반 구현 계획** -1. test 코드 작성 -2. npm test -> 실패 -3. 코드 구현 -4. npm test -> 통과 - ### 1. parser (문자열 -> 숫자 배열 반환) -- [ ] parser 테스트 코드 작성 - - [ ] 빈 문자열 입력 시 `[]` 반환 테스트 - - [ ] `"1,2:3"` -> `[1,2,3]` 테스트 - - [ ] `"//;\n1;2;3"` -> `[1,2,3]` 테스트 - - [ ] `"//|\n1|2:3"` -> `[1,2,3]` 테스트 - - - [ ] 기본 구분자(, :) 분리 및 숫자 배열 변환 - [ ] 커스텀 구분자 지정(문자열 앞부분의 "//", "\n") ### 2. validator (숫자 배열 유효성 검사) -- [ ] validator 테스트 코드 작성 - - [ ] 숫자 배열 -> 통과 테스트 - - [ ] 숫자가 아닌 값 발생 오류 테스트(NaN 체크) - - [ ] 양수가 아닌 값 발생 오류 테스트 - [ ] 숫자가 아닌 값이 포함된 경우 검증 - [ ] 양수가 아닌 값인 경우 검증 ### 3. calculator (합산) -- [ ] calculator 테스트 코드 작성 - - [ ] 빈 배열 입력 시 `0` 반환 테스트 - - [ ] `[1,2,3]` -> `6` 반환 테스트 - [ ] 빈 배열 합산 시 0 반환 - [ ] 그 외 숫자 배열 합산 ### 4. App.js (전체 통합 테스트) -- [ ] `App.js` 통합 테스트 코드 작성 - - [ ] 입력/출력 - - [ ] `"1,2:3"` 입력 -> `"결과 : 6"` 출력 테스트 - - [ ] `"//;\n1;2;3"` 입력 -> `"결과 : 6"` 출력 테스트 - - [ ] `"1,a,3"` 입력 -> `[ERROR] 숫자가 아닌 값이 포함되어 있습니다.` 출력 테스트 - - [ ] 모든 모듈 연동 -- [ ] `App.run()` 실행 로직 완성 \ No newline at end of file +- [ ] `App.run()` 실행 로직 완성 +- [ ] `AplicationTest.js` 테스트 확인 \ No newline at end of file From 028b5423e9a5f5f04972d7004d53881948798601 Mon Sep 17 00:00:00 2001 From: suhyun113 <163711629+suhyun113@users.noreply.github.com> Date: Mon, 20 Oct 2025 20:46:56 +0900 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20=EA=B5=AC?= =?UTF-8?q?=EB=B6=84=EC=9E=90(,=20:)=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20?= =?UTF-8?q?=EC=88=AB=EC=9E=90=20=EB=B0=B0=EC=97=B4=20=EB=B3=80=ED=99=98=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/InputParser.js | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/InputParser.js diff --git a/README.md b/README.md index 13c4f393..5445c70a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ ## 🔧 구현할 기능 목록 ### 1. parser (문자열 -> 숫자 배열 반환) -- [ ] 기본 구분자(, :) 분리 및 숫자 배열 변환 +- [X] 기본 구분자(, :) 분리 및 숫자 배열 변환 - [ ] 커스텀 구분자 지정(문자열 앞부분의 "//", "\n") ### 2. validator (숫자 배열 유효성 검사) diff --git a/src/InputParser.js b/src/InputParser.js new file mode 100644 index 00000000..1c8e0f6d --- /dev/null +++ b/src/InputParser.js @@ -0,0 +1,22 @@ +export class InputParser { + static parse(input) { + // 입력이 비어있거나 공백인 경우 + const raw = (input || "").trim(); + if (raw.lenth === 0) { + return []; + } + + // 기본 구분자: 쉼표(,)와 콜론(:) + const delimiters = [",", ":"]; + const regex = new RegExp(`[${delimiters.join("")}]`); + const tokens = raw.split(regex); + + // 숫자 배열로 변환 + const numbers = tokens + .map((token) => token.trim()) + .filter((token) => token.length > 0) + .map((token) => Number(token)); // 숫자로 변환 + + return numbers; + } +} \ No newline at end of file From 18e132f760c1ecca9009a93290c192502183f547 Mon Sep 17 00:00:00 2001 From: suhyun113 <163711629+suhyun113@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:01:10 +0900 Subject: [PATCH 04/10] =?UTF-8?q?feat:=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=EA=B5=AC=EB=B6=84=EC=9E=90=20=EC=A7=80=EC=A0=95(=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=EC=97=B4=20=EC=95=9E=EB=B6=80=EB=B6=84=EC=9D=98=20"//?= =?UTF-8?q?",=20"\n")=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/InputParser.js | 30 ++++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5445c70a..2ff9d692 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ ### 1. parser (문자열 -> 숫자 배열 반환) - [X] 기본 구분자(, :) 분리 및 숫자 배열 변환 -- [ ] 커스텀 구분자 지정(문자열 앞부분의 "//", "\n") +- [X] 커스텀 구분자 지정(문자열 앞부분의 "//", "\n") ### 2. validator (숫자 배열 유효성 검사) - [ ] 숫자가 아닌 값이 포함된 경우 검증 diff --git a/src/InputParser.js b/src/InputParser.js index 1c8e0f6d..d878bc50 100644 --- a/src/InputParser.js +++ b/src/InputParser.js @@ -2,21 +2,35 @@ export class InputParser { static parse(input) { // 입력이 비어있거나 공백인 경우 const raw = (input || "").trim(); - if (raw.lenth === 0) { + if (raw.length === 0) { return []; } // 기본 구분자: 쉼표(,)와 콜론(:) - const delimiters = [",", ":"]; - const regex = new RegExp(`[${delimiters.join("")}]`); - const tokens = raw.split(regex); + let delimiters = [",", ":"]; + let numbersPart = raw; + + // 커스텀 구분자 + if (raw.startsWith("//")) { + const match = + raw.match(/^\/\/(.)\n(.*)/s) || // 실제 줄바꿈 + raw.match(/^\/\/(.)\\n(.*)/s); // 문자열 리터럴 "\n" + if (!match) { + throw new Error("[ERROR] 잘못된 커스텀 구분자 형식입니다."); + } + const [, custom, rest] = match; + delimiters = [",", ":", custom]; + numbersPart = rest; + } + + const escaped = delimiters.map((d) => d.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')); + const regex = new RegExp(`(?:${escaped.join("|")})`, "g"); // 숫자 배열로 변환 - const numbers = tokens + return numbersPart + .split(regex) .map((token) => token.trim()) .filter((token) => token.length > 0) - .map((token) => Number(token)); // 숫자로 변환 - - return numbers; + .map((token) => Number(token)); // 숫자로 변환 } } \ No newline at end of file From af6c14317712bdcc60439a76bf18457670f49d14 Mon Sep 17 00:00:00 2001 From: suhyun113 <163711629+suhyun113@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:12:33 +0900 Subject: [PATCH 05/10] =?UTF-8?q?feat:=20=EC=88=AB=EC=9E=90=EA=B0=80=20?= =?UTF-8?q?=EC=95=84=EB=8B=8C=20=EA=B0=92=EC=9D=B4=20=ED=8F=AC=ED=95=A8?= =?UTF-8?q?=EB=90=9C=20=EA=B2=BD=EC=9A=B0=20=EA=B2=80=EC=A6=9D=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/InputValidator.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 src/InputValidator.js diff --git a/README.md b/README.md index 2ff9d692..f1f50e4a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ - [X] 커스텀 구분자 지정(문자열 앞부분의 "//", "\n") ### 2. validator (숫자 배열 유효성 검사) -- [ ] 숫자가 아닌 값이 포함된 경우 검증 +- [X] 숫자가 아닌 값이 포함된 경우 검증 - [ ] 양수가 아닌 값인 경우 검증 ### 3. calculator (합산) diff --git a/src/InputValidator.js b/src/InputValidator.js new file mode 100644 index 00000000..0d9c7bd1 --- /dev/null +++ b/src/InputValidator.js @@ -0,0 +1,10 @@ +export class InputValidator { + static validate(numbers) { + // 숫자가 아닌 값이 포함된 경우 + const hasNonNumber = numbers.some((n) => + typeof n !== "number" || isNaN(n)); + if (hasNonNumber) { + throw new Error("[ERROR] 숫자가 아닌 값이 포함되어 있습니다."); + } + } +} \ No newline at end of file From bf5f82cf75a87f08472ed8e0a2d3510da4eb154f Mon Sep 17 00:00:00 2001 From: suhyun113 <163711629+suhyun113@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:14:58 +0900 Subject: [PATCH 06/10] =?UTF-8?q?feat:=20=EC=96=91=EC=88=98=EA=B0=80=20?= =?UTF-8?q?=EC=95=84=EB=8B=8C=20=EA=B0=92=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/InputValidator.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f1f50e4a..64d27852 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ ### 2. validator (숫자 배열 유효성 검사) - [X] 숫자가 아닌 값이 포함된 경우 검증 -- [ ] 양수가 아닌 값인 경우 검증 +- [X] 양수가 아닌 값인 경우 검증 ### 3. calculator (합산) - [ ] 빈 배열 합산 시 0 반환 diff --git a/src/InputValidator.js b/src/InputValidator.js index 0d9c7bd1..7ee6b6af 100644 --- a/src/InputValidator.js +++ b/src/InputValidator.js @@ -6,5 +6,13 @@ export class InputValidator { if (hasNonNumber) { throw new Error("[ERROR] 숫자가 아닌 값이 포함되어 있습니다."); } + + // 양수가 아닌 값(0 또는 음수) + const hasNegative = numbers.some((n) => n <= 0); + if (hasNegative) { + throw new Error("[ERROR] 양수가 아닌 값이 포함되어 있습니다."); + } + + return true; } } \ No newline at end of file From cc0f6c2c2d3ba7fb9677e500a14454e10fc82a71 Mon Sep 17 00:00:00 2001 From: suhyun113 <163711629+suhyun113@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:19:03 +0900 Subject: [PATCH 07/10] =?UTF-8?q?feat:=20=EB=B9=88=20=EB=B0=B0=EC=97=B4=20?= =?UTF-8?q?=ED=95=A9=EC=82=B0=20=EC=8B=9C=200=20=EB=B0=98=ED=99=98=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/Calculator.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 src/Calculator.js diff --git a/README.md b/README.md index 64d27852..a6d7fe40 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ - [X] 양수가 아닌 값인 경우 검증 ### 3. calculator (합산) -- [ ] 빈 배열 합산 시 0 반환 +- [X] 빈 배열 합산 시 0 반환 - [ ] 그 외 숫자 배열 합산 ### 4. App.js (전체 통합 테스트) diff --git a/src/Calculator.js b/src/Calculator.js new file mode 100644 index 00000000..54780cb1 --- /dev/null +++ b/src/Calculator.js @@ -0,0 +1,8 @@ +export class Calculator { + static sum(numbers) { + // numbers가 비어 있으면 0 반환 + if (!numbers || numbers.length === 0){ + return 0; + } + } +} \ No newline at end of file From bea9d28fac8094181868a41d531175c15b6a38ed Mon Sep 17 00:00:00 2001 From: suhyun113 <163711629+suhyun113@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:21:08 +0900 Subject: [PATCH 08/10] =?UTF-8?q?feat:=20=EA=B7=B8=20=EC=99=B8=20=EC=88=AB?= =?UTF-8?q?=EC=9E=90=20=EB=B0=B0=EC=97=B4=20=ED=95=A9=EC=82=B0=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/Calculator.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a6d7fe40..517b3052 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ ### 3. calculator (합산) - [X] 빈 배열 합산 시 0 반환 -- [ ] 그 외 숫자 배열 합산 +- [X] 그 외 숫자 배열 합산 ### 4. App.js (전체 통합 테스트) - [ ] 모든 모듈 연동 diff --git a/src/Calculator.js b/src/Calculator.js index 54780cb1..6e821db8 100644 --- a/src/Calculator.js +++ b/src/Calculator.js @@ -1,8 +1,12 @@ export class Calculator { static sum(numbers) { - // numbers가 비어 있으면 0 반환 + // 빈 배열인 경우 0 반환 if (!numbers || numbers.length === 0){ return 0; } + + // 그 외 숫자 배열인 경우 모든 숫자 합산 + const total = numbers.reduce((acc, cur) => acc + cur, 0); + return total; } } \ No newline at end of file From 697698f7bb3ac93c36bd1b3a8542a8494ed9c4a5 Mon Sep 17 00:00:00 2001 From: suhyun113 <163711629+suhyun113@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:28:19 +0900 Subject: [PATCH 09/10] =?UTF-8?q?feat:=20parser,=20validator,=20calculator?= =?UTF-8?q?=20=EB=AA=A8=EB=93=88=20=EC=97=B0=EB=8F=99=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/App.js | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 517b3052..fb5c12bb 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,6 @@ - [X] 그 외 숫자 배열 합산 ### 4. App.js (전체 통합 테스트) -- [ ] 모든 모듈 연동 +- [X] 모든 모듈 연동 - [ ] `App.run()` 실행 로직 완성 - [ ] `AplicationTest.js` 테스트 확인 \ No newline at end of file diff --git a/src/App.js b/src/App.js index 091aa0a5..63ff65f8 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,12 @@ +import { MissionUtils } from "@woowacourse/mission-utils"; +import { InputParser } from "./InputParser"; +import { InputValidator } from "./InputValidator"; +import { Calculator } from "./Calculator"; + class App { - async run() {} + async run() { + + } } export default App; From 39b6f204e5af16094c47d9a4928d3dd59f8e29ab Mon Sep 17 00:00:00 2001 From: suhyun113 <163711629+suhyun113@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:49:38 +0900 Subject: [PATCH 10/10] =?UTF-8?q?feat:=20App.run()=20=EC=8B=A4=ED=96=89=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- src/App.js | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index fb5c12bb..1ea6bae7 100644 --- a/README.md +++ b/README.md @@ -27,5 +27,5 @@ ### 4. App.js (전체 통합 테스트) - [X] 모든 모듈 연동 -- [ ] `App.run()` 실행 로직 완성 -- [ ] `AplicationTest.js` 테스트 확인 \ No newline at end of file +- [X] `App.run()` 실행 로직 완성 +- [X] `AplicationTest.js` 테스트 확인 \ No newline at end of file diff --git a/src/App.js b/src/App.js index 63ff65f8..b23bdb6e 100644 --- a/src/App.js +++ b/src/App.js @@ -1,11 +1,22 @@ import { MissionUtils } from "@woowacourse/mission-utils"; -import { InputParser } from "./InputParser"; -import { InputValidator } from "./InputValidator"; -import { Calculator } from "./Calculator"; +import { InputParser } from "./InputParser.js"; +import { InputValidator } from "./InputValidator.js"; +import { Calculator } from "./Calculator.js"; class App { async run() { - + try { + const input = await MissionUtils.Console.readLineAsync("덧셈할 문자열을 입력해 주세요.\n"); + + const numbers = InputParser.parse(input); + InputValidator.validate(numbers); + const result = Calculator.sum(numbers); + + MissionUtils.Console.print(`결과 : ${result}`) + } catch (error) { + MissionUtils.Console.print(error.message); + throw error; + } } }