diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..7e784f82d --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,19 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": ["@typescript-eslint"], + "rules": {} +} diff --git a/.gitignore b/.gitignore index a338e5c21..426fadc86 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ # Dependency directories -node_modules/ \ No newline at end of file +node_modules/ + +dist \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..69a5ed96d --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,13 @@ +{ + "printWidth": 120, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": true, + "trailingComma": "all", + "bracketSpacing": true, + "jsxBracketSameLine": true, + "arrowParens": "avoid", + "vueIndentScriptAndStyle": false, + "endOfLine": "auto" +} diff --git a/index.html b/index.html index 454e4e55f..6f132fd23 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,24 @@ - - + 자판기 - + - +
+

🍿 자판기 🍿

-
- + + +
- \ No newline at end of file +
+ + + diff --git a/package-lock.json b/package-lock.json index cdb7ded9e..371cd935b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,10 +13,14 @@ "@babel/preset-env": "^7.16.11", "@babel/preset-typescript": "^7.16.7", "@types/jest": "^27.4.1", + "@typescript-eslint/eslint-plugin": "^5.16.0", + "@typescript-eslint/parser": "^5.16.0", "babel-jest": "^27.4.6", "babel-loader": "^8.2.3", "clean-webpack-plugin": "^4.0.0", "css-loader": "^6.6.0", + "eslint": "^8.11.0", + "gh-pages": "^3.2.3", "html-webpack-plugin": "^5.5.0", "jest": "^27.4.7", "style-loader": "^3.3.1", @@ -1684,6 +1688,91 @@ "node": ">=10.0.0" } }, + "node_modules/@eslint/eslintrc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -2730,6 +2819,249 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz", + "integrity": "sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.16.0", + "@typescript-eslint/type-utils": "5.16.0", + "@typescript-eslint/utils": "5.16.0", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.16.0.tgz", + "integrity": "sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.16.0", + "@typescript-eslint/types": "5.16.0", + "@typescript-eslint/typescript-estree": "5.16.0", + "debug": "^4.3.2" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz", + "integrity": "sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.16.0", + "@typescript-eslint/visitor-keys": "5.16.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.16.0.tgz", + "integrity": "sha512-SKygICv54CCRl1Vq5ewwQUJV/8padIWvPgCxlWPGO/OgQLCijY9G7lDu6H+mqfQtbzDNlVjzVWQmeqbLMBLEwQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.16.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.16.0.tgz", + "integrity": "sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz", + "integrity": "sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.16.0", + "@typescript-eslint/visitor-keys": "5.16.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.16.0.tgz", + "integrity": "sha512-iYej2ER6AwmejLWMWzJIHy3nPJeGDuCqf8Jnb+jAQVoPpmWzwQOfa9hWVB8GIQE5gsCv/rfN4T+AYb/V06WseQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.16.0", + "@typescript-eslint/types": "5.16.0", + "@typescript-eslint/typescript-estree": "5.16.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz", + "integrity": "sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.16.0", + "eslint-visitor-keys": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -2986,6 +3318,15 @@ "acorn": "^8" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/acorn-walk": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", @@ -3307,50 +3648,6 @@ "webpack": ">=2" } }, - "node_modules/babel-loader/node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/babel-loader/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/babel-loader/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/babel-plugin-dynamic-import-node": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", @@ -3898,6 +4195,12 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -4388,10 +4691,22 @@ "buffer-indexof": "^1.0.0" } }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "dev": true, "dependencies": { "utila": "~0.4" @@ -4495,6 +4810,12 @@ "integrity": "sha512-9LkRQwjW6/wnSfevR21a3k8sOJ+XWSH7kkzs9/EUenKmuDkndP3W9y1yCZpOxufwGbX3JV8glZZSDb4o95zwXQ==", "dev": true }, + "node_modules/email-addresses": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz", + "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==", + "dev": true + }, "node_modules/emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -4636,6 +4957,58 @@ "node": ">=0.10.0" } }, + "node_modules/eslint": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz", + "integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -4658,6 +5031,259 @@ "node": ">=4.0" } }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/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, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/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 + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "dependencies": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -4671,6 +5297,18 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -4924,6 +5562,44 @@ "bser": "2.1.1" } }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -4969,6 +5645,23 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -4982,6 +5675,40 @@ "node": ">=8" } }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, "node_modules/follow-redirects": { "version": "1.14.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", @@ -5034,6 +5761,20 @@ "node": ">= 0.6" } }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, "node_modules/fs-monkey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", @@ -5066,6 +5807,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -5119,6 +5866,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gh-pages": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.2.3.tgz", + "integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==", + "dev": true, + "dependencies": { + "async": "^2.6.1", + "commander": "^2.18.0", + "email-addresses": "^3.0.1", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^8.1.0", + "globby": "^6.1.0" + }, + "bin": { + "gh-pages": "bin/gh-pages.js", + "gh-pages-clean": "bin/gh-pages-clean.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -5527,6 +6296,31 @@ "node": ">= 4" } }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -5546,18 +6340,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-local/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -5918,21 +6700,6 @@ "node": ">=8" } }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7763,6 +8530,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "node_modules/json5": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", @@ -7778,6 +8551,15 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -7889,6 +8671,12 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", @@ -7910,6 +8698,21 @@ "node": ">=10" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -8400,6 +9203,18 @@ "tslib": "^2.0.3" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -8554,6 +9369,18 @@ "node": ">= 6" } }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -8941,6 +9768,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/regexpu-core": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", @@ -9602,6 +10441,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/style-loader": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", @@ -9786,12 +10637,6 @@ "node": ">=0.10.0" } }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, "node_modules/terser/node_modules/source-map": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", @@ -9815,6 +10660,12 @@ "node": ">=8" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "node_modules/throat": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", @@ -9889,6 +10740,18 @@ "node": ">=8" } }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ts-jest": { "version": "27.1.3", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz", @@ -10058,6 +10921,27 @@ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", "dev": true }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -10223,6 +11107,12 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "node_modules/v8-to-istanbul": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", @@ -12152,6 +13042,72 @@ "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==", "dev": true }, + "@eslint/eslintrc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -13020,6 +13976,143 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, + "@typescript-eslint/eslint-plugin": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz", + "integrity": "sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.16.0", + "@typescript-eslint/type-utils": "5.16.0", + "@typescript-eslint/utils": "5.16.0", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.16.0.tgz", + "integrity": "sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.16.0", + "@typescript-eslint/types": "5.16.0", + "@typescript-eslint/typescript-estree": "5.16.0", + "debug": "^4.3.2" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz", + "integrity": "sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.16.0", + "@typescript-eslint/visitor-keys": "5.16.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.16.0.tgz", + "integrity": "sha512-SKygICv54CCRl1Vq5ewwQUJV/8padIWvPgCxlWPGO/OgQLCijY9G7lDu6H+mqfQtbzDNlVjzVWQmeqbLMBLEwQ==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "5.16.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.16.0.tgz", + "integrity": "sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz", + "integrity": "sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.16.0", + "@typescript-eslint/visitor-keys": "5.16.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.16.0.tgz", + "integrity": "sha512-iYej2ER6AwmejLWMWzJIHy3nPJeGDuCqf8Jnb+jAQVoPpmWzwQOfa9hWVB8GIQE5gsCv/rfN4T+AYb/V06WseQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.16.0", + "@typescript-eslint/types": "5.16.0", + "@typescript-eslint/typescript-estree": "5.16.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz", + "integrity": "sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.16.0", + "eslint-visitor-keys": "^3.0.0" + } + }, "@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -13248,6 +14341,13 @@ "dev": true, "requires": {} }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, "acorn-walk": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", @@ -13483,37 +14583,6 @@ "loader-utils": "^1.4.0", "make-dir": "^3.1.0", "schema-utils": "^2.6.5" - }, - "dependencies": { - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - } } }, "babel-plugin-dynamic-import-node": { @@ -13954,6 +15023,12 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -14334,6 +15409,15 @@ "buffer-indexof": "^1.0.0" } }, + "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" + } + }, "dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -14419,6 +15503,12 @@ "integrity": "sha512-9LkRQwjW6/wnSfevR21a3k8sOJ+XWSH7kkzs9/EUenKmuDkndP3W9y1yCZpOxufwGbX3JV8glZZSDb4o95zwXQ==", "dev": true }, + "email-addresses": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz", + "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==", + "dev": true + }, "emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -14507,16 +15597,204 @@ "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "eslint": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz", + "integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "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, - "optional": true + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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 + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "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 + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "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" + } + }, + "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.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true } } }, @@ -14538,12 +15816,55 @@ } } }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "requires": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + } + }, "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.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, "esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -14749,6 +16070,32 @@ "bser": "2.1.1" } }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", + "dev": true + }, + "filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -14790,6 +16137,17 @@ } } }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -14800,6 +16158,33 @@ "path-exists": "^4.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" + }, + "dependencies": { + "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" + } + } + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, "follow-redirects": { "version": "1.14.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", @@ -14829,6 +16214,17 @@ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", "dev": true }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, "fs-monkey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", @@ -14854,6 +16250,12 @@ "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 + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -14889,6 +16291,21 @@ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, + "gh-pages": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.2.3.tgz", + "integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==", + "dev": true, + "requires": { + "async": "^2.6.1", + "commander": "^2.18.0", + "email-addresses": "^3.0.1", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^8.1.0", + "globby": "^6.1.0" + } + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -15198,6 +16615,24 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -15206,17 +16641,6 @@ "requires": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" - }, - "dependencies": { - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - } } }, "imurmurhash": { @@ -15477,15 +16901,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -16858,6 +18273,12 @@ "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": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", @@ -16867,6 +18288,15 @@ "minimist": "^1.2.5" } }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -16956,6 +18386,12 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", @@ -16974,6 +18410,15 @@ "yallist": "^4.0.0" } }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -17347,6 +18792,15 @@ "tslib": "^2.0.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" + } + }, "parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -17462,6 +18916,15 @@ "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, "portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -17750,6 +19213,12 @@ "define-properties": "^1.1.3" } }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "regexpu-core": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", @@ -18272,6 +19741,15 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "style-loader": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", @@ -18355,12 +19833,6 @@ "source-map-support": "~0.5.20" }, "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, "source-map": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", @@ -18412,6 +19884,12 @@ "minimatch": "^3.0.4" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "throat": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", @@ -18471,6 +19949,15 @@ "punycode": "^2.1.1" } }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "ts-jest": { "version": "27.1.3", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz", @@ -18576,6 +20063,23 @@ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", "dev": true }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -18695,6 +20199,12 @@ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "v8-to-istanbul": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", diff --git a/package.json b/package.json index c9465bd78..972e29418 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "scripts": { "test": "jest --watch --no-cache", "start": "webpack serve --open", - "build": "webpack" + "build": "webpack", + "predeploy": "npm run build", + "deploy": "gh-pages -d dist" }, "repository": { "type": "git", @@ -20,10 +22,14 @@ "@babel/preset-env": "^7.16.11", "@babel/preset-typescript": "^7.16.7", "@types/jest": "^27.4.1", + "@typescript-eslint/eslint-plugin": "^5.16.0", + "@typescript-eslint/parser": "^5.16.0", "babel-jest": "^27.4.6", "babel-loader": "^8.2.3", "clean-webpack-plugin": "^4.0.0", "css-loader": "^6.6.0", + "eslint": "^8.11.0", + "gh-pages": "^3.2.3", "html-webpack-plugin": "^5.5.0", "jest": "^27.4.7", "style-loader": "^3.3.1", @@ -37,5 +43,5 @@ "bugs": { "url": "https://github.com/woowacourse/javascript-vendingmachine/issues" }, - "homepage": "https://github.com/woowacourse/javascript-vendingmachine#readme" + "homepage": "https://intae92.github.io/javascript-vendingmachine" } diff --git a/src/css/font.css b/src/css/font.css new file mode 100644 index 000000000..afd92fa18 --- /dev/null +++ b/src/css/font.css @@ -0,0 +1,9 @@ +@import url(https://hangeul.pstatic.net/hangeul_static/css/nanum-gothic.css); + +* { + font-family: inherit; +} + +body { + font-family: 'NanumGothic'; +} diff --git a/src/css/global.css b/src/css/global.css new file mode 100644 index 000000000..017d23ec7 --- /dev/null +++ b/src/css/global.css @@ -0,0 +1,12 @@ +:root { + --primary-color: #00bcd4; + --primary-button-text-color: #fff; + --primary-input-bg-color: #fff; + --input-outline-color: #ccc; + --input-border-color: #eee; + --input-outline-focus-color: #777; + --input-border-focus-color: #bbb; + --button-hover-color: rgba(0, 188, 212, 0.16); + --primary-text-color: rgba(0, 0, 0, 0.87); + --list-border-color: #dcdcdc; +} diff --git a/src/css/index.css b/src/css/index.css new file mode 100644 index 000000000..2c32b3bbf --- /dev/null +++ b/src/css/index.css @@ -0,0 +1,202 @@ +@import './global.css'; +@import './font.css'; + +body { + width: 100vw; + height: 100vh; + margin: 0; +} + +h1 { + margin: 0; +} + +#app { + display: flex; + flex-direction: column; + width: 30%; + min-width: 465px; + margin: auto; + gap: 20px; +} + +header { + text-align: center; + margin: 40px 0 10px; +} + +nav { + margin: 2em 0; +} + +section { + display: flex; + flex-direction: column; + flex-wrap: wrap; + align-content: center; +} + +input[type='number']::-webkit-outer-spin-button, +input[type='number']::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +input[type='submit'] { + cursor: pointer; + background: var(--primary-color); + color: var(--primary-button-text-color); + outline: 1px solid var(--primary-color); + border: 1px solid var(--primary-color); + border-radius: 2px; + width: 56px; + height: 28px; + margin-left: 10px; +} + +input { + background-color: var(--primary-input-bg-color); + outline: 1px solid var(--input-outline-color); + border: 1px solid var(--input-border-color); + border-radius: 2px; + width: 120px; + height: 24px; + padding: 1px 2px; +} + +input:focus { + outline: 1px solid var(--input-outline-focus-color); + border: 1px solid var(--input-border-focus-color); +} + +#change-add-input { + width: 300px; +} + +button { + cursor: pointer; + width: 117px; + height: 36px; + border: none; + border-radius: 5px; +} + +button:hover { + background: var(--button-hover-color); +} + +h4 { + margin: 0; + font-style: normal; + font-weight: 600; + font-size: 20px; + line-height: 24px; + text-align: center; + letter-spacing: 0.15px; + color: var(--primary-text-color); +} + +#change-add-container { + margin: auto; +} + +#product-list-container { + width: 100%; +} + +#product-list-wrapper { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; +} +#product-list-wrapper ul { + padding: 0; +} + +#change-list-wrapper { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; +} + +#change-list-wrapper ul { + padding: 0; +} + +li { + list-style-type: none; + text-align: center; + font-style: normal; + display: flex; + justify-content: center; + border-bottom: 1px solid var(--list-border-color); +} + +#product-list { + width: 100%; +} + +#product-list li { + width: 100%; +} + +#product-list li span { + margin: 12px 0 8px; + width: 100%; + height: 30px; + font-size: 15px; + line-height: 24px; + letter-spacing: 0.5px; + color: var(--primary-text-color); +} + +#product-list li input { + width: 80%; + text-align: center; + outline: 1px dotted var(--input-outline-focus-color); + border: 1px dotted var(--input-border-focus-color); +} + +.product-control-buttons { + display: flex; + gap: 10px; + justify-content: center; +} + +.product-control-buttons button { + width: 40%; + height: 30px; + margin-top: -2px; +} + +.product-modify-submit-button { + width: 90%; + margin-top: -8px; +} + +#change-list li { + width: 300px; +} + +#change-list li span { + margin: 8px 30px 0; + width: 70px; + height: 30px; + font-size: 15px; + line-height: 24px; + letter-spacing: 0.5px; + color: var(--primary-text-color); +} + +.list-header { + font-weight: 600; + font-size: 15px; + line-height: 24px; + display: flex; + align-items: center; + letter-spacing: 0.5px; + color: var(--primary-text-color); + border-top: 1px solid var(--list-border-color); +} diff --git a/src/docs/README.md b/src/docs/README.md new file mode 100644 index 000000000..6d5aa5933 --- /dev/null +++ b/src/docs/README.md @@ -0,0 +1,39 @@ +# 🎯 μš”κ΅¬μ‚¬ν•­ - κ΄€λ¦¬μž κΈ°λŠ₯ + +### 곡톡 + +- [x] 도메인 μ˜μ—­μ„ νƒ€μž…μŠ€ν¬λ¦½νŠΈλ₯Ό μ΄μš©ν•˜μ—¬ κ΅¬ν˜„ν•œλ‹€. + - Interface λ˜λŠ” type을 μ΄μš©ν•˜μ—¬, μ£Όμš” 도메인 객체의 νƒ€μž…μ„ μ •μ˜ν•˜κ³  μ„€κ³„ν•œλ‹€. + +### λΌμš°νŒ… κΈ°λŠ₯ + +- [x] Browser History Apiλ₯Ό μ΄μš©ν•˜μ—¬ SPA처럼 λΌμš°νŒ…μ„ μ μš©ν•œλ‹€. + - 맀번 νŽ˜μ΄μ§€λ₯Ό λ‘œλ“œ ν•˜λŠ” 것이 μ•„λ‹Œ, νžˆμŠ€ν† λ¦¬λ₯Ό κ΄€λ¦¬ν•˜κ³ , νŽ˜μ΄μ§€λ₯Ό url에 따라 λ™μ μœΌλ‘œ λ Œλ”λ§ν•œλ‹€ + - μƒν’ˆ 관리, μž”λˆ μΆ©μ „, μƒν’ˆ ꡬ맀 νŽ˜μ΄μ§€λŠ” λͺ¨λ‘ λ™μ μœΌλ‘œ λ Œλ”λ§ν•΄μ•Ό ν•œλ‹€. + +### μƒν’ˆ 관리 νƒ­ + +**μƒν’ˆ 관리탭은 μžνŒκΈ°κ°€ λ³΄μœ ν•˜κ³  μžˆλŠ” μƒν’ˆμ„ μΆ”κ°€ν•˜λŠ” κΈ°λŠ₯을 μˆ˜ν–‰ν•œλ‹€.** + +- [x] 졜초 μƒν’ˆ λͺ©λ‘μ€ λΉ„μ›Œμ§„ μƒνƒœμ΄λ‹€. +- [x] μƒν’ˆλͺ…, 가격, μˆ˜λŸ‰μ„ μž…λ ₯ν•΄ μƒν’ˆμ„ μΆ”κ°€ν•  수 μžˆλ‹€. + - μƒν’ˆλͺ…은 μ΅œλŒ€ 10κΈ€μžκΉŒμ§€ κ°€λŠ₯ν•˜λ‹€. + - μƒν’ˆ 가격은 100원뢀터 μ‹œμž‘ν•˜λ©°, μ΅œλŒ€ 10,000μ›κΉŒμ§€ κ°€λŠ₯ν•˜λ‹€. 그리고 10μ›μœΌλ‘œ λ‚˜λˆ„μ–΄ λ–¨μ–΄μ Έμ•Ό ν•œλ‹€. + - ν•œ μ œν’ˆλ‹Ή μˆ˜λŸ‰μ€ μ΅œλŒ€ 20κ°œκΉŒμ§€ 넣을 μˆ˜μžˆλ‹€. +- [x] κ΄€λ¦¬μžλŠ” μΆ”κ°€ν•œ μƒν’ˆμ„ 확인할 수 μžˆλ‹€. +- [x] κ΄€λ¦¬μžλŠ” μΆ”κ°€ν•œ μƒν’ˆμ„ μˆ˜μ •, μ‚­μ œν•  수 μžˆλ‹€. +- [x] μˆ˜μ • μ‹œ μƒν’ˆλͺ…, 가격, μˆ˜λŸ‰ 정보 μ˜μ—­ μžμ²΄κ°€ 인풋 μ˜μ—­μœΌλ‘œ λ³€κ²½λœλ‹€. +- [x] μ‚­μ œ μ‹œ confirm을 ν™œμš©ν•˜μ—¬ μ‚¬μš©μžμ—κ²Œ λ‹€μ‹œ ν•œλ²ˆ ν™•μΈν•œλ‹€. + +### μž”λˆ μΆ©μ „ νƒ­ + +- [x] μž”λˆ 좩전탭은 μžνŒκΈ°κ°€ λ³΄μœ ν•  κΈˆμ•‘μ„ μΆ©μ „ν•˜λŠ” κΈ°λŠ₯을 μˆ˜ν–‰ν•œλ‹€. +- [x] μž”λˆ μΆ©μ „ νƒ­μ—μ„œ 졜초 μžνŒκΈ°κ°€ λ³΄μœ ν•œ κΈˆμ•‘μ€ 0원이며, 각 λ™μ „μ˜ κ°œμˆ˜λŠ” 0κ°œμ΄λ‹€. +- [x] μž”λˆ μΆ©μ „ μž…λ ₯ μš”μ†Œμ— μΆ©μ „ν•  κΈˆμ•‘μ„ μž…λ ₯ν•œ ν›„, μΆ©μ „ν•˜κΈ° λ²„νŠΌμ„ 눌러 자판기 보유 κΈˆμ•‘μ„ μΆ©μ „ν•  수 μžˆλ‹€. +- [x] μž”λˆμ€ 10μ›μœΌλ‘œ λ‚˜λˆ„μ–΄ λ–¨μ–΄μ§€λŠ” κΈˆμ•‘λ§Œ νˆ¬μž…ν•  수 μžˆλ‹€. λ³΄μœ ν•  수 μžˆλŠ” μ΅œλŒ€ κΈˆμ•‘μ€ 100,000원이닀. +- [x] 자판기 보유 κΈˆμ•‘λ§ŒνΌμ˜ 동전이 λ¬΄μž‘μœ„λ‘œ μƒμ„±λœλ‹€. +- [x] 자판기 보유 κΈˆμ•‘μ„ λˆ„μ ν•˜μ—¬ μΆ©μ „ν•  수 μžˆλ‹€. μΆ”κ°€ μΆ©μ „ κΈˆμ•‘λ§ŒνΌμ˜ 동전이 λ¬΄μž‘μœ„λ‘œ μƒμ„±λ˜μ–΄ κΈ°μ‘΄ 동전듀에 더해진닀. + +### ν…ŒμŠ€νŠΈ μš”κ΅¬μ‚¬ν•­ + +- [x] λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ— λŒ€ν•œ λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό Jest둜 μž‘μ„±ν•œλ‹€. diff --git a/src/index.ts b/src/index.ts index e69de29bb..c9d22b471 100644 --- a/src/index.ts +++ b/src/index.ts @@ -0,0 +1,22 @@ +import './css/index'; +import { PATH_NAME } from './js/constants'; +import router from './js/routes'; + +const routes = new router(); +routes.init(); + +const productManageButton = document.querySelector('#product-manage-button'); +const changeAddButton = document.querySelector('#change-add-button'); +// const btn3 = document.querySelector('#product-purchase-button'); + +productManageButton.addEventListener('click', () => { + routes.go(PATH_NAME.PRODUCT_MANAGE); +}); + +changeAddButton.addEventListener('click', () => { + routes.go(PATH_NAME.ADD_CHANGE); +}); + +window.addEventListener('popstate', function () { + routes.back(); +}); diff --git a/src/js/__test__/vendingMachine.test.js b/src/js/__test__/vendingMachine.test.js new file mode 100644 index 000000000..ce9e4afe4 --- /dev/null +++ b/src/js/__test__/vendingMachine.test.js @@ -0,0 +1,84 @@ +import { ERROR_MESSAGE } from '../constants'; +import vendingMachine from '../model/VendingMachine'; + +describe('자판기 κΈ°λ³Έ κΈ°λŠ₯ ν…ŒμŠ€νŠΈ', () => { + describe('자판기 μƒν’ˆ μΆ”κ°€ κΈ°λŠ₯ ν…ŒμŠ€νŠΈ', () => { + it('μžνŒκΈ°μ— μƒν’ˆμ„ μΆ”κ°€ν•  수 μžˆμ–΄μ•Ό ν•œλ‹€.', () => { + const product = { + name: 'μ½”μΉ΄μ½œλΌ', + price: 1000, + amount: 5, + }; + + vendingMachine.addProduct(product); + expect(vendingMachine.products.includes(product)); + }); + + it('μžνŒκΈ°μ— 같은 μ΄λ¦„μ˜ μƒν’ˆμ„ μΆ”κ°€ν•˜λ €κ³  ν•˜λ©΄, 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.', () => { + const product = { + name: 'μ½”μΉ΄μ½œλΌ', + price: 2000, + amount: 8, + }; + + expect(() => vendingMachine.addProduct(product)).toThrowError(ERROR_MESSAGE.PRODUCT_NAME_IS_DUPLICATED); + }); + + it('μžνŒκΈ°μ— μΆ”κ°€ 될 μƒν’ˆμ˜ 이름이 10κΈ€μžλ₯Ό μ΄ˆκ³Όν•˜λ©΄, 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.', () => { + const product = { + name: 'μ½”μΉ΄μ½œλΌλ³΄λ‹€μ œλ‘œνŽ©μ‹œκ°€λ§›μžˆλ‹€', + price: 1000, + amount: 5, + }; + + expect(() => vendingMachine.addProduct(product)).toThrowError(ERROR_MESSAGE.PRODUCT_NAME_LENGTH); + }); + + it('μžνŒκΈ°μ— μΆ”κ°€ 될 μƒν’ˆμ˜ 가격이 100원을 λ„˜μ§€ μ•ŠμœΌλ©΄, 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.', () => { + const product = { + name: 'νŽ©μ‹œ', + price: 99, + amount: 5, + }; + + expect(() => vendingMachine.addProduct(product)).toThrowError(ERROR_MESSAGE.PRODUCT_PRICE); + }); + + it('μžνŒκΈ°μ— μΆ”κ°€ 될 μƒν’ˆμ˜ 가격이 10,000원이 λ„˜μœΌλ©΄, 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.', () => { + const product = { + name: 'μ œλ‘œνŽ©μ‹œ', + price: 10001, + amount: 5, + }; + + expect(() => vendingMachine.addProduct(product)).toThrowError(ERROR_MESSAGE.PRODUCT_PRICE); + }); + + it('μžνŒκΈ°μ— μΆ”κ°€ 될 μƒν’ˆμ˜ μˆ˜λŸ‰μ΄ 20κ°œκ°€ λ„˜μœΌλ©΄, 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.', () => { + const product = { + name: 'μ œλ‘œμ½”μΉ΄μ½œλΌ', + price: 1000, + amount: 21, + }; + + expect(() => vendingMachine.addProduct(product)).toThrowError(ERROR_MESSAGE.PRODUCT_AMOUNT); + }); + }); + + describe('μž”λˆ μΆ©μ „ κΈ°λŠ₯ ν…ŒμŠ€νŠΈ', () => { + it('μžνŒκΈ°κ°€ κ°€μ§„ 총 κΈˆμ•‘μ΄ 100,000원을 λ„˜μœΌλ©΄, 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.', () => { + const money = 100010; + expect(() => vendingMachine.inputChanges(money)).toThrowError(ERROR_MESSAGE.TOO_MUCH_VENDING_MACHINE_CHANGE); + }); + + it('μžνŒκΈ°μ— μΆ©μ „ν•˜λ €λŠ” κΈˆμ•‘μ΄ 0원을 λ„˜μ§€ λͺ»ν•˜λ©΄, 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.', () => { + const money = 0; + expect(() => vendingMachine.inputChanges(money)).toThrowError(ERROR_MESSAGE.IS_NOT_POSITIVE_INTEGER); + }); + + it('μžνŒκΈ°μ— μΆ©μ „ν•˜λ €λŠ” κΈˆμ•‘μ΄ 10μ›μœΌλ‘œ λ‚˜λˆ„μ–΄ λ–¨μ–΄μ§€μ§€ μ•ŠμœΌλ©΄, 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.', () => { + const money = 9; + expect(() => vendingMachine.inputChanges(money)).toThrowError(ERROR_MESSAGE.IS_NOT_UNIT_OF_TEN); + }); + }); +}); diff --git a/src/js/components/AddChangeComponent.ts b/src/js/components/AddChangeComponent.ts new file mode 100644 index 000000000..17e30e3b9 --- /dev/null +++ b/src/js/components/AddChangeComponent.ts @@ -0,0 +1,57 @@ +import vendingMachine from '../model/VendingMachine'; + +class AddChangeComponent { + $changeAddForm: HTMLElement; + $totalChange: HTMLElement; + noticeStateChanged: Function; + parentElement: HTMLElement; + + constructor(parentElement: HTMLElement, noticeStateChanged: Function) { + this.parentElement = parentElement; + this.noticeStateChanged = noticeStateChanged; + } + + private bindEventAndElement = () => { + this.$totalChange = document.querySelector('#total-change'); + this.$changeAddForm = document.querySelector('#change-add-form'); + this.$changeAddForm.addEventListener('submit', this.onSubmitChangeAdd); + }; + + private onSubmitChangeAdd = (e: SubmitEvent) => { + e.preventDefault(); + const inputChange = parseInt((this.$changeAddForm.querySelector('#change-add-input')).value); + + try { + vendingMachine.inputChanges(inputChange); + this.noticeStateChanged(); + } catch (message) { + alert(message); + } + }; + + refreshChange = () => { + this.$totalChange.textContent = vendingMachine.getTotalMoney().toString(); + }; + + render = () => { + this.parentElement.insertAdjacentHTML('beforeend', this.template()); + this.bindEventAndElement(); + }; + + private template = () => ` +
+

