diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..0581aac64 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,16 @@ +// eslint-disable-next-line no-undef +module.exports = { + env: { + browser: true, + es2021: true, + }, + extends: ['eslint:recommended', 'plugin:prettier/recommended'], + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + ecmaVersion: 12, + sourceType: 'module', + }, + rules: {}, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..b512c09d4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..904c1187f --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,11 @@ +{ + "printWidth": 100, + "tabWidth": 2, + "singleQuote": true, + "trailingComma": "all", + "bracketSpacing": true, + "semi": true, + "useTabs": false, + "arrowParens": "avoid", + "endOfLine": "lf" +} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..a72e0ed60 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,24 @@ +## ✏️ Todos +- [X] 기능 목록 정리 +- [X] eslint, prettier 세팅 +- [X] 1, 2, 3, 4번 메뉴 버튼 생성 +- [X] **역** 지하철 역 등록 +- [X] (추가)**역** localStorage에 지하철 역 등록 +- [X] (추가)**역** 역 삭제 (localStorage에서도 삭제) +- [X] **역** 지하철 역 등록 시 이름 에러 핸들링 +- [X] **역** 지하철 역 목록 조회 +- [X] **노선** 노선 등록 (input 받기) +- [X] (추가)**노선** localStorage에 노선 등록 +- [X] **노선** 노선 등록 시 이름 에러 핸들링 +- [X] **노선** 노선 삭제 +- [X] **노선** 노선 목록 조회 +- [X] (추가)**역&노선** localStorage가 비어있을 때 출력 +- [X] **구간** 구간 추가 +- [X] (추가)**구간** localStorage에 구간 추가 +- [X] (추가)**노선** 종점역 로직 수정 +- [X] (추가)**구간** 구간 출력 +- [X] **구간** 구간 삭제 +- [X] **구간** 구간 종점 삭제 시 다음 역을 종점으로 +- [X] **구간** 노선 포함 역 2개 이하면 제거 불가 +- [X] 노선에 등록된 역 목록 조회 +- [X] (추가)**역** 노선에 등록된 역 삭제 불가 diff --git a/index.html b/index.html index fc99deac2..3ad467e6a 100644 --- a/index.html +++ b/index.html @@ -7,6 +7,12 @@

🚇 지하철 노선도 관리

