diff --git a/README.md b/README.md
index 13420b29..1841bd66 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,61 @@
-# javascript-calculator-precourse
\ No newline at end of file
+# javascript-calculator-precourse
+
+## 기능
+
+- [x] "덧셈할 문자열을 입력해 주세요." 출력
+
+- [x] 입력받기
+
+- [x] 입력값이 0인지 확인
+
+ 입력값이 비었을 경우 결과값 0으로 처리
+
+- [x] 커스텀 구분자 사용시
+
+ 1. 커스텀 시작 구분자("//"), 커스텀 종료 구분자("\n")가 잘못 표기시에 예외상황 발생
+ 2. 입력 문자열이 "//"로 시작하고 "\n"끝났을 경우 커스텀 구분자 추출
+ 3. 커스텀 구분자를 구분자 배열에 추가
+ 4. 커스텀 구분자가 존재하지 않을시 기본구분자 사용
+
+- [x] 기본 구분자 사용 시
+
+ 1. 구분자(쉼표, 콜론, 커스텀 구분자)가 잘못 표기시에 예외상황 발생
+ 2. 기본 구분자 마저 존재하지 않을시 예외 발생
+ 3. 구분자(쉼표, 콜론, 커스텀 구분자)를 기준으로 분리
+
+- [x] 나뉜 문자열을 숫자 배열로 변환 (빈 문자열 제외)
+
+ 숫자가 아닌 문자가 포함된 경우 예외 발생
+
+- [x] 숫자 배열의 모든 값을 합산
+
+- [x] "결과 : ${결과값}" 출력
+
+- [x] 프로그램 종료
+
+## 입력방식 조건
+
+정상 입력 형식은 다음 예시와 같다:
+
+- "1,2,3" → 쉼표(,) 구분
+- "1,2:3" → 쉼표(,)와 콜론(:) 혼용
+- "//;\n1;2;3" → 커스텀 구분자 세미콜론(;)
+- "//;\n1;2:3" → 커스텀 구분자와 기본 구분자(:) 혼용
+
+위의 형식을 제외한 모든 입력은 예외로 처리한다.
+
+## 예외 처리시
+
+"[ERROR]"로 시작하는 메시지와 함께 Error를 발생시킨 후 애플리케이션은 종료되어야 한다.
+
+## 만났던 오류
+
+- 폴더 및 파일 이름 대소문자 불일치로 인한 import 오류
+ 파일명을 PromptOutput에서 promptOutput 변경하였습니다
이유는 FSD 환경에서는 PascalCase도 가능하지만,
+ 현재 프로젝트는 React/TypeScript 환경이 아니므로 camelCase로 통일
+
+## 아쉬운점
+
+상수사용, enum, 사용하지 못한 점
+파일명에 대한 아쉬움
+함수를 더 쪼갤 수 있었을 것 같다는 것에 대한 아쉬움
diff --git a/src/App.js b/src/App.js
index 091aa0a5..ce8eab95 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,5 +1,9 @@
+import { calculator } from "./page/index.js";
+
class App {
- async run() {}
+ async run() {
+ await calculator();
+ }
}
export default App;
diff --git a/src/entities/delimiter/index.js b/src/entities/delimiter/index.js
new file mode 100644
index 00000000..fb768c8e
--- /dev/null
+++ b/src/entities/delimiter/index.js
@@ -0,0 +1 @@
+export { Delimiters } from "./model/delimiters.js";
diff --git a/src/entities/delimiter/model/delimiters.js b/src/entities/delimiter/model/delimiters.js
new file mode 100644
index 00000000..3eb50d64
--- /dev/null
+++ b/src/entities/delimiter/model/delimiters.js
@@ -0,0 +1,15 @@
+export class Delimiters {
+ constructor() {
+ this.delimiterArray = [",", ":"];
+ }
+
+ addCustumDelimiter(elimiter) {
+ if (!this.delimiterArray.includes(elimiter)) {
+ this.delimiterArray.push(elimiter);
+ }
+ }
+
+ getDelimiterArray() {
+ return this.delimiterArray;
+ }
+}
diff --git a/src/entities/number/index.js b/src/entities/number/index.js
new file mode 100644
index 00000000..b3d8207b
--- /dev/null
+++ b/src/entities/number/index.js
@@ -0,0 +1 @@
+export { NumberArray } from "./model/numberArray.js";
diff --git a/src/entities/number/model/numberArray.js b/src/entities/number/model/numberArray.js
new file mode 100644
index 00000000..b2fa100a
--- /dev/null
+++ b/src/entities/number/model/numberArray.js
@@ -0,0 +1,23 @@
+export class NumberArray {
+ constructor() {
+ this.numberArray = [];
+ }
+
+ isNumber(number) {
+ return Number.isInteger(Number(number)) && Number(number) >= 0;
+ }
+
+ addNumber(number) {
+ this.numberArray.push(Number(number));
+ }
+
+ getArray() {
+ return this.numberArray;
+ }
+ getSum() {
+ return this.numberArray.reduce(
+ (acc, curr) => Number(acc) + Number(curr),
+ 0
+ );
+ }
+}
diff --git a/src/features/checkDelimiter/index.js b/src/features/checkDelimiter/index.js
new file mode 100644
index 00000000..a606e809
--- /dev/null
+++ b/src/features/checkDelimiter/index.js
@@ -0,0 +1 @@
+export { parseCustomDelimiter } from "./parseCustomDelimiter/parseCustomDelimiter.js";
diff --git a/src/features/checkDelimiter/parseCustomDelimiter/parseCustomDelimiter.js b/src/features/checkDelimiter/parseCustomDelimiter/parseCustomDelimiter.js
new file mode 100644
index 00000000..35bb930d
--- /dev/null
+++ b/src/features/checkDelimiter/parseCustomDelimiter/parseCustomDelimiter.js
@@ -0,0 +1,28 @@
+import { Delimiters } from "../../../entities/delimiter/index.js";
+import { customError } from "../../../shared/error/index.js";
+
+export function parseCustomDelimiter(input) {
+ const startMarker = input.indexOf("//");
+ const endMarker = input.indexOf("\\n");
+
+ const delimiterManager = new Delimiters();
+ let inputString = input;
+
+ if (
+ (startMarker === -1 && endMarker !== -1) ||
+ (startMarker === 0 && endMarker === -1)
+ ) {
+ customError();
+ }
+
+ if (startMarker === 0 && endMarker !== -1) {
+ const customDelimiter = input.slice(startMarker + 2, endMarker - 1);
+ delimiterManager.addCustumDelimiter(customDelimiter);
+ inputString = input.slice(endMarker + 2);
+ }
+
+ return {
+ DelimiterArray: delimiterManager.getDelimiterArray(),
+ Input: inputString,
+ };
+}
diff --git a/src/features/input/index.js b/src/features/input/index.js
new file mode 100644
index 00000000..85e6195b
--- /dev/null
+++ b/src/features/input/index.js
@@ -0,0 +1 @@
+export { readInput } from "./readInput/readInput.js";
diff --git a/src/features/input/readInput/readInput.js b/src/features/input/readInput/readInput.js
new file mode 100644
index 00000000..b0db3c36
--- /dev/null
+++ b/src/features/input/readInput/readInput.js
@@ -0,0 +1,6 @@
+import { Console } from "@woowacourse/mission-utils";
+
+export async function readInput() {
+ const input = await Console.readLineAsync("");
+ return input;
+}
diff --git a/src/features/output/index.js b/src/features/output/index.js
new file mode 100644
index 00000000..3210d1ac
--- /dev/null
+++ b/src/features/output/index.js
@@ -0,0 +1,2 @@
+export { promptOutput } from "./promptOutput/promptOutput.js";
+export { resultOutput } from "./resultOutput/resultOutput.js";
diff --git a/src/features/output/promptOutput/PromptOutput.js b/src/features/output/promptOutput/PromptOutput.js
new file mode 100644
index 00000000..ba717035
--- /dev/null
+++ b/src/features/output/promptOutput/PromptOutput.js
@@ -0,0 +1,4 @@
+import { Console } from "@woowacourse/mission-utils";
+export async function promptOutput() {
+ Console.print("덧셈할 문자열을 입력해 주세요.");
+}
diff --git a/src/features/output/resultOutput/resultOutput.js b/src/features/output/resultOutput/resultOutput.js
new file mode 100644
index 00000000..09904289
--- /dev/null
+++ b/src/features/output/resultOutput/resultOutput.js
@@ -0,0 +1,5 @@
+import { Console } from "@woowacourse/mission-utils";
+
+export function resultOutput(sum) {
+ Console.print(`결과 : ${sum}`);
+}
diff --git a/src/features/splitInput/index.js b/src/features/splitInput/index.js
new file mode 100644
index 00000000..97888684
--- /dev/null
+++ b/src/features/splitInput/index.js
@@ -0,0 +1 @@
+export { splitInput } from "./splitInput/splitInput.js";
diff --git a/src/features/splitInput/splitInput/splitInput.js b/src/features/splitInput/splitInput/splitInput.js
new file mode 100644
index 00000000..67b4d128
--- /dev/null
+++ b/src/features/splitInput/splitInput/splitInput.js
@@ -0,0 +1,11 @@
+import { delimiterError } from "../../../shared/error/index.js";
+
+export function splitInput(input, delimiterArray) {
+ if (!delimiterArray.some((delimiter) => input.includes(delimiter))) {
+ delimiterError();
+ }
+ for (const delimiter of delimiterArray) {
+ input = input.replaceAll(delimiter, " ");
+ }
+ return input.split(" ");
+}
diff --git a/src/features/sumNumber/index.js b/src/features/sumNumber/index.js
new file mode 100644
index 00000000..9d9b99d9
--- /dev/null
+++ b/src/features/sumNumber/index.js
@@ -0,0 +1 @@
+export { sumNumber } from "./sumNumber/sumNumber.js";
diff --git a/src/features/sumNumber/sumNumber/sumNumber.js b/src/features/sumNumber/sumNumber/sumNumber.js
new file mode 100644
index 00000000..87057428
--- /dev/null
+++ b/src/features/sumNumber/sumNumber/sumNumber.js
@@ -0,0 +1,11 @@
+import { NumberArray } from "../../../entities/number/index.js";
+import { numberError } from "../../../shared/error/index.js";
+
+export function sumNumber(numberArray) {
+ const array = new NumberArray();
+ numberArray.forEach((number) => {
+ if (!array.isNumber(number)) numberError();
+ array.addNumber(number);
+ });
+ return array.getSum();
+}
diff --git a/src/features/validate/index.js b/src/features/validate/index.js
new file mode 100644
index 00000000..c0f1d98f
--- /dev/null
+++ b/src/features/validate/index.js
@@ -0,0 +1 @@
+export { vaildateInput } from "./validateInput/validateInput.js";
diff --git a/src/features/validate/validateInput/lib/isEmpty.js b/src/features/validate/validateInput/lib/isEmpty.js
new file mode 100644
index 00000000..38abc899
--- /dev/null
+++ b/src/features/validate/validateInput/lib/isEmpty.js
@@ -0,0 +1,4 @@
+export function isEmpty(input) {
+ if (input.trim() === "") return true;
+ return false;
+}
diff --git a/src/features/validate/validateInput/validateInput.js b/src/features/validate/validateInput/validateInput.js
new file mode 100644
index 00000000..ac696538
--- /dev/null
+++ b/src/features/validate/validateInput/validateInput.js
@@ -0,0 +1,6 @@
+import { isEmpty } from "./lib/isEmpty.js";
+
+export function vaildateInput(input) {
+ if (isEmpty(input)) return false;
+ return true;
+}
diff --git a/src/page/calculator/Calculator.js b/src/page/calculator/Calculator.js
new file mode 100644
index 00000000..4858ce2a
--- /dev/null
+++ b/src/page/calculator/Calculator.js
@@ -0,0 +1,24 @@
+import { parseCustomDelimiter } from "../../features/checkDelimiter/index.js";
+import { readInput } from "../../features/input/index.js";
+import { promptOutput, resultOutput } from "../../features/output/index.js";
+import { splitInput } from "../../features/splitInput/index.js";
+import { sumNumber } from "../../features/sumNumber/index.js";
+import { vaildateInput } from "../../features/validate/index.js";
+export async function calculator() {
+ await promptOutput();
+ const input = await readInput();
+ if (!vaildateInput(input)) {
+ resultOutput(0);
+ return;
+ }
+ const parsedInput = parseCustomDelimiter(input);
+
+ const numbers = await splitInput(
+ parsedInput.Input,
+ parsedInput.DelimiterArray
+ );
+
+ const result = await sumNumber(numbers);
+ resultOutput(result);
+ return;
+}
diff --git a/src/page/index.js b/src/page/index.js
new file mode 100644
index 00000000..71f7f030
--- /dev/null
+++ b/src/page/index.js
@@ -0,0 +1 @@
+export { calculator } from "./calculator/calculator.js";
diff --git a/src/shared/error/customError/customError.js b/src/shared/error/customError/customError.js
new file mode 100644
index 00000000..4da30a1a
--- /dev/null
+++ b/src/shared/error/customError/customError.js
@@ -0,0 +1,3 @@
+export function customError() {
+ throw new Error("[Error] : 커스텀 구분자 생성 실패");
+}
diff --git a/src/shared/error/delimiterError/delimiterError.js b/src/shared/error/delimiterError/delimiterError.js
new file mode 100644
index 00000000..f366fd1a
--- /dev/null
+++ b/src/shared/error/delimiterError/delimiterError.js
@@ -0,0 +1,3 @@
+export function delimiterError() {
+ throw new Error("[Error] : 구분자는 쉼표(,) , 콜론(:) , 커스텀 입니다");
+}
diff --git a/src/shared/error/index.js b/src/shared/error/index.js
new file mode 100644
index 00000000..72e95286
--- /dev/null
+++ b/src/shared/error/index.js
@@ -0,0 +1,3 @@
+export { customError } from "./customError/customError.js";
+export { delimiterError } from "./delimiterError/delimiterError.js";
+export { numberError } from "./numberError/numberError.js";
diff --git a/src/shared/error/numberError/numberError.js b/src/shared/error/numberError/numberError.js
new file mode 100644
index 00000000..d34934ef
--- /dev/null
+++ b/src/shared/error/numberError/numberError.js
@@ -0,0 +1,3 @@
+export function numberError() {
+ throw new Error("[ERROR] : 정수만 입력 가능합니다");
+}