μžνŒκΈ°κ°€ λ³΄μœ ν•  κΈˆμ•‘μ„ μž…λ ₯ν•΄μ£Όμ„Έμš”

+
+ + +
+

ν˜„μž¬ 보유 κΈˆμ•‘: 원

+
`; +} + +export default AddChangeComponent; diff --git a/src/js/components/AddProductComponent.ts b/src/js/components/AddProductComponent.ts new file mode 100644 index 000000000..59c1339ea --- /dev/null +++ b/src/js/components/AddProductComponent.ts @@ -0,0 +1,77 @@ +import vendingMachine from '../model/VendingMachine'; +import { Product } from '../interfaces/VendingMachine.interface'; + +class AddProductComponent { + parentElement: HTMLElement; + noticeStateChanged: Function; + $productAddForm: HTMLElement; + $productList: HTMLElement; + + constructor(parentElement: HTMLElement, noticeStateChanged: Function) { + this.parentElement = parentElement; + this.noticeStateChanged = noticeStateChanged; + } + + private bindEventAndElement = () => { + this.$productAddForm = this.parentElement.querySelector('#product-add-form'); + this.$productList = this.parentElement.querySelector('#product-list'); + + this.$productAddForm.addEventListener('submit', this.onSubmitNewProduct); + }; + + private onSubmitNewProduct = (e: SubmitEvent) => { + e.preventDefault(); + + const name = (this.$productAddForm.querySelector('#product-name-input')).value; + const price = (this.$productAddForm.querySelector('#product-price-input')).value; + const amount = (this.$productAddForm.querySelector('#product-amount-input')).value; + + const newProduct: Product = { + name: name, + price: parseInt(price), + amount: parseInt(amount), + }; + + try { + vendingMachine.addProduct(newProduct); + this.noticeStateChanged('add', newProduct); + } catch (message) { + alert(message); + } + }; + + refreshComponent = () => {}; + + render = () => { + this.parentElement.insertAdjacentHTML('beforeend', this.template()); + this.bindEventAndElement(); + }; + + private template = () => ` +
+

