diff --git a/README.md b/README.md
index 13420b29..0c5bff3e 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,36 @@
-# javascript-calculator-precourse
\ No newline at end of file
+# javascript-calculator-precourse
+
+# 문자열 덧셈 계산기 기능 구현 목록
+
+- 문자열 입력 받기.
+ - `덧셈할 문자열을 입력해 주세요.` 시작 문구 출력.
+ - `Console.print()` 사용.
+ - `Console.readLineAsync()` 사용.
+
+
+
+- 결과 계산하기.
+
+ - 구분자로 분리한 숫자 배열 생성.
+ - 정규표현식 사용하여 `,`와 `:`으로 분리.
+ - 커스텀 구분자로 분리.
+ - 생성된 숫자 배열을 `reduce` 내장 메소드 사용하여, 합 계산.br>
+
+- 결과 출력하기.
+- `Console.print()` 사용.
+
+
+
+- 예외 처리하기.
+
+ - "[ERROR]"로 시작하는 메시지와 함께 Error를 발생.
+ - 커스텀 구분자 예외 처리.
+ - 커스텀 구분자가 문자가 아닌 경우 Error 처리.
+ - 커스텀 구분자 구분 표시(`\n`)가 없는 경우 Error 처리.
+ - 피연산자 예외 처리.
+ - Operands가 숫자가 아닌 경우 Error 처리.
+ - 구분자가 아닌 다른 문자 포함된(구분자를 잘못 입력한) 경우 Error 처리.
+ - 양수가 아닌 경우 Error 처리.
+ - 빈 문자열 입력 시, `0` 출력.
+
+- 애플리케이션 종료.
diff --git a/package-lock.json b/package-lock.json
index a1211435..bd7e7bd3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -52,6 +52,7 @@
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
@@ -2969,6 +2970,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001663",
"electron-to-chromium": "^1.5.28",
diff --git a/src/App.js b/src/App.js
index 091aa0a5..c54904d2 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,5 +1,83 @@
+import { Console } from "@woowacourse/mission-utils";
+import {
+ CALCULATOR_MESSAGE,
+ EMPTY_STRING,
+ ERROR_MESSAGE,
+} from "./Constants.js";
+import {
+ isValidCharSeparator,
+ isValidCustomEndIndex,
+ isValidIsOperands,
+ isValidVaildSeparator,
+ isValidOperandRange,
+} from "./validation.js";
+
class App {
- async run() {}
+ async run() {
+ await this.enterInput();
+
+ try {
+ this.calculateResult();
+ this.printResult();
+ } catch (error) {
+ throw error;
+ }
+ }
+ async enterInput() {
+ this.input = await Console.readLineAsync(
+ CALCULATOR_MESSAGE.CALCULATOR_START
+ );
+ }
+
+ printResult() {
+ Console.print(CALCULATOR_MESSAGE.CALCULATOR_RESULT + this.sum);
+ }
+
+ calculateResult() {
+ const operands = this.splitInput();
+
+ if (operands.length === 1 && operands[0] === EMPTY_STRING) {
+ this.sum = 0;
+ return;
+ }
+
+ this.validateOperands(operands);
+ this.sum = operands.reduce((acc, cur) => acc + Number(cur), 0);
+ }
+
+ splitInput() {
+ if (this.input.startsWith("//")) {
+ const customEndIndex = this.input.indexOf("\\n");
+ const separator = this.input.slice(2, customEndIndex);
+ const separatedInput = this.input.slice(customEndIndex + 2);
+
+ this.validateSeperator(customEndIndex, separator);
+ return separatedInput.split(separator);
+ }
+
+ return this.input.split(/,|:/);
+ }
+
+ validateSeperator(customEndIndex, seperator) {
+ if (!isValidCustomEndIndex(customEndIndex)) {
+ throw new Error(ERROR_MESSAGE.INVALID_CUSTOM_END);
+ }
+ if (!isValidCharSeparator(seperator)) {
+ throw new Error(ERROR_MESSAGE.INVALID_CHARACTER);
+ }
+ }
+
+ validateOperands(Input) {
+ if (!isValidIsOperands(Input)) {
+ throw new Error(ERROR_MESSAGE.INVALID_NUMBER);
+ }
+ if (!isValidVaildSeparator(Input)) {
+ throw new Error(ERROR_MESSAGE.INVALID_SEPARATOR);
+ }
+ if (!isValidOperandRange(Input)) {
+ throw new Error(ERROR_MESSAGE.INVALID_RANGE);
+ }
+ }
}
export default App;
diff --git a/src/constants.js b/src/constants.js
new file mode 100644
index 00000000..524343dd
--- /dev/null
+++ b/src/constants.js
@@ -0,0 +1,12 @@
+export const CALCULATOR_MESSAGE = {
+ CALCULATOR_START: "덧셈할 문자열을 입력해 주세요.\n",
+ CALCULATOR_RESULT: "결과 : ",
+};
+
+export const ERROR_MESSAGE = {
+ INVALID_CUSTOM_END: "[ERROR] 커스텀 구분자가 정확히 지정되지 않았습니다.",
+ INVALID_NUMBER: "[ERROR] 숫자를 입력해주세요.",
+ INVALID_RANGE: "[ERROR] 양수를 입력해주세요.",
+};
+
+export const EMPTY_STRING = "";
diff --git a/src/validation.js b/src/validation.js
new file mode 100644
index 00000000..0842359d
--- /dev/null
+++ b/src/validation.js
@@ -0,0 +1,19 @@
+export function isValidCharSeparator(seperator) {
+ return seperator.length === 1 && isNaN(seperator);
+}
+
+export function isValidCustomEndIndex(endIndex) {
+ return endIndex !== -1;
+}
+
+export function isValidIsOperands(input) {
+ return input.every((operand) => !isNaN(parseInt(operand)));
+}
+
+export function isValidVaildSeparator(input) {
+ return input.every((operand) => !Number.isNaN(Number(operand)));
+}
+
+export function isValidOperandRange(input) {
+ return input.every((operand) => 0 < Number(operand));
+}