diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..01c7fd7fd --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,15 @@ +module.exports = { + env: { + browser: true, + es2021: true, + }, + extends: [ + 'airbnb-base', + ], + parserOptions: { + ecmaVersion: 12, + sourceType: 'module', + }, + rules: { + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..37944d1df --- /dev/null +++ b/.gitignore @@ -0,0 +1,151 @@ +# Created by https://www.toptal.com/developers/gitignore/api/macos,node,vscode +# Edit at https://www.toptal.com/developers/gitignore?templates=macos,node,vscode + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test +.env*.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +### vscode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# End of https://www.toptal.com/developers/gitignore/api/macos,node,vscode diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..5f17fec9e --- /dev/null +++ b/docs/README.md @@ -0,0 +1,142 @@ +# ๐Ÿš‡ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๋ฏธ์…˜ + +## ๐Ÿ“„ ๋ฏธ์…˜ ์†Œ๊ฐœ +์ง€ํ•˜์ฒ  ์—ญ, ๋…ธ์„ , ๊ตฌ๊ฐ„์„ ๊ด€๋ฆฌ ํ•˜๊ณ  ์กฐํšŒํ•˜๋Š” ์„œ๋น„์Šค + +## โš™๏ธ ์‹คํ–‰ ๋ฐฉ๋ฒ• +``` +git clone https://github.com/sunhpark42/javascript-subway-map-precourse.git; cd javascript-subway-map-precourse; git checkout sunhpark42; npx http-server +``` +* ๋งŒ์•ฝ http-server ๊ฐ€ ์—†๋‹ค๋ฉด `npm install http-server`๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์žฌ ์‹œํ–‰. + +## ๐Ÿ’ป ๊ฐœ๋ฐœ +### ๊ฐœ๋ฐœ๊ธฐ๊ฐ„ + * 2020.12.09 - 2020.12.15 +### ์‚ฌ์šฉ ์–ธ์–ด +

+ + +

+ +## โš’ ๊ธฐ๋Šฅ ๋ช…์„ธ +### ๋ฉ”๋‰ด +1. ์ด๋ฒคํŠธ ๊ด€๋ฆฌ + - [x] '1. ์—ญ ๊ด€๋ฆฌ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์—ญ ๊ด€๋ฆฌ ๋ทฐ๋ฅผ ์š”์ฒญํ•œ๋‹ค. + - [x] '2. ๋…ธ์„  ๊ด€๋ฆฌ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ๋…ธ์„  ๊ด€๋ฆฌ ๋ทฐ๋ฅผ ์š”์ฒญํ•œ๋‹ค. + - [x] '3. ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ ๋ทฐ๋ฅผ ์š”์ฒญํ•œ๋‹ค. + - [x] '4. ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ถœ๋ ฅ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ถœ๋ ฅ ๋ทฐ๋ฅผ ์š”์ฒญํ•œ๋‹ค. +2. ํ™”๋ฉด ํ‘œ์‹œ + - [x] ์—ญ ๊ด€๋ฆฌ ๋ทฐ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค. + - [x] ๋…ธ์„  ๊ด€๋ฆฌ ๋ทฐ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค. + - [x] ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ ๋ทฐ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค. + - [x] ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ถœ๋ ฅ ๋ทฐ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค. + +### ์ง€ํ•˜์ฒ  ์—ญ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ +1. ์ด๋ฒคํŠธ ๊ด€๋ฆฌ (Controller) + - [x] '์—ญ ์ถ”๊ฐ€' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์—ญ ๋ชฉ๋ก ์ถ”๊ฐ€์™€, ์—ญ ๋ชฉ๋ก ํ™”๋ฉด ๊ฐฑ์‹ ์„ ์š”์ฒญํ•œ๋‹ค. + - [x] ์˜ˆ์™ธ ์‚ฌํ•ญ์— ํ•ด๋‹นํ•˜๋Š” ๊ฒฝ์šฐ, ์—๋Ÿฌ๋ฉ”์„ธ์ง€ ์ถœ๋ ฅ ๋ฐ ์—ญ ์ž…๋ ฅ ํ™”๋ฉด ๊ฐฑ์‹ ์„ ์š”์ฒญํ•˜๊ณ , ์ถ”๊ฐ€ ๋ฐ ๋ชฉ๋ก ๊ฐฑ์‹ ์€ ํ•˜์ง€ ์•Š๋Š”๋‹ค. + - [x] '์‚ญ์ œ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์„ ์š”์ฒญํ•œ๋‹ค. + - [x] ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์—์„œ 'ํ™•์ธ' ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์—ญ ๋ชฉ๋ก์—์„œ ํ•ด๋‹น ์—ญ ์‚ญ์ œ์™€, ์—ญ ๋ชฉ๋ก ํ™”๋ฉด ๊ฐฑ์‹ ์„ ์š”์ฒญํ•œ๋‹ค. + - [x] ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์—์„œ '์ทจ์†Œ' ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€์•Š๋Š”๋‹ค. +2. ํ™”๋ฉด ํ‘œ์‹œ (View) + - [x] ์ „์ฒด ํ™”๋ฉด์„ ํ‘œ์‹œํ•œ๋‹ค (์—ญ ์ž…๋ ฅ ๋ฐ ์—ญ ๋ชฉ๋ก) + - [x] ์—ญ ์ž…๋ ฅ ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•œ๋‹ค. + - [x] ์—ญ ๋ชฉ๋ก ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•œ๋‹ค. + - [x] ์ž…๋ ฅ๋œ ๊ฐ’์ด ์ž˜๋ชป๋˜์—ˆ์Œ์„ ๊ฒฝ๊ณ ํ•˜๋Š” ์ฐฝ์„ ๋„์šด๋‹ค. + - [x] ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์„ ๋„์šด๋‹ค. + - [x] ํ™•์ธ ๋ฐ ์ทจ์†Œ ๋ฒ„ํŠผ +3. ์ฃผ์š” ๊ธฐ๋Šฅ (Model) + - [x] ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ์—ญ ์ด๋ฆ„์ด ์œ ํšจํ•œ์ง€ ํ™•์ธํ•œ๋‹ค. + - [x] ์˜ˆ์™ธ ์ฒ˜๋ฆฌ + 1. ์—ญ ์ด๋ฆ„์ด 2์ž ๋ฏธ๋งŒ์ธ ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ. + 2. ์—ญ ์ด๋ฆ„์— ๊ณต๋ฐฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ + 3. ์—ญ ์ด๋ฆ„์— ๋ชจ์Œ์ด๋‚˜ ์ž์Œ๋งŒ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ์„ ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ. + 4. ์—ญ ์ด๋ฆ„์— ์˜๋ฌธ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ(ํ•œ๊ตญ ์ง€ํ•˜์ฒ ๋กœ ๊ฐ€์ •ํ•จ) + 5. ์—ญ ์ด๋ฆ„์— ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ + - [x] ๊ธฐ์กด ์—ญ ๋ชฉ๋ก์— ์ค‘๋ณต๋œ ์ด๋ฆ„์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. + - [x] ์‚ฌ์šฉ์ž๊ฐ€ ์‚ญ์ œํ•˜๊ธฐ๋กœ ์„ ํƒํ•œ ์—ญ์ด ๋…ธ์„ ์— ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. + - [x] ์—ญ์„ ์—ญ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•œ๋‹ค. + - [x] ํ•ด๋‹น ์—ญ์ด ํฌํ•จ๋œ ๋…ธ์„ ์ด ์ตœ์†Œ ์—ญ ์กฐ๊ฑด (2๊ฐœ ์ด์ƒ)์„ ๋งŒ์กฑํ•˜๋Š”์ง€ ํ™•์ธ + - [x] ์—ญ์„ ์—ญ ๋ชฉ๋ก์—์„œ ์‚ญ์ œํ•œ๋‹ค. + - [x] ์—ญ์„ ํ•ด๋‹น ์—ญ์ด ํฌํ•จ๋œ ๋…ธ์„ ์—์„œ ์‚ญ์ œํ•œ๋‹ค. + - [x] ๊ณ ๋ คํ•ด์•ผ ํ•  ์‚ฌํ•ญ + - ๋งŒ์•ฝ, ์—ญ์ด ํ•˜๋‚˜๋„ ์—†๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ์ง€? + - ์ตœ์†Œ ์—ญ์˜ ๊ฐœ์ˆ˜๋ฅผ ์ง€์ •ํ•  ๊ฒƒ์ธ์ง€ + - ์‚ญ์ œํ–ˆ์„ ๋•Œ ๊ฐ ๋…ธ์„ ์— 2๊ฐœ ์ดํ•˜๊ฐ€ ๋˜๋Š” ๊ณณ์ด ์žˆ์œผ๋ฉด ์‚ญ์ œ๋ฅผ ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ธ์ง€. => ์ฑ„ํƒ + - ์‚ญ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๊ฒฝ๊ณ  ์ฐฝ์„ ๋„์šธ ๊ฒƒ์ธ์ง€? => ์ฑ„ํƒ + +### ์ง€ํ•˜์ฒ  ๋…ธ์„  ๊ด€๋ฆฌ ๊ธฐ๋Šฅ +1. ์ด๋ฒคํŠธ ๊ด€๋ฆฌ (Controller) + - [x] '๋…ธ์„  ์ถ”๊ฐ€' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ๋…ธ์„  ๋ชฉ๋ก ์ถ”๊ฐ€์™€, ๋…ธ์„  ๋ชฉ๋ก ํ™”๋ฉด ๊ฐฑ์‹ ์„ ์š”์ฒญํ•œ๋‹ค. + - [x] '์‚ญ์ œ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์„ ์š”์ฒญํ•œ๋‹ค. + - [x] ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์—์„œ 'ํ™•์ธ' ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋…ธ์„  ๋ชฉ๋ก์—์„œ ํ•ด๋‹น ๋…ธ์„  ์‚ญ์ œ์™€, ๋…ธ์„  ๋ชฉ๋ก ํ™”๋ฉด ๊ฐฑ์‹ ์„ ์š”์ฒญํ•œ๋‹ค. + - [x] ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์—์„œ '์ทจ์†Œ' ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค. +2. ํ™”๋ฉด ํ‘œ์‹œ (View) + - [x] ์ „์ฒด ํ™”๋ฉด์„ ํ‘œ์‹œํ•œ๋‹ค. (๋…ธ์„  ์ž…๋ ฅ ๋ฐ ๋…ธ์„  ๋ชฉ๋ก) + - [x] ๋…ธ์„  ์ž…๋ ฅ ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•œ๋‹ค. + - [x] ๋…ธ์„  ๋ชฉ๋ก ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•œ๋‹ค. + - [x] ์ž…๋ ฅ๋œ ๊ฐ’์ด ์ž˜๋ชป๋˜์—ˆ์Œ์„ ๊ฒฝ๊ณ ํ•˜๋Š” ์ฐฝ์„ ๋„์šด๋‹ค. + - [x] ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์„ ๋„์šด๋‹ค. + * ํ™•์ธ ๋ฐ ์ทจ์†Œ ๋ฒ„ํŠผ +3. ์ฃผ์š” ๊ธฐ๋Šฅ (Model) + - [x] ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋…ธ์„  ์ด๋ฆ„์ด ์œ ํšจํ•œ์ง€ ํ™•์ธํ•œ๋‹ค. + - [x] ์˜ˆ์™ธ ์ฒ˜๋ฆฌ + 1. ๋…ธ์„  ์ด๋ฆ„์ด 2์ž ๋ฏธ๋งŒ์ธ ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ + 2. ๋…ธ์„  ์ด๋ฆ„์— ๊ณต๋ฐฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ + 3. ๋…ธ์„  ์ด๋ฆ„์— ๋ชจ์Œ์ด๋‚˜ ์ž์Œ๋งŒ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ์„ ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ + 4. ๋…ธ์„  ์ด๋ฆ„์— ์˜๋ฌธ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ (ํ•œ๊ตญ ์ง€ํ•˜์ฒ ๋กœ ๊ฐ€์ •ํ•จ) + 5. ๋…ธ์„  ์ด๋ฆ„์— ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ + - [x] ์˜ˆ์™ธ ์‚ฌํ•ญ์— ํ•ด๋‹นํ•˜๋Š” ๊ฒฝ์šฐ ์—ญ ์ž…๋ ฅ ํ™”๋ฉด ๊ฐฑ์‹ ์„ ์š”์ฒญํ•˜๊ณ , ์ถ”๊ฐ€ ๋ฐ ๋ชฉ๋ก ๊ฐฑ์‹ ์€ ํ•˜์ง€ ์•Š๋Š”๋‹ค. + - [x] ๊ธฐ์กด ๋…ธ์„  ๋ชฉ๋ก์— ์ค‘๋ณต๋œ ์ด๋ฆ„์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. + - [x] ์ƒํ–‰ ์ข…์ ์—ญ๊ณผ ํ•˜ํ–‰ ์ข…์ ์—ญ์ด ๊ฐ™์€ ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ ํ•œ๋‹ค. (๋…ธ์„ ์— ์—ญ์ด ํ•˜๋‚˜๋ฟ์ธ ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ) + - [x] ๋…ธ์„ ์„ ๋…ธ์„  ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•œ๋‹ค. + - [x] ๋…ธ์„ ์„ ๋…ธ์„  ๋ชฉ๋ก์—์„œ ์‚ญ์ œํ•œ๋‹ค. + - [x] ํ•ด๋‹น ๋…ธ์„ ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํ•ด๋‹น ๋…ธ์„ ์— ํฌํ•จ๋˜์–ด ์žˆ๋˜ ์—ญ์˜ ์ •๋ณด์—์„œ ์‚ญ์ œํ•œ๋‹ค. + +### ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ +1. ์ด๋ฒคํŠธ ๊ด€๋ฆฌ (Controller) + - [x] ๊ฐ '๋…ธ์„ ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น ๋…ธ์„  ๊ด€๋ฆฌ ํ™”๋ฉด์„ ๋„์›Œ์ค„ ๊ฒƒ์„ ์š”์ฒญํ•œ๋‹ค. + - [x] ๋…ธ์„  ๊ด€๋ฆฌ ํ™”๋ฉด์—์„œ '๋“ฑ๋ก' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๊ฒฝ์šฐ ๊ตฌ๊ฐ„ ๋ชฉ๋ก ์ถ”๊ฐ€์™€, ๊ตฌ๊ฐ„ ๋ชฉ๋ก ํ™”๋ฉด ๊ฐฑ์‹ ์„ ์š”์ฒญํ•œ๋‹ค. + - [x] ๋…ธ์„  ๊ด€๋ฆฌ ํ™”๋ฉด์—์„œ '๋…ธ์„ ์—์„œ ์ œ๊ฑฐ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๊ฒฝ์šฐ ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์„ ์š”์ฒญํ•œ๋‹ค. + - [x] ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์—์„œ 'ํ™•์ธ' ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋…ธ์„  ๋ชฉ๋ก์—์„œ ํ•ด๋‹น ๊ตฌ๊ฐ„ ์‚ญ์ œ์™€, ๊ตฌ๊ฐ„ ๋ชฉ๋ก ํ™”๋ฉด ๊ฐฑ์‹ ์„ ์š”์ฒญํ•œ๋‹ค. + - [x] ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์—์„œ '์ทจ์†Œ' ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๊ตฌ๊ฐ„ ์ž…๋ ฅ ํ™”๋ฉด ๊ฐฑ์‹ ์„ ์š”์ฒญํ•œ๋‹ค. +2. ํ™”๋ฉด ํ‘œ์‹œ (View) + - [x] ์ˆ˜์ •ํ•  ๋…ธ์„  ํ™”๋ฉด์„ ํ‘œ์‹œํ•œ๋‹ค. + - [x] ๋…ธ์„  ๊ด€๋ฆฌ ํ™”๋ฉด์„ ํ‘œ์‹œํ•œ๋‹ค. + - [x] ๋…ธ์„  ๊ด€๋ฆฌ ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•œ๋‹ค. + - [x] ์ž…๋ ฅ๋œ ๊ฐ’์ด ์ž˜๋ชป๋˜์—ˆ์Œ์„ ๊ฒฝ๊ณ ํ•˜๋Š” ์ฐฝ์„ ๋„์šด๋‹ค. + - [x] ์‚ญ์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ฐฝ์„ ๋„์šด๋‹ค. + * ํ™•์ธ ๋ฐ ์ทจ์†Œ ๋ฒ„ํŠผ ์ถ”๊ฐ€ +3. ์ฃผ์š” ๊ธฐ๋Šฅ (Model) + - [x] ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ์ˆœ์„œ ๊ฐ’์ด ์œ ํšจํ•œ์ง€ ํ™•์ธํ•œ๋‹ค. + - [x] ์˜ˆ์™ธ ์ฒ˜๋ฆฌ + 1. ์ˆœ์„œ๊ฐ€ ์Œ์ˆ˜์ธ ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ + 2. ์ˆœ์„œ๊ฐ€ ์ˆซ์ž๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ + 3. ์ˆœ์„œ๊ฐ€ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ (์˜ˆ. 2๊นŒ์ง€ ์žˆ๋Š”๋ฐ 4์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒฝ์šฐ) + - [x] ๊ธฐ์กด ๋…ธ์„ ์— ์ค‘๋ณต๋œ ์ด๋ฆ„์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.(์ค‘๋ณต๋œ ์ด๋ฆ„์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ) + - [x] ๋…ธ์„ ์— ํฌํ•จ๋œ ์—ญ์ด ๋‘๊ฐœ ์ดํ•˜์ธ์ง€ ํ™•์ธํ•œ๋‹ค. + - [x] ๋…ธ์„ ์— ์—ญ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. + - [x] ๋…ธ์„ ์—์„œ ์—ญ์„ ์‚ญ์ œํ•œ๋‹ค. + +### ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ +1. ํ™”๋ฉดํ‘œ์‹œ (View) + - [x] ์—ญ ๋ชฉ๋ก์„ ์ถœ๋ ฅํ•œ๋‹ค. + +### ๊ธฐ๋Šฅ ์—ฐ๊ฒฐ +- [x] ๊ธฐ๋Šฅ ์—ฐ๊ฒฐ + +### ๊ธฐํƒ€ +- [x] ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ๊ฐ’์ด ์—†๋Š” ๊ฒฝ์šฐ default ๊ฐ’ ์‚ฝ์ž…, ์žˆ๋Š” ๊ฒฝ์šฐ ๊ธฐ์กด์˜ ์Šคํ† ๋ฆฌ์ง€ ๊ฐ’์„ ์ด์šฉ. + - ์ด๊ฒฝ์šฐ ๋‘˜ ์ค‘ ํ•˜๋‚˜์— ๊ฐ’์ด ์—†๋Š” ๊ฒฝ์šฐ์— ๋ชจ๋‘ ๋””ํดํŠธ ๊ฐ’์œผ๋กœ ์„ค์ •ํ•˜๋„๋ก ํ•จ. + - ์—ญ, ๋…ธ์„  ๋‚ด์˜ ์—ญ ๋ชฉ๋ก๊ฐ„์˜ ์—ฐ๊ฒฐ์„ฑ ์œ ์ง€๋ฅผ ์œ„ํ•จ. +- [x] ์—ญ - ๋…ธ์„  ๊ฐ„ ์˜์กด์„ฑ ์ถ”๊ฐ€ํ•˜๊ธฐ + - [x] ์—ญ์ด ์‚ญ์ œ๋  ๊ฒฝ์šฐ ํ•ด๋‹น ์—ญ์ด ํฌํ•จ๋œ ๋…ธ์„ ์—์„œ ์—ญ ์‚ญ์ œ +- [x] ๊ฐ ์ƒํ™ฉ๋ณ„ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€ ์ถ”๊ฐ€ + +## โœ”๏ธ ์ปค๋ฐ‹ ๊ทœ์น™ +* feat : ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€ +* fix : ๋ฒ„๊ทธ ์ˆ˜์ • +* docs : ๋ฌธ์„œ์˜ ์ˆ˜์ • +* style : ์ฝ”๋“œ์˜ ์ˆ˜์ • ์—†์ด ์Šคํƒ€์ผ๋งŒ ๋ณ€๊ฒฝ +* refactor : ์ฝ”๋“œ๋ฅผ ๋ฆฌํŽ™ํ† ๋ง +* test : Test ๊ด€๋ จํ•œ ์ฝ”๋“œ์˜ ์ถ”๊ฐ€, ์ˆ˜์ • \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..43c5df79f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1522 @@ +{ + "name": "javascript-subway-map-precourse", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@eslint/eslintrc": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", + "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, + "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.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-includes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz", + "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "get-intrinsic": "^1.0.1", + "is-string": "^1.0.5" + } + }, + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "confusing-browser-globals": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", + "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "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" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "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" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.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.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "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" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.15.0.tgz", + "integrity": "sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.2.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-config-airbnb-base": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", + "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", + "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.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": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "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" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "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": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "file-entry-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", + "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", + "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "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": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "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.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "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" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "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" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "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.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", + "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + } + }, + "object.values": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", + "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "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": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.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 + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "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 + }, + "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" + } + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "string.prototype.trimend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", + "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", + "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "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-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "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 + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..1f229c938 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "javascript-subway-map-precourse", + "version": "1.0.0", + "description": "WooWa_course season 3, last mission ", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/sunhpark42/javascript-subway-map-precourse.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/sunhpark42/javascript-subway-map-precourse/issues" + }, + "homepage": "https://github.com/sunhpark42/javascript-subway-map-precourse#readme", + "devDependencies": { + "eslint": "^7.15.0", + "eslint-config-airbnb-base": "^14.2.1", + "eslint-plugin-import": "^2.22.1" + } +} diff --git a/src/LineManger/LineErrorMsg.js b/src/LineManger/LineErrorMsg.js new file mode 100644 index 000000000..a90657b35 --- /dev/null +++ b/src/LineManger/LineErrorMsg.js @@ -0,0 +1,60 @@ +export default class LineErrorMsg { + static error(number) { + const errorMsg = [ + this.lengthError(), + this.spaceError(), + this.koranCharacterError(), + this.notKoreanError(), + this.specialCharError(), + this.duplicateError(), + this.onlyNumberError(), + this.sameStartEndError(), + this.cancelDeleteError(), + ]; + return errorMsg[number * (-1)]; + } + + /* + * INPUT ERROR + */ + + static lengthError() { + return '๋…ธ์„  ์ด๋ฆ„์€ 2๊ธ€์ž ์ด์ƒ์œผ๋กœ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”.\n'; + } + + static spaceError() { + return '๋…ธ์„  ์ด๋ฆ„ ์‚ฌ์ด์—๋Š” ๊ณต๋ฐฑ์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.\n'; + } + + static koranCharacterError() { + return '์™„์ „ํ•œ ํ•œ๊ธ€ ๋‹จ์–ด๋กœ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.\nex. ใ…์—ญ (x) ๋‹ค์—ญ (o)\n'; + } + + static notKoreanError() { + return '๋…ธ์„  ์ด๋ฆ„์€ ํ•œ๊ธ€๋กœ๋งŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n'; + } + + static specialCharError() { + return '๋…ธ์„  ์ด๋ฆ„์—๋Š” ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ๋“ค์–ด ๊ฐˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.\n'; + } + + static duplicateError() { + return '์ด๋ฏธ ํ•ด๋‹น ์ด๋ฆ„์˜ ๋…ธ์„ ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.\n'; + } + + static onlyNumberError() { + return '๋…ธ์„  ์ด๋ฆ„์€ ์ˆซ์ž๋กœ๋งŒ ์ด๋ฃจ์–ด ์งˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.\n'; + } + + static sameStartEndError() { + return '์ƒํ–‰์„  ์ข…์ ๊ณผ ํ•˜ํ–‰์„  ์ข…์ ์€ ๊ฐ™์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.\n'; + } + + /* + * DELETE ERROR + */ + + static cancelDeleteError() { + return '์‚ญ์ œ๋ฅผ ์ทจ์†Œํ–ˆ์Šต๋‹ˆ๋‹ค.'; + } +} diff --git a/src/LineManger/LineManagerController.js b/src/LineManger/LineManagerController.js new file mode 100644 index 000000000..9fa540628 --- /dev/null +++ b/src/LineManger/LineManagerController.js @@ -0,0 +1,45 @@ +import LineManagerView from './LineManagerView.js'; +import LineManagerModel from './LineManagerModel.js'; + +export default class LineManagerController { + static buttonEventController() { + document.addEventListener('click', (event) => { + const eventId = event.target.id; + const eventClassName = event.target.className; + if (eventId === 'line-add-button') { + this.addButtonClicked(); + } + if (eventClassName === 'line-delete-button') { + const button = event.path[0]; + this.deleteButtonClicked(button); + } + }); + } + + static addButtonClicked() { + const line = document.getElementById('line-name-input').value; + const lineStart = document.getElementById('line-start-station-selector').value; + const lineEnd = document.getElementById('line-end-station-selector').value; + const isValid = LineManagerModel.isValidInput(line, lineStart, lineEnd); + if (isValid !== 1) { + LineManagerView.alertError(isValid); + LineManagerView.lineInputView(); + return; + } + LineManagerModel.add(line, lineStart, lineEnd); + LineManagerView.lineInputView(); + LineManagerView.lineTableView(); + } + + static deleteButtonClicked(button) { + const buttons = document.getElementsByClassName('line-delete-button'); + const buttonsArray = Array.from(buttons); + const line = buttons[buttonsArray.indexOf(button)].dataset.deleteTarget; + if (!LineManagerView.confirmDelete()) { + LineManagerView.alertError(-8); + return; + } + LineManagerModel.delete(line); + LineManagerView.lineTableView(); + } +} diff --git a/src/LineManger/LineManagerModel.js b/src/LineManger/LineManagerModel.js new file mode 100644 index 000000000..063eabf3f --- /dev/null +++ b/src/LineManger/LineManagerModel.js @@ -0,0 +1,93 @@ +export default class LineManagerModel { + /* + * INPUT CHECK + */ + static isValidInput(line, lineStart, lineEnd) { + let isValid = 1; + const validationCheckFunction = [ + this.isValidLength(line), + this.isSpace(line), + this.iskoreanCharacterError(line), + this.isAlpha(line), + this.isSpecialChar(line), + this.isDuplicated(line), + this.isOnlyNumber(line), + this.isSame(lineStart, lineEnd), + ]; + validationCheckFunction.forEach((func, index) => { + if (func && isValid === 1) { + isValid = (-1) * index; + } + }); + return isValid; + } + + static isValidLength(line) { + return line.length < 2; + } + + static isSpace(line) { + return line.indexOf(' ') > -1; + } + + static iskoreanCharacterError(line) { + return /[^๊ฐ€-ํžฃa-z0-9]/.test(line); + } + + static isAlpha(line) { + return /[a-z]/.test(line); + } + + static isSpecialChar(line) { + return /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(line); + } + + static isDuplicated(line) { + const lines = Object.keys(JSON.parse(localStorage.getItem('Lines'))); + return lines.indexOf(line) > -1; + } + + static isOnlyNumber(line) { + return !(/[^0-9]/.test(line)); + } + + static isSame(lineStart, lineEnd) { + return lineStart === lineEnd; + } + + /* + * Add + */ + static add(line, lineStart, lineEnd) { + const lines = JSON.parse(localStorage.getItem('Lines')); + const stations = JSON.parse(localStorage.getItem('Stations')); + + lines[line] = { "stations": [lineStart, lineEnd] }; + if (stations[lineStart].lines.indexOf(line) < 0) { + stations[lineStart].lines.push(line); + } + if (stations[lineEnd].lines.indexOf(line) < 0) { + stations[lineEnd].lines.push(line); + } + + localStorage.setItem('Lines', JSON.stringify(lines)); + localStorage.setItem('Stations', JSON.stringify(stations)); + } + + /* + * DELETE + */ + static delete(line) { + const lines = JSON.parse(localStorage.getItem('Lines')); + const stations = JSON.parse(localStorage.getItem('Stations')); + const stationsIncludedByLine = lines[line].stations; + + stationsIncludedByLine.forEach((station) => { + stations[station].lines.splice(stations[station].lines.indexOf(line), 1); + }); + delete lines[line]; + + localStorage.setItem('Stations', JSON.stringify(stations)); + localStorage.setItem('Lines', JSON.stringify(lines)); + } +} diff --git a/src/LineManger/LineManagerView.js b/src/LineManger/LineManagerView.js new file mode 100644 index 000000000..53e5a5a02 --- /dev/null +++ b/src/LineManger/LineManagerView.js @@ -0,0 +1,60 @@ +import LineErrorMsg from './LineErrorMsg.js'; + +export default class LineManagerView { + static view() { + document.getElementById('sub-view-container').innerHTML = ` +

๋…ธ์„  ์ด๋ฆ„

+

๐Ÿš‰ ์ง€ํ•˜์ฒ  ๋…ธ์„  ๋ชฉ๋ก

+
+
+
+ `; + this.lineInputView(); + this.lineTableView(); + } + + static lineInputView() { + const stations = JSON.parse(localStorage.getItem('Stations')); + document.getElementById('line-input').innerHTML = ` + +

์ƒํ–‰ ์ข…์  + +

+

ํ•˜ํ–‰ ์ข…์  + +

+ `; + } + + static lineTableView() { + const lines = JSON.parse(localStorage.getItem('Lines')); + document.getElementById('line-table').innerHTML = ` + + + + + + + + ${Object.keys(lines).map((line) => ` + + + + + + `).join('')} +
๋…ธ์„  ์ด๋ฆ„์ƒํ–‰ ์ข…์ ์—ญํ•˜ํ–‰ ์ข…์ ์—ญ์„ค์ •
${line}${lines[line].stations[0]}${lines[line].stations[(lines[line].stations.length - 1)]}
`; + } + + static alertError(errorNum) { + alert(LineErrorMsg.error(errorNum)); + } + + static confirmDelete() { + return window.confirm('์ •๋ง๋กœ ์‚ญ์ œ ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?'); + } +} \ No newline at end of file diff --git a/src/MapPrintManager/MapPrintManagerView.js b/src/MapPrintManager/MapPrintManagerView.js new file mode 100644 index 000000000..35eadda4e --- /dev/null +++ b/src/MapPrintManager/MapPrintManagerView.js @@ -0,0 +1,13 @@ +export default class MapPrintManagerView { + static view() { + const lines = JSON.parse(localStorage.getItem('Lines')); + document.getElementById('sub-view-container').innerHTML = ` + ${Object.keys(lines).map((line) => `
+

${line}

+ `).join('')} +
+ `; + } +} diff --git a/src/Menu/MenuController.js b/src/Menu/MenuController.js new file mode 100644 index 000000000..8252cb6b6 --- /dev/null +++ b/src/Menu/MenuController.js @@ -0,0 +1,21 @@ +import MenuView from './MenuView.js'; + +export default class MenuController { + static buttonEventController() { + document.addEventListener('click', (event) => { + const eventId = event.target.id; + if (eventId === 'station-manager-button') { + MenuView.stationManagerView(); + } + if (eventId === 'line-manager-button') { + MenuView.lineManagerView(); + } + if (eventId === 'section-manager-button') { + MenuView.sectionManagerView(); + } + if (eventId === 'map-print-manager-button') { + MenuView.mapPrintManagerView(); + } + }); + } +} diff --git a/src/Menu/MenuView.js b/src/Menu/MenuView.js new file mode 100644 index 000000000..b5c96e47c --- /dev/null +++ b/src/Menu/MenuView.js @@ -0,0 +1,32 @@ +import StationManagerView from '../StationManger/StationManagerView.js' +import LineManagerView from '../LineManger/LineManagerView.js'; +import SectionManagerView from '../SectionManager/SectionManagerView.js'; +import MapPrintManagerView from '../MapPrintManager/MapPrintManagerView.js'; + +export default class MenuView { + static menuButtonListView() { + document.getElementById('app').innerHTML += ` + + + + +
+ `; + } + + static stationManagerView() { + StationManagerView.view(); + } + + static lineManagerView() { + LineManagerView.view(); + } + + static sectionManagerView() { + SectionManagerView.view(); + } + + static mapPrintManagerView() { + MapPrintManagerView.view(); + } +} diff --git a/src/SectionManager/SectionErrorMsg.js b/src/SectionManager/SectionErrorMsg.js new file mode 100644 index 000000000..1bc1bff03 --- /dev/null +++ b/src/SectionManager/SectionErrorMsg.js @@ -0,0 +1,35 @@ +export default class SectionErrorMsg { + static error(number) { + const errorMsg = [ + this.lengthError(), + this.duplicateError(), + this.stationNumberError(), + this.cancelDeleteError(), + ]; + return errorMsg[number * (-1)]; + } + + /* + * INPUT ERROR + */ + + static lengthError() { + return '์ˆœ์„œ๋Š” 0 ์ด์ƒ์˜ ์ •์ˆ˜๋งŒ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n์ตœ๋Œ€ ์ž…๋ ฅ ์ˆœ์„œ ๋ฒˆํ˜ธ๋Š” ๋งˆ์ง€๋ง‰ ์ˆœ์„œ ๋ฒˆํ˜ธ + 1 ์ž…๋‹ˆ๋‹ค.\n'; + } + + static duplicateError() { + return '์ด๋ฏธ ํ•ด๋‹น ์—ญ์ด ๋…ธ์„ ์— ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.\n'; + } + + /* + * DELETE ERROR + */ + + static stationNumberError() { + return 'ํฌํ•จ๋œ ๋…ธ์„ ์ด 2๊ฐœ ์ดํ•˜๋กœ ์—ญ ์‚ญ์ œ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๋‹ค.'; + } + + static cancelDeleteError() { + return '์‚ญ์ œ๋ฅผ ์ทจ์†Œํ–ˆ์Šต๋‹ˆ๋‹ค.'; + } +} diff --git a/src/SectionManager/SectionManagerController.js b/src/SectionManager/SectionManagerController.js new file mode 100644 index 000000000..73c74f507 --- /dev/null +++ b/src/SectionManager/SectionManagerController.js @@ -0,0 +1,62 @@ +import SectionManagerView from './SectionManagerView.js'; +import SectionManagerModel from './SectionManagerModel.js'; + +export default class SectionManagerController { + static buttonEventController() { + let line = null; + document.addEventListener('click', (event) => { + const eventId = event.target.id; + const eventClassName = event.target.className; + if (eventId === 'section-add-button') { + this.addButtonClicked(line); + } else if (eventClassName === 'section-delete-button') { + const button = event.path[0]; + this.deleteButtonClicked(line, button); + } else if (eventClassName === 'section-line-menu-button') { + const button = event.path[0]; + line = this.sectionLineMenuClicked(button); + } + }); + } + + static addButtonClicked(line) { + const index = document.getElementById('section-order-input').value; + const station = document.getElementById('section-station-selector').value; + const isValid = SectionManagerModel.isValidInput(line, index, station); + if (isValid === 1) { + SectionManagerModel.add(line, station, index); + SectionManagerView.sectionInputView(line); + SectionManagerView.sectionTableView(line); + } + if (isValid !== 1) { + SectionManagerView.alertInputError(isValid); + SectionManagerView.sectionInputView(line); + } + } + + static deleteButtonClicked(line, button) { + const buttons = document.getElementsByClassName('section-delete-button'); + const buttonsArray = Array.from(buttons); + const station = buttons[buttonsArray.indexOf(button)].dataset.deleteTarget; + const isValid = SectionManagerModel.checkNumOfStations(line, station); + if (isValid === false) { + SectionManagerView.alertInputError(-2); + return; + } + if (!SectionManagerView.confirmDelete()) { + SectionManagerView.alertInputError(-3); + return; + } + SectionManagerModel.delete(line, station); + SectionManagerView.sectionTableView(line); + } + + static sectionLineMenuClicked(button) { + const buttons = document.getElementsByClassName('section-line-menu-button'); + const buttonsArray = Array.from(buttons); + const line = buttons[buttonsArray.indexOf(button)].dataset.menu; + SectionManagerView.sectionInputView(line); + SectionManagerView.sectionTableView(line); + return line; + } +} diff --git a/src/SectionManager/SectionManagerModel.js b/src/SectionManager/SectionManagerModel.js new file mode 100644 index 000000000..25d4d6b0b --- /dev/null +++ b/src/SectionManager/SectionManagerModel.js @@ -0,0 +1,57 @@ +export default class SectionManagerModel { + static isValidInput(line, index, station) { + if (!SectionManagerModel.isValidNumber(line, index)) { + return 0; + } + if (SectionManagerModel.isDuplicated(line, station)) { + return -1; + } + return 1; + } + + static isValidNumber(line, number) { + return (number !== '') && this.isValidRange(line, number) && this.isNumber(number); + } + + static isValidRange(line, number) { + const linesLength = JSON.parse(localStorage.getItem('Lines'))[line].stations.length; + return linesLength + 1 >= number && number >= 0; + } + + static isNumber(number) { + return !/[^0-9]/.test(`${number}`); + } + + static isDuplicated(line, station) { + const lines = JSON.parse(localStorage.getItem('Lines')); + const stationIncludedByLine = lines[line].stations; + return stationIncludedByLine.indexOf(station) > -1; + } + + static add(line, station, index) { + const lines = JSON.parse(localStorage.getItem('Lines')); + const stationIncludedByLine = lines[line].stations; + const stations = JSON.parse(localStorage.getItem('Stations')); + + if (stations[station].lines.indexOf(line) < 0) { + stations[station].lines.push(line); + } + stationIncludedByLine.splice(index, 0, station); + lines[line].stations = stationIncludedByLine; + + localStorage.setItem('Stations', JSON.stringify(stations)); + localStorage.setItem('Lines', JSON.stringify(lines)); + } + + static checkNumOfStations(line) { + return JSON.parse(localStorage.getItem('Lines'))[line].stations.length > 2; + } + + static delete(line, station) { + const lines = JSON.parse(localStorage.getItem('Lines')); + const stationIncludedByLine = JSON.parse(localStorage.getItem('Lines'))[line].stations; + stationIncludedByLine.splice(stationIncludedByLine.indexOf(station), 1); + lines[line].stations = stationIncludedByLine; + localStorage.setItem('Lines', JSON.stringify(lines)); + } +} diff --git a/src/SectionManager/SectionManagerView.js b/src/SectionManager/SectionManagerView.js new file mode 100644 index 000000000..88fbd302c --- /dev/null +++ b/src/SectionManager/SectionManagerView.js @@ -0,0 +1,59 @@ +import SectionErrorMsg from './SectionErrorMsg.js'; + +export default class SectionManagerView { + static view() { + document.getElementById('sub-view-container').innerHTML = ` +
+
+
+
+ `; + this.sectionSelectView(); + } + + static sectionSelectView() { + const lines = JSON.parse(localStorage.getItem('Lines')); + document.getElementById('section-select').innerHTML = ` +

๊ตฌ๊ฐ„์„ ์ˆ˜์ •ํ•  ๋…ธ์„ ์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”.

+ ${Object.keys(lines).map((line) => ` `).join('')} + `; + } + + static sectionInputView(line) { + const stations = JSON.parse(localStorage.getItem('Stations')); + document.getElementById('section-input').innerHTML = ` +

${line} ๊ด€๋ฆฌ

+

๊ตฌ๊ฐ„ ๋“ฑ๋ก

+ + + `; + } + + static sectionTableView(line) { + const lines = JSON.parse(localStorage.getItem('Lines')); + const stations = lines[line].stations; + document.getElementById('section-table').innerHTML = ` + + + + + + ${stations.map((station) => ` + + + + + `).join('')} +
์ˆœ์„œ์ด๋ฆ„์„ค์ •
${stations.indexOf(station)}${station}
`; + } + + static alertInputError(errorNum) { + alert(SectionErrorMsg.error(errorNum)); + } + + static confirmDelete() { + return window.confirm('์ •๋ง๋กœ ์‚ญ์ œ ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?'); + } +} diff --git a/src/StationManger/StationErrorMsg.js b/src/StationManger/StationErrorMsg.js new file mode 100644 index 000000000..5bbdfef2a --- /dev/null +++ b/src/StationManger/StationErrorMsg.js @@ -0,0 +1,59 @@ +export default class StationErrorMsg { + static error(number) { + const errorMsg = [ + this.lengthError(), + this.spaceError(), + this.koranCharacterError(), + this.notKoreanError(), + this.specialCharError(), + this.duplicateError(), + this.onlyNumberError(), + this.stationNumberError(), + this.cancelDeleteError(), + ]; + return errorMsg[number * (-1)]; + } + + /* + * INPUT ERROR + */ + static lengthError() { + return '์—ญ ์ด๋ฆ„์€ 2๊ธ€์ž ์ด์ƒ์œผ๋กœ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”.\n'; + } + + static spaceError() { + return '์—ญ ์ด๋ฆ„ ์‚ฌ์ด์—๋Š” ๊ณต๋ฐฑ์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.\n'; + } + + static koranCharacterError() { + return '์™„์ „ํ•œ ํ•œ๊ธ€ ๋‹จ์–ด๋กœ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.\nex. ใ…์—ญ (x) ๋‹ค์—ญ (o)\n'; + } + + static notKoreanError() { + return '์—ญ ์ด๋ฆ„์€ ํ•œ๊ธ€๋กœ๋งŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n'; + } + + static specialCharError() { + return '์—ญ ์ด๋ฆ„์—๋Š” ํŠน์ˆ˜ ๋ฌธ์ž๊ฐ€ ๋“ค์–ด ๊ฐˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.\n'; + } + + static duplicateError() { + return '์ด๋ฏธ ํ•ด๋‹น ์ด๋ฆ„์˜ ์—ญ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.\n'; + } + + static onlyNumberError() { + return '์—ญ ์ด๋ฆ„์€ ์ˆซ์ž๋กœ๋งŒ ์ด๋ฃจ์–ด ์งˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.\n'; + } + + /* + * DELETE ERROR + */ + + static stationNumberError() { + return 'ํ•ด๋‹น ์—ญ์ด ํฌํ•จ๋œ ๋…ธ์„  ์ค‘, ํฌํ•จ ๋œ ์—ญ์ด 3๊ฐœ ๋ฏธ๋งŒ์ธ ์—ญ์ด ์žˆ์–ด ์‚ญ์ œ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๋‹ค.'; + } + + static cancelDeleteError() { + return '์‚ญ์ œ๋ฅผ ์ทจ์†Œํ–ˆ์Šต๋‹ˆ๋‹ค.'; + } +} diff --git a/src/StationManger/StationManagerController.js b/src/StationManger/StationManagerController.js new file mode 100644 index 000000000..e58a70ca9 --- /dev/null +++ b/src/StationManger/StationManagerController.js @@ -0,0 +1,48 @@ +import StationManagerView from './StationManagerView.js'; +import StationManagerModel from './StationManagerModel.js'; + +export default class StationManagerController { + static buttonEventController() { + document.addEventListener('click', (event) => { + const eventId = event.target.id; + const eventClassName = event.target.className; + if (eventId === 'station-add-button') { + this.addButtonClicked(); + } + if (eventClassName === 'station-delete-button') { + const button = event.path[0]; + this.deleteButtonClicked(button); + } + }); + } + + static addButtonClicked() { + const station = document.getElementById('station-name-input').value; + const isValid = StationManagerModel.isValidInput(station); + if (isValid !== 1) { + StationManagerView.alertError(isValid); + StationManagerView.stationInputView(); + return; + } + StationManagerModel.add(station); + StationManagerView.stationInputView(); + StationManagerView.stationTableView(); + } + + static deleteButtonClicked(button) { + const buttons = document.getElementsByClassName('station-delete-button'); + const buttonsArray = Array.from(buttons); + const station = buttons[buttonsArray.indexOf(button)].dataset.deleteTarget; + const isValid = StationManagerModel.checkAfterDelete(station); + if (isValid !== 1) { + StationManagerView.alertError(isValid); + return; + } + if (!StationManagerView.confirmDelete()) { + StationManagerView.alertError(-8); + return; + } + StationManagerModel.delete(station); + StationManagerView.stationTableView(); + } +} diff --git a/src/StationManger/StationManagerModel.js b/src/StationManger/StationManagerModel.js new file mode 100644 index 000000000..1d0d289b3 --- /dev/null +++ b/src/StationManger/StationManagerModel.js @@ -0,0 +1,95 @@ +export default class StationManagerModel { + /* + * INPUT CHECK + */ + + static isValidInput(station) { + let isValid = 1; + const validationCheckFunction = [ + this.isValidLength(station), + this.isSpace(station), + this.iskoreanCharacterError(station), + this.isAlpha(station), + this.isSpecialChar(station), + this.isDuplicated(station), + this.isOnlyNumber(station), + ]; + validationCheckFunction.forEach((func, index) => { + if (func && isValid === 1) { + isValid = (-1) * index; + } + }); + return isValid; + } + + static isValidLength(station) { + return station.length < 2; + } + + static isSpace(station) { + return station.indexOf(' ') > -1; + } + + static iskoreanCharacterError(station) { + return /[^๊ฐ€-ํžฃa-x0-9]/.test(station); + } + + static isAlpha(station) { + return /[a-z]/.test(station); + } + + static isSpecialChar(station) { + return /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(station); + } + + static isDuplicated(station) { + const stations = JSON.parse(localStorage.getItem('Stations')); + return Object.keys(stations).indexOf(station) > -1; + } + + static isOnlyNumber(station) { + return !(/[^0-9]/.test(station)); + } + + /* + * Add + */ + + static add(station) { + const stations = JSON.parse(localStorage.getItem('Stations')); + stations[station] = { "lines": [] }; + localStorage.setItem('Stations', JSON.stringify(stations)); + } + + /* + * DELETE + */ + + static delete(station) { + const stations = JSON.parse(localStorage.getItem('Stations')); + const lines = JSON.parse(localStorage.getItem('Lines')); + const linesIncludingStation = stations[station].lines; + + linesIncludingStation.forEach((line) => { + lines[line].stations.splice(lines[line].stations.indexOf(station), 1); + }); + delete stations[station]; + + localStorage.setItem('Lines', JSON.stringify(lines)); + localStorage.setItem('Stations', JSON.stringify(stations)); + } + + static checkAfterDelete(station) { + const stations = JSON.parse(localStorage.getItem('Stations')); + const lines = JSON.parse(localStorage.getItem('Lines')); + const linesIncludingStation = stations[station].lines; + + let isValid = 1; + linesIncludingStation.forEach((line) => { + if (lines[line].stations.length <= 2) { + isValid = -7; + } + }); + return isValid; + } +} diff --git a/src/StationManger/StationManagerView.js b/src/StationManger/StationManagerView.js new file mode 100644 index 000000000..e9d40c809 --- /dev/null +++ b/src/StationManger/StationManagerView.js @@ -0,0 +1,49 @@ +import StationErrorMsg from './StationErrorMsg.js'; + +export default class StationManagerView { + static view() { + this.stationInitView(); + this.stationInputView(); + this.stationTableView(); + } + + static stationInitView() { + document.getElementById('sub-view-container').innerHTML = ` +
+
+ `; + } + + static stationInputView() { + document.getElementById('station-input-view').innerHTML = ` +

์—ญ ์ด๋ฆ„

+ + + `; + } + + static stationTableView() { + const stations = JSON.parse(localStorage.getItem('Stations')); + document.getElementById('station-table-view').innerHTML = ` +

๐Ÿš‰ ์ง€ํ•˜์ฒ  ์—ญ ๋ชฉ๋ก

+ + + + + + ${Object.keys(stations).map((station) => ` + + + + `).join('')} +
์—ญ ์ด๋ฆ„์„ค์ •
${station}
`; + } + + static alertError(errorNum) { + alert(StationErrorMsg.error(errorNum)); + } + + static confirmDelete() { + return window.confirm('์ •๋ง๋กœ ์‚ญ์ œ ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?'); + } +} diff --git a/src/index.js b/src/index.js index e69de29bb..d3514520a 100644 --- a/src/index.js +++ b/src/index.js @@ -0,0 +1,42 @@ +import MenuView from './Menu/MenuView.js'; +import MenuController from './Menu/MenuController.js'; +import StationManagerController from './StationManger/StationManagerController.js'; +import LineManagerController from './LineManger/LineManagerController.js'; +import SectionManagerController from './SectionManager/SectionManagerController.js'; + +export default class SubwayManager { + constructor() { + if (this.checkLocalStorage()) { + this.setLocalStrageDefault(); + } + MenuView.menuButtonListView(); + MenuController.buttonEventController(); + SectionManagerController.buttonEventController(); + LineManagerController.buttonEventController(); + StationManagerController.buttonEventController(); + } + + checkLocalStorage() { + const stations = localStorage.getItem('Stations'); + const lines = localStorage.getItem('Lines'); + return !(stations && lines) || (stations === '{}') || (lines === '{}'); + } + + setLocalStrageDefault() { + const stationDefault = { + "์ธ์ฒœ": { "lines": ["1ํ˜ธ์„ ", "3ํ˜ธ์„ "] }, + "์„œ์šธ์—ญ": { "lines": ["1ํ˜ธ์„ ", "2ํ˜ธ์„ "] }, + "์†Œ์š”์‚ฐ": { "lines": ["1ํ˜ธ์„ ", "3ํ˜ธ์„ "] }, + "์‹ ๋„๋ฆผ": { "lines": ["2ํ˜ธ์„ "] } + }; + const lineDefault = { + "1ํ˜ธ์„ ": { "stations": ["์ธ์ฒœ", "์„œ์šธ์—ญ", "์†Œ์š”์‚ฐ"] }, + "2ํ˜ธ์„ ": { "stations": ["์‹ ๋„๋ฆผ", "์„œ์šธ์—ญ"] }, + "3ํ˜ธ์„ ": { "stations": ["์†Œ์š”์‚ฐ", "์ธ์ฒœ"] } + }; + localStorage.setItem('Stations', JSON.stringify(stationDefault)); + localStorage.setItem('Lines', JSON.stringify(lineDefault)); + } +} + +new SubwayManager();