μΆ”κ°€ν•  μƒν’ˆ 정보λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”.

+
+ + + + +
+
`; +} + +export default AddProductComponent; diff --git a/src/js/components/ChangeListComponent.ts b/src/js/components/ChangeListComponent.ts new file mode 100644 index 000000000..dd1b6c913 --- /dev/null +++ b/src/js/components/ChangeListComponent.ts @@ -0,0 +1,66 @@ +import vendingMachine from '../model/VendingMachine'; + +class ChangeListComponent { + $changeList: HTMLElement; + $contentsContainer: HTMLElement; + $amountCoin500: HTMLElement; + $amountCoin100: HTMLElement; + $amountCoin50: HTMLElement; + $amountCoin10: HTMLElement; + parentElement: HTMLElement; + + constructor(parentElement: HTMLElement) { + this.parentElement = parentElement; + } + + private bindElement = () => { + this.$changeList = document.querySelector('#change-list'); + this.$amountCoin500 = document.querySelector('#amount-coin-500'); + this.$amountCoin100 = document.querySelector('#amount-coin-100'); + this.$amountCoin50 = document.querySelector('#amount-coin-50'); + this.$amountCoin10 = document.querySelector('#amount-coin-10'); + }; + + refreshChange = () => { + const { coin10, coin50, coin100, coin500 } = vendingMachine.getChanges(); + + this.$amountCoin500.textContent = `${coin500}개`; + this.$amountCoin100.textContent = `${coin100}개`; + this.$amountCoin50.textContent = `${coin50}개`; + this.$amountCoin10.textContent = `${coin10}개`; + }; + + render = () => { + this.parentElement.insertAdjacentHTML('beforeend', this.template()); + this.bindElement(); + }; + + private template = () => ` +
+