+
+ + + + +
diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..e9a1f5b44 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,943 @@ +{ + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "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 + }, + "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" + } + }, + "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-prettier": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.0.0.tgz", + "integrity": "sha512-8Y8lGLVPPZdaNA7JXqnvETVC7IiVRgAP6afQu9gOQRn90YY3otMNh+x7Vr2vMePQntF+5erdSUBqSzCmU/AxaQ==", + "dev": true + }, + "eslint-plugin-prettier": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.2.0.tgz", + "integrity": "sha512-kOUSJnFjAUFKwVxuzy6sA5yyMx6+o9ino4gCdShzBNx4eyFRudWRYKCFolKjoM40PEiuU6Cn7wBLfq3WsGg7qg==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "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-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "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" + } + }, + "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 + }, + "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 + }, + "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" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "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-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" + } + }, + "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 + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "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": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "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 + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "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" + } + }, + "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" + } + } + } + }, + "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-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 + }, + "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 + }, + "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..81ac2d887 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "javascript-subway-map-precourse", + "version": "1.0.0", + "description": "## 🚀 기능 요구사항", + "main": "index.js", + "directories": { + "doc": "docs" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/zigsong/javascript-subway-map-precourse.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/zigsong/javascript-subway-map-precourse/issues" + }, + "homepage": "https://github.com/zigsong/javascript-subway-map-precourse#readme", + "devDependencies": { + "eslint": "^7.15.0", + "eslint-config-prettier": "^7.0.0", + "eslint-plugin-prettier": "^3.2.0", + "prettier": "^2.2.1" + } +} diff --git a/src/index.js b/src/index.js index e69de29bb..7f55a0144 100644 --- a/src/index.js +++ b/src/index.js @@ -0,0 +1,18 @@ +import { initStationManager } from './managers/stationManager.js'; +import { initLineManager } from './managers/lineManager.js'; +import { initSectionManager } from './managers/sectionManager.js'; +import { initMapManager } from './managers/mapManager.js'; + +export default function SubwayMap() { + const stationMngBtn = document.getElementById('station-manager-button'); + const lineMngBtn = document.getElementById('line-manager-button'); + const sectionMngBtn = document.getElementById('section-manager-button'); + const mapPrintMngBtn = document.getElementById('map-print-manager-button'); + + stationMngBtn.addEventListener('click', () => initStationManager()); + lineMngBtn.addEventListener('click', () => initLineManager()); + sectionMngBtn.addEventListener('click', () => initSectionManager()); + mapPrintMngBtn.addEventListener('click', () => initMapManager()); +} + +new SubwayMap(); diff --git a/src/managers/lineManager.js b/src/managers/lineManager.js new file mode 100644 index 000000000..afd0dd515 --- /dev/null +++ b/src/managers/lineManager.js @@ -0,0 +1,146 @@ +import { + clearPage, + createTextInput, + createSubmitBtn, + createSelectbox, + createTable, +} from '../utils/utils.js'; +import { getLocalStorage, setLocalStorage } from '../utils/storage.js'; +import { lineText as T } from '../utils/constants.js'; + +const app = document.getElementById('app'); +const STORAGE_KEY_STATION = 'stations'; +const STORAGE_KEY_LINE = 'lines'; +const DATA_KEY_LINE = 'line'; + +export const initLineManager = () => { + clearPage(); + createPage(); +}; + +const createPage = () => { + createTextInput(T.INPUT_LABEL, T.INPUT_ID, T.PLACEHOLDER); + createSelectArea(); + const submitBtn = createSubmitBtn(T.SUBMIT_ID, T.SUBMIT_TEXT); + handleSubmit(submitBtn); + createResultArea(); +}; + +const createSelectArea = () => { + const selectArea = document.createElement('div'); + const stations = getLocalStorage(STORAGE_KEY_STATION); + + const upwardSelect = createSelectbox(T.START_SELECTOR_ID, stations); + const upwardLabel = document.createElement('b'); + upwardLabel.innerHTML = T.START_SELECTOR_TEXT; + + const downwardSelect = createSelectbox(T.END_SELECTOR_ID, stations); + const downwardLabel = document.createElement('b'); + downwardLabel.innerHTML = T.END_SELECTOR_TEXT; + + selectArea.append(upwardLabel, upwardSelect, document.createElement('br')); + selectArea.append(downwardLabel, downwardSelect); + + app.append(selectArea); +}; + +const handleSubmit = submitBtn => { + app.append(document.createElement('br'), submitBtn); + + const inputText = document.getElementById(T.INPUT_ID); + const upwardSelect = document.getElementById(T.START_SELECTOR_ID); + const downwardSelect = document.getElementById(T.END_SELECTOR_ID); + + let startStation = upwardSelect.value; + let endStation = downwardSelect.value; + upwardSelect.addEventListener('change', () => (startStation = upwardSelect.value)); + downwardSelect.addEventListener('change', () => (endStation = downwardSelect.value)); + + submitBtn.addEventListener('click', () => { + addLine(inputText.value, startStation, endStation); + inputText.value = ''; + }); +}; + +const addLine = (line, start, end) => { + if (!validateName(line)) return; + + const currLines = getLocalStorage(STORAGE_KEY_LINE); + const updatedLines = currLines ? currLines : {}; + updatedLines[line] = [start, end]; + setLocalStorage(STORAGE_KEY_LINE, updatedLines); + addToTable(line, start, end); +}; + +const validateName = lineName => { + const lines = getLocalStorage(STORAGE_KEY_LINE); + if (lines && Object.keys(lines).includes(lineName)) { + alert(T.ALERT_DUPLICATE_NAME); + return false; + } + return true; +}; + +const createResultArea = () => { + const tableName = document.createElement('h2'); + tableName.innerHTML = T.RESULT_TITLE; + app.append(tableName); + + const lineTableHeaders = [T.TABLE_HEADER_1, T.TABLE_HEADER_2, T.TABLE_HEADER_3, T.TABLE_HEADER_4]; + const lineTable = createTable(T.TABLE_ID, lineTableHeaders); + const lines = getLocalStorage(STORAGE_KEY_LINE); + if (lines) { + addTableData(lineTable, lines); + } + + app.append(lineTable); +}; + +const addTableData = (table, lines) => { + Object.entries(lines).map(([line, stations]) => { + const tableRow = addTableRow(line, stations[0], stations[stations.length - 1]); + table.append(tableRow); + }); +}; + +const addTableRow = (line, upwardEnd, downwardEnd) => { + const tableRow = document.createElement('tr'); + tableRow.dataset[DATA_KEY_LINE] = `_${line}`; + + const nameData = document.createElement('td'); + nameData.innerHTML = line; + const upwardEndData = document.createElement('td'); + upwardEndData.innerHTML = upwardEnd; + const downwardEndData = document.createElement('td'); + downwardEndData.innerHTML = downwardEnd; + const deleteBtn = createDeleteBtn(line); + + tableRow.append(nameData, upwardEndData, downwardEndData, deleteBtn); + return tableRow; +}; + +const addToTable = (line, start, end) => { + const lineTable = document.getElementById(T.TABLE_ID); + const newRow = addTableRow(line, start, end); + lineTable.append(newRow); +}; + +const createDeleteBtn = line => { + const deleteBtn = document.createElement('button'); + deleteBtn.setAttribute('class', T.DELETE_BTN_CLASS); + deleteBtn.innerHTML = T.DELETE_BTN_TEXT; + deleteBtn.addEventListener('click', () => deleteLine(line)); + + return deleteBtn; +}; + +const deleteLine = line => { + if (confirm(T.ALERT_CONFIRM_DELETE)) { + const lineTable = document.getElementById(T.TABLE_ID); + const currLines = getLocalStorage(STORAGE_KEY_LINE); + delete currLines[line]; + setLocalStorage(STORAGE_KEY_LINE, currLines); + const rowToBeDeleted = lineTable.querySelector(`[data-${DATA_KEY_LINE}=_${line}]`); + lineTable.removeChild(rowToBeDeleted); + } +}; diff --git a/src/managers/mapManager.js b/src/managers/mapManager.js new file mode 100644 index 000000000..314443806 --- /dev/null +++ b/src/managers/mapManager.js @@ -0,0 +1,39 @@ +import { clearPage } from '../utils/utils.js'; +import { getLocalStorage } from '../utils/storage.js'; +import { mapText as T } from '../utils/constants.js'; + +const app = document.getElementById('app'); +const STORAGE_KEY_LINE = 'lines'; + +export const initMapManager = () => { + clearPage(); + createResultArea(); +}; + +const createResultArea = () => { + const resultArea = document.createElement('div'); + resultArea.setAttribute('class', T.RESULT_AREA_CLASS); + + const lines = getLocalStorage(STORAGE_KEY_LINE); + if (lines) { + printResult(resultArea, lines); + } +}; + +const printResult = (resultArea, data) => { + Object.entries(data).map(([line, stations]) => { + const lineTitle = document.createElement('h3'); + lineTitle.innerHTML = line; + const stationList = document.createElement('ul'); + + stations.map(station => { + const stationItem = document.createElement('li'); + stationItem.innerHTML = station; + stationList.append(stationItem); + }); + + resultArea.append(lineTitle, stationList); + }); + + app.append(resultArea); +}; diff --git a/src/managers/sectionManager.js b/src/managers/sectionManager.js new file mode 100644 index 000000000..6b773c34c --- /dev/null +++ b/src/managers/sectionManager.js @@ -0,0 +1,192 @@ +import { clearPage, createSubmitBtn, createSelectbox, createTable } from '../utils/utils.js'; +import { getLocalStorage, setLocalStorage } from '../utils/storage.js'; +import { sectionText as T } from '../utils/constants.js'; + +const app = document.getElementById('app'); +const STORAGE_KEY_STATION = 'stations'; +const STORAGE_KEY_LINE = 'lines'; + +export const initSectionManager = () => { + clearPage(); + printGuideText(); +}; + +const printGuideText = () => { + const sectionHeader = document.createElement('div'); + const sectionTitle = document.createElement('h3'); + sectionTitle.innerText = T.GUIDE_TEXT; + sectionHeader.append(sectionTitle); + createMenuButtons(sectionHeader); + + app.append(sectionHeader); +}; + +const createMenuButtons = sectionHeader => { + const lines = getLocalStorage(STORAGE_KEY_LINE); + if (lines) { + Object.keys(lines).map(line => { + const menuBtn = document.createElement('button'); + menuBtn.setAttribute('class', T.MENU_BUTTON_CLASS); + menuBtn.innerHTML = line; + menuBtn.style.margin = '2px'; + menuBtn.addEventListener('click', () => { + clearInputs(); + createPage(line); + createResultArea(line); + }); + sectionHeader.append(menuBtn); + }); + } +}; + +const clearInputs = () => { + const sectionInputArea = document.getElementById(T.INPUT_ID); + const selectArea = document.getElementById(T.SELECTOR_ID); + const sectionTable = document.getElementById(T.TABLE_ID); + + if (sectionInputArea && selectArea && sectionTable) { + app.removeChild(sectionInputArea); + app.removeChild(selectArea); + app.removeChild(sectionTable); + } +}; + +const createPage = line => { + const sectionInputArea = document.createElement('div'); + sectionInputArea.setAttribute('id', T.INPUT_ID); + + const manageTitle = document.createElement('h3'); + manageTitle.innerHTML = `${line} ${T.MANAGE_TEXT}`; + const registerTitle = document.createElement('b'); + registerTitle.innerHTML = T.REGISTER_TEXT; + + sectionInputArea.append(manageTitle, registerTitle); + app.append(sectionInputArea); + + createSelectArea(line); +}; + +const createSelectArea = line => { + const selectArea = document.createElement('div'); + selectArea.setAttribute('id', T.SELECTOR_ID); + + const stations = getLocalStorage(STORAGE_KEY_STATION); + const stationSelect = createSelectbox(T.SELECTOR_ID, stations); + + let selectedStation = stationSelect.value; + stationSelect.addEventListener('change', () => (selectedStation = stationSelect.value)); + const orderInput = createNumberInput(); + const submitBtn = createSubmitBtn(T.SUBMIT_ID, T.SUBMIT_TEXT); + + submitBtn.addEventListener('click', () => addToSection(line, selectedStation, orderInput)); + selectArea.append(stationSelect, orderInput, submitBtn); + app.append(selectArea); +}; + +const createNumberInput = () => { + const orderInput = document.createElement('input'); + orderInput.type = 'number'; + orderInput.setAttribute('id', T.ORDER_INPUT_ID); + orderInput.setAttribute('placholder', T.PLACEHOLDER); + + return orderInput; +}; + +const addToSection = (line, station, orderInput) => { + const order = orderInput.value; + if (!validateOrder(line, order)) return; + orderInput.value = ''; + + const currLines = getLocalStorage(STORAGE_KEY_LINE); + const currStations = currLines[line]; + + currStations.splice(order, 0, station); + const updatedLines = currLines; + updatedLines[line] = currStations; + setLocalStorage(STORAGE_KEY_LINE, updatedLines); + + removeCurrResult(); + createResultArea(line); +}; + +const validateOrder = (line, order) => { + const lines = getLocalStorage(STORAGE_KEY_LINE); + if (order < 0) { + alert(T.ALERT_NEGATIVE_ORDER); + return false; + } else if (order > lines[line].length) { + alert(T.ALERT_OVERLOAD_ORDER); + return false; + } + return true; +}; + +const removeCurrResult = () => { + const sectionTable = document.getElementById(T.TABLE_ID); + app.removeChild(sectionTable); +}; + +const createResultArea = line => { + const sectionTableHeaders = [T.TABLE_HEADER_1, T.TABLE_HEADER_2, T.TABLE_HEADER_3]; + const sectionTable = createTable(T.TABLE_ID, sectionTableHeaders); + sectionTable.style.marginTop = '20px'; + app.append(sectionTable); + + const lines = getLocalStorage(STORAGE_KEY_LINE); + if (lines) { + const stations = lines[line]; + addTableData(sectionTable, line, stations); + } + + app.append(sectionTable); +}; + +const addTableData = (table, line, stations) => { + stations.map((station, idx) => { + const tableRow = document.createElement('tr'); + tableRow.dataset['line'] = line; + tableRow.dataset['station'] = station; + + const indexData = document.createElement('td'); + indexData.innerHTML = idx; + const nameData = document.createElement('td'); + nameData.innerHTML = station; + const deleteBtn = createDeleteBtn(station, line); + + tableRow.append(indexData, nameData, deleteBtn); + table.append(tableRow); + }); +}; + +const createDeleteBtn = (station, line) => { + const deleteBtn = document.createElement('button'); + deleteBtn.setAttribute('class', T.DELETE_BTN_CLASS); + deleteBtn.innerHTML = T.DELETE_BTN_TEXT; + deleteBtn.addEventListener('click', () => deleteStation(station, line)); + + return deleteBtn; +}; + +const deleteStation = (station, line) => { + const currLines = getLocalStorage(STORAGE_KEY_LINE); + const currStations = getLocalStorage(STORAGE_KEY_LINE)[line]; + + if (!isAbleToDelete(currStations)) return; + + if (confirm(T.ALERT_CONFIRM_DELETE)) { + currStations.splice(currStations.indexOf(station), 1); + const updatedLines = currLines; + updatedLines[line] = currStations; + setLocalStorage(STORAGE_KEY_LINE, updatedLines); + removeCurrResult(); + createResultArea(line); + } +}; + +const isAbleToDelete = stations => { + if (stations.length <= 2) { + alert(T.ALERT_STATION_UNDER_TWO); + return false; + } + return true; +}; diff --git a/src/managers/stationManager.js b/src/managers/stationManager.js new file mode 100644 index 000000000..9bb177f05 --- /dev/null +++ b/src/managers/stationManager.js @@ -0,0 +1,131 @@ +import { clearPage, createSubmitBtn, createTextInput, createTable } from '../utils/utils.js'; +import { getLocalStorage, setLocalStorage } from '../utils/storage.js'; +import { stationText as T } from '../utils/constants.js'; + +const app = document.getElementById('app'); +const STORAGE_KEY_STATION = 'stations'; +const DATA_KEY_STATION = 'station'; +const STORAGE_KEY_LINE = 'lines'; + +export const initStationManager = () => { + clearPage(); + createPage(); +}; + +const createPage = () => { + createTextInput(T.INPUT_LABEL, T.INPUT_ID, T.PLACEHOLDER); + const submitBtn = createSubmitBtn(T.SUBMIT_ID, T.SUBMIT_TEXT); + handleSubmit(submitBtn); + createResultArea(); +}; + +const handleSubmit = submitBtn => { + const inputArea = document.getElementById(T.INPUT_CONTAINER); + inputArea.append(submitBtn); + const inputText = document.getElementById(T.INPUT_ID); + + inputText.addEventListener('keypress', e => { + if (e.key === 'Enter') { + addStation(inputText.value); + inputText.value = ''; + } + }); + + submitBtn.addEventListener('click', () => { + addStation(inputText.value); + inputText.value = ''; + }); +}; + +const addStation = name => { + if (!validateName(name)) return; + + const currStations = getLocalStorage(STORAGE_KEY_STATION); + const updatedStations = currStations ? [...currStations, name] : [name]; + setLocalStorage(STORAGE_KEY_STATION, updatedStations); + addToTable(name); +}; + +const validateName = name => { + const stations = getLocalStorage(STORAGE_KEY_STATION); + if (stations && stations.includes(name)) { + alert(T.ALERT_DUPLICATE_NAME); + return false; + } else if (name.length < 2) { + alert(T.ALERT_NAME_UNDER_TWO); + return false; + } + return true; +}; + +const createResultArea = () => { + const tableName = document.createElement('h2'); + tableName.innerHTML = T.RESULT_TITLE; + + const stationTableHeaders = [T.TABLE_HEADER_1, T.TABLE_HEADER_2]; + const stationTable = createTable(T.TABLE_ID, stationTableHeaders); + + const stations = getLocalStorage(STORAGE_KEY_STATION); + if (stations) { + addTableData(stationTable, stations); + } + + app.append(tableName, stationTable); +}; + +const addTableData = (table, stations) => { + stations.map(station => { + const tableRow = addTableRow(station); + table.append(tableRow); + }); +}; + +const addTableRow = station => { + const tableRow = document.createElement('tr'); + tableRow.dataset[DATA_KEY_STATION] = station; + const nameData = document.createElement('td'); + nameData.innerHTML = station; + const deleteBtn = createDeleteBtn(station); + + tableRow.append(nameData, deleteBtn); + return tableRow; +}; + +const addToTable = name => { + const stationTable = document.getElementById(T.TABLE_ID); + const newRow = addTableRow(name); + stationTable.append(newRow); +}; + +const createDeleteBtn = station => { + const deleteBtn = document.createElement('button'); + deleteBtn.setAttribute('class', T.DELETE_BTN_CLASS); + deleteBtn.innerHTML = T.DELETE_BTN_TEXT; + deleteBtn.addEventListener('click', () => deleteStation(station)); + + return deleteBtn; +}; + +const deleteStation = name => { + if (!isAbleToDelete(name)) return; + + if (confirm(T.ALERT_CONFIRM_DELETE)) { + const stationTable = document.getElementById(T.TABLE_ID); + const currStations = getLocalStorage(STORAGE_KEY_STATION); + const updatedStations = currStations.filter(station => station !== name); + setLocalStorage(STORAGE_KEY_STATION, updatedStations); + const rowToBeDeleted = stationTable.querySelector(`[data-${DATA_KEY_STATION}=${name}]`); + stationTable.removeChild(rowToBeDeleted); + } +}; + +const isAbleToDelete = name => { + const lines = getLocalStorage(STORAGE_KEY_LINE); + for (let stations of Object.values(lines)) { + if (stations.includes(name)) { + alert(T.ALERT_STATION_IN_LINE); + return false; + } + } + return true; +}; diff --git a/src/utils/constants.js b/src/utils/constants.js new file mode 100644 index 000000000..8ed8f643d --- /dev/null +++ b/src/utils/constants.js @@ -0,0 +1,67 @@ +export const stationText = { + INPUT_LABEL: '역 이름', + INPUT_ID: 'station-name-input', + PLACEHOLDER: '역 이름을 입력해주세요', + SUBMIT_ID: 'station-add-button', + SUBMIT_TEXT: '역 추가', + INPUT_CONTAINER: 'input-container', + ALERT_DUPLICATE_NAME: '중복된 역 이름이 존재합니다.', + ALERT_NAME_UNDER_TWO: '역 이름을 2자 이상으로 입력해 주세요.', + RESULT_TITLE: '🚉 지하철 역 목록', + TABLE_HEADER_1: '역 이름', + TABLE_HEADER_2: '설정', + TABLE_ID: 'station-table', + DELETE_BTN_CLASS: 'station-delete-button', + DELETE_BTN_TEXT: '삭제', + ALERT_STATION_IN_LINE: '노선에 등록된 역은 삭제할 수 없습니다.', + ALERT_CONFIRM_DELETE: '정말 삭제하시겠습니까?', +}; + +export const lineText = { + INPUT_LABEL: '노선 이름', + INPUT_ID: 'line-name-input', + PLACEHOLDER: '노선 이름을 입력해주세요', + SUBMIT_ID: 'line-add-button', + SUBMIT_TEXT: '노선 추가', + START_SELECTOR_ID: 'line-start-station-selector', + START_SELECTOR_TEXT: '상행 종점', + END_SELECTOR_ID: 'line-end-station-selector', + END_SELECTOR_TEXT: '하행 종점', + ALERT_DUPLICATE_NAME: '중복된 노선 이름이 존재합니다.', + RESULT_TITLE: '🚉 지하철 노선 목록', + TABLE_HEADER_1: '노선 이름', + TABLE_HEADER_2: '상행 종점역', + TABLE_HEADER_3: '하행 종점역', + TABLE_HEADER_4: '설정', + TABLE_ID: 'line-table', + DELETE_BTN_CLASS: 'line-delete-button', + DELETE_BTN_TEXT: '삭제', + ALERT_CONFIRM_DELETE: '정말 삭제하시겠습니까?', +}; + +export const sectionText = { + GUIDE_TEXT: '구간을 수정할 노선을 선택해주세요.', + MENU_BUTTON_CLASS: 'section-line-menu-button', + INPUT_ID: 'section-input', + TABLE_ID: 'section-table', + MANAGE_TEXT: '관리', + REGISTER_TEXT: '구간 등록', + SELECTOR_ID: 'section-station-selector', + ORDER_INPUT_ID: 'section-order-input', + PLACEHOLDER: '순서', + SUBMIT_ID: 'section-add-button', + SUBMIT_TEXT: '등록', + TABLE_HEADER_1: '순서', + TABLE_HEADER_2: '이름', + TABLE_HEADER_3: '설정', + DELETE_BTN_CLASS: 'section-delete-button', + DELETE_BTN_TEXT: '노선에서 제거', + ALERT_NEGATIVE_ORDER: '0보다 큰 순서를 입력해 주세요.', + ALERT_OVERLOAD_ORDER: '노선 범위에 포함되는 순서를 입력해 주세요.', + ALERT_STATION_UNDER_TWO: '노선에 포함된 역이 2개 이하일 때는 역을 삭제할 수 없습니다.', + ALERT_CONFIRM_DELETE: '정말 삭제하시겠습니까?', +}; + +export const mapText = { + RESULT_AREA_CLASS: 'map', +}; diff --git a/src/utils/storage.js b/src/utils/storage.js new file mode 100644 index 000000000..9925c64b3 --- /dev/null +++ b/src/utils/storage.js @@ -0,0 +1,7 @@ +export const getLocalStorage = key => { + return JSON.parse(localStorage.getItem(key)); +}; + +export const setLocalStorage = (key, value) => { + localStorage.setItem(key, JSON.stringify(value)); +}; diff --git a/src/utils/utils.js b/src/utils/utils.js new file mode 100644 index 000000000..9f4a300ab --- /dev/null +++ b/src/utils/utils.js @@ -0,0 +1,59 @@ +const app = document.getElementById('app'); + +export const clearPage = () => { + const contents = app.childNodes; + let i = contents.length; + while (i-- > 4) { + app.removeChild(contents[i]); + } +}; + +export const createTextInput = (labelName, inputId, placeHolder) => { + const inputArea = document.createElement('p'); + inputArea.setAttribute('id', 'input-container'); + const inputLabel = document.createElement('b'); + inputLabel.innerHTML = labelName; + + const inputText = document.createElement('input'); + inputText.setAttribute('id', inputId); + inputText.setAttribute('placeholder', placeHolder); + + inputArea.append(inputLabel, document.createElement('br'), inputText); + app.append(inputArea); +}; + +export const createSubmitBtn = (btnId, btnText) => { + const submitBtn = document.createElement('button'); + submitBtn.setAttribute('id', btnId); + submitBtn.innerHTML = btnText; + + return submitBtn; +}; + +export const createSelectbox = (selectorId, options) => { + const select = document.createElement('select'); + select.setAttribute('id', selectorId); + + options.map(val => { + const option = document.createElement('option'); + option.value = val; + option.text = val; + select.options.add(option); + }); + + return select; +}; + +export const createTable = (tableId, tableHeaders) => { + const table = document.createElement('table'); + table.setAttribute('border', 1); + table.setAttribute('id', tableId); + + tableHeaders.map(tableHeader => { + const header = document.createElement('th'); + header.innerHTML = tableHeader; + table.append(header); + }); + + return table; +};