From dba0ed5fbb94f8a53505348b274be3e09fdb6896 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 16:59:18 +0900 Subject: [PATCH 01/41] =?UTF-8?q?docs:=20README.md=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기능 그룹 (MVC) - 예외 처리 - 테스트 목록 - 코드 스타일 및 브랜치 전략 --- docs/README.md | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..27e3e8406e --- /dev/null +++ b/docs/README.md @@ -0,0 +1,114 @@ +## 기능 그룹 (MVC) + +* Models + - [ ] 사용자 정보 `class` + - [ ] 구입 금액 (필드) + - [ ] 로또 개수 (필드) + - [ ] 소유한 로또 번호 목록 (필드) + - [ ] 로또 구입금액 `예외처리` + - [ ] 로또 정보 (보너스 번호 포함) `class` + - [ ] 로또 객체: Lotto 클래스 (필드) + - [ ] 당첨 번호 목록 (필드) + - [ ] 로또 당첨 번호 `예외처리` + - [ ] 보너스 번호 (필드) + - [ ] 보너스 번호 `예외처리` + + +* Views + - [ ] 입력창 및 메세지 출력 `class` + - [ ] 구입금액 입력 + - [ ] 당첨번호 입력 + - [ ] 보너스번호 입력 + - [ ] 출력창 및 메세지 출력 `class` + - [ ] 로또 개수 & 번호 목록 출력 + - [ ] 당첨 통계 출력: 제목, 내역, 결과(수익률) + + +* Controllers + - [ ] 로또 게임 처리/연산 `class` + - [ ] 사용자가 소유할 로또 번호 목록 생성 + - [ ] 당첨 내역 연산 + - [ ] 당첨 결과(수익률) 연산 + +
+ +## 예외 처리 +* 로또 구입 금액 + - [ ] 숫자가 아닐 경우 + - [ ] 0원 이하일 경우 + - [ ] 1000원 단위가 아닐 경우 + + +* 로또 당첨 번호 + - [ ] 숫자가 아닐 경우 + - [ ] 1~45 사이의 숫자가 아닐 경우 + - [ ] 소수점이 있을 경우 + - [ ] 중복된 숫자가 있을 경우 + - [ ] 6개가 아닐 경우 + + +* 보너스 번호 + - [ ] 숫자가 아닐 경우 + - [ ] 1~45 사이의 숫자가 아닐 경우 + - [ ] 소수점이 있을 경우 + - [ ] 당첨 번호와 중복될 경우 + +
+ +## 테스트 목록 +
구현하면서 추가 예정
+ +
+ +## 코드 스타일 및 브랜치 전략 +* 코드 스타일 + -
+ eslint(airbnb style) 사용 + + `npm init @eslint/config` 로 eslint를 설치한다. + + `npx install-peerdeps --dev eslint-config-airbnb` 로 airbnb eslint 설정 패키지를 설치한다. + + .eslintrc.cjs 파일을 생성하여 코드 스타일을 정의한다. + + test 코드를 위해 `jest : true` 를 기입한다. +
+ + -
+ prettier 사용 + + `npm i -D prettier eslint-config-prettier` 로 prettier와 eslint-config-prettier를 설치한다. + + > `eslint-config-prettier`: prettier와 겹치는 eslint 룰을 비활성화한다. + + .eslintrc.cjs의 `extends : [...]` 에 `prettier` 를 추가한다. + + .prettierrc.cjs 파일을 생성한 후 prettier 규칙을 추가한다. +
+ + -
+ JSDoc 작성 + + 클래스, 함수, 변수의 문서화 및 타입을 명확히 하기 위해 JSDoc을 작성한다. + + ```js + /** + * 두 숫자의 합을 연산하는 함수 + * @param {number} a + * @param {number} b + * @returns {number} + */ + function sum(a, b) { + return a + b; + } + ``` +
+ + +* 브랜치 전략 + - Git Flow 전략을 기본으로 사용하되 아래의 사항을 지킨다. + - 최종 브랜치는 'jinmidnight01' 이다. + - 주 작업 브랜치는 'develop'이다. + - 필요시 기능 그룹 'feature/{feature}' 브랜치를 생성하여 작업한다. + - 특정 기능 그룹이 완성되면 'develop' 브랜치에 병합한다. + - 애플리케이션이 완성되면 'develop' 브랜치를 최종 브랜치에 병합한다. \ No newline at end of file From faad6d952282430e4c50b2a1c1205566eace8811 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 17:08:07 +0900 Subject: [PATCH 02/41] =?UTF-8?q?style:=20eslint(airbnb),=20prettier=20?= =?UTF-8?q?=EC=84=A4=EC=B9=98=20=EB=B0=8F=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.cjs | 30 + .prettierrc.cjs | 12 + package-lock.json | 3929 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 11 +- 4 files changed, 3892 insertions(+), 90 deletions(-) create mode 100644 .eslintrc.cjs create mode 100644 .prettierrc.cjs diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000000..d0d8c6b13d --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,30 @@ +module.exports = { + env: { + browser: true, + commonjs: true, + es2021: true, + node: true, + jest: true, + }, + extends: ['airbnb-base', 'prettier'], + overrides: [ + { + env: { + node: true, + }, + files: [ + '.eslintrc.{js,cjs}', + ], + parserOptions: { + sourceType: 'script', + }, + }, + ], + parserOptions: { + ecmaVersion: 'latest', + }, + rules: { + 'import/prefer-default-export': 'off', + 'import/extensions': ['off'], + }, +}; \ No newline at end of file diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 0000000000..53e59d95df --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1,12 @@ +module.exports = { + printWidth: 80, + tabWidth: 2, + useTabs: false, + semi: true, + singleQuote: true, + trailingComma: 'all', + bracketSpacing: true, + arrowParens: 'avoid', + proseWrap: 'never', + endOfLine: 'auto', +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 779fba30f4..0ab3edddba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,13 +15,31 @@ "@babel/core": "^7.23.0", "@babel/preset-env": "^7.22.20", "babel-jest": "^29.7.0", - "jest": "29.6.0" + "eslint": "^8.2.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0", + "jest": "29.6.0", + "prettier": "^3.0.3" }, "engines": { "node": ">=18.17.1", "npm": ">=9.6.7" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -1808,6 +1826,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.2.tgz", + "integrity": "sha512-54cIh74Z1rp4oIjsHjqN+WM4fMyCBYe+LpZ9jWm51CZ1fbH3SkAzQD/3XLoNkjbJ7YEmjobLXyvQrFypRHOrXw==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", @@ -1863,6 +1894,103 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.6.0.tgz", + "integrity": "sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "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", @@ -2312,6 +2440,12 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, "node_modules/@types/node": { "version": "20.8.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.6.tgz", @@ -2351,6 +2485,52 @@ "npm": ">=9.6.7" } }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -2412,6 +2592,141 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.8.2.tgz", + "integrity": "sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -2633,6 +2948,20 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2771,6 +3100,12 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "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", @@ -2790,6 +3125,17 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-js-pure": { + "version": "3.33.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.33.2.tgz", + "integrity": "sha512-a8zeCdyVk7uF2elKIGz67AjcXOxjRbwOLz8SbklEso1V+2DoW4OkAMZN9S9GBgvZIaqQi/OemFX4OiSoQEmg1Q==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -2825,6 +3171,12 @@ "node": ">= 8" } }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2856,6 +3208,12 @@ } } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -2865,6 +3223,37 @@ "node": ">=0.10.0" } }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -2883,6 +3272,18 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.556", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.556.tgz", @@ -2907,6 +3308,19 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2916,6 +3330,99 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2934,7 +3441,474 @@ "node": ">=8" } }, - "node_modules/esprima": { + "node_modules/eslint": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.2.0.tgz", + "integrity": "sha512-erw7XmM+CLxTOickrimJ1SiF55jiNlVSp2qqm0NuBWPtHYQCegD5ZMaW0c3i5ytPqL+SSLaCxdvQXFPLJn+ABw==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.0.4", + "@humanwhocodes/config-array": "^0.6.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^6.0.0", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.2.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-airbnb": { + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", + "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", + "dev": true, + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5" + }, + "engines": { + "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.25.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", + "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.1", + "has": "^1.0.3", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz", + "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.16.3", + "aria-query": "^4.2.2", + "array-includes": "^3.1.4", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.3.5", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.7", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.2.1", + "language-tags": "^1.0.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/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/eslint-plugin-react": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", + "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz", + "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", + "integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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==", @@ -2947,6 +3921,39 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3004,12 +4011,24 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, "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/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -3019,6 +4038,18 @@ "bser": "2.1.1" } }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3044,6 +4075,35 @@ "node": ">=8" } }, + "node_modules/flat-cache": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3064,6 +4124,48 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -3082,6 +4184,21 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -3103,6 +4220,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -3123,6 +4256,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -3132,6 +4277,33 @@ "node": ">=4" } }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -3147,6 +4319,15 @@ "node": ">= 0.4.0" } }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3156,6 +4337,69 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -3171,6 +4415,40 @@ "node": ">=10.17.0" } }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -3215,24 +4493,116 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, - "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, "dependencies": { - "has": "^1.0.3" + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "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", @@ -3251,6 +4621,30 @@ "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-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -3260,6 +4654,49 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3272,6 +4709,69 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3996,12 +5496,30 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "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/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -4014,6 +5532,30 @@ "node": ">=6" } }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -4023,6 +5565,24 @@ "node": ">=6" } }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -4032,6 +5592,19 @@ "node": ">=6" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -4056,6 +5629,24 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4162,6 +5753,15 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4207,6 +5807,112 @@ "node": ">=8" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4231,6 +5937,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -4282,6 +6005,18 @@ "node": ">=6" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -4372,6 +6107,30 @@ "node": ">=8" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -4398,6 +6157,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -4408,7 +6176,33 @@ "sisteransi": "^1.0.5" }, "engines": { - "node": ">= 6" + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" } }, "node_modules/pure-rand": { @@ -4466,6 +6260,35 @@ "@babel/runtime": "^7.8.4" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/regexpu-core": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", @@ -4560,6 +6383,53 @@ "node": ">=10" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -4569,6 +6439,35 @@ "semver": "bin/semver.js" } }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4590,6 +6489,20 @@ "node": ">=8" } }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -4675,6 +6588,71 @@ "node": ">=8" } }, + "node_modules/string.prototype.matchall": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", + "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", + "set-function-name": "^2.0.0", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -4755,6 +6733,12 @@ "node": ">=8" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -4782,6 +6766,51 @@ "node": ">=8.0" } }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -4803,6 +6832,86 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undici-types": { "version": "5.25.3", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", @@ -4879,6 +6988,21 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, "node_modules/v8-to-istanbul": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", @@ -4917,6 +7041,41 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -5009,6 +7168,12 @@ } }, "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, "@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -6250,6 +8415,16 @@ "regenerator-runtime": "^0.14.0" } }, + "@babel/runtime-corejs3": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.2.tgz", + "integrity": "sha512-54cIh74Z1rp4oIjsHjqN+WM4fMyCBYe+LpZ9jWm51CZ1fbH3SkAzQD/3XLoNkjbJ7YEmjobLXyvQrFypRHOrXw==", + "dev": true, + "requires": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + } + }, "@babel/template": { "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", @@ -6296,6 +8471,78 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.6.0.tgz", + "integrity": "sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -6672,6 +8919,12 @@ "@types/istanbul-lib-report": "*" } }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, "@types/node": { "version": "20.8.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.6.tgz", @@ -6707,6 +8960,37 @@ "resolved": "https://registry.npmjs.org/@woowacourse/mission-utils/-/mission-utils-2.1.1.tgz", "integrity": "sha512-/YWWF67WhdnQ/cyjqz4mPLhL8vElekpfeSs6JYqLVPCKOEMUxvFj6rq7QidTK05h1mLPeZogGkJCky1GQgt91Q==" }, + "acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -6750,6 +9034,102 @@ "sprintf-js": "~1.0.2" } }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, + "array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + } + }, + "array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + } + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "axe-core": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.8.2.tgz", + "integrity": "sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g==", + "dev": true + }, + "axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, "babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -6917,6 +9297,17 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -7007,6 +9398,12 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, "convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -7022,104 +9419,591 @@ "browserslist": "^4.22.1" } }, - "create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "core-js-pure": { + "version": "3.33.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.33.2.tgz", + "integrity": "sha512-a8zeCdyVk7uF2elKIGz67AjcXOxjRbwOLz8SbklEso1V+2DoW4OkAMZN9S9GBgvZIaqQi/OemFX4OiSoQEmg1Q==", + "dev": true + }, + "create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "requires": {} + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "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 + }, + "define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "electron-to-chromium": { + "version": "1.4.556", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.556.tgz", + "integrity": "sha512-6RPN0hHfzDU8D56E72YkDvnLw5Cj2NMXZGg3UkgyoHxjVhG99KZpsKgBWMmTy0Ei89xwan+rbRsVB9yzATmYzQ==", + "dev": true + }, + "emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + } + }, + "es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "eslint": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.2.0.tgz", + "integrity": "sha512-erw7XmM+CLxTOickrimJ1SiF55jiNlVSp2qqm0NuBWPtHYQCegD5ZMaW0c3i5ytPqL+SSLaCxdvQXFPLJn+ABw==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.0.4", + "@humanwhocodes/config-array": "^0.6.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^6.0.0", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.2.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "eslint-config-airbnb": { + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", + "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^15.0.0", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5" + } + }, + "eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + } + }, + "eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "dev": true, + "requires": {} + }, + "eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", "dev": true, "requires": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "eslint-plugin-import": { + "version": "2.25.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", + "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", "dev": true, "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.1", + "has": "^1.0.3", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } } }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "eslint-plugin-jsx-a11y": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz", + "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==", "dev": true, "requires": { - "ms": "2.1.2" + "@babel/runtime": "^7.16.3", + "aria-query": "^4.2.2", + "array-includes": "^3.1.4", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.3.5", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.7", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.2.1", + "language-tags": "^1.0.5", + "minimatch": "^3.0.4" + }, + "dependencies": { + "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 + } } }, - "dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "eslint-plugin-react": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", + "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.0.4", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", + "prop-types": "^15.7.2", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz", + "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==", "dev": true, "requires": {} }, - "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 - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.4.556", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.556.tgz", - "integrity": "sha512-6RPN0hHfzDU8D56E72YkDvnLw5Cj2NMXZGg3UkgyoHxjVhG99KZpsKgBWMmTy0Ei89xwan+rbRsVB9yzATmYzQ==", - "dev": true - }, - "emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "eslint-scope": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", + "integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "is-arrayish": "^0.2.1" + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } } }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } }, "esprima": { "version": "4.0.1", @@ -7127,6 +10011,30 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -7169,12 +10077,24 @@ "jest-util": "^29.7.0" } }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, "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 }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, "fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -7184,6 +10104,15 @@ "bser": "2.1.1" } }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -7203,6 +10132,32 @@ "path-exists": "^4.0.0" } }, + "flat-cache": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -7216,6 +10171,36 @@ "dev": true, "optional": true }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -7228,6 +10213,18 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, "get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -7240,6 +10237,16 @@ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -7254,12 +10261,39 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -7272,12 +10306,57 @@ "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", "dev": true }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.2" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -7290,6 +10369,30 @@ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -7322,21 +10425,83 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + } + }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, - "is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, "requires": { - "has": "^1.0.3" + "has-tostringtag": "^1.0.0" } }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, "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", @@ -7349,18 +10514,103 @@ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true }, + "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, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, "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 }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.11" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -7918,30 +11168,94 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, + "jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + } + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, "kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "requires": { + "language-subtag-registry": "^0.3.20" + } + }, "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 }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -7963,6 +11277,21 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -8047,6 +11376,12 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -8086,6 +11421,79 @@ "path-key": "^3.0.0" } }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "object.hasown": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "dev": true, + "requires": { + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8104,6 +11512,20 @@ "mimic-fn": "^2.1.0" } }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -8139,6 +11561,15 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -8202,6 +11633,18 @@ "find-up": "^4.0.0" } }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true + }, "pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -8221,6 +11664,12 @@ } } }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -8231,6 +11680,31 @@ "sisteransi": "^1.0.5" } }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + } + } + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true + }, "pure-rand": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", @@ -8273,6 +11747,23 @@ "@babel/runtime": "^7.8.4" } }, + "regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "regexpu-core": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", @@ -8342,12 +11833,67 @@ "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + } + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, "semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true }, + "set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "requires": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "requires": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -8363,6 +11909,17 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -8433,6 +11990,56 @@ "strip-ansi": "^6.0.1" } }, + "string.prototype.matchall": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", + "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", + "set-function-name": "^2.0.0", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -8486,6 +12093,12 @@ "minimatch": "^3.0.4" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -8507,6 +12120,44 @@ "is-number": "^7.0.0" } }, + "tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -8519,6 +12170,65 @@ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true }, + "typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, "undici-types": { "version": "5.25.3", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", @@ -8563,6 +12273,21 @@ "picocolors": "^1.0.0" } }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, "v8-to-istanbul": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", @@ -8592,6 +12317,32 @@ "isexe": "^2.0.0" } }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 80eb8de6af..e0ef1b19d3 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,16 @@ "@babel/core": "^7.23.0", "@babel/preset-env": "^7.22.20", "babel-jest": "^29.7.0", - "jest": "29.6.0" + "eslint": "^8.2.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0", + "jest": "29.6.0", + "prettier": "^3.0.3" }, "scripts": { "test": "jest --detectOpenHandles --watch" From 8d8126b06bba71cdf10f57123823d0c6a537bd76 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 18:01:25 +0900 Subject: [PATCH 03/41] =?UTF-8?q?feat(views):=20=EA=B5=AC=EC=9E=85?= =?UTF-8?q?=EA=B8=88=EC=95=A1=20=EC=9E=85=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - InputView 클래스 생성 - MESSAGES 클래스 생성 --- docs/README.md | 2 +- src/App.js | 8 ++++++-- src/constants/messages.js | 5 +++++ src/views/InputView.js | 10 ++++++++++ 4 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 src/constants/messages.js create mode 100644 src/views/InputView.js diff --git a/docs/README.md b/docs/README.md index 27e3e8406e..dd85e15679 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,7 +16,7 @@ * Views - [ ] 입력창 및 메세지 출력 `class` - - [ ] 구입금액 입력 + - [x] 구입금액 입력 - [ ] 당첨번호 입력 - [ ] 보너스번호 입력 - [ ] 출력창 및 메세지 출력 `class` diff --git a/src/App.js b/src/App.js index c38b30d5b2..b27fc2db0c 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,9 @@ +import InputView from "./views/InputView.js"; + class App { - async play() {} + async play() { + const lottoPrice = await InputView.getLottoPrice(); + } } -export default App; +export default App; \ No newline at end of file diff --git a/src/constants/messages.js b/src/constants/messages.js new file mode 100644 index 0000000000..c5ec5fcb81 --- /dev/null +++ b/src/constants/messages.js @@ -0,0 +1,5 @@ +const MESSAGES = Object.freeze({ + LOTTO_PRICE_INPUT: '구입금액을 입력해 주세요.', +}); + +export default MESSAGES; \ No newline at end of file diff --git a/src/views/InputView.js b/src/views/InputView.js new file mode 100644 index 0000000000..a6c299703b --- /dev/null +++ b/src/views/InputView.js @@ -0,0 +1,10 @@ +import { Console } from '@woowacourse/mission-utils'; +import MESSAGES from '../constants/messages.js'; + +class InputView { + static getLottoPrice() { + return Console.readLineAsync(MESSAGES.LOTTO_PRICE_INPUT); + } +} + +export default InputView; \ No newline at end of file From fa9526b9bc85be6f87a1504c8a00c48314aacda8 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 18:04:18 +0900 Subject: [PATCH 04/41] =?UTF-8?q?docs:=20README.md=EC=97=90=EC=84=9C=20'?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90'=EB=A5=BC=20'=EA=B5=AC=EB=A7=A4?= =?UTF-8?q?=EC=9E=90'=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index dd85e15679..28f92bb5f7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ ## 기능 그룹 (MVC) * Models - - [ ] 사용자 정보 `class` + - [ ] 구매자 정보 `class` - [ ] 구입 금액 (필드) - [ ] 로또 개수 (필드) - [ ] 소유한 로또 번호 목록 (필드) @@ -26,7 +26,7 @@ * Controllers - [ ] 로또 게임 처리/연산 `class` - - [ ] 사용자가 소유할 로또 번호 목록 생성 + - [ ] 구매자가 소유할 로또 번호 목록 생성 - [ ] 당첨 내역 연산 - [ ] 당첨 결과(수익률) 연산 From 08195b5854af1c70c8f71892b8d2f16268652021 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 18:20:33 +0900 Subject: [PATCH 05/41] =?UTF-8?q?feat(models):=20=EA=B5=AC=EB=A7=A4?= =?UTF-8?q?=EC=9E=90=20=EC=A0=95=EB=B3=B4=20class=EC=97=90=20'=EA=B5=AC?= =?UTF-8?q?=EC=9E=85=20=EA=B8=88=EC=95=A1'=20=ED=95=84=EB=93=9C=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 - models/Customer.js 추가 - Customer.js에 생성자 구현: (param) 구입 금액 - App.js에 customer 상수 구현 --- docs/README.md | 2 +- src/App.js | 2 ++ src/models/Customer.js | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 src/models/Customer.js diff --git a/docs/README.md b/docs/README.md index 28f92bb5f7..8ce9eba001 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,7 +2,7 @@ * Models - [ ] 구매자 정보 `class` - - [ ] 구입 금액 (필드) + - [x] 구입 금액 (필드) - [ ] 로또 개수 (필드) - [ ] 소유한 로또 번호 목록 (필드) - [ ] 로또 구입금액 `예외처리` diff --git a/src/App.js b/src/App.js index b27fc2db0c..605e6596ef 100644 --- a/src/App.js +++ b/src/App.js @@ -1,8 +1,10 @@ import InputView from "./views/InputView.js"; +import Customer from "./models/Customer.js"; class App { async play() { const lottoPrice = await InputView.getLottoPrice(); + const customer = new Customer(lottoPrice); } } diff --git a/src/models/Customer.js b/src/models/Customer.js new file mode 100644 index 0000000000..9a52fe392f --- /dev/null +++ b/src/models/Customer.js @@ -0,0 +1,9 @@ +class Customer { + #lottoPrice; + + constructor(lottoPrice) { + this.#lottoPrice = lottoPrice; + } +} + +export default Customer; \ No newline at end of file From c4ef024438fefefeee99d67ec5a461cf2337439f Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 18:33:48 +0900 Subject: [PATCH 06/41] =?UTF-8?q?refactor(views):=20getLottoPrice=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=EC=97=90=20=EA=B0=9C=ED=96=89=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/InputView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/InputView.js b/src/views/InputView.js index a6c299703b..dac10f6a0d 100644 --- a/src/views/InputView.js +++ b/src/views/InputView.js @@ -3,7 +3,7 @@ import MESSAGES from '../constants/messages.js'; class InputView { static getLottoPrice() { - return Console.readLineAsync(MESSAGES.LOTTO_PRICE_INPUT); + return Console.readLineAsync(`${MESSAGES.LOTTO_PRICE_INPUT}\n`); } } From c7c7bd5b3892a90020331b79a622e037f47eae41 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 19:20:11 +0900 Subject: [PATCH 07/41] =?UTF-8?q?docs:=20README=EC=97=90=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=AA=A9=EB=A1=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 브랜치 전략에 문구 'MVC를 기준으로' 추가 --- docs/README.md | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 8ce9eba001..1534660f3b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -56,7 +56,48 @@
## 테스트 목록 -
구현하면서 추가 예정
+* 구입 금액 테스트 + - [ ] 숫자가 맞는지 + - [ ] 0원 보다 큰 금액인지 + - [ ] 1000원 단위인지 + + +* 사용자 로또 번호 목록 테스트 + - [ ] 숫자가 맞는지 + - [ ] 1~45 사이의 숫자가 맞는지 + - [ ] 소수점이 없는지 + - [ ] 중복된 숫자가 없는지 + - [ ] 6개인지 + - [ ] 오름차순으로 정렬되어 있는지 + - [ ] 랜덤으로 생성되는지 + + +* 당첨 번호 테스트 + - [ ] 숫자가 맞는지 + - [ ] 1~45 사이의 숫자가 맞는지 + - [ ] 소수점이 없는지 + - [ ] 중복된 숫자가 없는지 + - [ ] 6개인지 + + +* 보너스 번호 테스트 + - [ ] 숫자가 맞는지 + - [ ] 1~45 사이의 숫자가 맞는지 + - [ ] 소수점이 없는지 + - [ ] 당첨 번호와 중복되지 않는지 + + +* 로또 개수 테스트 + - [ ] 3개 일치 여부가 맞는지 + - [ ] 4개 일치 여부가 맞는지 + - [ ] 5개 일치 여부가 맞는지 + - [ ] 5개 일치 + 보너스 번호 일치 여부가 맞는지 + - [ ] 6개 일치 여부가 맞는지 + + +* 수익률 테스트 + - [ ] 수익률 연산이 맞는지 +
@@ -109,6 +150,6 @@ - Git Flow 전략을 기본으로 사용하되 아래의 사항을 지킨다. - 최종 브랜치는 'jinmidnight01' 이다. - 주 작업 브랜치는 'develop'이다. - - 필요시 기능 그룹 'feature/{feature}' 브랜치를 생성하여 작업한다. + - 필요시 MVC를 기준으로, 기능 그룹 'feature/{feature}' 브랜치를 생성하여 작업한다. - 특정 기능 그룹이 완성되면 'develop' 브랜치에 병합한다. - 애플리케이션이 완성되면 'develop' 브랜치를 최종 브랜치에 병합한다. \ No newline at end of file From acb8d82de6c625cb7b635e65739387cf4d40ac84 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 19:57:41 +0900 Subject: [PATCH 08/41] =?UTF-8?q?refactor(views):=20InputView=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EC=97=90=EC=84=9C=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EB=A6=AC=ED=84=B0=EB=9F=B4=20=EB=B0=A9=EC=8B=9D=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9E=AC=EA=B5=AC=EC=A1=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/InputView.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/InputView.js b/src/views/InputView.js index dac10f6a0d..df16b4bb03 100644 --- a/src/views/InputView.js +++ b/src/views/InputView.js @@ -1,10 +1,10 @@ import { Console } from '@woowacourse/mission-utils'; import MESSAGES from '../constants/messages.js'; -class InputView { - static getLottoPrice() { +const InputView = { + getLottoPrice() { return Console.readLineAsync(`${MESSAGES.LOTTO_PRICE_INPUT}\n`); - } + }, } export default InputView; \ No newline at end of file From c357414c1eaa2e670c025316d8f62b35087b69b6 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 20:51:07 +0900 Subject: [PATCH 09/41] =?UTF-8?q?test:=20=EA=B5=AC=EC=9E=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=EC=97=90=20=EA=B3=B5=EB=B0=B1=EC=9D=B4=20=EC=97=86?= =?UTF-8?q?=EB=8A=94=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - LottoPriceTest 파일 생성 --- __tests__/LottoPriceTest.js | 9 +++++++++ docs/README.md | 6 ++++++ 2 files changed, 15 insertions(+) create mode 100644 __tests__/LottoPriceTest.js diff --git a/__tests__/LottoPriceTest.js b/__tests__/LottoPriceTest.js new file mode 100644 index 0000000000..c431b488ad --- /dev/null +++ b/__tests__/LottoPriceTest.js @@ -0,0 +1,9 @@ +import Validations from '../src/constants/Validations'; + +describe('구입 금액 테스트', () => { + test.each([ + ['10 00', ' 2000 ', ' 30 000'] + ])('공백이 없는지', (lottoPrice) => { + expect(() => { Validations.hasSpace(lottoPrice) }).toThrow('[ERROR] 공백 없이 입력해 주세요.'); + }); +}); diff --git a/docs/README.md b/docs/README.md index 1534660f3b..6693aee1cc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -34,12 +34,14 @@ ## 예외 처리 * 로또 구입 금액 + - [ ] 공백이 있을 경우 - [ ] 숫자가 아닐 경우 - [ ] 0원 이하일 경우 - [ ] 1000원 단위가 아닐 경우 * 로또 당첨 번호 + - [ ] 공백이 있을 경우 - [ ] 숫자가 아닐 경우 - [ ] 1~45 사이의 숫자가 아닐 경우 - [ ] 소수점이 있을 경우 @@ -48,6 +50,7 @@ * 보너스 번호 + - [ ] 공백이 있을 경우 - [ ] 숫자가 아닐 경우 - [ ] 1~45 사이의 숫자가 아닐 경우 - [ ] 소수점이 있을 경우 @@ -57,6 +60,7 @@ ## 테스트 목록 * 구입 금액 테스트 + - [x] 공백이 없는지 - [ ] 숫자가 맞는지 - [ ] 0원 보다 큰 금액인지 - [ ] 1000원 단위인지 @@ -73,6 +77,7 @@ * 당첨 번호 테스트 + - [ ] 공백이 없는지 - [ ] 숫자가 맞는지 - [ ] 1~45 사이의 숫자가 맞는지 - [ ] 소수점이 없는지 @@ -81,6 +86,7 @@ * 보너스 번호 테스트 + - [ ] 공백이 없는지 - [ ] 숫자가 맞는지 - [ ] 1~45 사이의 숫자가 맞는지 - [ ] 소수점이 없는지 From dcc00f01e00b41d98104f8c39b55ac1e049d13a0 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 20:56:42 +0900 Subject: [PATCH 10/41] =?UTF-8?q?feat(constants):=20=EA=B5=AC=EC=9E=85=20?= =?UTF-8?q?=EA=B8=88=EC=95=A1=20=EA=B3=B5=EB=B0=B1=EC=9D=B4=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20=EC=98=88=EC=99=B8=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Errors.js, Validations.js 파일 추가 --- docs/README.md | 2 +- src/constants/Errors.js | 5 +++++ src/constants/Validations.js | 11 +++++++++++ src/constants/messages.js | 4 ++-- src/models/Customer.js | 9 ++++++++- src/views/InputView.js | 4 ++-- 6 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 src/constants/Errors.js create mode 100644 src/constants/Validations.js diff --git a/docs/README.md b/docs/README.md index 6693aee1cc..91146a9e7e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -34,7 +34,7 @@ ## 예외 처리 * 로또 구입 금액 - - [ ] 공백이 있을 경우 + - [x] 공백이 있을 경우 - [ ] 숫자가 아닐 경우 - [ ] 0원 이하일 경우 - [ ] 1000원 단위가 아닐 경우 diff --git a/src/constants/Errors.js b/src/constants/Errors.js new file mode 100644 index 0000000000..0619d07467 --- /dev/null +++ b/src/constants/Errors.js @@ -0,0 +1,5 @@ +const Errors = Object.freeze({ + INPUT_HAS_SPACE: '[ERROR] 공백 없이 입력해 주세요.', +}); + +export default Errors; \ No newline at end of file diff --git a/src/constants/Validations.js b/src/constants/Validations.js new file mode 100644 index 0000000000..6695edc364 --- /dev/null +++ b/src/constants/Validations.js @@ -0,0 +1,11 @@ +import Errors from "./Errors.js"; + +const Validations = Object.freeze({ + hasSpace(input) { + if (/\s+/.test(input)) { + throw new Error(Errors.INPUT_HAS_SPACE); + } + }, +}); + +export default Validations; \ No newline at end of file diff --git a/src/constants/messages.js b/src/constants/messages.js index c5ec5fcb81..00779fe895 100644 --- a/src/constants/messages.js +++ b/src/constants/messages.js @@ -1,5 +1,5 @@ -const MESSAGES = Object.freeze({ +const Messages = Object.freeze({ LOTTO_PRICE_INPUT: '구입금액을 입력해 주세요.', }); -export default MESSAGES; \ No newline at end of file +export default Messages; \ No newline at end of file diff --git a/src/models/Customer.js b/src/models/Customer.js index 9a52fe392f..32bb9a3447 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -1,9 +1,16 @@ +import Validations from '../constants/Validations.js'; + class Customer { #lottoPrice; constructor(lottoPrice) { + this.#validateLottoPrice(lottoPrice); this.#lottoPrice = lottoPrice; } + + #validateLottoPrice(lottoPrice) { + Validations.hasSpace(lottoPrice); + } } -export default Customer; \ No newline at end of file +export default Customer; diff --git a/src/views/InputView.js b/src/views/InputView.js index df16b4bb03..9ea905b820 100644 --- a/src/views/InputView.js +++ b/src/views/InputView.js @@ -1,9 +1,9 @@ import { Console } from '@woowacourse/mission-utils'; -import MESSAGES from '../constants/messages.js'; +import Messages from '../constants/Messages.js'; const InputView = { getLottoPrice() { - return Console.readLineAsync(`${MESSAGES.LOTTO_PRICE_INPUT}\n`); + return Console.readLineAsync(`${Messages.LOTTO_PRICE_INPUT}\n`); }, } From e4bdcf54f5426b7e1f089fc654d00926aa246c96 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 21:02:51 +0900 Subject: [PATCH 11/41] =?UTF-8?q?test(LottoPrice):=20=EA=B5=AC=EC=9E=85=20?= =?UTF-8?q?=EA=B8=88=EC=95=A1=EC=9D=B4=20=EC=88=AB=EC=9E=90=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=EC=9D=B4=20=EB=A7=9E=EB=8A=94=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/LottoPriceTest.js | 6 ++++++ docs/README.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/__tests__/LottoPriceTest.js b/__tests__/LottoPriceTest.js index c431b488ad..a93d38a566 100644 --- a/__tests__/LottoPriceTest.js +++ b/__tests__/LottoPriceTest.js @@ -6,4 +6,10 @@ describe('구입 금액 테스트', () => { ])('공백이 없는지', (lottoPrice) => { expect(() => { Validations.hasSpace(lottoPrice) }).toThrow('[ERROR] 공백 없이 입력해 주세요.'); }); + + test.each([ + ['1000s', '2s000', 's30000'] + ])('숫자가 맞는지', (lottoPrice) => { + expect(() => { Validations.isNumber(lottoPrice) }).toThrow('[ERROR] 숫자만 입력해 주세요.'); + }); }); diff --git a/docs/README.md b/docs/README.md index 91146a9e7e..b34e35640f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -61,7 +61,7 @@ ## 테스트 목록 * 구입 금액 테스트 - [x] 공백이 없는지 - - [ ] 숫자가 맞는지 + - [x] 숫자가 맞는지 - [ ] 0원 보다 큰 금액인지 - [ ] 1000원 단위인지 From 1795c7a2bb5855cce70cf427afb3470a82791b26 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 21:32:37 +0900 Subject: [PATCH 12/41] =?UTF-8?q?feat(validations):=20=EA=B5=AC=EC=9E=85?= =?UTF-8?q?=20=EA=B8=88=EC=95=A1=EC=9D=B4=20=EC=88=AB=EC=9E=90=EA=B0=80=20?= =?UTF-8?q?=EC=95=84=EB=8B=8C=20=EA=B2=BD=EC=9A=B0=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Validations.js 파일 위치 옮김 - Validations.js, InputView.js 객체리터럴에서 클래스로 변경: 정적 메소드 활용 - test: 구입 금액 숫자가 아닌지 테스트 케이스 추가 --- __tests__/LottoPriceTest.js | 18 +++++++++--------- docs/README.md | 2 +- src/Validations.js | 18 ++++++++++++++++++ src/constants/Errors.js | 3 ++- src/constants/Validations.js | 11 ----------- src/models/Customer.js | 3 ++- src/views/InputView.js | 7 ++++--- 7 files changed, 36 insertions(+), 26 deletions(-) create mode 100644 src/Validations.js delete mode 100644 src/constants/Validations.js diff --git a/__tests__/LottoPriceTest.js b/__tests__/LottoPriceTest.js index a93d38a566..3974c3d454 100644 --- a/__tests__/LottoPriceTest.js +++ b/__tests__/LottoPriceTest.js @@ -1,15 +1,15 @@ -import Validations from '../src/constants/Validations'; +import Validations from '../src/Validations'; describe('구입 금액 테스트', () => { - test.each([ - ['10 00', ' 2000 ', ' 30 000'] - ])('공백이 없는지', (lottoPrice) => { - expect(() => { Validations.hasSpace(lottoPrice) }).toThrow('[ERROR] 공백 없이 입력해 주세요.'); + test.each([['10 00', ' 2000 ', ' 30 000']])('공백이 없는지', lottoPrice => { + expect(() => { + Validations.hasSpace(lottoPrice); + }).toThrow('[ERROR] 공백 없이 입력해 주세요.'); }); - test.each([ - ['1000s', '2s000', 's30000'] - ])('숫자가 맞는지', (lottoPrice) => { - expect(() => { Validations.isNumber(lottoPrice) }).toThrow('[ERROR] 숫자만 입력해 주세요.'); + test.each([['1000s', '2s000', 's30000', '']])('숫자가 맞는지', lottoPrice => { + expect(() => { + Validations.isNumber(lottoPrice); + }).toThrow('[ERROR] 숫자만 입력해 주세요.'); }); }); diff --git a/docs/README.md b/docs/README.md index b34e35640f..b6bf69ab4e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -35,7 +35,7 @@ ## 예외 처리 * 로또 구입 금액 - [x] 공백이 있을 경우 - - [ ] 숫자가 아닐 경우 + - [x] 숫자가 아닐 경우 - [ ] 0원 이하일 경우 - [ ] 1000원 단위가 아닐 경우 diff --git a/src/Validations.js b/src/Validations.js new file mode 100644 index 0000000000..f494713787 --- /dev/null +++ b/src/Validations.js @@ -0,0 +1,18 @@ +import Errors from './constants/Errors.js'; + +class Validations { + static hasSpace(input) { + if (/\s+/.test(input)) { + throw new Error(Errors.HAS_SPACE); + } + } + + static isNumber(input) { + const number = Number(input); + if (input.length === 0 || Number.isNaN(number)) { + throw new Error(Errors.NOT_NUMBER); + } + } +} + +export default Validations; \ No newline at end of file diff --git a/src/constants/Errors.js b/src/constants/Errors.js index 0619d07467..9b451fe204 100644 --- a/src/constants/Errors.js +++ b/src/constants/Errors.js @@ -1,5 +1,6 @@ const Errors = Object.freeze({ - INPUT_HAS_SPACE: '[ERROR] 공백 없이 입력해 주세요.', + HAS_SPACE: '[ERROR] 공백 없이 입력해 주세요.', + NOT_NUMBER: '[ERROR] 숫자만 입력해 주세요.', }); export default Errors; \ No newline at end of file diff --git a/src/constants/Validations.js b/src/constants/Validations.js deleted file mode 100644 index 6695edc364..0000000000 --- a/src/constants/Validations.js +++ /dev/null @@ -1,11 +0,0 @@ -import Errors from "./Errors.js"; - -const Validations = Object.freeze({ - hasSpace(input) { - if (/\s+/.test(input)) { - throw new Error(Errors.INPUT_HAS_SPACE); - } - }, -}); - -export default Validations; \ No newline at end of file diff --git a/src/models/Customer.js b/src/models/Customer.js index 32bb9a3447..cf1e2c1b22 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -1,4 +1,4 @@ -import Validations from '../constants/Validations.js'; +import Validations from '../Validations.js'; class Customer { #lottoPrice; @@ -10,6 +10,7 @@ class Customer { #validateLottoPrice(lottoPrice) { Validations.hasSpace(lottoPrice); + Validations.isNumber(lottoPrice); } } diff --git a/src/views/InputView.js b/src/views/InputView.js index 9ea905b820..a655089e1a 100644 --- a/src/views/InputView.js +++ b/src/views/InputView.js @@ -1,10 +1,11 @@ import { Console } from '@woowacourse/mission-utils'; import Messages from '../constants/Messages.js'; -const InputView = { - getLottoPrice() { +class InputView { + static getLottoPrice() { return Console.readLineAsync(`${Messages.LOTTO_PRICE_INPUT}\n`); - }, + }; + } export default InputView; \ No newline at end of file From f273978fbfeaefedc3aeadecaa5531413a4fca41 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 21:36:44 +0900 Subject: [PATCH 13/41] =?UTF-8?q?test:=20=EA=B5=AC=EC=9E=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=EC=9D=B4=200=EC=9B=90=EB=B3=B4=EB=8B=A4=20=ED=81=B0?= =?UTF-8?q?=20=EA=B8=88=EC=95=A1=EC=9D=B8=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/LottoPriceTest.js | 6 ++++++ docs/README.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/__tests__/LottoPriceTest.js b/__tests__/LottoPriceTest.js index 3974c3d454..d12a65a1bf 100644 --- a/__tests__/LottoPriceTest.js +++ b/__tests__/LottoPriceTest.js @@ -12,4 +12,10 @@ describe('구입 금액 테스트', () => { Validations.isNumber(lottoPrice); }).toThrow('[ERROR] 숫자만 입력해 주세요.'); }); + + test.each([['0', '-1000', '-1']])('0원 보다 큰 금액인지', lottoPrice => { + expect(() => { + Validations.isPlus(lottoPrice); + }).toThrow('[ERROR] 양수만 입력해 주세요.'); + }); }); diff --git a/docs/README.md b/docs/README.md index b6bf69ab4e..a435bc9470 100644 --- a/docs/README.md +++ b/docs/README.md @@ -62,7 +62,7 @@ * 구입 금액 테스트 - [x] 공백이 없는지 - [x] 숫자가 맞는지 - - [ ] 0원 보다 큰 금액인지 + - [x] 0원 보다 큰 금액인지 - [ ] 1000원 단위인지 From 525e5d7d55546d494547047a6966a773e37c3c2d Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 21:39:12 +0900 Subject: [PATCH 14/41] =?UTF-8?q?feat(validations):=20=EA=B5=AC=EC=9E=85?= =?UTF-8?q?=20=EA=B8=88=EC=95=A1=EC=9D=B4=200=EC=9B=90=20=EC=9D=B4?= =?UTF-8?q?=ED=95=98=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- src/Validations.js | 7 +++++++ src/constants/Errors.js | 1 + src/models/Customer.js | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index a435bc9470..36a0cdfe8f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -36,7 +36,7 @@ * 로또 구입 금액 - [x] 공백이 있을 경우 - [x] 숫자가 아닐 경우 - - [ ] 0원 이하일 경우 + - [x] 0원 이하일 경우 - [ ] 1000원 단위가 아닐 경우 diff --git a/src/Validations.js b/src/Validations.js index f494713787..7f240d7c6a 100644 --- a/src/Validations.js +++ b/src/Validations.js @@ -13,6 +13,13 @@ class Validations { throw new Error(Errors.NOT_NUMBER); } } + + static isPlus(input) { + const number = Number(input); + if (number <= 0) { + throw new Error(Errors.IS_NOT_PLUS); + } + } } export default Validations; \ No newline at end of file diff --git a/src/constants/Errors.js b/src/constants/Errors.js index 9b451fe204..6240f3505e 100644 --- a/src/constants/Errors.js +++ b/src/constants/Errors.js @@ -1,6 +1,7 @@ const Errors = Object.freeze({ HAS_SPACE: '[ERROR] 공백 없이 입력해 주세요.', NOT_NUMBER: '[ERROR] 숫자만 입력해 주세요.', + IS_NOT_PLUS: '[ERROR] 양수만 입력해 주세요.' }); export default Errors; \ No newline at end of file diff --git a/src/models/Customer.js b/src/models/Customer.js index cf1e2c1b22..5a37968217 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -11,6 +11,7 @@ class Customer { #validateLottoPrice(lottoPrice) { Validations.hasSpace(lottoPrice); Validations.isNumber(lottoPrice); + Validations.isPlus(lottoPrice); } } From add7431132cf17e72c7b3511f57589661570f808 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 21:41:26 +0900 Subject: [PATCH 15/41] =?UTF-8?q?test:=20=EA=B5=AC=EC=9E=85=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=EC=9D=B4=201000=EC=9B=90=20=EB=8B=A8=EC=9C=84?= =?UTF-8?q?=EC=9D=B8=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/LottoPriceTest.js | 6 ++++++ docs/README.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/__tests__/LottoPriceTest.js b/__tests__/LottoPriceTest.js index d12a65a1bf..fa3efeb67f 100644 --- a/__tests__/LottoPriceTest.js +++ b/__tests__/LottoPriceTest.js @@ -18,4 +18,10 @@ describe('구입 금액 테스트', () => { Validations.isPlus(lottoPrice); }).toThrow('[ERROR] 양수만 입력해 주세요.'); }); + + test.each([['1500', '1200', '200001']])('1000원 단위인지', lottoPrice => { + expect(() => { + Validations.isThousandUnit(lottoPrice); + }).toThrow('[ERROR] 1000원 단위로만 입력해주세요.'); + }); }); diff --git a/docs/README.md b/docs/README.md index 36a0cdfe8f..ad4716234c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -63,7 +63,7 @@ - [x] 공백이 없는지 - [x] 숫자가 맞는지 - [x] 0원 보다 큰 금액인지 - - [ ] 1000원 단위인지 + - [x] 1000원 단위인지 * 사용자 로또 번호 목록 테스트 From 09a864028d91d1fd9484ae0b00960954eecd037c Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 21:43:29 +0900 Subject: [PATCH 16/41] =?UTF-8?q?feat(validations):=20=EA=B5=AC=EC=9E=85?= =?UTF-8?q?=20=EA=B8=88=EC=95=A1=EC=9D=B4=201000=EC=9B=90=20=EB=8B=A8?= =?UTF-8?q?=EC=9C=84=EA=B0=80=20=EC=95=84=EB=8B=90=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - feat(models): 로또 구입 금액 예외처리 기능 완성 --- docs/README.md | 4 ++-- src/Validations.js | 7 +++++++ src/constants/Errors.js | 3 ++- src/models/Customer.js | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index ad4716234c..21c0e554c1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,7 +5,7 @@ - [x] 구입 금액 (필드) - [ ] 로또 개수 (필드) - [ ] 소유한 로또 번호 목록 (필드) - - [ ] 로또 구입금액 `예외처리` + - [x] 로또 구입금액 `예외처리` - [ ] 로또 정보 (보너스 번호 포함) `class` - [ ] 로또 객체: Lotto 클래스 (필드) - [ ] 당첨 번호 목록 (필드) @@ -37,7 +37,7 @@ - [x] 공백이 있을 경우 - [x] 숫자가 아닐 경우 - [x] 0원 이하일 경우 - - [ ] 1000원 단위가 아닐 경우 + - [x] 1000원 단위가 아닐 경우 * 로또 당첨 번호 diff --git a/src/Validations.js b/src/Validations.js index 7f240d7c6a..4cbf86d76b 100644 --- a/src/Validations.js +++ b/src/Validations.js @@ -20,6 +20,13 @@ class Validations { throw new Error(Errors.IS_NOT_PLUS); } } + + static isThousandUnit(input) { + const number = Number(input); + if (number % 1000 !== 0) { + throw new Error(Errors.IS_NOT_THOUSAND_UNIT); + } + } } export default Validations; \ No newline at end of file diff --git a/src/constants/Errors.js b/src/constants/Errors.js index 6240f3505e..94549604e6 100644 --- a/src/constants/Errors.js +++ b/src/constants/Errors.js @@ -1,7 +1,8 @@ const Errors = Object.freeze({ HAS_SPACE: '[ERROR] 공백 없이 입력해 주세요.', NOT_NUMBER: '[ERROR] 숫자만 입력해 주세요.', - IS_NOT_PLUS: '[ERROR] 양수만 입력해 주세요.' + IS_NOT_PLUS: '[ERROR] 양수만 입력해 주세요.', + IS_NOT_THOUSAND_UNIT: '[ERROR] 1000원 단위로만 입력해주세요.', }); export default Errors; \ No newline at end of file diff --git a/src/models/Customer.js b/src/models/Customer.js index 5a37968217..5db1757ddd 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -12,6 +12,7 @@ class Customer { Validations.hasSpace(lottoPrice); Validations.isNumber(lottoPrice); Validations.isPlus(lottoPrice); + Validations.isThousandUnit(lottoPrice); } } From cf3f8b18c1f7ff5fd7bd61157f276c740a4746c9 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 21:58:00 +0900 Subject: [PATCH 17/41] =?UTF-8?q?feat(views):=20OutputView=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=A1=9C=EB=98=90=20=EA=B0=9C=EC=88=98=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - feat(models): 로도 개수 필드 추가 - Conditions.js 파일 추가 --- docs/README.md | 7 ++++--- src/App.js | 2 ++ src/constants/Conditions.js | 5 +++++ src/constants/messages.js | 1 + src/models/Customer.js | 12 +++++++++++- src/views/OutputView.js | 11 +++++++++++ 6 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 src/constants/Conditions.js create mode 100644 src/views/OutputView.js diff --git a/docs/README.md b/docs/README.md index 21c0e554c1..f91d2496cb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,7 +3,7 @@ * Models - [ ] 구매자 정보 `class` - [x] 구입 금액 (필드) - - [ ] 로또 개수 (필드) + - [x] 로또 개수 (필드) - [ ] 소유한 로또 번호 목록 (필드) - [x] 로또 구입금액 `예외처리` - [ ] 로또 정보 (보너스 번호 포함) `class` @@ -20,7 +20,8 @@ - [ ] 당첨번호 입력 - [ ] 보너스번호 입력 - [ ] 출력창 및 메세지 출력 `class` - - [ ] 로또 개수 & 번호 목록 출력 + - [x] 로또 개수 + - [ ] 번호 목록 출력 - [ ] 당첨 통계 출력: 제목, 내역, 결과(수익률) @@ -66,7 +67,7 @@ - [x] 1000원 단위인지 -* 사용자 로또 번호 목록 테스트 +* 사용자 로또 개수 및 번호 목록 테스트 - [ ] 숫자가 맞는지 - [ ] 1~45 사이의 숫자가 맞는지 - [ ] 소수점이 없는지 diff --git a/src/App.js b/src/App.js index 605e6596ef..b4e8c49db0 100644 --- a/src/App.js +++ b/src/App.js @@ -1,10 +1,12 @@ import InputView from "./views/InputView.js"; +import OutputView from "./views/OutputView.js"; import Customer from "./models/Customer.js"; class App { async play() { const lottoPrice = await InputView.getLottoPrice(); const customer = new Customer(lottoPrice); + OutputView.printLottoCount(customer.getLottoCount()); } } diff --git a/src/constants/Conditions.js b/src/constants/Conditions.js new file mode 100644 index 0000000000..00bf230297 --- /dev/null +++ b/src/constants/Conditions.js @@ -0,0 +1,5 @@ +const Conditions = Object.freeze({ + ONE_LOTTO_PRICE : 1000, +}); + +export default Conditions; \ No newline at end of file diff --git a/src/constants/messages.js b/src/constants/messages.js index 00779fe895..906ab23a22 100644 --- a/src/constants/messages.js +++ b/src/constants/messages.js @@ -1,5 +1,6 @@ const Messages = Object.freeze({ LOTTO_PRICE_INPUT: '구입금액을 입력해 주세요.', + LOTTO_COUNT: '개를 구매했습니다.', }); export default Messages; \ No newline at end of file diff --git a/src/models/Customer.js b/src/models/Customer.js index 5db1757ddd..468023d050 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -1,11 +1,17 @@ import Validations from '../Validations.js'; +import Conditions from '../constants/Conditions.js'; class Customer { + /** @type {number} */ #lottoPrice; + /** @type {number} */ + #lottoCount; + constructor(lottoPrice) { this.#validateLottoPrice(lottoPrice); - this.#lottoPrice = lottoPrice; + this.#lottoPrice = Number(lottoPrice); + this.#lottoCount = this.#lottoPrice / Conditions.ONE_LOTTO_PRICE; } #validateLottoPrice(lottoPrice) { @@ -14,6 +20,10 @@ class Customer { Validations.isPlus(lottoPrice); Validations.isThousandUnit(lottoPrice); } + + getLottoCount() { + return this.#lottoCount; + } } export default Customer; diff --git a/src/views/OutputView.js b/src/views/OutputView.js new file mode 100644 index 0000000000..60bd7245fd --- /dev/null +++ b/src/views/OutputView.js @@ -0,0 +1,11 @@ +import { Console } from '@woowacourse/mission-utils'; +import Messages from '../constants/Messages.js'; + +class OutputView { + static printLottoCount(lottoCount) { + return Console.print(`\n${lottoCount}${Messages.LOTTO_COUNT}`); + }; + +} + +export default OutputView; \ No newline at end of file From dce80247575b16233e5bb80bf285199b8bfe15ad Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 22:27:33 +0900 Subject: [PATCH 18/41] =?UTF-8?q?feat(controllers):=20=EA=B5=AC=EB=A7=A4?= =?UTF-8?q?=EC=9E=90=EA=B0=80=20=EC=86=8C=EC=9C=A0=ED=95=A0=20=EB=A1=9C?= =?UTF-8?q?=EB=98=90=20=EB=B2=88=ED=98=B8=20=EB=AA=A9=EB=A1=9D=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 4 ++-- src/constants/Conditions.js | 3 +++ src/controllers/LottoGameController.js | 23 +++++++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/controllers/LottoGameController.js diff --git a/docs/README.md b/docs/README.md index f91d2496cb..caebb3ab5a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -27,7 +27,7 @@ * Controllers - [ ] 로또 게임 처리/연산 `class` - - [ ] 구매자가 소유할 로또 번호 목록 생성 + - [x] 구매자가 소유할 로또 번호 목록 생성 - [ ] 당첨 내역 연산 - [ ] 당첨 결과(수익률) 연산 @@ -67,7 +67,7 @@ - [x] 1000원 단위인지 -* 사용자 로또 개수 및 번호 목록 테스트 +* 사용자 로또 번호 목록 테스트 - [ ] 숫자가 맞는지 - [ ] 1~45 사이의 숫자가 맞는지 - [ ] 소수점이 없는지 diff --git a/src/constants/Conditions.js b/src/constants/Conditions.js index 00bf230297..7307502e07 100644 --- a/src/constants/Conditions.js +++ b/src/constants/Conditions.js @@ -1,5 +1,8 @@ const Conditions = Object.freeze({ ONE_LOTTO_PRICE : 1000, + NUMBER_MIN : 1, + NUMBER_MAX : 45, + NUMBER_PICK_COUNT : 6, }); export default Conditions; \ No newline at end of file diff --git a/src/controllers/LottoGameController.js b/src/controllers/LottoGameController.js new file mode 100644 index 0000000000..75cad26452 --- /dev/null +++ b/src/controllers/LottoGameController.js @@ -0,0 +1,23 @@ +import { Random } from "@woowacourse/mission-utils"; +import Conditions from "../constants/Conditions.js"; + +class LottoGameController { + static generateCustomerNumbers(lottoCount) { + const customerNumbers = []; + for (let i = 0; i < lottoCount; i += 1) { + const temp = Random.pickUniqueNumbersInRange( + Conditions.NUMBER_MIN, + Conditions.NUMBER_MAX, + Conditions.NUMBER_PICK_COUNT); + this.sortInAscendingOrder(temp); + customerNumbers.push(temp); + } + return customerNumbers; + } + + static sortInAscendingOrder(userNumbers) { + userNumbers.sort((a, b) => a - b); + } +} + +export default LottoGameController; \ No newline at end of file From 9693137cfa23bb227fd3dd08f588d59391fff13b Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 22:31:59 +0900 Subject: [PATCH 19/41] =?UTF-8?q?feat(models):=20=EA=B5=AC=EB=A7=A4?= =?UTF-8?q?=EC=9E=90=20=EC=A0=95=EB=B3=B4=EC=97=90=EC=84=9C=20=EC=86=8C?= =?UTF-8?q?=EC=9C=A0=ED=95=9C=20=EB=A1=9C=EB=98=90=20=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- src/App.js | 7 ++++++- src/models/Customer.js | 8 ++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index caebb3ab5a..2157031123 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,7 @@ - [ ] 구매자 정보 `class` - [x] 구입 금액 (필드) - [x] 로또 개수 (필드) - - [ ] 소유한 로또 번호 목록 (필드) + - [x] 소유한 로또 번호 목록 (필드) - [x] 로또 구입금액 `예외처리` - [ ] 로또 정보 (보너스 번호 포함) `class` - [ ] 로또 객체: Lotto 클래스 (필드) diff --git a/src/App.js b/src/App.js index b4e8c49db0..3ee696ec35 100644 --- a/src/App.js +++ b/src/App.js @@ -1,12 +1,17 @@ import InputView from "./views/InputView.js"; import OutputView from "./views/OutputView.js"; import Customer from "./models/Customer.js"; +import LottoGameController from "./controllers/LottoGameController.js"; class App { async play() { const lottoPrice = await InputView.getLottoPrice(); const customer = new Customer(lottoPrice); - OutputView.printLottoCount(customer.getLottoCount()); + + const lottoCount = customer.getLottoCount(); + OutputView.printLottoCount(lottoCount); + const lottoNumbers = LottoGameController.generateCustomerNumbers(lottoCount); + customer.setLottoNumbers(lottoNumbers); } } diff --git a/src/models/Customer.js b/src/models/Customer.js index 468023d050..2e338283fa 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -8,10 +8,14 @@ class Customer { /** @type {number} */ #lottoCount; + /** @type {Array} */ + #lottoNumbers; + constructor(lottoPrice) { this.#validateLottoPrice(lottoPrice); this.#lottoPrice = Number(lottoPrice); this.#lottoCount = this.#lottoPrice / Conditions.ONE_LOTTO_PRICE; + this.#lottoNumbers = []; } #validateLottoPrice(lottoPrice) { @@ -24,6 +28,10 @@ class Customer { getLottoCount() { return this.#lottoCount; } + + setLottoNumbers(lottoNumbers) { + this.#lottoNumbers = lottoNumbers; + } } export default Customer; From 5789b19ec72b192501b94535e4c52137200a77af Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 22:49:55 +0900 Subject: [PATCH 20/41] =?UTF-8?q?feat(views):=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=EC=B0=BD=EC=97=90=20=EA=B5=AC=EB=A7=A4=EC=9E=90=20=EB=A1=9C?= =?UTF-8?q?=EB=98=90=20=EB=B2=88=ED=98=B8=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- src/App.js | 3 ++- src/constants/messages.js | 2 ++ src/models/Customer.js | 4 ++++ src/views/OutputView.js | 7 ++++++- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 2157031123..11140a3aa1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,7 +21,7 @@ - [ ] 보너스번호 입력 - [ ] 출력창 및 메세지 출력 `class` - [x] 로또 개수 - - [ ] 번호 목록 출력 + - [x] 번호 목록 출력 - [ ] 당첨 통계 출력: 제목, 내역, 결과(수익률) diff --git a/src/App.js b/src/App.js index 3ee696ec35..4e33163abf 100644 --- a/src/App.js +++ b/src/App.js @@ -9,9 +9,10 @@ class App { const customer = new Customer(lottoPrice); const lottoCount = customer.getLottoCount(); - OutputView.printLottoCount(lottoCount); const lottoNumbers = LottoGameController.generateCustomerNumbers(lottoCount); customer.setLottoNumbers(lottoNumbers); + OutputView.printLottoCount(lottoCount); + OutputView.printLottoNumbers(customer.getLottoNumbers()); } } diff --git a/src/constants/messages.js b/src/constants/messages.js index 906ab23a22..3bbd7fe235 100644 --- a/src/constants/messages.js +++ b/src/constants/messages.js @@ -1,6 +1,8 @@ const Messages = Object.freeze({ LOTTO_PRICE_INPUT: '구입금액을 입력해 주세요.', LOTTO_COUNT: '개를 구매했습니다.', + LEFT_BRACKET : '[', + RIGHT_BRACKET : ']', }); export default Messages; \ No newline at end of file diff --git a/src/models/Customer.js b/src/models/Customer.js index 2e338283fa..347f657279 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -32,6 +32,10 @@ class Customer { setLottoNumbers(lottoNumbers) { this.#lottoNumbers = lottoNumbers; } + + getLottoNumbers() { + return this.#lottoNumbers; + } } export default Customer; diff --git a/src/views/OutputView.js b/src/views/OutputView.js index 60bd7245fd..d2770f5a43 100644 --- a/src/views/OutputView.js +++ b/src/views/OutputView.js @@ -3,9 +3,14 @@ import Messages from '../constants/Messages.js'; class OutputView { static printLottoCount(lottoCount) { - return Console.print(`\n${lottoCount}${Messages.LOTTO_COUNT}`); + Console.print(`\n${lottoCount}${Messages.LOTTO_COUNT}`); }; + static printLottoNumbers(lottoNumbers) { + lottoNumbers.forEach((lottoNumber) => { + Console.print(`${Messages.LEFT_BRACKET}${lottoNumber.join(', ')}${Messages.RIGHT_BRACKET}`); + }); + }; } export default OutputView; \ No newline at end of file From 52925a9dc784e161ff790ad8e270b787739dcfba Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 23:17:47 +0900 Subject: [PATCH 21/41] =?UTF-8?q?test:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EB=B2=88=ED=98=B8=20=EB=AA=A9=EB=A1=9D?= =?UTF-8?q?=EC=9D=B4=20=EC=A0=84=EB=B6=80=20=EC=88=AB=EC=9E=90=EA=B0=80=20?= =?UTF-8?q?=EB=A7=9E=EB=8A=94=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/CustomerNumbersTest.js | 30 ++++++++++++++++++++++++++++++ __tests__/LottoPriceTest.js | 2 +- docs/README.md | 2 +- 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 __tests__/CustomerNumbersTest.js diff --git a/__tests__/CustomerNumbersTest.js b/__tests__/CustomerNumbersTest.js new file mode 100644 index 0000000000..72d34497e5 --- /dev/null +++ b/__tests__/CustomerNumbersTest.js @@ -0,0 +1,30 @@ +import { MissionUtils } from "@woowacourse/mission-utils"; +import Validations from '../src/Validations.js'; +import Customer from '../src/models/Customer.js'; +import LottoGameController from '../src/controllers/LottoGameController.js'; + +const mockRandoms = (numbers) => { + MissionUtils.Random.pickUniqueNumbersInRange = jest.fn(); + numbers.reduce((acc, number) => { + return acc.mockReturnValueOnce(number); + }, MissionUtils.Random.pickUniqueNumbersInRange); +}; + +describe('사용자 로또 번호 목록 테스트', () => { + test.each([ + [[1, 2, 'e', 4, 5, 6]], + [['s', 3, 5, 7, 8]], + [[ '', ' ', '', ' ', '', 'ff']], + ])('숫자가 맞는지', lottoNumbers => { + mockRandoms(lottoNumbers); + + LottoGameController.generateCustomerNumbers(lottoNumbers). + forEach((lottoNumber) => { + expect(() => { + lottoNumber.forEach((number) => { Validations.isNumber(number) }); + }).toThrow('[ERROR] 숫자만 입력해 주세요.'); + }); + }); + +}); + diff --git a/__tests__/LottoPriceTest.js b/__tests__/LottoPriceTest.js index fa3efeb67f..cc4a5eaf53 100644 --- a/__tests__/LottoPriceTest.js +++ b/__tests__/LottoPriceTest.js @@ -1,4 +1,4 @@ -import Validations from '../src/Validations'; +import Validations from '../src/Validations.js'; describe('구입 금액 테스트', () => { test.each([['10 00', ' 2000 ', ' 30 000']])('공백이 없는지', lottoPrice => { diff --git a/docs/README.md b/docs/README.md index 11140a3aa1..82b7502c7e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -68,7 +68,7 @@ * 사용자 로또 번호 목록 테스트 - - [ ] 숫자가 맞는지 + - [x] 숫자가 맞는지 - [ ] 1~45 사이의 숫자가 맞는지 - [ ] 소수점이 없는지 - [ ] 중복된 숫자가 없는지 From ba0d3184ccca619db7831282b40735b092918c31 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 23:19:50 +0900 Subject: [PATCH 22/41] =?UTF-8?q?test:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EB=B2=88=ED=98=B8=20=EB=AA=A9=EB=A1=9D?= =?UTF-8?q?=EC=9D=B4=20=EC=A0=84=EB=B6=80=201~45=20=EC=82=AC=EC=9D=B4?= =?UTF-8?q?=EC=9D=98=20=EC=88=AB=EC=9E=90=EC=9D=B8=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/CustomerNumbersTest.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/__tests__/CustomerNumbersTest.js b/__tests__/CustomerNumbersTest.js index 72d34497e5..14f859448a 100644 --- a/__tests__/CustomerNumbersTest.js +++ b/__tests__/CustomerNumbersTest.js @@ -26,5 +26,19 @@ describe('사용자 로또 번호 목록 테스트', () => { }); }); + test.each([ + [[1, 2, 3, 4, 5, 6, 56]], + [[60, 59, 58, 57]], + [[ 0, 3, 5]], + ])('1~45 사이의 숫자가 맞는지', lottoNumbers => { + mockRandoms(lottoNumbers); + + LottoGameController.generateCustomerNumbers(lottoNumbers). + forEach((lottoNumber) => { + expect(() => { + lottoNumber.forEach((number) => { Validations.isInRange(number) }); + }).toThrow('[ERROR] 1~45 사이의 숫자만 입력해주세요.'); + }); + }); }); From 87d48fb7577b8db5387cec259f6c31a9efe43750 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 23:26:43 +0900 Subject: [PATCH 23/41] =?UTF-8?q?feat(validations):=20=EC=88=AB=EC=9E=90?= =?UTF-8?q?=EA=B0=80=201~45=20=EC=82=AC=EC=9D=B4=EC=9D=98=20=EC=88=AB?= =?UTF-8?q?=EC=9E=90=EA=B0=80=20=EC=95=84=EB=8B=90=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 2 +- src/Validations.js | 7 +++++++ src/constants/Errors.js | 1 + src/models/Customer.js | 8 ++++++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/App.js b/src/App.js index 4e33163abf..123567ec7b 100644 --- a/src/App.js +++ b/src/App.js @@ -6,8 +6,8 @@ import LottoGameController from "./controllers/LottoGameController.js"; class App { async play() { const lottoPrice = await InputView.getLottoPrice(); - const customer = new Customer(lottoPrice); + const customer = new Customer(lottoPrice); const lottoCount = customer.getLottoCount(); const lottoNumbers = LottoGameController.generateCustomerNumbers(lottoCount); customer.setLottoNumbers(lottoNumbers); diff --git a/src/Validations.js b/src/Validations.js index 4cbf86d76b..b0deb220d4 100644 --- a/src/Validations.js +++ b/src/Validations.js @@ -27,6 +27,13 @@ class Validations { throw new Error(Errors.IS_NOT_THOUSAND_UNIT); } } + + static isInRange(input) { + const number = Number(input); + if (number < 1 || number > 45) { + throw new Error(Errors.IS_NOT_IN_RANGE); + } + } } export default Validations; \ No newline at end of file diff --git a/src/constants/Errors.js b/src/constants/Errors.js index 94549604e6..a732ab8aca 100644 --- a/src/constants/Errors.js +++ b/src/constants/Errors.js @@ -3,6 +3,7 @@ const Errors = Object.freeze({ NOT_NUMBER: '[ERROR] 숫자만 입력해 주세요.', IS_NOT_PLUS: '[ERROR] 양수만 입력해 주세요.', IS_NOT_THOUSAND_UNIT: '[ERROR] 1000원 단위로만 입력해주세요.', + IS_NOT_IN_RANGE: '[ERROR] 1~45 사이의 숫자만 입력해주세요.', }); export default Errors; \ No newline at end of file diff --git a/src/models/Customer.js b/src/models/Customer.js index 347f657279..019c02dd52 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -25,11 +25,19 @@ class Customer { Validations.isThousandUnit(lottoPrice); } + #validateLottoNumbers(lottoNumbers) { + lottoNumbers.forEach((lottoNumber) => { + Validations.isNumber(lottoNumber); + Validations.isInRange(lottoNumber); + }); + } + getLottoCount() { return this.#lottoCount; } setLottoNumbers(lottoNumbers) { + this.#validateLottoNumbers(lottoNumbers); this.#lottoNumbers = lottoNumbers; } From de2d4ede2bf208f7be23c6b5a764b744a3bf3123 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 23:28:32 +0900 Subject: [PATCH 24/41] =?UTF-8?q?test:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EB=B2=88=ED=98=B8=EA=B0=80=20=EC=86=8C?= =?UTF-8?q?=EC=88=98=EC=A0=90=EC=9D=B4=20=EC=97=86=EB=8A=94=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/CustomerNumbersTest.js | 15 +++++++++++++++ docs/README.md | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/__tests__/CustomerNumbersTest.js b/__tests__/CustomerNumbersTest.js index 14f859448a..8ab47de1dd 100644 --- a/__tests__/CustomerNumbersTest.js +++ b/__tests__/CustomerNumbersTest.js @@ -40,5 +40,20 @@ describe('사용자 로또 번호 목록 테스트', () => { }).toThrow('[ERROR] 1~45 사이의 숫자만 입력해주세요.'); }); }); + + test.each([ + [[1, 2, 3, 4.5, 56]], + [[60, 59.1, 57]], + [[ 0, 3, 5.3]], + ])('1~45 사이의 숫자가 맞는지', lottoNumbers => { + mockRandoms(lottoNumbers); + + LottoGameController.generateCustomerNumbers(lottoNumbers). + forEach((lottoNumber) => { + expect(() => { + lottoNumber.forEach((number) => { Validations.isInteger(number) }); + }).toThrow('[ERROR] 정수만 입력해주세요.'); + }); + }); }); diff --git a/docs/README.md b/docs/README.md index 82b7502c7e..49d483fc37 100644 --- a/docs/README.md +++ b/docs/README.md @@ -69,8 +69,8 @@ * 사용자 로또 번호 목록 테스트 - [x] 숫자가 맞는지 - - [ ] 1~45 사이의 숫자가 맞는지 - - [ ] 소수점이 없는지 + - [x] 1~45 사이의 숫자가 맞는지 + - [x] 소수점이 없는지 - [ ] 중복된 숫자가 없는지 - [ ] 6개인지 - [ ] 오름차순으로 정렬되어 있는지 From dff17398e2862ee6bb01da0fadfe3fda758369d8 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 23:43:15 +0900 Subject: [PATCH 25/41] =?UTF-8?q?test:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EB=B2=88=ED=98=B8=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/CustomerNumbersTest.js | 50 +++++++++++++++++++++++++++++--- docs/README.md | 7 ++--- src/Validations.js | 28 ++++++++++++++++++ src/constants/Errors.js | 4 +++ 4 files changed, 81 insertions(+), 8 deletions(-) diff --git a/__tests__/CustomerNumbersTest.js b/__tests__/CustomerNumbersTest.js index 8ab47de1dd..eac00fe20d 100644 --- a/__tests__/CustomerNumbersTest.js +++ b/__tests__/CustomerNumbersTest.js @@ -42,10 +42,10 @@ describe('사용자 로또 번호 목록 테스트', () => { }); test.each([ - [[1, 2, 3, 4.5, 56]], - [[60, 59.1, 57]], - [[ 0, 3, 5.3]], - ])('1~45 사이의 숫자가 맞는지', lottoNumbers => { + [[1, 2, 3, 4.5, 33]], + [[40, 39.1, 43]], + [[2, 3, 5.3]], + ])('소수점이 없는지', lottoNumbers => { mockRandoms(lottoNumbers); LottoGameController.generateCustomerNumbers(lottoNumbers). @@ -55,5 +55,47 @@ describe('사용자 로또 번호 목록 테스트', () => { }).toThrow('[ERROR] 정수만 입력해주세요.'); }); }); + + test.each([ + [[1, 2, 3, 3, 4]], + [[40, 39, 39]], + [[1, 5, 5]], + ])('중복된 숫자가 없는지', lottoNumbers => { + mockRandoms(lottoNumbers); + + LottoGameController.generateCustomerNumbers(lottoNumbers). + forEach((lottoNumber) => { + expect(() => { + Validations.isNotDuplicated(lottoNumber)}).toThrow('[ERROR] 중복된 숫자가 없이 입력해주세요.'); + }); + }); + + test.each([ + [[1, 2, 3, 3, 4]], + [[40, 39, 39]], + [[1, 5, 5]], + ])('길이가 6인지', lottoNumbers => { + mockRandoms(lottoNumbers); + + LottoGameController.generateCustomerNumbers(lottoNumbers). + forEach((lottoNumber) => { + expect(() => { + Validations.isNotProperLength(lottoNumber)}).toThrow('[ERROR] 길이가 6이어야 합니다.'); + }); + }); + + test.each([ + [[1, 2, 3, 5, 4]], + [[40, 39, 39, 46, 45]], + [[1, 5, 6, 7, 8, 2]], + ])('오름차순으로 정렬되어 있는지', lottoNumbers => { + mockRandoms(lottoNumbers); + + LottoGameController.generateCustomerNumbers(lottoNumbers). + forEach((lottoNumber) => { + expect(() => { + Validations.isNotSorted(lottoNumber)}).toThrow('[ERROR] 오름차순으로 정렬되어 있어야 합니다.'); + }); + }); }); diff --git a/docs/README.md b/docs/README.md index 49d483fc37..e3cea45e71 100644 --- a/docs/README.md +++ b/docs/README.md @@ -71,10 +71,9 @@ - [x] 숫자가 맞는지 - [x] 1~45 사이의 숫자가 맞는지 - [x] 소수점이 없는지 - - [ ] 중복된 숫자가 없는지 - - [ ] 6개인지 - - [ ] 오름차순으로 정렬되어 있는지 - - [ ] 랜덤으로 생성되는지 + - [x] 중복된 숫자가 없는지 + - [x] 6개인지 + - [x] 오름차순으로 정렬되어 있는지 * 당첨 번호 테스트 diff --git a/src/Validations.js b/src/Validations.js index b0deb220d4..7e96506073 100644 --- a/src/Validations.js +++ b/src/Validations.js @@ -34,6 +34,34 @@ class Validations { throw new Error(Errors.IS_NOT_IN_RANGE); } } + + static isInteger(input) { + const number = Number(input); + if (!Number.isInteger(number)) { + throw new Error(Errors.IS_NOT_INTEGER); + } + } + + static isNotDuplicated(input) { + input.forEach((number, index) => { + if (input.indexOf(number) !== index) { + throw new Error(Errors.IS_NOT_DUPLICATED); + } + }); + } + + static isNotProperLength(input) { + if (input.length !== 6) { + throw new Error(Errors.IS_NOT_PROPER_LENGTH); + } + } + + static isNotSorted(input) { + const sortedInput = [...input].sort((a, b) => a - b); + if (JSON.stringify(input) !== JSON.stringify(sortedInput)) { + throw new Error(Errors.IS_NOT_SORTED); + } + } } export default Validations; \ No newline at end of file diff --git a/src/constants/Errors.js b/src/constants/Errors.js index a732ab8aca..a4a1c01d0c 100644 --- a/src/constants/Errors.js +++ b/src/constants/Errors.js @@ -4,6 +4,10 @@ const Errors = Object.freeze({ IS_NOT_PLUS: '[ERROR] 양수만 입력해 주세요.', IS_NOT_THOUSAND_UNIT: '[ERROR] 1000원 단위로만 입력해주세요.', IS_NOT_IN_RANGE: '[ERROR] 1~45 사이의 숫자만 입력해주세요.', + IS_NOT_INTEGER: '[ERROR] 정수만 입력해주세요.', + IS_NOT_DUPLICATED: '[ERROR] 중복된 숫자가 없이 입력해주세요.', + IS_NOT_PROPER_LENGTH: '[ERROR] 길이가 6이어야 합니다.', + IS_NOT_SORTED: '[ERROR] 오름차순으로 정렬되어 있어야 합니다.' }); export default Errors; \ No newline at end of file From a1bbf14ec0e71215568df0ec45e685b5100d8b83 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Wed, 8 Nov 2023 23:57:02 +0900 Subject: [PATCH 26/41] =?UTF-8?q?feat(develop):=20=EC=B5=9C=EC=A2=85=20?= =?UTF-8?q?=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- src/App.js | 6 ++++++ src/constants/messages.js | 2 ++ src/controllers/LottoGameController.js | 2 ++ src/models/LottoTotal.js | 20 ++++++++++++++++++++ src/views/InputView.js | 7 +++++++ 6 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/models/LottoTotal.js diff --git a/docs/README.md b/docs/README.md index e3cea45e71..313d6b6dc2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ ## 기능 그룹 (MVC) * Models - - [ ] 구매자 정보 `class` + - [x] 구매자 정보 `class` - [x] 구입 금액 (필드) - [x] 로또 개수 (필드) - [x] 소유한 로또 번호 목록 (필드) diff --git a/src/App.js b/src/App.js index 123567ec7b..6eac44326d 100644 --- a/src/App.js +++ b/src/App.js @@ -1,6 +1,7 @@ import InputView from "./views/InputView.js"; import OutputView from "./views/OutputView.js"; import Customer from "./models/Customer.js"; +import LottoTotal from "./models/lottoTotal.js"; import LottoGameController from "./controllers/LottoGameController.js"; class App { @@ -13,6 +14,11 @@ class App { customer.setLottoNumbers(lottoNumbers); OutputView.printLottoCount(lottoCount); OutputView.printLottoNumbers(customer.getLottoNumbers()); + + const winningNumbers = await InputView.getWinningNumbers(); + const bonusNumber = await InputView.getBonusNumber(); + const lottoTotal = new LottoTotal(winningNumbers, bonusNumber); + } } diff --git a/src/constants/messages.js b/src/constants/messages.js index 3bbd7fe235..2909aae1da 100644 --- a/src/constants/messages.js +++ b/src/constants/messages.js @@ -3,6 +3,8 @@ const Messages = Object.freeze({ LOTTO_COUNT: '개를 구매했습니다.', LEFT_BRACKET : '[', RIGHT_BRACKET : ']', + WINNING_NUMBERS_INPUT: '당첨 번호를 입력해 주세요.', + BONUS_NUMBER_INPUT: '보너스 번호를 입력해 주세요.', }); export default Messages; \ No newline at end of file diff --git a/src/controllers/LottoGameController.js b/src/controllers/LottoGameController.js index 75cad26452..bff6e09a1a 100644 --- a/src/controllers/LottoGameController.js +++ b/src/controllers/LottoGameController.js @@ -1,5 +1,6 @@ import { Random } from "@woowacourse/mission-utils"; import Conditions from "../constants/Conditions.js"; +import Customer from './../models/Customer'; class LottoGameController { static generateCustomerNumbers(lottoCount) { @@ -18,6 +19,7 @@ class LottoGameController { static sortInAscendingOrder(userNumbers) { userNumbers.sort((a, b) => a - b); } + } export default LottoGameController; \ No newline at end of file diff --git a/src/models/LottoTotal.js b/src/models/LottoTotal.js new file mode 100644 index 0000000000..54359156f6 --- /dev/null +++ b/src/models/LottoTotal.js @@ -0,0 +1,20 @@ +class LottoTotal { + #winningNumbers; + + #bonusNumber; + + constructor(winningNumbers, bonusNumber) { + this.#winningNumbers = winningNumbers; + this.#bonusNumber = bonusNumber; + } + + getWinningNumbers() { + return this.#winningNumbers; + } + + getBonusNumber() { + return this.#bonusNumber; + } +} + +export default LottoTotal; \ No newline at end of file diff --git a/src/views/InputView.js b/src/views/InputView.js index a655089e1a..a5c60283e0 100644 --- a/src/views/InputView.js +++ b/src/views/InputView.js @@ -6,6 +6,13 @@ class InputView { return Console.readLineAsync(`${Messages.LOTTO_PRICE_INPUT}\n`); }; + static getWinningNumbers() { + return Console.readLineAsync(`${Messages.WINNING_NUMBERS_INPUT}\n`); + } + + static getBonusNumber() { + return Console.readLineAsync(`${Messages.BONUS_NUMBER_INPUT}\n`); + } } export default InputView; \ No newline at end of file From 302c9e3fd2e94d5fcd123c0e8c866837a7f2400f Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Thu, 9 Nov 2023 09:10:02 +0900 Subject: [PATCH 27/41] =?UTF-8?q?test:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EB=B2=88=ED=98=B8=20=EB=AA=A9=EB=A1=9D?= =?UTF-8?q?=EC=9D=B4=20=EB=9E=9C=EB=8D=A4=EC=9C=BC=EB=A1=9C=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EB=90=98=EB=8A=94=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/CustomerNumbersTest.js | 153 ++++++++++++++++--------------- docs/README.md | 3 +- 2 files changed, 83 insertions(+), 73 deletions(-) diff --git a/__tests__/CustomerNumbersTest.js b/__tests__/CustomerNumbersTest.js index eac00fe20d..a1d2244a0e 100644 --- a/__tests__/CustomerNumbersTest.js +++ b/__tests__/CustomerNumbersTest.js @@ -1,101 +1,110 @@ -import { MissionUtils } from "@woowacourse/mission-utils"; +import { MissionUtils } from '@woowacourse/mission-utils'; import Validations from '../src/Validations.js'; import Customer from '../src/models/Customer.js'; import LottoGameController from '../src/controllers/LottoGameController.js'; -const mockRandoms = (numbers) => { +const mockRandoms = numbers => { MissionUtils.Random.pickUniqueNumbersInRange = jest.fn(); - numbers.reduce((acc, number) => { - return acc.mockReturnValueOnce(number); - }, MissionUtils.Random.pickUniqueNumbersInRange); + numbers.reduce( + (acc, number) => acc.mockReturnValueOnce(number), + MissionUtils.Random.pickUniqueNumbersInRange, + ); }; describe('사용자 로또 번호 목록 테스트', () => { test.each([ [[1, 2, 'e', 4, 5, 6]], [['s', 3, 5, 7, 8]], - [[ '', ' ', '', ' ', '', 'ff']], + [['', ' ', '', ' ', '', 'ff']], ])('숫자가 맞는지', lottoNumbers => { mockRandoms(lottoNumbers); - LottoGameController.generateCustomerNumbers(lottoNumbers). - forEach((lottoNumber) => { - expect(() => { - lottoNumber.forEach((number) => { Validations.isNumber(number) }); - }).toThrow('[ERROR] 숫자만 입력해 주세요.'); - }); + LottoGameController.generateCustomerNumbers(lottoNumbers).forEach( + lottoNumber => { + expect(() => { + lottoNumber.forEach(number => { + Validations.isNumber(number); + }); + }).toThrow('[ERROR] 숫자만 입력해 주세요.'); + }, + ); }); - test.each([ - [[1, 2, 3, 4, 5, 6, 56]], - [[60, 59, 58, 57]], - [[ 0, 3, 5]], - ])('1~45 사이의 숫자가 맞는지', lottoNumbers => { - mockRandoms(lottoNumbers); + test.each([[[1, 2, 3, 4, 5, 6, 56]], [[60, 59, 58, 57]], [[0, 3, 5]]])( + '1~45 사이의 숫자가 맞는지', + lottoNumbers => { + mockRandoms(lottoNumbers); - LottoGameController.generateCustomerNumbers(lottoNumbers). - forEach((lottoNumber) => { - expect(() => { - lottoNumber.forEach((number) => { Validations.isInRange(number) }); - }).toThrow('[ERROR] 1~45 사이의 숫자만 입력해주세요.'); - }); - }); + LottoGameController.generateCustomerNumbers(lottoNumbers).forEach( + lottoNumber => { + expect(() => { + lottoNumber.forEach(number => { + Validations.isInRange(number); + }); + }).toThrow('[ERROR] 1~45 사이의 숫자만 입력해주세요.'); + }, + ); + }, + ); - test.each([ - [[1, 2, 3, 4.5, 33]], - [[40, 39.1, 43]], - [[2, 3, 5.3]], - ])('소수점이 없는지', lottoNumbers => { - mockRandoms(lottoNumbers); + test.each([[[1, 2, 3, 4.5, 33]], [[40, 39.1, 43]], [[2, 3, 5.3]]])( + '소수점이 없는지', + lottoNumbers => { + mockRandoms(lottoNumbers); - LottoGameController.generateCustomerNumbers(lottoNumbers). - forEach((lottoNumber) => { - expect(() => { - lottoNumber.forEach((number) => { Validations.isInteger(number) }); - }).toThrow('[ERROR] 정수만 입력해주세요.'); - }); - }); + LottoGameController.generateCustomerNumbers(lottoNumbers).forEach( + lottoNumber => { + expect(() => { + lottoNumber.forEach(number => { + Validations.isInteger(number); + }); + }).toThrow('[ERROR] 정수만 입력해주세요.'); + }, + ); + }, + ); - test.each([ - [[1, 2, 3, 3, 4]], - [[40, 39, 39]], - [[1, 5, 5]], - ])('중복된 숫자가 없는지', lottoNumbers => { - mockRandoms(lottoNumbers); + test.each([[[1, 2, 3, 3, 4]], [[40, 39, 39]], [[1, 5, 5]]])( + '중복된 숫자가 없는지', + lottoNumbers => { + mockRandoms(lottoNumbers); - LottoGameController.generateCustomerNumbers(lottoNumbers). - forEach((lottoNumber) => { - expect(() => { - Validations.isNotDuplicated(lottoNumber)}).toThrow('[ERROR] 중복된 숫자가 없이 입력해주세요.'); - }); - }); + LottoGameController.generateCustomerNumbers(lottoNumbers).forEach( + lottoNumber => { + expect(() => { + Validations.isNotDuplicated(lottoNumber); + }).toThrow('[ERROR] 중복된 숫자가 없이 입력해주세요.'); + }, + ); + }, + ); - test.each([ - [[1, 2, 3, 3, 4]], - [[40, 39, 39]], - [[1, 5, 5]], - ])('길이가 6인지', lottoNumbers => { - mockRandoms(lottoNumbers); + test.each([[[1, 2, 3, 3, 4]], [[40, 39, 38]], [[1, 5, 4]]])( + '길이가 6인지', + lottoNumbers => { + mockRandoms(lottoNumbers); - LottoGameController.generateCustomerNumbers(lottoNumbers). - forEach((lottoNumber) => { - expect(() => { - Validations.isNotProperLength(lottoNumber)}).toThrow('[ERROR] 길이가 6이어야 합니다.'); - }); - }); + LottoGameController.generateCustomerNumbers(lottoNumbers).forEach( + lottoNumber => { + expect(() => { + Validations.isNotProperLength(lottoNumber); + }).toThrow('[ERROR] 길이가 6이어야 합니다.'); + }, + ); + }, + ); test.each([ - [[1, 2, 3, 5, 4]], - [[40, 39, 39, 46, 45]], - [[1, 5, 6, 7, 8, 2]], - ])('오름차순으로 정렬되어 있는지', lottoNumbers => { + [[1, 2, 3, 5, 6, 9]], + [[5, 7, 9, 11, 13, 17]], + [[7, 8, 40, 41, 42, 43]], + ])('랜덤으로 생성되는지', lottoNumbers => { mockRandoms(lottoNumbers); - LottoGameController.generateCustomerNumbers(lottoNumbers). - forEach((lottoNumber) => { - expect(() => { - Validations.isNotSorted(lottoNumber)}).toThrow('[ERROR] 오름차순으로 정렬되어 있어야 합니다.'); - }); + LottoGameController.generateCustomerNumbers(lottoNumbers).forEach( + lottoNumber => { + expect(lottoNumber).toEqual(lottoNumbers); + }, + ); }); }); - diff --git a/docs/README.md b/docs/README.md index 313d6b6dc2..2a560f5f9c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ ## 기능 그룹 (MVC) * Models - - [x] 구매자 정보 `class` + - [ ] 구매자 정보 `class` - [x] 구입 금액 (필드) - [x] 로또 개수 (필드) - [x] 소유한 로또 번호 목록 (필드) @@ -74,6 +74,7 @@ - [x] 중복된 숫자가 없는지 - [x] 6개인지 - [x] 오름차순으로 정렬되어 있는지 + - [x] 랜덤으로 생성되는지 * 당첨 번호 테스트 From ee3c0c665f389b4cf175df49af0384c884a4495c Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Thu, 9 Nov 2023 10:21:19 +0900 Subject: [PATCH 28/41] =?UTF-8?q?feat(views):=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EC=B0=BD=EC=97=90=EC=84=9C=20=EB=8B=B9=EC=B2=A8=EB=B2=88?= =?UTF-8?q?=ED=98=B8/=EB=B3=B4=EB=84=88=EC=8A=A4=20=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=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 --- .eslintrc.cjs | 1 + __tests__/CustomerNumbersTest.js | 1 - docs/README.md | 4 ++-- src/App.js | 3 +-- src/constants/Errors.js | 2 +- src/controllers/LottoGameController.js | 1 - src/models/Customer.js | 1 - src/views/InputView.js | 10 +++++----- src/views/OutputView.js | 16 ++++++++++------ 9 files changed, 20 insertions(+), 19 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index d0d8c6b13d..b29f0baa59 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -26,5 +26,6 @@ module.exports = { rules: { 'import/prefer-default-export': 'off', 'import/extensions': ['off'], + 'class-methods-use-this': 'off', }, }; \ No newline at end of file diff --git a/__tests__/CustomerNumbersTest.js b/__tests__/CustomerNumbersTest.js index a1d2244a0e..f21e0fe9b8 100644 --- a/__tests__/CustomerNumbersTest.js +++ b/__tests__/CustomerNumbersTest.js @@ -1,6 +1,5 @@ import { MissionUtils } from '@woowacourse/mission-utils'; import Validations from '../src/Validations.js'; -import Customer from '../src/models/Customer.js'; import LottoGameController from '../src/controllers/LottoGameController.js'; const mockRandoms = numbers => { diff --git a/docs/README.md b/docs/README.md index 2a560f5f9c..6acbb31029 100644 --- a/docs/README.md +++ b/docs/README.md @@ -17,8 +17,8 @@ * Views - [ ] 입력창 및 메세지 출력 `class` - [x] 구입금액 입력 - - [ ] 당첨번호 입력 - - [ ] 보너스번호 입력 + - [x] 당첨번호 입력 + - [x] 보너스번호 입력 - [ ] 출력창 및 메세지 출력 `class` - [x] 로또 개수 - [x] 번호 목록 출력 diff --git a/src/App.js b/src/App.js index 6eac44326d..4b49ce24b0 100644 --- a/src/App.js +++ b/src/App.js @@ -1,7 +1,7 @@ import InputView from "./views/InputView.js"; import OutputView from "./views/OutputView.js"; import Customer from "./models/Customer.js"; -import LottoTotal from "./models/lottoTotal.js"; +import LottoTotal from "./models/LottoTotal.js"; import LottoGameController from "./controllers/LottoGameController.js"; class App { @@ -18,7 +18,6 @@ class App { const winningNumbers = await InputView.getWinningNumbers(); const bonusNumber = await InputView.getBonusNumber(); const lottoTotal = new LottoTotal(winningNumbers, bonusNumber); - } } diff --git a/src/constants/Errors.js b/src/constants/Errors.js index a4a1c01d0c..48bdd6d498 100644 --- a/src/constants/Errors.js +++ b/src/constants/Errors.js @@ -7,7 +7,7 @@ const Errors = Object.freeze({ IS_NOT_INTEGER: '[ERROR] 정수만 입력해주세요.', IS_NOT_DUPLICATED: '[ERROR] 중복된 숫자가 없이 입력해주세요.', IS_NOT_PROPER_LENGTH: '[ERROR] 길이가 6이어야 합니다.', - IS_NOT_SORTED: '[ERROR] 오름차순으로 정렬되어 있어야 합니다.' + IS_NOT_SORTED: '[ERROR] 오름차순으로 정렬되어 있어야 합니다.', }); export default Errors; \ No newline at end of file diff --git a/src/controllers/LottoGameController.js b/src/controllers/LottoGameController.js index bff6e09a1a..f6e75713f1 100644 --- a/src/controllers/LottoGameController.js +++ b/src/controllers/LottoGameController.js @@ -1,6 +1,5 @@ import { Random } from "@woowacourse/mission-utils"; import Conditions from "../constants/Conditions.js"; -import Customer from './../models/Customer'; class LottoGameController { static generateCustomerNumbers(lottoCount) { diff --git a/src/models/Customer.js b/src/models/Customer.js index 019c02dd52..2b043d61ea 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -37,7 +37,6 @@ class Customer { } setLottoNumbers(lottoNumbers) { - this.#validateLottoNumbers(lottoNumbers); this.#lottoNumbers = lottoNumbers; } diff --git a/src/views/InputView.js b/src/views/InputView.js index a5c60283e0..a6ff6de13d 100644 --- a/src/views/InputView.js +++ b/src/views/InputView.js @@ -4,15 +4,15 @@ import Messages from '../constants/Messages.js'; class InputView { static getLottoPrice() { return Console.readLineAsync(`${Messages.LOTTO_PRICE_INPUT}\n`); - }; - + } + static getWinningNumbers() { - return Console.readLineAsync(`${Messages.WINNING_NUMBERS_INPUT}\n`); + return Console.readLineAsync(`\n${Messages.WINNING_NUMBERS_INPUT}\n`); } static getBonusNumber() { - return Console.readLineAsync(`${Messages.BONUS_NUMBER_INPUT}\n`); + return Console.readLineAsync(`\n${Messages.BONUS_NUMBER_INPUT}\n`); } } -export default InputView; \ No newline at end of file +export default InputView; diff --git a/src/views/OutputView.js b/src/views/OutputView.js index d2770f5a43..8d23c478ce 100644 --- a/src/views/OutputView.js +++ b/src/views/OutputView.js @@ -4,13 +4,17 @@ import Messages from '../constants/Messages.js'; class OutputView { static printLottoCount(lottoCount) { Console.print(`\n${lottoCount}${Messages.LOTTO_COUNT}`); - }; - + } + static printLottoNumbers(lottoNumbers) { - lottoNumbers.forEach((lottoNumber) => { - Console.print(`${Messages.LEFT_BRACKET}${lottoNumber.join(', ')}${Messages.RIGHT_BRACKET}`); + lottoNumbers.forEach(lottoNumber => { + Console.print( + `${Messages.LEFT_BRACKET}${lottoNumber.join(', ')}${ + Messages.RIGHT_BRACKET + }`, + ); }); - }; + } } -export default OutputView; \ No newline at end of file +export default OutputView; From 432355f0d035528b09b5105528db0b1fa88b8019 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Thu, 9 Nov 2023 10:37:36 +0900 Subject: [PATCH 29/41] =?UTF-8?q?feat(models):=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EB=A1=9C=EB=98=90=20=EB=B2=88=ED=98=B8=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 숫자가 아닐 경우 - 1~45 사이의 숫자가 아닐 경우 - 소수점이 있을 경우 - 중복된 숫자가 있을 경우 - 6개가 아닐 경우 - 오름차순이 아닐 경우 --- .eslintrc.cjs | 1 + __tests__/CustomerNumbersTest.js | 17 ++++++++++++++++- docs/README.md | 10 ++++++++++ src/Validations.js | 4 ++-- src/models/Customer.js | 11 +++++++++-- 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index b29f0baa59..caf3d746b5 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -27,5 +27,6 @@ module.exports = { 'import/prefer-default-export': 'off', 'import/extensions': ['off'], 'class-methods-use-this': 'off', + 'no-unused-vars': 'off', }, }; \ No newline at end of file diff --git a/__tests__/CustomerNumbersTest.js b/__tests__/CustomerNumbersTest.js index f21e0fe9b8..22b5e4f350 100644 --- a/__tests__/CustomerNumbersTest.js +++ b/__tests__/CustomerNumbersTest.js @@ -86,13 +86,28 @@ describe('사용자 로또 번호 목록 테스트', () => { LottoGameController.generateCustomerNumbers(lottoNumbers).forEach( lottoNumber => { expect(() => { - Validations.isNotProperLength(lottoNumber); + Validations.isProperLength(lottoNumber); }).toThrow('[ERROR] 길이가 6이어야 합니다.'); }, ); }, ); + test.each([[[1, 2, 3, 5, 4]], [[40, 39, 38, 37, 36]], [[1, 5, 4, 3, 6]]])( + '오름차순으로 정렬되어 있는지', + lottoNumbers => { + mockRandoms(lottoNumbers); + + LottoGameController.generateCustomerNumbers(lottoNumbers).forEach( + lottoNumber => { + expect(() => { + Validations.isSorted(lottoNumber); + }).toThrow('ERROR] 오름차순으로 정렬되어 있어야 합니다.'); + }, + ); + }, + ); + test.each([ [[1, 2, 3, 5, 6, 9]], [[5, 7, 9, 11, 13, 17]], diff --git a/docs/README.md b/docs/README.md index 6acbb31029..931b797ab1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,6 +6,7 @@ - [x] 로또 개수 (필드) - [x] 소유한 로또 번호 목록 (필드) - [x] 로또 구입금액 `예외처리` + - [x] 소유한 로또 번호 목록 `예외처리` - [ ] 로또 정보 (보너스 번호 포함) `class` - [ ] 로또 객체: Lotto 클래스 (필드) - [ ] 당첨 번호 목록 (필드) @@ -41,6 +42,15 @@ - [x] 1000원 단위가 아닐 경우 +* 사용자 로또 번호 목록 + - [x] 숫자가 아닐 경우 + - [x] 1~45 사이의 숫자가 아닐 경우 + - [x] 소수점이 있을 경우 + - [x] 중복된 숫자가 있을 경우 + - [x] 6개가 아닐 경우 + - [x] 오름차순이 아닐 경우 + + * 로또 당첨 번호 - [ ] 공백이 있을 경우 - [ ] 숫자가 아닐 경우 diff --git a/src/Validations.js b/src/Validations.js index 7e96506073..08afb82058 100644 --- a/src/Validations.js +++ b/src/Validations.js @@ -50,13 +50,13 @@ class Validations { }); } - static isNotProperLength(input) { + static isProperLength(input) { if (input.length !== 6) { throw new Error(Errors.IS_NOT_PROPER_LENGTH); } } - static isNotSorted(input) { + static isSorted(input) { const sortedInput = [...input].sort((a, b) => a - b); if (JSON.stringify(input) !== JSON.stringify(sortedInput)) { throw new Error(Errors.IS_NOT_SORTED); diff --git a/src/models/Customer.js b/src/models/Customer.js index 2b043d61ea..c66fa19d7f 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -27,8 +27,14 @@ class Customer { #validateLottoNumbers(lottoNumbers) { lottoNumbers.forEach((lottoNumber) => { - Validations.isNumber(lottoNumber); - Validations.isInRange(lottoNumber); + lottoNumber.forEach((number) => { + Validations.isNumber(number); + Validations.isInRange(number); + Validations.isInteger(number); + }); + Validations.isNotDuplicated(lottoNumber); + Validations.isProperLength(lottoNumber); + Validations.isSorted(lottoNumber); }); } @@ -37,6 +43,7 @@ class Customer { } setLottoNumbers(lottoNumbers) { + this.#validateLottoNumbers(lottoNumbers); this.#lottoNumbers = lottoNumbers; } From 2c25433660db01bcc74dfeec2e87c65b620e73db Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Thu, 9 Nov 2023 10:52:20 +0900 Subject: [PATCH 30/41] =?UTF-8?q?feat(Lotto):=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EB=8B=B9=EC=B2=A8=20=EB=B2=88=ED=98=B8=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EA=B8=B0=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 --- docs/README.md | 18 +++++++++--------- src/Lotto.js | 17 ++++++++++++----- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/docs/README.md b/docs/README.md index 931b797ab1..371fb11787 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,9 +8,9 @@ - [x] 로또 구입금액 `예외처리` - [x] 소유한 로또 번호 목록 `예외처리` - [ ] 로또 정보 (보너스 번호 포함) `class` - - [ ] 로또 객체: Lotto 클래스 (필드) - - [ ] 당첨 번호 목록 (필드) - - [ ] 로또 당첨 번호 `예외처리` + - [x] 로또 객체: Lotto 클래스 (필드) + - [x] 당첨 번호 목록 (필드) + - [x] 로또 당첨 번호 `예외처리` - [ ] 보너스 번호 (필드) - [ ] 보너스 번호 `예외처리` @@ -52,12 +52,12 @@ * 로또 당첨 번호 - - [ ] 공백이 있을 경우 - - [ ] 숫자가 아닐 경우 - - [ ] 1~45 사이의 숫자가 아닐 경우 - - [ ] 소수점이 있을 경우 - - [ ] 중복된 숫자가 있을 경우 - - [ ] 6개가 아닐 경우 + - [x] 공백이 있을 경우 + - [x] 숫자가 아닐 경우 + - [x] 1~45 사이의 숫자가 아닐 경우 + - [x] 소수점이 있을 경우 + - [x] 중복된 숫자가 있을 경우 + - [x] 6개가 아닐 경우 * 보너스 번호 diff --git a/src/Lotto.js b/src/Lotto.js index cb0b1527e9..8322e2b7ed 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -1,3 +1,5 @@ +import Validations from "./Validations"; + class Lotto { #numbers; @@ -7,12 +9,17 @@ class Lotto { } #validate(numbers) { - if (numbers.length !== 6) { - throw new Error("[ERROR] 로또 번호는 6개여야 합니다."); - } + Validations.hasSpace(numbers); + const numbersArray = numbers.split(",").map((number) => Number(number)); + numbersArray.forEach((number) => { + Validations.isNumber(number); + Validations.isInRange(number); + Validations.isInteger(number); + }); + Validations.isNotDuplicated(numbersArray); + Validations.isProperLength(numbersArray); } - - // TODO: 추가 기능 구현 + } export default Lotto; From 9c3550866367a1db04f129dcded80aee59c228d2 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Thu, 9 Nov 2023 11:14:26 +0900 Subject: [PATCH 31/41] =?UTF-8?q?test:=20=EB=8B=B9=EC=B2=A8=20=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 숫자가 맞는지 - 1~45 사이의 숫자가 맞는지 - 소수점이 없는지 - 중복된 숫자가 없는지 - 6개인지 --- __tests__/CustomerNumbersTest.js | 2 +- __tests__/LottoTest.js | 74 +++++++++++++++++++++++++++++--- docs/README.md | 12 +++--- src/App.js | 3 +- src/Lotto.js | 8 ++-- 5 files changed, 79 insertions(+), 20 deletions(-) diff --git a/__tests__/CustomerNumbersTest.js b/__tests__/CustomerNumbersTest.js index 22b5e4f350..d9c3209f68 100644 --- a/__tests__/CustomerNumbersTest.js +++ b/__tests__/CustomerNumbersTest.js @@ -79,7 +79,7 @@ describe('사용자 로또 번호 목록 테스트', () => { ); test.each([[[1, 2, 3, 3, 4]], [[40, 39, 38]], [[1, 5, 4]]])( - '길이가 6인지', + '6개인지', lottoNumbers => { mockRandoms(lottoNumbers); diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index 97bd457659..9926a3dd40 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -1,18 +1,80 @@ -import Lotto from "../src/Lotto.js"; +import { MissionUtils } from '@woowacourse/mission-utils'; +import Lotto from '../src/Lotto.js'; +import Validations from '../src/Validations.js'; -describe("로또 클래스 테스트", () => { - test("로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.", () => { +const mockRandoms = numbers => { + MissionUtils.Random.pickUniqueNumbersInRange = jest.fn(); + numbers.reduce( + (acc, number) => acc.mockReturnValueOnce(number), + MissionUtils.Random.pickUniqueNumbersInRange, + ); +}; + +describe('로또 클래스 테스트', () => { + test('로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.', () => { expect(() => { new Lotto([1, 2, 3, 4, 5, 6, 7]); - }).toThrow("[ERROR]"); + }).toThrow('[ERROR]'); }); // TODO: 이 테스트가 통과할 수 있게 구현 코드 작성 - test("로또 번호에 중복된 숫자가 있으면 예외가 발생한다.", () => { + test('로또 번호에 중복된 숫자가 있으면 예외가 발생한다.', () => { expect(() => { new Lotto([1, 2, 3, 4, 5, 5]); - }).toThrow("[ERROR]"); + }).toThrow('[ERROR]'); }); // 아래에 추가 테스트 작성 가능 + test.each([[['1000s', '2s000', 's30000', '']], [['s', 1, 30]]])( + '숫자가 맞는지', + winningNumbers => { + expect(() => { + new Lotto(winningNumbers); + }).toThrow('[ERROR] 숫자만 입력해 주세요.'); + }, + ); + + test.each([[[1, 2, 3, 4, 5, 6, 56]], [[60, 59, 58, 57]], [[0, 3, 5]]])( + '1~45 사이의 숫자가 맞는지', + winningNumbers => { + mockRandoms(winningNumbers); + + expect(() => { + new Lotto(winningNumbers); + }).toThrow('[ERROR] 1~45 사이의 숫자만 입력해주세요.'); + }, + ); + + test.each([[[1, 2, 3, 4, 5, 6, 7.5]], [[44, 43, 42, 37.4]], [[2, 3, 20.1]]])( + '소수점이 없는지', + winningNumbers => { + mockRandoms(winningNumbers); + + expect(() => { + new Lotto(winningNumbers); + }).toThrow('[ERROR] 정수만 입력해주세요.'); + }, + ); + + test.each([[[1, 2, 3, 4, 5, 5]], [[44, 43, 42, 42]], [[2, 20, 20]]])( + '중복된 숫자가 없는지', + winningNumbers => { + mockRandoms(winningNumbers); + + expect(() => { + new Lotto(winningNumbers); + }).toThrow('[ERROR] 중복된 숫자가 없이 입력해주세요.'); + }, + ); + + test.each([[[1, 2, 3, 4, 5, 7, 8]], [[42, 43, 41, 4]], [[3, 33, 2, 35]]])( + '6개인지', + winningNumbers => { + mockRandoms(winningNumbers); + + expect(() => { + new Lotto(winningNumbers); + }).toThrow('[ERROR] 길이가 6이어야 합니다.'); + }, + ); }); diff --git a/docs/README.md b/docs/README.md index 371fb11787..19b9c3bc0d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -52,7 +52,6 @@ * 로또 당첨 번호 - - [x] 공백이 있을 경우 - [x] 숫자가 아닐 경우 - [x] 1~45 사이의 숫자가 아닐 경우 - [x] 소수점이 있을 경우 @@ -88,12 +87,11 @@ * 당첨 번호 테스트 - - [ ] 공백이 없는지 - - [ ] 숫자가 맞는지 - - [ ] 1~45 사이의 숫자가 맞는지 - - [ ] 소수점이 없는지 - - [ ] 중복된 숫자가 없는지 - - [ ] 6개인지 + - [x] 숫자가 맞는지 + - [x] 1~45 사이의 숫자가 맞는지 + - [x] 소수점이 없는지 + - [x] 중복된 숫자가 없는지 + - [x] 6개인지 * 보너스 번호 테스트 diff --git a/src/App.js b/src/App.js index 4b49ce24b0..ca66ea5da0 100644 --- a/src/App.js +++ b/src/App.js @@ -15,7 +15,8 @@ class App { OutputView.printLottoCount(lottoCount); OutputView.printLottoNumbers(customer.getLottoNumbers()); - const winningNumbers = await InputView.getWinningNumbers(); + const temp = await InputView.getWinningNumbers(); + const winningNumbers = temp.split(',').map((number) => Number(number)); const bonusNumber = await InputView.getBonusNumber(); const lottoTotal = new LottoTotal(winningNumbers, bonusNumber); } diff --git a/src/Lotto.js b/src/Lotto.js index 8322e2b7ed..b9a1dc22e1 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -9,15 +9,13 @@ class Lotto { } #validate(numbers) { - Validations.hasSpace(numbers); - const numbersArray = numbers.split(",").map((number) => Number(number)); - numbersArray.forEach((number) => { + numbers.forEach((number) => { Validations.isNumber(number); Validations.isInRange(number); Validations.isInteger(number); }); - Validations.isNotDuplicated(numbersArray); - Validations.isProperLength(numbersArray); + Validations.isNotDuplicated(numbers); + Validations.isProperLength(numbers); } } From 4037b4cbffb2a97c6dea876ff5c18e85aaebe984 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Thu, 9 Nov 2023 11:27:18 +0900 Subject: [PATCH 32/41] =?UTF-8?q?feat(models):=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20class=EC=97=90=20=EB=B3=B4=EB=84=88?= =?UTF-8?q?=EC=8A=A4=20=EB=B2=88=ED=98=B8=20=ED=95=84=EB=93=9C=EC=99=80=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/LottoTest.js | 7 +++++++ docs/README.md | 16 ++++++++-------- src/App.js | 5 ++++- src/Lotto.js | 5 ++++- src/Validations.js | 9 ++++++++- src/constants/Errors.js | 3 ++- src/models/LottoTotal.js | 24 +++++++++++++++++++----- 7 files changed, 52 insertions(+), 17 deletions(-) diff --git a/__tests__/LottoTest.js b/__tests__/LottoTest.js index 9926a3dd40..c54da57176 100644 --- a/__tests__/LottoTest.js +++ b/__tests__/LottoTest.js @@ -13,6 +13,7 @@ const mockRandoms = numbers => { describe('로또 클래스 테스트', () => { test('로또 번호의 개수가 6개가 넘어가면 예외가 발생한다.', () => { expect(() => { + // eslint-disable-next-line no-new new Lotto([1, 2, 3, 4, 5, 6, 7]); }).toThrow('[ERROR]'); }); @@ -20,6 +21,7 @@ describe('로또 클래스 테스트', () => { // TODO: 이 테스트가 통과할 수 있게 구현 코드 작성 test('로또 번호에 중복된 숫자가 있으면 예외가 발생한다.', () => { expect(() => { + // eslint-disable-next-line no-new new Lotto([1, 2, 3, 4, 5, 5]); }).toThrow('[ERROR]'); }); @@ -29,6 +31,7 @@ describe('로또 클래스 테스트', () => { '숫자가 맞는지', winningNumbers => { expect(() => { + // eslint-disable-next-line no-new new Lotto(winningNumbers); }).toThrow('[ERROR] 숫자만 입력해 주세요.'); }, @@ -40,6 +43,7 @@ describe('로또 클래스 테스트', () => { mockRandoms(winningNumbers); expect(() => { + // eslint-disable-next-line no-new new Lotto(winningNumbers); }).toThrow('[ERROR] 1~45 사이의 숫자만 입력해주세요.'); }, @@ -51,6 +55,7 @@ describe('로또 클래스 테스트', () => { mockRandoms(winningNumbers); expect(() => { + // eslint-disable-next-line no-new new Lotto(winningNumbers); }).toThrow('[ERROR] 정수만 입력해주세요.'); }, @@ -62,6 +67,7 @@ describe('로또 클래스 테스트', () => { mockRandoms(winningNumbers); expect(() => { + // eslint-disable-next-line no-new new Lotto(winningNumbers); }).toThrow('[ERROR] 중복된 숫자가 없이 입력해주세요.'); }, @@ -73,6 +79,7 @@ describe('로또 클래스 테스트', () => { mockRandoms(winningNumbers); expect(() => { + // eslint-disable-next-line no-new new Lotto(winningNumbers); }).toThrow('[ERROR] 길이가 6이어야 합니다.'); }, diff --git a/docs/README.md b/docs/README.md index 19b9c3bc0d..490c49d6cf 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,7 @@ ## 기능 그룹 (MVC) * Models - - [ ] 구매자 정보 `class` + - [x] 구매자 정보 `class` - [x] 구입 금액 (필드) - [x] 로또 개수 (필드) - [x] 소유한 로또 번호 목록 (필드) @@ -11,8 +11,8 @@ - [x] 로또 객체: Lotto 클래스 (필드) - [x] 당첨 번호 목록 (필드) - [x] 로또 당첨 번호 `예외처리` - - [ ] 보너스 번호 (필드) - - [ ] 보너스 번호 `예외처리` + - [x] 보너스 번호 (필드) + - [x] 보너스 번호 `예외처리` * Views @@ -60,11 +60,11 @@ * 보너스 번호 - - [ ] 공백이 있을 경우 - - [ ] 숫자가 아닐 경우 - - [ ] 1~45 사이의 숫자가 아닐 경우 - - [ ] 소수점이 있을 경우 - - [ ] 당첨 번호와 중복될 경우 + - [x] 공백이 있을 경우 + - [x] 숫자가 아닐 경우 + - [x] 1~45 사이의 숫자가 아닐 경우 + - [x] 소수점이 있을 경우 + - [x] 당첨 번호와 중복될 경우
diff --git a/src/App.js b/src/App.js index ca66ea5da0..574005b92a 100644 --- a/src/App.js +++ b/src/App.js @@ -1,6 +1,7 @@ import InputView from "./views/InputView.js"; import OutputView from "./views/OutputView.js"; import Customer from "./models/Customer.js"; +import Lotto from "./Lotto.js"; import LottoTotal from "./models/LottoTotal.js"; import LottoGameController from "./controllers/LottoGameController.js"; @@ -17,8 +18,10 @@ class App { const temp = await InputView.getWinningNumbers(); const winningNumbers = temp.split(',').map((number) => Number(number)); + const lotto = new Lotto(winningNumbers); + const bonusNumber = await InputView.getBonusNumber(); - const lottoTotal = new LottoTotal(winningNumbers, bonusNumber); + const lottoTotal = new LottoTotal(lotto, bonusNumber); } } diff --git a/src/Lotto.js b/src/Lotto.js index b9a1dc22e1..14fd74e15a 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -1,4 +1,4 @@ -import Validations from "./Validations"; +import Validations from "./Validations.js"; class Lotto { #numbers; @@ -18,6 +18,9 @@ class Lotto { Validations.isProperLength(numbers); } + getNumbers() { + return this.#numbers; + } } export default Lotto; diff --git a/src/Validations.js b/src/Validations.js index 08afb82058..0250bb1674 100644 --- a/src/Validations.js +++ b/src/Validations.js @@ -45,7 +45,7 @@ class Validations { static isNotDuplicated(input) { input.forEach((number, index) => { if (input.indexOf(number) !== index) { - throw new Error(Errors.IS_NOT_DUPLICATED); + throw new Error(Errors.IS_DUPLICATED); } }); } @@ -62,6 +62,13 @@ class Validations { throw new Error(Errors.IS_NOT_SORTED); } } + + static isBonusNumberNotDuplicated(bonusNumber, lotto) { + const numbers = lotto.getNumbers(); + if (numbers.includes(bonusNumber)) { + throw new Error(Errors.IS_BONUS_NUMBER_DUPLICATED); + } + } } export default Validations; \ No newline at end of file diff --git a/src/constants/Errors.js b/src/constants/Errors.js index 48bdd6d498..a59d08bcd1 100644 --- a/src/constants/Errors.js +++ b/src/constants/Errors.js @@ -5,9 +5,10 @@ const Errors = Object.freeze({ IS_NOT_THOUSAND_UNIT: '[ERROR] 1000원 단위로만 입력해주세요.', IS_NOT_IN_RANGE: '[ERROR] 1~45 사이의 숫자만 입력해주세요.', IS_NOT_INTEGER: '[ERROR] 정수만 입력해주세요.', - IS_NOT_DUPLICATED: '[ERROR] 중복된 숫자가 없이 입력해주세요.', + IS_DUPLICATED: '[ERROR] 중복된 숫자가 없이 입력해주세요.', IS_NOT_PROPER_LENGTH: '[ERROR] 길이가 6이어야 합니다.', IS_NOT_SORTED: '[ERROR] 오름차순으로 정렬되어 있어야 합니다.', + IS_BONUS_NUMBER_DUPLICATED: '[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다.' }); export default Errors; \ No newline at end of file diff --git a/src/models/LottoTotal.js b/src/models/LottoTotal.js index 54359156f6..c8ad689bb2 100644 --- a/src/models/LottoTotal.js +++ b/src/models/LottoTotal.js @@ -1,15 +1,29 @@ +import Lotto from "../Lotto.js"; +import Validations from "../Validations.js"; + class LottoTotal { - #winningNumbers; + /** @type {Lotto} */ + #lotto; + /** @type {number} */ #bonusNumber; - constructor(winningNumbers, bonusNumber) { - this.#winningNumbers = winningNumbers; + constructor(lotto, bonusNumber) { + this.#lotto = lotto; + this.#validateBonusNumber(bonusNumber, lotto); this.#bonusNumber = bonusNumber; } - getWinningNumbers() { - return this.#winningNumbers; + #validateBonusNumber(bonusNumber, lotto) { + Validations.hasSpace(bonusNumber); + Validations.isNumber(bonusNumber); + Validations.isInRange(bonusNumber); + Validations.isInteger(bonusNumber); + Validations.isBonusNumberNotDuplicated(bonusNumber, lotto); + } + + getLotto() { + return this.#lotto; } getBonusNumber() { From d67f313c2e8410a34c8e26d062b24ef48fa1079a Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Thu, 9 Nov 2023 11:44:22 +0900 Subject: [PATCH 33/41] =?UTF-8?q?test:=20=EB=B3=B4=EB=84=88=EC=8A=A4=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 공백이 없는지 - 숫자가 맞는지 - 1~45 사이의 숫자가 맞는지 - 소수점이 없는지 - 당첨 번호와 중복되지 않는지 --- __tests__/BonusNumberTest.js | 42 ++++++++++++++++++++++++++++++++++++ docs/README.md | 14 ++++++------ src/Validations.js | 2 +- 3 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 __tests__/BonusNumberTest.js diff --git a/__tests__/BonusNumberTest.js b/__tests__/BonusNumberTest.js new file mode 100644 index 0000000000..88991627b9 --- /dev/null +++ b/__tests__/BonusNumberTest.js @@ -0,0 +1,42 @@ +import Validations from '../src/Validations.js'; +import Lotto from '../src/Lotto.js'; +import LottoTotal from '../src/models/LottoTotal.js'; + +const mockLotto = new Lotto([1,2,3,4,5,6]) + +describe('보너스 번호 테스트', () => { + test.each([['10 00', ' 2000 ', ' 30 000']])('공백이 없는지', bonusNumber => { + expect(() => { + // eslint-disable-next-line no-new + new LottoTotal(mockLotto, bonusNumber); + }).toThrow('[ERROR] 공백 없이 입력해 주세요.'); + }); + + test.each([['1000s', '2s000', 's30000', '']])('숫자가 맞는지', bonusNumber => { + expect(() => { + // eslint-disable-next-line no-new + new LottoTotal(mockLotto, bonusNumber); + }).toThrow('[ERROR] 숫자만 입력해 주세요.'); + }); + + test.each([['0', '-10', '455']])('1~45 사이의 숫자가 맞는지', bonusNumber => { + expect(() => { + // eslint-disable-next-line no-new + new LottoTotal(mockLotto, bonusNumber); + }).toThrow('[ERROR] 1~45 사이의 숫자만 입력해주세요.'); + }); + + test.each([['15.1', '12.2', '6.3']])('소수점이 없는지', bonusNumber => { + expect(() => { + // eslint-disable-next-line no-new + new LottoTotal(mockLotto, bonusNumber); + }).toThrow('[ERROR] 정수만 입력해주세요.'); + }); + + test.each([['1', '2', '3']])('당첨 번호와 중복되지 않는지', bonusNumber => { + expect(() => { + // eslint-disable-next-line no-new + new LottoTotal(mockLotto, bonusNumber); + }).toThrow('[ERROR] 보너스 번호는 당첨 번호와 중복될 수 없습니다.'); + }); +}); diff --git a/docs/README.md b/docs/README.md index 490c49d6cf..727da0d8e3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,7 +7,7 @@ - [x] 소유한 로또 번호 목록 (필드) - [x] 로또 구입금액 `예외처리` - [x] 소유한 로또 번호 목록 `예외처리` - - [ ] 로또 정보 (보너스 번호 포함) `class` + - [x] 로또 정보 (보너스 번호 포함) `class` - [x] 로또 객체: Lotto 클래스 (필드) - [x] 당첨 번호 목록 (필드) - [x] 로또 당첨 번호 `예외처리` @@ -16,7 +16,7 @@ * Views - - [ ] 입력창 및 메세지 출력 `class` + - [x] 입력창 및 메세지 출력 `class` - [x] 구입금액 입력 - [x] 당첨번호 입력 - [x] 보너스번호 입력 @@ -95,11 +95,11 @@ * 보너스 번호 테스트 - - [ ] 공백이 없는지 - - [ ] 숫자가 맞는지 - - [ ] 1~45 사이의 숫자가 맞는지 - - [ ] 소수점이 없는지 - - [ ] 당첨 번호와 중복되지 않는지 + - [x] 공백이 없는지 + - [x] 숫자가 맞는지 + - [x] 1~45 사이의 숫자가 맞는지 + - [x] 소수점이 없는지 + - [x] 당첨 번호와 중복되지 않는지 * 로또 개수 테스트 diff --git a/src/Validations.js b/src/Validations.js index 0250bb1674..e7863fcb82 100644 --- a/src/Validations.js +++ b/src/Validations.js @@ -65,7 +65,7 @@ class Validations { static isBonusNumberNotDuplicated(bonusNumber, lotto) { const numbers = lotto.getNumbers(); - if (numbers.includes(bonusNumber)) { + if (numbers.includes(Number(bonusNumber))) { throw new Error(Errors.IS_BONUS_NUMBER_DUPLICATED); } } From 4ac54dcc999917065ad43f5293d6f15de5ebb988 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Thu, 9 Nov 2023 13:58:48 +0900 Subject: [PATCH 34/41] =?UTF-8?q?feat:=20Error=20=EB=B0=9C=EC=83=9D?= =?UTF-8?q?=EC=8B=9C=20=EC=A7=81=EC=A0=84=20=EC=9E=85=EB=A0=A5=EC=B0=BD?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 1 + src/App.js | 54 +++++++++++++++++++++++++++++++++-------- src/views/OutputView.js | 11 +++++---- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/docs/README.md b/docs/README.md index 727da0d8e3..2e0b67729c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -23,6 +23,7 @@ - [ ] 출력창 및 메세지 출력 `class` - [x] 로또 개수 - [x] 번호 목록 출력 + - [x] 에러 메세지 출력 - [ ] 당첨 통계 출력: 제목, 내역, 결과(수익률) diff --git a/src/App.js b/src/App.js index 574005b92a..184a29a062 100644 --- a/src/App.js +++ b/src/App.js @@ -7,21 +7,55 @@ import LottoGameController from "./controllers/LottoGameController.js"; class App { async play() { - const lottoPrice = await InputView.getLottoPrice(); + let customer; + while (true) { + try { + const lottoPrice = await InputView.getLottoPrice(); + customer = new Customer(lottoPrice); + break; + } catch(e) { + OutputView.printError(`${e.message}\n`); + } + } - const customer = new Customer(lottoPrice); const lottoCount = customer.getLottoCount(); - const lottoNumbers = LottoGameController.generateCustomerNumbers(lottoCount); - customer.setLottoNumbers(lottoNumbers); OutputView.printLottoCount(lottoCount); - OutputView.printLottoNumbers(customer.getLottoNumbers()); - const temp = await InputView.getWinningNumbers(); - const winningNumbers = temp.split(',').map((number) => Number(number)); - const lotto = new Lotto(winningNumbers); + let lottoNumbers; + while (true) { + try { + lottoNumbers = LottoGameController.generateCustomerNumbers(lottoCount); + customer.setLottoNumbers(lottoNumbers); + OutputView.printLottoNumbers(customer.getLottoNumbers()); + break; + } catch(e) { + OutputView.printError(e.message); + } + } + + let lotto; + while (true) { + try { + const temp = await InputView.getWinningNumbers(); + const winningNumbers = temp.split(',').map((number) => Number(number)); + lotto = new Lotto(winningNumbers); + break; + } catch(e) { + OutputView.printError(e.message); + } + } + + let bonusNumber; + while (true) { + try { + bonusNumber = await InputView.getBonusNumber(); + const lottoTotal = new LottoTotal(lotto, bonusNumber); + break; + } catch(e) { + OutputView.printError(e.message); + } + } - const bonusNumber = await InputView.getBonusNumber(); - const lottoTotal = new LottoTotal(lotto, bonusNumber); } } diff --git a/src/views/OutputView.js b/src/views/OutputView.js index 8d23c478ce..2683e0692c 100644 --- a/src/views/OutputView.js +++ b/src/views/OutputView.js @@ -8,13 +8,14 @@ class OutputView { static printLottoNumbers(lottoNumbers) { lottoNumbers.forEach(lottoNumber => { - Console.print( - `${Messages.LEFT_BRACKET}${lottoNumber.join(', ')}${ - Messages.RIGHT_BRACKET - }`, - ); + Console.print(`${Messages.LEFT_BRACKET}${lottoNumber.join(', ')}${Messages.RIGHT_BRACKET}`); }); } + + static printError(message) { + Console.print(message); + } + } export default OutputView; From 03f66d54350ef5a0b99a7791f9e3b80609c14381 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Thu, 9 Nov 2023 14:56:14 +0900 Subject: [PATCH 35/41] =?UTF-8?q?feat(controllers):=20=EB=8B=B9=EC=B2=A8?= =?UTF-8?q?=20=EB=82=B4=EC=97=AD=20=EC=97=B0=EC=82=B0=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.cjs | 2 ++ docs/README.md | 2 +- src/App.js | 11 ++++++++--- src/constants/Conditions.js | 8 ++++++++ src/controllers/LottoGameController.js | 21 +++++++++++++++++++++ 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index caf3d746b5..c083c8fde4 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -28,5 +28,7 @@ module.exports = { 'import/extensions': ['off'], 'class-methods-use-this': 'off', 'no-unused-vars': 'off', + 'no-await-in-loop': 'off', + 'no-constant-condition': 'off', }, }; \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 2e0b67729c..82e5b2980c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -30,7 +30,7 @@ * Controllers - [ ] 로또 게임 처리/연산 `class` - [x] 구매자가 소유할 로또 번호 목록 생성 - - [ ] 당첨 내역 연산 + - [x] 당첨 내역 연산 - [ ] 당첨 결과(수익률) 연산
diff --git a/src/App.js b/src/App.js index 184a29a062..1b93dfacad 100644 --- a/src/App.js +++ b/src/App.js @@ -45,17 +45,22 @@ class App { } } - let bonusNumber; + let lottoTotal; while (true) { try { - bonusNumber = await InputView.getBonusNumber(); - const lottoTotal = new LottoTotal(lotto, bonusNumber); + const bonusNumber = await InputView.getBonusNumber(); + lottoTotal = new LottoTotal(lotto, bonusNumber); break; } catch(e) { OutputView.printError(e.message); } } + const match = LottoGameController.matchRank( + customer.getLottoNumbers(), + lottoTotal.getLotto().getNumbers(), + lottoTotal.getBonusNumber() + ); } } diff --git a/src/constants/Conditions.js b/src/constants/Conditions.js index 7307502e07..1e47a5e20b 100644 --- a/src/constants/Conditions.js +++ b/src/constants/Conditions.js @@ -3,6 +3,14 @@ const Conditions = Object.freeze({ NUMBER_MIN : 1, NUMBER_MAX : 45, NUMBER_PICK_COUNT : 6, + INITIAL_MATCH_COUNT : 0, + FIRST: 0, + SECOND: 1, + THIRD: 2, + FOURTH: 3, + FIFTH: 4, + COUNT: 1, + TOTAL_RANK: 5, }); export default Conditions; \ No newline at end of file diff --git a/src/controllers/LottoGameController.js b/src/controllers/LottoGameController.js index f6e75713f1..4fb0156bc2 100644 --- a/src/controllers/LottoGameController.js +++ b/src/controllers/LottoGameController.js @@ -19,6 +19,27 @@ class LottoGameController { userNumbers.sort((a, b) => a - b); } + static matchRank(customerNumbers, winningNumbers, bonusNumber) { + const matchCounts = Array(Conditions.TOTAL_RANK).fill(Conditions.INITIAL_MATCH_COUNT); + for (let i = 0; i < customerNumbers.length; i += 1) { + const matchCount = this.matchCount(customerNumbers[i], winningNumbers); + const isBonusMatch = customerNumbers[i].includes(bonusNumber); + switch (matchCount) { + case 6: matchCounts[Conditions.FIRST] += Conditions.COUNT; break; + case 5 && isBonusMatch: matchCounts[Conditions.SECOND] += Conditions.COUNT; break; + case 5: matchCounts[Conditions.THIRD] += Conditions.COUNT; break; + case 4: matchCounts[Conditions.FOURTH] += Conditions.COUNT; break; + case 3: matchCounts[Conditions.FIFTH] += Conditions.COUNT; break; + default: break; + } + } + return matchCounts; + } + + static matchCount(customerNumber, winningNumbers) { + return customerNumber.filter(number => winningNumbers.includes(number)).length; + } + } export default LottoGameController; \ No newline at end of file From e11a094bd315ca0164d2241e3728d374befd73c6 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Fri, 10 Nov 2023 02:40:08 +0900 Subject: [PATCH 36/41] =?UTF-8?q?test:=20=EB=A1=9C=EB=98=90=20=EA=B0=9C?= =?UTF-8?q?=EC=88=98=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - feat(controllers): 로또 개수 연산 기능 수정 --- __tests__/MatchRankTest.js | 154 +++++++++++++++++++++++++ docs/README.md | 10 +- src/App.js | 6 +- src/controllers/LottoGameController.js | 43 ++++--- 4 files changed, 193 insertions(+), 20 deletions(-) create mode 100644 __tests__/MatchRankTest.js diff --git a/__tests__/MatchRankTest.js b/__tests__/MatchRankTest.js new file mode 100644 index 0000000000..644eb8bec7 --- /dev/null +++ b/__tests__/MatchRankTest.js @@ -0,0 +1,154 @@ +import Validations from '../src/Validations.js'; +import LottoGameController from '../src/controllers/LottoGameController.js'; + +describe('로또 개수 테스트', () => { + test.each([ + [ + [ + [ + [1, 3, 4, 5, 6, 7], + [2, 5, 6, 7, 8, 9], + ], + [4, 5, 6, 3, 7, 1], + 12, + ], + ], + [ + [ + [ + [1, 10, 15, 20, 25, 35], + [11, 12, 13, 14, 15, 16], + ], + [15, 20, 25, 10, 35, 1], + 12, + ], + ], + ])('6개 일치 여부가 맞는지', inputs => { + const matchCounts = LottoGameController.matchRank( + inputs[0], + inputs[1], + inputs[2], + ); + expect(matchCounts.findIndex(e => e !== 0)).toEqual(0); + }); + + test.each([ + [ + [ + [ + [1, 2, 3, 4, 5, 6], + [33, 34, 35, 36, 37, 38], + ], + [4, 5, 6, 3, 2, 11], + 1, + ], + ], + [ + [ + [ + [1, 5, 10, 15, 20, 25], + [3, 4, 7, 8, 9, 11], + ], + [5, 10, 1, 15, 20, 28], + 25, + ], + ], + ])('5개 일치 + 보너스 번호 일치 여부가 맞는지', inputs => { + const matchCounts = LottoGameController.matchRank( + inputs[0], + inputs[1], + inputs[2], + ); + expect(matchCounts.findIndex(e => e !== 0)).toEqual(1); + }); + + test.each([ + [ + [ + [ + [1, 3, 4, 5, 6, 7], + [2, 5, 6, 7, 8, 9], + ], + [4, 5, 6, 3, 7, 11], + 12, + ], + ], + [ + [ + [ + [1, 10, 15, 20, 25, 35], + [11, 12, 13, 14, 15, 16], + ], + [15, 20, 25, 10, 35, 28], + 12, + ], + ], + ])('5개 일치 여부가 맞는지', inputs => { + const matchCounts = LottoGameController.matchRank( + inputs[0], + inputs[1], + inputs[2], + ); + expect(matchCounts.findIndex(e => e !== 0)).toEqual(2); + }); + + test.each([ + [ + [ + [ + [1, 2, 3, 4, 5, 6], + [33, 34, 35, 36, 37, 38], + ], + [4, 5, 6, 3, 10, 11], + 12, + ], + ], + [ + [ + [ + [1, 5, 10, 15, 20, 25], + [11, 16, 22, 27, 28, 42], + ], + [15, 20, 25, 10, 27, 28], + 12, + ], + ], + ])('4개 일치 여부가 맞는지', inputs => { + const matchCounts = LottoGameController.matchRank( + inputs[0], + inputs[1], + inputs[2], + ); + expect(matchCounts.findIndex(e => e !== 0)).toEqual(3); + }); + + test.each([ + [ + [ + [ + [1, 2, 3, 4, 5, 6], + [23, 24, 25, 26, 27, 28], + ], + [4, 5, 6, 9, 10, 11], + 12, + ], + ], + [ + [ + [ + [1, 5, 10, 15, 20, 25], + [16, 21, 35, 40, 41, 42], + ], + [15, 20, 25, 26, 27, 28], + 12, + ], + ], + ])('3개 일치 여부가 맞는지', inputs => { + const matchCounts = LottoGameController.matchRank( + inputs[0], + inputs[1], + inputs[2], + ); + expect(matchCounts.findIndex(e => e !== 0)).toEqual(4); + }); +}); diff --git a/docs/README.md b/docs/README.md index 82e5b2980c..4595ff221f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -104,11 +104,11 @@ * 로또 개수 테스트 - - [ ] 3개 일치 여부가 맞는지 - - [ ] 4개 일치 여부가 맞는지 - - [ ] 5개 일치 여부가 맞는지 - - [ ] 5개 일치 + 보너스 번호 일치 여부가 맞는지 - - [ ] 6개 일치 여부가 맞는지 + - [x] 3개 일치 여부가 맞는지 + - [x] 4개 일치 여부가 맞는지 + - [x] 5개 일치 여부가 맞는지 + - [x] 5개 일치 + 보너스 번호 일치 여부가 맞는지 + - [x] 6개 일치 여부가 맞는지 * 수익률 테스트 diff --git a/src/App.js b/src/App.js index 1b93dfacad..d6f452dfa2 100644 --- a/src/App.js +++ b/src/App.js @@ -56,11 +56,15 @@ class App { } } - const match = LottoGameController.matchRank( + console.log(customer.getLottoNumbers()); + console.log(lottoTotal.getLotto().getNumbers()); + console.log(lottoTotal.getBonusNumber()); + const matchCounts = LottoGameController.matchRank( customer.getLottoNumbers(), lottoTotal.getLotto().getNumbers(), lottoTotal.getBonusNumber() ); + console.log(matchCounts); } } diff --git a/src/controllers/LottoGameController.js b/src/controllers/LottoGameController.js index 4fb0156bc2..d3cf13bb08 100644 --- a/src/controllers/LottoGameController.js +++ b/src/controllers/LottoGameController.js @@ -1,14 +1,15 @@ -import { Random } from "@woowacourse/mission-utils"; -import Conditions from "../constants/Conditions.js"; +import { Random } from '@woowacourse/mission-utils'; +import Conditions from '../constants/Conditions.js'; class LottoGameController { static generateCustomerNumbers(lottoCount) { const customerNumbers = []; for (let i = 0; i < lottoCount; i += 1) { const temp = Random.pickUniqueNumbersInRange( - Conditions.NUMBER_MIN, + Conditions.NUMBER_MIN, Conditions.NUMBER_MAX, - Conditions.NUMBER_PICK_COUNT); + Conditions.NUMBER_PICK_COUNT, + ); this.sortInAscendingOrder(temp); customerNumbers.push(temp); } @@ -20,26 +21,40 @@ class LottoGameController { } static matchRank(customerNumbers, winningNumbers, bonusNumber) { - const matchCounts = Array(Conditions.TOTAL_RANK).fill(Conditions.INITIAL_MATCH_COUNT); + const matchCounts = Array(Conditions.TOTAL_RANK).fill( + Conditions.INITIAL_MATCH_COUNT, + ); for (let i = 0; i < customerNumbers.length; i += 1) { const matchCount = this.matchCount(customerNumbers[i], winningNumbers); const isBonusMatch = customerNumbers[i].includes(bonusNumber); switch (matchCount) { - case 6: matchCounts[Conditions.FIRST] += Conditions.COUNT; break; - case 5 && isBonusMatch: matchCounts[Conditions.SECOND] += Conditions.COUNT; break; - case 5: matchCounts[Conditions.THIRD] += Conditions.COUNT; break; - case 4: matchCounts[Conditions.FOURTH] += Conditions.COUNT; break; - case 3: matchCounts[Conditions.FIFTH] += Conditions.COUNT; break; - default: break; + case 6: + matchCounts[Conditions.FIRST] += Conditions.COUNT; + break; + case 4: + matchCounts[Conditions.FOURTH] += Conditions.COUNT; + break; + case 3: + matchCounts[Conditions.FIFTH] += Conditions.COUNT; + break; + default: + break; + } + if (matchCount === 5 && isBonusMatch) { + matchCounts[Conditions.SECOND] += Conditions.COUNT; + } else if (matchCount === 5) { + matchCounts[Conditions.THIRD] += Conditions.COUNT; } } return matchCounts; } static matchCount(customerNumber, winningNumbers) { - return customerNumber.filter(number => winningNumbers.includes(number)).length; + return customerNumber.filter(number => winningNumbers.includes(number)) + .length; } - + + static; } -export default LottoGameController; \ No newline at end of file +export default LottoGameController; From 7544a4422a706d8dbd26cf0f0e84b708845fb6e6 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Fri, 10 Nov 2023 03:08:48 +0900 Subject: [PATCH 37/41] =?UTF-8?q?feat(views):=20OutputView=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=8B=B9=EC=B2=A8=20=ED=86=B5=EA=B3=84=20=EC=A0=9C?= =?UTF-8?q?=EB=AA=A9=20=EB=B0=8F=20=EB=82=B4=EC=97=AD=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.js | 6 ++---- src/constants/messages.js | 16 +++++++++++++--- src/controllers/LottoGameController.js | 1 - src/models/LottoTotal.js | 2 +- src/views/InputView.js | 6 +++--- src/views/OutputView.js | 9 ++++++++- 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/App.js b/src/App.js index d6f452dfa2..db2330f357 100644 --- a/src/App.js +++ b/src/App.js @@ -56,15 +56,13 @@ class App { } } - console.log(customer.getLottoNumbers()); - console.log(lottoTotal.getLotto().getNumbers()); - console.log(lottoTotal.getBonusNumber()); const matchCounts = LottoGameController.matchRank( customer.getLottoNumbers(), lottoTotal.getLotto().getNumbers(), lottoTotal.getBonusNumber() ); - console.log(matchCounts); + + OutputView.printMatchCounts(matchCounts); } } diff --git a/src/constants/messages.js b/src/constants/messages.js index 2909aae1da..65542bbf4f 100644 --- a/src/constants/messages.js +++ b/src/constants/messages.js @@ -1,10 +1,20 @@ const Messages = Object.freeze({ - LOTTO_PRICE_INPUT: '구입금액을 입력해 주세요.', + LOTTO_PRICE: '구입금액을 입력해 주세요.', LOTTO_COUNT: '개를 구매했습니다.', LEFT_BRACKET : '[', RIGHT_BRACKET : ']', - WINNING_NUMBERS_INPUT: '당첨 번호를 입력해 주세요.', - BONUS_NUMBER_INPUT: '보너스 번호를 입력해 주세요.', + WINNING_NUMBERS: '당첨 번호를 입력해 주세요.', + BONUS_NUMBER: '보너스 번호를 입력해 주세요.', + MATCH_RESULT: '당첨 통계', + BREAK_LINE: '---', + RANK : { + 0: '6개 일치 (2,000,000,000원) - ', + 1: '5개 일치, 보너스 볼 일치 (30,000,000원) - ', + 2: '5개 일치 (1,500,000원) - ', + 3: '4개 일치 (50,000원) - ', + 4: '3개 일치 (5,000원) - ', + }, + COUNT_UNIT : '개', }); export default Messages; \ No newline at end of file diff --git a/src/controllers/LottoGameController.js b/src/controllers/LottoGameController.js index d3cf13bb08..cdc1c57d2a 100644 --- a/src/controllers/LottoGameController.js +++ b/src/controllers/LottoGameController.js @@ -54,7 +54,6 @@ class LottoGameController { .length; } - static; } export default LottoGameController; diff --git a/src/models/LottoTotal.js b/src/models/LottoTotal.js index c8ad689bb2..6d75d87520 100644 --- a/src/models/LottoTotal.js +++ b/src/models/LottoTotal.js @@ -11,7 +11,7 @@ class LottoTotal { constructor(lotto, bonusNumber) { this.#lotto = lotto; this.#validateBonusNumber(bonusNumber, lotto); - this.#bonusNumber = bonusNumber; + this.#bonusNumber = Number(bonusNumber); } #validateBonusNumber(bonusNumber, lotto) { diff --git a/src/views/InputView.js b/src/views/InputView.js index a6ff6de13d..496c230e18 100644 --- a/src/views/InputView.js +++ b/src/views/InputView.js @@ -3,15 +3,15 @@ import Messages from '../constants/Messages.js'; class InputView { static getLottoPrice() { - return Console.readLineAsync(`${Messages.LOTTO_PRICE_INPUT}\n`); + return Console.readLineAsync(`${Messages.LOTTO_PRICE}\n`); } static getWinningNumbers() { - return Console.readLineAsync(`\n${Messages.WINNING_NUMBERS_INPUT}\n`); + return Console.readLineAsync(`\n${Messages.WINNING_NUMBERS}\n`); } static getBonusNumber() { - return Console.readLineAsync(`\n${Messages.BONUS_NUMBER_INPUT}\n`); + return Console.readLineAsync(`\n${Messages.BONUS_NUMBER}\n`); } } diff --git a/src/views/OutputView.js b/src/views/OutputView.js index 2683e0692c..cbb2d5861e 100644 --- a/src/views/OutputView.js +++ b/src/views/OutputView.js @@ -16,6 +16,13 @@ class OutputView { Console.print(message); } + static printMatchCounts(matchCounts) { + Console.print(`\n${Messages.MATCH_RESULT}`); + Console.print(`${Messages.BREAK_LINE}`); + for (let i = matchCounts.length - 1; i >= 0; i -= 1) { + Console.print(`${Messages.RANK[i]}${matchCounts[i]}${Messages.COUNT_UNIT}`); + } + } } -export default OutputView; +export default OutputView; \ No newline at end of file From c3c0a1471790caa6145bba8b37ce2dca2f69a62b Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Fri, 10 Nov 2023 03:40:01 +0900 Subject: [PATCH 38/41] =?UTF-8?q?feat(controllers):=20=EB=8B=B9=EC=B2=A8?= =?UTF-8?q?=20=EA=B2=B0=EA=B3=BC(=EC=88=98=EC=9D=B5=EB=A5=A0)=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=20=EA=B8=B0=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 --- .eslintrc.cjs | 1 + docs/README.md | 4 +-- src/App.js | 1 - src/constants/Conditions.js | 24 ++++++++------- src/controllers/LottoGameController.js | 42 ++++++++++++++------------ 5 files changed, 39 insertions(+), 33 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index c083c8fde4..960b6a7da6 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -30,5 +30,6 @@ module.exports = { 'no-unused-vars': 'off', 'no-await-in-loop': 'off', 'no-constant-condition': 'off', + 'no-param-reassign': 'off', }, }; \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 4595ff221f..febb805dfc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -28,10 +28,10 @@ * Controllers - - [ ] 로또 게임 처리/연산 `class` + - [x] 로또 게임 처리/연산 `class` - [x] 구매자가 소유할 로또 번호 목록 생성 - [x] 당첨 내역 연산 - - [ ] 당첨 결과(수익률) 연산 + - [x] 당첨 결과(수익률) 연산
diff --git a/src/App.js b/src/App.js index db2330f357..92151c34d4 100644 --- a/src/App.js +++ b/src/App.js @@ -61,7 +61,6 @@ class App { lottoTotal.getLotto().getNumbers(), lottoTotal.getBonusNumber() ); - OutputView.printMatchCounts(matchCounts); } } diff --git a/src/constants/Conditions.js b/src/constants/Conditions.js index 1e47a5e20b..5b4887b5a8 100644 --- a/src/constants/Conditions.js +++ b/src/constants/Conditions.js @@ -1,16 +1,18 @@ const Conditions = Object.freeze({ - ONE_LOTTO_PRICE : 1000, - NUMBER_MIN : 1, - NUMBER_MAX : 45, - NUMBER_PICK_COUNT : 6, - INITIAL_MATCH_COUNT : 0, - FIRST: 0, - SECOND: 1, - THIRD: 2, - FOURTH: 3, - FIFTH: 4, + ONE_LOTTO_PRICE: 1000, + NUMBER_MIN: 1, + NUMBER_MAX: 45, + NUMBER_PICK_COUNT: 6, + INITIAL_MATCH_COUNT: 0, + RANK: [ + { INDEX: 0, PRIZE: 2000000000}, + { INDEX: 1, PRIZE: 30000000}, + { INDEX: 2, PRIZE: 1500000}, + { INDEX: 3, PRIZE: 50000}, + { INDEX: 4, PRIZE: 5000}, + ], COUNT: 1, TOTAL_RANK: 5, }); -export default Conditions; \ No newline at end of file +export default Conditions; diff --git a/src/controllers/LottoGameController.js b/src/controllers/LottoGameController.js index cdc1c57d2a..bb131663ec 100644 --- a/src/controllers/LottoGameController.js +++ b/src/controllers/LottoGameController.js @@ -27,24 +27,7 @@ class LottoGameController { for (let i = 0; i < customerNumbers.length; i += 1) { const matchCount = this.matchCount(customerNumbers[i], winningNumbers); const isBonusMatch = customerNumbers[i].includes(bonusNumber); - switch (matchCount) { - case 6: - matchCounts[Conditions.FIRST] += Conditions.COUNT; - break; - case 4: - matchCounts[Conditions.FOURTH] += Conditions.COUNT; - break; - case 3: - matchCounts[Conditions.FIFTH] += Conditions.COUNT; - break; - default: - break; - } - if (matchCount === 5 && isBonusMatch) { - matchCounts[Conditions.SECOND] += Conditions.COUNT; - } else if (matchCount === 5) { - matchCounts[Conditions.THIRD] += Conditions.COUNT; - } + this.updateMatchCounts(matchCounts, matchCount, isBonusMatch); } return matchCounts; } @@ -54,6 +37,27 @@ class LottoGameController { .length; } + static updateMatchCounts(matchCounts, matchCount, isBonusMatch) { + switch (matchCount) { + case 6: matchCounts[Conditions.RANK[0].INDEX] += Conditions.COUNT; break; + case 4: matchCounts[Conditions.RANK[3].INDEX] += Conditions.COUNT; break; + case 3: matchCounts[Conditions.RANK[4].INDEX] += Conditions.COUNT; break; + default: break; + } + if (matchCount === 5 && isBonusMatch) { + matchCounts[Conditions.RANK[1].INDEX] += Conditions.COUNT; + } else if (matchCount === 5) { + matchCounts[Conditions.RANK[2].INDEX] += Conditions.COUNT; + } + } + + static returnOfInvestment(matchCounts, lottoPrice) { + const totalPrize = matchCounts.reduce((acc, cur, index) => { + acc += cur * Conditions.RANK[index].PRIZE; + return acc; + }, 0); + return (totalPrize / lottoPrice * 100).toFixed(1); + } } -export default LottoGameController; +export default LottoGameController; \ No newline at end of file From 1f5383cca7df02888fff46bac7093a04baa93a8f Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Fri, 10 Nov 2023 04:20:43 +0900 Subject: [PATCH 39/41] =?UTF-8?q?test:=20=EC=88=98=EC=9D=B5=EB=A5=A0=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 수익률 연산이 맞는지 --- __tests__/ReturnOfInvestmentTest.js | 21 +++++++++++++++++++++ docs/README.md | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 __tests__/ReturnOfInvestmentTest.js diff --git a/__tests__/ReturnOfInvestmentTest.js b/__tests__/ReturnOfInvestmentTest.js new file mode 100644 index 0000000000..29115e6d20 --- /dev/null +++ b/__tests__/ReturnOfInvestmentTest.js @@ -0,0 +1,21 @@ +import LottoGameController from '../src/controllers/LottoGameController'; + +describe('수익률 테스트', () => { + test.each([[[[0, 0, 0, 0, 1], 9000]]])('수익률 연산이 맞는지', inputs => { + expect( + LottoGameController.returnOfInvestment(inputs[0], inputs[1]), + ).toEqual('55.6'); + }); + + test.each([[[[0, 0, 1, 0, 1], 3000]]])('수익률 연산이 맞는지', inputs => { + expect( + LottoGameController.returnOfInvestment(inputs[0], inputs[1]), + ).toEqual('50166.7'); + }); + + test.each([[[[0, 1, 1, 0, 1], 40000]]])('수익률 연산이 맞는지', inputs => { + expect( + LottoGameController.returnOfInvestment(inputs[0], inputs[1]), + ).toEqual('78762.5'); + }); +}); diff --git a/docs/README.md b/docs/README.md index febb805dfc..bf5fb90600 100644 --- a/docs/README.md +++ b/docs/README.md @@ -112,7 +112,7 @@ * 수익률 테스트 - - [ ] 수익률 연산이 맞는지 + - [x] 수익률 연산이 맞는지
From 0bf449b7050cc57b40fae54b4b3b216034888cd9 Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Fri, 10 Nov 2023 04:30:27 +0900 Subject: [PATCH 40/41] =?UTF-8?q?feat(views):=20OutputView=20=EC=88=98?= =?UTF-8?q?=EC=9D=B5=EB=A5=A0=20=EC=B6=9C=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=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 --- docs/README.md | 2 +- src/App.js | 6 ++++++ src/constants/messages.js | 1 + src/models/Customer.js | 4 ++++ src/views/OutputView.js | 4 ++++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index bf5fb90600..e4abae9120 100644 --- a/docs/README.md +++ b/docs/README.md @@ -24,7 +24,7 @@ - [x] 로또 개수 - [x] 번호 목록 출력 - [x] 에러 메세지 출력 - - [ ] 당첨 통계 출력: 제목, 내역, 결과(수익률) + - [x] 당첨 통계 출력: 제목, 내역, 결과(수익률) * Controllers diff --git a/src/App.js b/src/App.js index 92151c34d4..a762aa00a3 100644 --- a/src/App.js +++ b/src/App.js @@ -62,6 +62,12 @@ class App { lottoTotal.getBonusNumber() ); OutputView.printMatchCounts(matchCounts); + + const returnOfInvestment = LottoGameController.returnOfInvestment( + matchCounts, + customer.getLottoPrice() + ); + OutputView.printReturnOfInvestment(returnOfInvestment); } } diff --git a/src/constants/messages.js b/src/constants/messages.js index 65542bbf4f..330c85e69e 100644 --- a/src/constants/messages.js +++ b/src/constants/messages.js @@ -15,6 +15,7 @@ const Messages = Object.freeze({ 4: '3개 일치 (5,000원) - ', }, COUNT_UNIT : '개', + RETURN_OF_INVESTMENT: (ROI) => `총 수익률은 ${ROI}%입니다.`, }); export default Messages; \ No newline at end of file diff --git a/src/models/Customer.js b/src/models/Customer.js index c66fa19d7f..ca68bb3a15 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -38,6 +38,10 @@ class Customer { }); } + getLottoPrice() { + return this.#lottoPrice; + } + getLottoCount() { return this.#lottoCount; } diff --git a/src/views/OutputView.js b/src/views/OutputView.js index cbb2d5861e..00d1181953 100644 --- a/src/views/OutputView.js +++ b/src/views/OutputView.js @@ -23,6 +23,10 @@ class OutputView { Console.print(`${Messages.RANK[i]}${matchCounts[i]}${Messages.COUNT_UNIT}`); } } + + static printReturnOfInvestment(returnOfInvestment) { + Console.print(`${Messages.RETURN_OF_INVESTMENT(returnOfInvestment)}`); + } } export default OutputView; \ No newline at end of file From 4f0422a6aeea08f6b2365266edb20eb733a3e4bb Mon Sep 17 00:00:00 2001 From: Jinhyo Park Date: Fri, 10 Nov 2023 04:41:26 +0900 Subject: [PATCH 41/41] =?UTF-8?q?docs:=20=EC=A3=BC=EC=84=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - controllers, models 폴더 - App.js, Lotto.js, Validations.js --- docs/README.md | 2 +- src/App.js | 7 +++++++ src/Lotto.js | 4 ++++ src/Validations.js | 10 ++++++++++ src/controllers/LottoGameController.js | 17 +++++++++++++++++ src/models/Customer.js | 18 +++++++++++++----- src/models/LottoTotal.js | 5 +++++ 7 files changed, 57 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index e4abae9120..32c2303155 100644 --- a/docs/README.md +++ b/docs/README.md @@ -20,7 +20,7 @@ - [x] 구입금액 입력 - [x] 당첨번호 입력 - [x] 보너스번호 입력 - - [ ] 출력창 및 메세지 출력 `class` + - [x] 출력창 및 메세지 출력 `class` - [x] 로또 개수 - [x] 번호 목록 출력 - [x] 에러 메세지 출력 diff --git a/src/App.js b/src/App.js index a762aa00a3..336db0ef72 100644 --- a/src/App.js +++ b/src/App.js @@ -7,6 +7,7 @@ import LottoGameController from "./controllers/LottoGameController.js"; class App { async play() { + // 구입금액 입력 let customer; while (true) { try { @@ -18,9 +19,11 @@ class App { } } + // 로또 구매 개수 출력 const lottoCount = customer.getLottoCount(); OutputView.printLottoCount(lottoCount); + // 구매자 로또 번호 출력 let lottoNumbers; while (true) { try { @@ -33,6 +36,7 @@ class App { } } + // 당첨 번호 입력 let lotto; while (true) { try { @@ -45,6 +49,7 @@ class App { } } + // 보너스 볼 입력 let lottoTotal; while (true) { try { @@ -56,6 +61,7 @@ class App { } } + // 당첨 통계 출력 const matchCounts = LottoGameController.matchRank( customer.getLottoNumbers(), lottoTotal.getLotto().getNumbers(), @@ -63,6 +69,7 @@ class App { ); OutputView.printMatchCounts(matchCounts); + // 수익률 출력 const returnOfInvestment = LottoGameController.returnOfInvestment( matchCounts, customer.getLottoPrice() diff --git a/src/Lotto.js b/src/Lotto.js index 14fd74e15a..5bcc1e195c 100644 --- a/src/Lotto.js +++ b/src/Lotto.js @@ -8,6 +8,10 @@ class Lotto { this.#numbers = numbers; } + /** + * 당첨 로또 번호 유효성 검사 + * @param {Array} numbers + */ #validate(numbers) { numbers.forEach((number) => { Validations.isNumber(number); diff --git a/src/Validations.js b/src/Validations.js index e7863fcb82..d0f37d01b7 100644 --- a/src/Validations.js +++ b/src/Validations.js @@ -1,12 +1,14 @@ import Errors from './constants/Errors.js'; class Validations { + /** 공백이 있는지 */ static hasSpace(input) { if (/\s+/.test(input)) { throw new Error(Errors.HAS_SPACE); } } + /** 숫자인지 */ static isNumber(input) { const number = Number(input); if (input.length === 0 || Number.isNaN(number)) { @@ -14,6 +16,7 @@ class Validations { } } + /** 양수인지 */ static isPlus(input) { const number = Number(input); if (number <= 0) { @@ -21,6 +24,7 @@ class Validations { } } + /** 1000원 단위인지 */ static isThousandUnit(input) { const number = Number(input); if (number % 1000 !== 0) { @@ -28,6 +32,7 @@ class Validations { } } + /** 1~45 사이의 숫자인지 */ static isInRange(input) { const number = Number(input); if (number < 1 || number > 45) { @@ -35,6 +40,7 @@ class Validations { } } + /** 소수점이 없는지 */ static isInteger(input) { const number = Number(input); if (!Number.isInteger(number)) { @@ -42,6 +48,7 @@ class Validations { } } + /** 중복된 숫자가 없는지 */ static isNotDuplicated(input) { input.forEach((number, index) => { if (input.indexOf(number) !== index) { @@ -50,12 +57,14 @@ class Validations { }); } + /** 길이가 6인지 */ static isProperLength(input) { if (input.length !== 6) { throw new Error(Errors.IS_NOT_PROPER_LENGTH); } } + /** 오름차순으로 정렬되어 있는지 */ static isSorted(input) { const sortedInput = [...input].sort((a, b) => a - b); if (JSON.stringify(input) !== JSON.stringify(sortedInput)) { @@ -63,6 +72,7 @@ class Validations { } } + /** 보너스 번호가 당첨 번호에 포함되어 있는지 */ static isBonusNumberNotDuplicated(bonusNumber, lotto) { const numbers = lotto.getNumbers(); if (numbers.includes(Number(bonusNumber))) { diff --git a/src/controllers/LottoGameController.js b/src/controllers/LottoGameController.js index bb131663ec..0a88dbae05 100644 --- a/src/controllers/LottoGameController.js +++ b/src/controllers/LottoGameController.js @@ -2,6 +2,10 @@ import { Random } from '@woowacourse/mission-utils'; import Conditions from '../constants/Conditions.js'; class LottoGameController { + /** + * 구매자 로또 번호 생성 + * @param {number} lottoCount + */ static generateCustomerNumbers(lottoCount) { const customerNumbers = []; for (let i = 0; i < lottoCount; i += 1) { @@ -20,6 +24,13 @@ class LottoGameController { userNumbers.sort((a, b) => a - b); } + /** + * 당처 번호와 구매자 로또 번호 비교 + * @param {Array} customerNumbers + * @param {Array} winningNumbers + * @param {number} bonusNumber + * @returns {Array} + */ static matchRank(customerNumbers, winningNumbers, bonusNumber) { const matchCounts = Array(Conditions.TOTAL_RANK).fill( Conditions.INITIAL_MATCH_COUNT, @@ -51,6 +62,12 @@ class LottoGameController { } } + /** + * 수익률 계산 + * @param {Array} matchCounts + * @param {number} lottoPrice + * @returns {number} + */ static returnOfInvestment(matchCounts, lottoPrice) { const totalPrize = matchCounts.reduce((acc, cur, index) => { acc += cur * Conditions.RANK[index].PRIZE; diff --git a/src/models/Customer.js b/src/models/Customer.js index ca68bb3a15..28b0cfef7d 100644 --- a/src/models/Customer.js +++ b/src/models/Customer.js @@ -18,6 +18,10 @@ class Customer { this.#lottoNumbers = []; } + /** + * 구입 금액 유효성 검사 + * @param {String} lottoPrice + */ #validateLottoPrice(lottoPrice) { Validations.hasSpace(lottoPrice); Validations.isNumber(lottoPrice); @@ -25,6 +29,10 @@ class Customer { Validations.isThousandUnit(lottoPrice); } + /** + * 구매자 로또 번호 유효성 검사 + * @param {Array} lottoNumbers + */ #validateLottoNumbers(lottoNumbers) { lottoNumbers.forEach((lottoNumber) => { lottoNumber.forEach((number) => { @@ -38,6 +46,11 @@ class Customer { }); } + setLottoNumbers(lottoNumbers) { + this.#validateLottoNumbers(lottoNumbers); + this.#lottoNumbers = lottoNumbers; + } + getLottoPrice() { return this.#lottoPrice; } @@ -46,11 +59,6 @@ class Customer { return this.#lottoCount; } - setLottoNumbers(lottoNumbers) { - this.#validateLottoNumbers(lottoNumbers); - this.#lottoNumbers = lottoNumbers; - } - getLottoNumbers() { return this.#lottoNumbers; } diff --git a/src/models/LottoTotal.js b/src/models/LottoTotal.js index 6d75d87520..68b99e24ab 100644 --- a/src/models/LottoTotal.js +++ b/src/models/LottoTotal.js @@ -14,6 +14,11 @@ class LottoTotal { this.#bonusNumber = Number(bonusNumber); } + /** + * 보너스 번호 유효성 검사 + * @param {number} bonusNumber + * @param {Lotto} lotto + */ #validateBonusNumber(bonusNumber, lotto) { Validations.hasSpace(bonusNumber); Validations.isNumber(bonusNumber);