μžνŒκΈ°κ°€ λ³΄μœ ν•œ 동전

+
    +
  • + 동전 + 개수 +
  • +
  • + 500원 + +
  • +
  • + 100원 + +
  • +
  • + 50원 + +
  • +
  • + 10원 + +
  • +
+
`; +} + +export default ChangeListComponent; diff --git a/src/js/components/ModifyProductComponent.ts b/src/js/components/ModifyProductComponent.ts new file mode 100644 index 000000000..57f38ab22 --- /dev/null +++ b/src/js/components/ModifyProductComponent.ts @@ -0,0 +1,97 @@ +import vendingMachine from '../model/VendingMachine'; +import ProductItemComponent from './ProductItemComponent'; +import { Product } from '../interfaces/VendingMachine.interface'; + +class ModifyProductComponent { + name: string; + price: number; + amount: number; + parentElement: HTMLElement; + $productList: HTMLElement; + + constructor(parentElement: HTMLElement) { + this.parentElement = parentElement; + } + + bindEvent = () => { + this.$productList = this.parentElement.querySelector('#product-list'); + this.$productList.addEventListener('click', this.onSubmitModifyCompleteButton); + }; + + private onSubmitModifyCompleteButton = (e: PointerEvent) => { + if ((e.target).className !== 'product-modify-submit-button') { + return; + } + + const ul = (e.target).closest('ul'); + const parentList = (e.target).closest('li'); + const product = { + name: (parentList.querySelector('.product-name-modify-input')).value, + price: parseInt((parentList.querySelector('.product-price-modify-input')).value), + amount: parseInt((parentList.querySelector('.product-amount-modify-input')).value), + }; + + const prevName = (parentList.querySelector('.product-modify-submit-button')).dataset.name; + + try { + vendingMachine.modifyProduct(prevName, product); + ul.replaceChild(this.replaceList(product, ProductItemComponent), parentList); + } catch (message) { + alert(message); + } + }; + + private replaceList = (product: Product, component: Function) => { + const fragment = new DocumentFragment(); + const li = document.createElement('li'); + + li.insertAdjacentHTML('beforeend', component(product)); + fragment.appendChild(li); + + return fragment; + }; + + render = (product: Product) => { + this.name = product.name; + this.price = product.price; + this.amount = product.amount; + return this.template(); + }; + + private template = () => ` + + + + + + + + + + + + + `; +} + +export default ModifyProductComponent; diff --git a/src/js/components/ProductItemComponent.ts b/src/js/components/ProductItemComponent.ts new file mode 100644 index 000000000..0a3e81b4d --- /dev/null +++ b/src/js/components/ProductItemComponent.ts @@ -0,0 +1,20 @@ +import { Product } from '../interfaces/VendingMachine.interface'; + +const ProductItemComponent = (product: Product) => { + const { name, price, amount } = product; + return ` + ${name} + ${price} + ${amount} + + + + + `; +}; + +export default ProductItemComponent; diff --git a/src/js/components/ProductListComponent.ts b/src/js/components/ProductListComponent.ts new file mode 100644 index 000000000..f39cbbf7c --- /dev/null +++ b/src/js/components/ProductListComponent.ts @@ -0,0 +1,106 @@ +import vendingMachine from '../model/VendingMachine'; +import ModifyProductComponent from './ModifyProductComponent'; +import ProductItemComponent from './ProductItemComponent'; +import { Product } from '../interfaces/VendingMachine.interface'; +import { REMOVE_CONFIRM_MESSAGE } from '../constants'; + +class ProductListComponent { + ModifyProductComponent: ModifyProductComponent; + parentElement: HTMLElement; + noticeStateChanged: Function; + $productList: HTMLElement; + + constructor(parentElement: HTMLElement, noticeStateChanged: Function) { + this.parentElement = parentElement; + this.noticeStateChanged = noticeStateChanged; + this.ModifyProductComponent = new ModifyProductComponent(parentElement); + } + + private bindEvent = () => { + this.$productList = this.parentElement.querySelector('#product-list'); + this.$productList.addEventListener('click', this.onClickModifyButton); + this.$productList.addEventListener('click', this.onClickRemoveButton); + }; + + private onClickModifyButton = (e: PointerEvent) => { + if ((e.target).className !== 'product-modify-button') { + return; + } + + const ul = (e.target).closest('ul'); + const oldLi = (e.target).closest('li'); + const product = { + name: (oldLi.querySelector('.product-name')).textContent, + price: parseInt((oldLi.querySelector('.product-price')).textContent), + amount: parseInt((oldLi.querySelector('.product-amount')).textContent), + }; + + ul.replaceChild(this.replaceList(product, this.ModifyProductComponent.render), oldLi); + this.ModifyProductComponent.bindEvent(); + }; + + private onClickRemoveButton = (e: PointerEvent) => { + if ((e.target).className !== 'product-remove-button') { + return; + } + + if (!window.confirm(REMOVE_CONFIRM_MESSAGE)) { + return; + } + + const parentList = (e.target).closest('li'); + const name = (parentList.querySelector('.product-name')).textContent; + + vendingMachine.removeProduct(name); + parentList.remove(); + }; + + private replaceList = (product: Product, component: Function) => { + const fragment = new DocumentFragment(); + const li = document.createElement('li'); + + li.insertAdjacentHTML('beforeend', component(product)); + fragment.appendChild(li); + + return fragment; + }; + + addProductItem(product: Product) { + const fragment = new DocumentFragment(); + const li = document.createElement('li'); + + li.insertAdjacentHTML('beforeend', ProductItemComponent(product)); + fragment.appendChild(li); + this.$productList.appendChild(fragment); + } + + refreshComponent = () => { + const products = vendingMachine.getProducts(); + + products.forEach(product => { + this.addProductItem(product); + }); + }; + + render = () => { + this.parentElement.insertAdjacentHTML('beforeend', this.template()); + this.bindEvent(); + }; + + private template = () => ` +
+
+

μƒν’ˆ ν˜„ν™©

+
    +
  • + μƒν’ˆλͺ… + 가격 + μˆ˜λŸ‰ + +
  • +
+
+
`; +} + +export default ProductListComponent; diff --git a/src/js/constants.ts b/src/js/constants.ts new file mode 100644 index 000000000..9637c1df2 --- /dev/null +++ b/src/js/constants.ts @@ -0,0 +1,29 @@ +const PATH_NAME = { + PRODUCT_MANAGE: '#!/product-manage', + ADD_CHANGE: '#!/change-add', +}; + +const RULES = { + MAX_PRODUCT_PRICE: 10000, + MIN_PRODUCT_PRICE: 100, + MAX_PRODUCT_AMOUNT: 20, + MIN_PRODUCT_AMOUNT: 0, + MINIMUM_CHANGE: 10, + MAX_LENGTH_PRODUCT_NAME: 10, + MAX_VENDING_MACHINE_CHANGE: 100000, + NOT_EXIST_INDEX: -1, +}; + +const ERROR_MESSAGE = { + PRODUCT_NAME_IS_DUPLICATED: '이미 μ‘΄μž¬ν•˜λŠ” μ΄λ¦„μ˜ μƒν’ˆμž…λ‹ˆλ‹€.', + PRODUCT_NAME_LENGTH: 'μƒν’ˆλͺ…은 μ΅œλŒ€ 10κΈ€μžκΉŒμ§€ μž…λ ₯ν•΄μ£Όμ„Έμš”.', + PRODUCT_PRICE: 'μƒν’ˆκ°€κ²©μ€ 100원~10,000원 사이여야 ν•˜λ©° 10μ›μœΌλ‘œ λ‚˜λˆ„μ–΄ λ–¨μ–΄μ Έμ•Ό ν•©λ‹ˆλ‹€.', + PRODUCT_AMOUNT: 'ν•œ μ œν’ˆλ‹Ή μˆ˜λŸ‰μ€ μ΅œλŒ€ 20개 μž…λ‹ˆλ‹€.', + TOO_MUCH_VENDING_MACHINE_CHANGE: 'μžνŒκΈ°κ°€ λ³΄μœ ν•  수 μžˆλŠ” μ΅œλŒ€ κΈˆμ•‘μ€ 100,000원 μž…λ‹ˆλ‹€.', + IS_NOT_UNIT_OF_TEN: 'νˆ¬μž…ν•  κΈˆμ•‘μ˜ λ‹¨μœ„λŠ” 10μ›μž…λ‹ˆλ‹€.', + IS_NOT_POSITIVE_INTEGER: 'νˆ¬μž…ν•  κΈˆμ•‘μ€ 0보닀 큰 κΈˆμ•‘μ΄μ–΄μ•Ό ν•©λ‹ˆλ‹€.', +}; + +const REMOVE_CONFIRM_MESSAGE = 'μ •λ§λ‘œ μ‚­μ œν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?'; + +export { PATH_NAME, RULES, ERROR_MESSAGE, REMOVE_CONFIRM_MESSAGE }; diff --git a/src/js/interfaces/VendingMachine.interface.ts b/src/js/interfaces/VendingMachine.interface.ts new file mode 100644 index 000000000..818f7e8ba --- /dev/null +++ b/src/js/interfaces/VendingMachine.interface.ts @@ -0,0 +1,14 @@ +interface Coin { + coin10: number; + coin50: number; + coin100: number; + coin500: number; +} + +interface Product { + name: string; + amount: number; + price: number; +} + +export type { Coin, Product }; diff --git a/src/js/model/VendingMachine.ts b/src/js/model/VendingMachine.ts new file mode 100644 index 000000000..fbd22f360 --- /dev/null +++ b/src/js/model/VendingMachine.ts @@ -0,0 +1,133 @@ +import { ERROR_MESSAGE, RULES } from '../constants'; +import { Product, Coin } from '../interfaces/VendingMachine.interface'; +import { getRandomInt } from '../utils/utils'; +import { + isValidProductPrice, + isValidProductAmount, + isValidProductNameLength, + isUnitOfTen, + isPositiveInteger, + isDuplicatedName, +} from './validator'; + +class VendingMachine { + private products: Array; + private changes: Coin; + private totalMoney: number; + private availableCoinTypeList: Array; + + constructor() { + this.products = []; + this.availableCoinTypeList = [500, 100, 50, 10]; + this.changes = { coin10: 0, coin50: 0, coin100: 0, coin500: 0 }; + this.totalMoney = 0; + } + + getProducts() { + return this.products; + } + + getChanges() { + return this.changes; + } + + getTotalMoney() { + return this.totalMoney; + } + + addProduct(product: Product) { + this.checkProductValidate(product); + this.products.push(product); + } + + findProductIndex(name: string) { + return this.products.findIndex(product => product.name === name); + } + + removeProduct(name: string) { + const productIndex = this.findProductIndex(name); + const isExist = productIndex >= 0; + + if (isExist) { + this.products.splice(productIndex, 1); + } + } + + modifyProduct(oldProductName: string, newProduct: Product) { + const oldProductIndex = this.findProductIndex(oldProductName); + this.checkProductValidate(newProduct, oldProductIndex); + this.products[oldProductIndex] = newProduct; + } + + inputChanges(money: number) { + this.checkInputChangesValidate(money); + this.totalMoney += money; + this.makeChangesToCoin(money); + } + + private makeChangesToCoin(money: number) { + const coin = this.getChangeCoin(money); + money -= coin; + + switch (coin) { + case 500: + this.changes.coin500 += 1; + break; + case 100: + this.changes.coin100 += 1; + break; + case 50: + this.changes.coin50 += 1; + break; + case 10: + this.changes.coin10 += 1; + break; + } + + if (money >= RULES.MINIMUM_CHANGE) { + this.makeChangesToCoin(money); + } + } + + private getChangeCoin(money: number) { + const coins = this.availableCoinTypeList.filter(coin => coin <= money); + const index = getRandomInt(coins.length); + return coins[index]; + } + + private checkProductValidate(product: Product, originalIndex: number = RULES.NOT_EXIST_INDEX) { + if (isDuplicatedName(this.findProductIndex(product.name), originalIndex)) { + throw new Error(ERROR_MESSAGE.PRODUCT_NAME_IS_DUPLICATED); + } + + if (!isValidProductNameLength(product.name)) { + throw new Error(ERROR_MESSAGE.PRODUCT_NAME_LENGTH); + } + + if (!isValidProductPrice(product.price)) { + throw new Error(ERROR_MESSAGE.PRODUCT_PRICE); + } + + if (!isValidProductAmount(product.amount)) { + throw new Error(ERROR_MESSAGE.PRODUCT_AMOUNT); + } + } + + private checkInputChangesValidate(money: number) { + if (!isPositiveInteger(money)) { + throw new Error(ERROR_MESSAGE.IS_NOT_POSITIVE_INTEGER); + } + + if (!isUnitOfTen(money)) { + throw new Error(ERROR_MESSAGE.IS_NOT_UNIT_OF_TEN); + } + + if (this.totalMoney + money > RULES.MAX_VENDING_MACHINE_CHANGE) { + throw new Error(ERROR_MESSAGE.TOO_MUCH_VENDING_MACHINE_CHANGE); + } + } +} + +const vendingMachine = new VendingMachine(); + +export default vendingMachine; diff --git a/src/js/model/validator.ts b/src/js/model/validator.ts new file mode 100644 index 000000000..34e36b188 --- /dev/null +++ b/src/js/model/validator.ts @@ -0,0 +1,29 @@ +import { RULES } from '../constants'; + +export const isDuplicatedName = (productIndex: number, originalIndex: number) => { + const isExist = productIndex >= 0; + const isAddWithDuplicatedName = isExist && originalIndex === RULES.NOT_EXIST_INDEX; + const isModifyWithDuplicateName = isExist && originalIndex !== productIndex; + + return isAddWithDuplicatedName || isModifyWithDuplicateName; +}; + +export const isValidProductNameLength = (name: string) => { + return name.length <= RULES.MAX_LENGTH_PRODUCT_NAME && name.length > 0; +}; + +export const isUnitOfTen = (price: number) => { + return price % RULES.MINIMUM_CHANGE === 0; +}; + +export const isPositiveInteger = (price: number) => { + return price > 0; +}; + +export const isValidProductPrice = (price: number) => { + return price >= RULES.MIN_PRODUCT_PRICE && price <= RULES.MAX_PRODUCT_PRICE && isUnitOfTen(price); +}; + +export const isValidProductAmount = (amount: number) => { + return amount > RULES.MIN_PRODUCT_AMOUNT && amount <= RULES.MAX_PRODUCT_AMOUNT; +}; diff --git a/src/js/pages/AddChange.ts b/src/js/pages/AddChange.ts new file mode 100644 index 000000000..25bcf5377 --- /dev/null +++ b/src/js/pages/AddChange.ts @@ -0,0 +1,28 @@ +import AddChangeComponent from '../components/AddChangeComponent'; +import ChangeListComponent from '../components/ChangeListComponent'; + +export default class ChangeAdd { + AddChangeComponent: AddChangeComponent; + ChangeListComponent: ChangeListComponent; + $inputSection: HTMLElement; + $contentsContainer: HTMLElement; + + constructor() { + this.$inputSection = document.querySelector('.input-section'); + this.$contentsContainer = document.querySelector('.contents-container'); + this.AddChangeComponent = new AddChangeComponent(this.$inputSection, this.stateChange); + this.ChangeListComponent = new ChangeListComponent(this.$contentsContainer); + } + + render = () => { + this.AddChangeComponent.render(); + this.ChangeListComponent.render(); + this.AddChangeComponent.refreshChange(); + this.ChangeListComponent.refreshChange(); + }; + + private stateChange = () => { + this.ChangeListComponent.refreshChange(); + this.AddChangeComponent.refreshChange(); + }; +} diff --git a/src/js/pages/ProductManage.ts b/src/js/pages/ProductManage.ts new file mode 100644 index 000000000..e0aa5b87d --- /dev/null +++ b/src/js/pages/ProductManage.ts @@ -0,0 +1,35 @@ +import { Product } from '../interfaces/VendingMachine.interface'; +import AddProductComponent from '../components/AddProductComponent'; +import ProductListComponent from '../components/ProductListComponent'; + +export default class ProductManage { + $inputSection: HTMLElement; + $contentsContainer: HTMLElement; + $productAddForm: HTMLElement; + AddProductComponent: AddProductComponent; + ProductListComponent: ProductListComponent; + + constructor() { + this.$inputSection = document.querySelector('.input-section'); + this.$contentsContainer = document.querySelector('.contents-container'); + this.AddProductComponent = new AddProductComponent(this.$inputSection, this.stateChange); + this.ProductListComponent = new ProductListComponent(this.$contentsContainer, this.stateChange); + } + + render() { + this.AddProductComponent.render(); + this.ProductListComponent.render(); + + this.stateChange(); + } + + private stateChange = (state: string = '', product: Product = null) => { + if (state === 'add') { + this.ProductListComponent.addProductItem(product); + return; + } + + this.AddProductComponent.refreshComponent(); + this.ProductListComponent.refreshComponent(); + }; +} diff --git a/src/js/routes.ts b/src/js/routes.ts new file mode 100644 index 000000000..e7c6c0f82 --- /dev/null +++ b/src/js/routes.ts @@ -0,0 +1,55 @@ +import { PATH_NAME } from './constants'; +import AddChange from './pages/AddChange'; +import ProductManage from './pages/ProductManage'; + +class router { + prevPath: string; + productManage: ProductManage; + addChange: AddChange; + + constructor() { + this.productManage = new ProductManage(); + this.addChange = new AddChange(); + this.prevPath = null; + } + + init() { + this.go(window.location.hash); + } + + back() { + this.go(window.location.hash); + } + + go(hash: string) { + if (this.prevPath === hash) { + return; + } + + this.prevPath = hash; + this.clear(); + + switch (hash) { + case PATH_NAME.PRODUCT_MANAGE: + history.pushState({}, 'μƒν’ˆ κ΄€λ¦¬ν•˜κΈ°', window.location.pathname + hash); + this.productManage.render(); + break; + case PATH_NAME.ADD_CHANGE: + history.pushState({}, 'μž”λˆ μΆ©μ „ν•˜κΈ°', window.location.pathname + hash); + this.addChange.render(); + break; + default: + break; + } + } + + private clear() { + const $inputSection = document.querySelector('.input-section'); + const $contentsContainer = document.querySelector('.contents-container'); + + $inputSection.replaceChildren(); + $contentsContainer.replaceChildren(); + } +} + +export default router; diff --git a/src/js/utils/utils.ts b/src/js/utils/utils.ts new file mode 100644 index 000000000..2310750c4 --- /dev/null +++ b/src/js/utils/utils.ts @@ -0,0 +1,3 @@ +export function getRandomInt(max: number) { + return Math.floor(Math.random() * max); +}