From c09c324e97a7d9292fdb6b1e208b49b132ce23ca Mon Sep 17 00:00:00 2001 From: ClairePeng Date: Wed, 1 Nov 2023 15:35:43 +0000 Subject: [PATCH 1/9] creates scorecard.js and starts testing for the example game on the brief --- frame.js | 0 package-lock.json | 3329 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 18 + scorecard.js | 164 +++ scorecard.test.js | 105 ++ 5 files changed, 3616 insertions(+) create mode 100644 frame.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 scorecard.js create mode 100644 scorecard.test.js diff --git a/frame.js b/frame.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..8c8ee65127 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3329 @@ +{ + "name": "makers_bowling-challenge", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "makers_bowling-challenge", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "jest": "^29.7.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", + "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "dependencies": { + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", + "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, + "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", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.3.tgz", + "integrity": "sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.6.tgz", + "integrity": "sha512-66BXMKb/sUWbMdBNdMvajU7i/44RkrA3z/Yt1c7R5xejt8qh84iU54yUWCtm0QwGJlDcf/gg4zd/x4mpLAlb/w==", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.3.tgz", + "integrity": "sha512-ciwyCLeuRfxboZ4isgdNZi/tkt06m8Tw6uGbBSBgWrnnZGNXiEyM27xc/PjXGQLqlZ6ylbgHMnm7ccF9tCkOeQ==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.3.tgz", + "integrity": "sha512-Lsh766rGEFbaxMIDH7Qa+Yha8cMVI3qAK6CHt3OR0YfxOIn5Z54iHiyDRycHrBqeIiqGa20Kpsv1cavfBKkRSw==", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.8.tgz", + "integrity": "sha512-NhRH7YzWq8WiNKVavKPBmtLYZHxNY19Hh+az28O/phfp68CF45pMFud+ZzJ8ewnxnC5smIdF3dqFeiSUQ5I+pw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-zONci81DZYCZjiLe0r6equvZut0b+dBRPBN5kBDjsONnutYNtJMoWQ9uR2RkL1gLG9NMTzvf+29e5RFfPbeKhQ==" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.2.tgz", + "integrity": "sha512-8toY6FgdltSdONav1XtUHl4LN1yTmLza+EuDazb/fEmRNCwjyqNVIQWs2IfC74IqjHkREs/nQ2FWq5kZU9IC0w==", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.3.tgz", + "integrity": "sha512-1nESsePMBlf0RPRffLZi5ujYh7IH1BWL4y9pr+Bn3cJBdxz+RTP8bUFljLz9HvzhhOSWKdyBZ4DIivdL6rvgZg==", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "20.8.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz", + "integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.2.tgz", + "integrity": "sha512-g7CK9nHdwjK2n0ymT2CW698FuWJRIx+RP6embAzZ2Qi8/ilIrA1Imt2LVSeHUzKvpoi7BhmmQcXz95eS0f2JXw==" + }, + "node_modules/@types/yargs": { + "version": "17.0.29", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.29.tgz", + "integrity": "sha512-nacjqA3ee9zRF/++a3FUY1suHTFKZeHba2n8WeDw9cCVdmzmHpIxyzOJBcpHvvEmS8E9KqWlSnWHUkOrkhWcvA==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.2.tgz", + "integrity": "sha512-5qcvofLPbfjmBfKaLfj/+f+Sbd6pN4zl7w7VSVI5uz7m9QZTuB2aZAa2uo1wHFBNN2x6g/SoTkXmd8mQnQF2Cw==" + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001559", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001559.tgz", + "integrity": "sha512-cPiMKZgqgkg5LY3/ntGeLFUpi6tzddBNS58A4tnTgQw1zON7u2sZMU7SzOeVH4tj20++9ggL+V6FDOFMTaFFYA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==" + }, + "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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.572", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.572.tgz", + "integrity": "sha512-RlFobl4D3ieetbnR+2EpxdzFl9h0RAJkPK3pfiwMug2nhBin2ZCsGIAJWdpNniLz43sgXam/CgipOmvTA+rUiA==" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", + "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "engines": { + "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==", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pure-rand": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", + "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", + "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000..828ddf92d2 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "makers_bowling-challenge", + "version": "1.0.0", + "description": "Bowling Challenge =================", + "main": "index.js", + "directories": { + "doc": "docs" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "jest": "^29.7.0" + } +} diff --git a/scorecard.js b/scorecard.js new file mode 100644 index 0000000000..0c218c208c --- /dev/null +++ b/scorecard.js @@ -0,0 +1,164 @@ +/* +10 Pin Scoring Rules: + +Every frame is 1-2 rolls + Open Frame(a, b) -> Less than 10 pins -> (a + b); + Spare(a, b = 10) -> 10 pins over 2 rolls -> (10) + (a); + Strike(a=10) -> 10 pins over 1 roll -> (10) + (a + b) or (10) + (10) + (b); + + For the 10th frame, if the player rolls a strike or spare, they can roll again for the bonus +*/ + +class ScoreCard { + constructor(){ + this.frames = [] //empty list of frames + }; + // ADDING FRAMES + /** + * adds a single frame + * @param {number} a // first roll -- 0-10 + * @param {number} b // second roll -- 0-10; b <= 10-a + */ + addFrame(a,b) { + this.frames.push([a,b]); + }; + /** + * adds a special 10th frame with up to 3 rolls if the player scores a strike or spare in the 2-roll frame. + * @param {number} a + * @param {number} b + * @param {number} c + */ + add10thFrame(a, b, c) { + this.frames.push([a, b, c]); + }; + + // FINDING FRAME TYPE: + // takes single frames from self.frames. + isStrike(frame){ + return frame[0] === 10; + }; + isSpare(frame){ + return frame[0] + frame[1] === 10; + }; + + // GETTING FRAME SCORE NO BONUS + getFrameScoreNoBonus(frame){ + let sum = 0; + frame.forEach((roll) => { + sum += roll; + }); + return sum; + } + + // GETTING THE SPARE BONUS: + getSpareBonus(frame){ + let bonus = 0; + // find the index of the current frame + const frameNum = this.frames.indexOf(frame); + // find the next frame + const nextFrame = this.frames[frameNum + 1]; + // find the first roll of the next frame + bonus = nextFrame[0]; + return bonus; + } + + // GETTING THE STRIKE BONUS: + getStrikeBonus(frame){ + let bonus = 0; + // find the index of the current frame + const frameNum = this.frames.indexOf(frame); + // find the next frame + const nextFrame = this.frames[frameNum + 1]; + + // if next frame is also a Strike: + if (this.isStrike(nextFrame)) { + // find the next next frame's first roll. + const nextNextFrame = this.frames[frameNum + 2]; + bonus = nextFrame[0] + nextNextFrame[0]; + } else { + // find both rolls of the next frame. + bonus = nextFrame[0] + nextFrame[1]; + } + return bonus; + } + + // GETTING FRAME TOTAL: + getFrameTotal(frame){ + let score = 0; + const frameNum = this.frames.indexOf(frame); + + if (this.isStrike(frame) && frameNum != 10) { + // STRIKE & NOT LAST FRAME + console.log(`Frame ${frameNum}: Strike!`) + + try { + // Get the next two rolls + score += this.getStrikeBonus(frame); + + } catch (error) { + // catch range error for when the game is still ongoing + if (error instanceof RangeError) { + // no bonus added if next 2 rolls haven't happened yet. + } else { + console.error('An error occured:', error.message); + } + } + + } else if (this.isSpare(frame) && frameNum != 10) { + // SPARE & NOT LAST FRAME + console.log(`Frame ${frameNum}: Spare!`) + try { + // Get the next roll + score += this.getSpareBonus(frame); + + } catch (error) { + // catch range error for when the game is still ongoing + if (error instanceof RangeError) { + // no bonus added if next 1 roll hasn't happened yet. + } else { + console.error('An error occured:', error.message); + } + } + + } else { + if (this.isStrike(frame)){ + // 10th FRAME STRIKE + console.log(`Frame ${frameNum}: Strike!`) + } else if (this.isSpare(frame)){ + // 10th FRAME SPARE + console.log(`Frame ${frameNum}: Spare!`) + } else { + // OPEN FRAME + console.log(`Frame ${frameNum}: Open Frame!`) + } + }; + + score += this.getFrameScoreNoBonus(frame); + return score; + }; + + // Get the total score for the game + getTotalGameScore() { + let score = 0; + // for frame in frames: + this.frames.forEach((frame) => { + score += this.getFrameTotal(frame) + }); + return score; + }; + + // Get the total score at a certain frame for the game after the bonus rolls have occured. + getTotalGameScoreAtFrame(frameNumber){ + const frameIndex = frameNumber - 1 + let score = 0; + // for frame in frames up to frameIndex: + for (let i = 0; i <= frameIndex; i++ ){ + const currentFrame = this.frames[i]; + score += this.getFrameTotal(currentFrame); + } + return score; + } + +}; + +module.exports = ScoreCard; \ No newline at end of file diff --git a/scorecard.test.js b/scorecard.test.js new file mode 100644 index 0000000000..660f445be5 --- /dev/null +++ b/scorecard.test.js @@ -0,0 +1,105 @@ +const ScoreCard = require('./scorecard'); + + +describe('Scorecard - example score', () => { + // arrange + const scorecard = new ScoreCard(); + + test('Frame 1: [1, 4]; FrameScore: 5; TotalScore: 5', () => { + scorecard.addFrame(1, 4); //Open + expect(scorecard.frames).toEqual([ + [1, 4] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[0])).toBe(5); + expect(scorecard.getTotalGameScoreAtFrame(1)).toBe(5); + expect(scorecard.getTotalGameScore()).toBe(5); + }); + + test('Frame 2: [4, 5]; FrameScore: 9; TotalScore: 14', () => { + scorecard.addFrame(4, 5); //Open + expect(scorecard.frames).toEqual([ + [1, 4], + [4, 5] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[1])).toBe(9); + expect(scorecard.getTotalGameScoreAtFrame(2)).toBe(14); + expect(scorecard.getTotalGameScore()).toBe(14); + }); + + test('Frame 3: [6, 4] SPARE; FrameScore at F3: 10*; TotalScore at F3: 24', () => { + scorecard.addFrame(6, 4); //Spare F3 + expect(scorecard.frames).toEqual([ + [1, 4], + [4, 5], + [6, 4] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[2])).toBe(10); + expect(scorecard.getTotalGameScoreAtFrame(3)).toBe(24); + expect(scorecard.getTotalGameScore()).toBe(24); + }); + + test('Frame 4: [5, 5] F3 SPARE BONUS => FrameScore at F3: 15; TotalScore at F3: 29', () => { + scorecard.addFrame(5, 5); //Spare F4 + // update the frame score for frame 3 to be 15 + expect(scorecard.getFrameTotal(scorecard.frames[2])).toBe(15); + // update the total score for frame 3 to be 29 + expect(scorecard.getTotalGameScoreAtFrame(3)).toBe(29); + }); + + test('Frame 4: [5, 5] SPARE; FrameScore at F4: 10*; TotalScore at F4: 39', () => { + expect(scorecard.frames).toEqual([ + [1, 4], + [4, 5], + [6, 4], + [5, 5] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[3])).toBe(10); + expect(scorecard.getTotalGameScoreAtFrame(4)).toBe(39); + expect(scorecard.getTotalGameScore()).toBe(39); + }); + + + test('Frame 5: [10, 0] F4 SPARE BONUS => FrameScore at F4: 20; TotalScore at F4: 49', () => { + scorecard.addFrame(10, 0); //Strike F5 --- SHOULD I ADD NONE INSTEAD? + // update the frame score for frame 4 to be 15 + expect(scorecard.getFrameTotal(scorecard.frames[3])).toBe(20); + // update the total score for frame 4 to be 29 + expect(scorecard.getTotalGameScoreAtFrame(4)).toBe(49); + }); + + test('Frame 5: [10, 0] STRIKE; FrameScore at F5: 10*; TotalScore at F5: 59', () => { + expect(scorecard.frames).toEqual([ + [1, 4], + [4, 5], + [6, 4], + [5, 5], + [10, 0] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[4])).toBe(10); + expect(scorecard.getTotalGameScoreAtFrame(5)).toBe(59); + expect(scorecard.getTotalGameScore()).toBe(59); + }); + + test('Frame 6: [0, 1] F5 STRIKE BONUS => FrameScore at F5: 11; TotalScore at F5: 60', () => { + scorecard.addFrame(0, 1); //Open F6 + // update the frame score for frame 5 to be 11 + expect(scorecard.getFrameTotal(scorecard.frames[4])).toBe(11); + // update the total score for frame 5 to be 60 + expect(scorecard.getTotalGameScoreAtFrame(5)).toBe(60); + }); + + test('Frame 6: [0, 1]; FrameScore at F6: 1; TotalScore at F6: 61', () => { + expect(scorecard.frames).toEqual([ + [1, 4], + [4, 5], + [6, 4], + [5, 5], + [10, 0], + [0, 1] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[5])).toBe(1); + expect(scorecard.getTotalGameScoreAtFrame(6)).toBe(61); + expect(scorecard.getTotalGameScore()).toBe(61); + }); + +}) \ No newline at end of file From 03072c3a5508a827662125e2c9741ad1b18ed5bf Mon Sep 17 00:00:00 2001 From: ClairePeng Date: Wed, 1 Nov 2023 15:58:05 +0000 Subject: [PATCH 2/9] passes all tests from example game --- scorecard.test.js | 89 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 3 deletions(-) diff --git a/scorecard.test.js b/scorecard.test.js index 660f445be5..50c67bbb04 100644 --- a/scorecard.test.js +++ b/scorecard.test.js @@ -26,7 +26,7 @@ describe('Scorecard - example score', () => { expect(scorecard.getTotalGameScore()).toBe(14); }); - test('Frame 3: [6, 4] SPARE; FrameScore at F3: 10*; TotalScore at F3: 24', () => { + test('Frame 3: [6, 4] SPARE; FrameScore at F3: 10*; TotalScore at F3: 24*', () => { scorecard.addFrame(6, 4); //Spare F3 expect(scorecard.frames).toEqual([ [1, 4], @@ -46,7 +46,7 @@ describe('Scorecard - example score', () => { expect(scorecard.getTotalGameScoreAtFrame(3)).toBe(29); }); - test('Frame 4: [5, 5] SPARE; FrameScore at F4: 10*; TotalScore at F4: 39', () => { + test('Frame 4: [5, 5] SPARE; FrameScore at F4: 10*; TotalScore at F4: 39*', () => { expect(scorecard.frames).toEqual([ [1, 4], [4, 5], @@ -67,7 +67,7 @@ describe('Scorecard - example score', () => { expect(scorecard.getTotalGameScoreAtFrame(4)).toBe(49); }); - test('Frame 5: [10, 0] STRIKE; FrameScore at F5: 10*; TotalScore at F5: 59', () => { + test('Frame 5: [10, 0] STRIKE; FrameScore at F5: 10*; TotalScore at F5: 59*', () => { expect(scorecard.frames).toEqual([ [1, 4], [4, 5], @@ -102,4 +102,87 @@ describe('Scorecard - example score', () => { expect(scorecard.getTotalGameScore()).toBe(61); }); + test('Frame 7: [7, 3] SPARE; FrameScore at F7: 10*; TotalScore at F7: 71*', () => { + scorecard.addFrame(7, 3); //Spare F7 + expect(scorecard.frames).toEqual([ + [1, 4], + [4, 5], + [6, 4], + [5, 5], + [10, 0], + [0, 1], + [7, 3] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[6])).toBe(10); + expect(scorecard.getTotalGameScoreAtFrame(7)).toBe(71); + expect(scorecard.getTotalGameScore()).toBe(71); + }); + + test('Frame 8: [6,4] F7 SPARE BONUS => FrameScore at F7: 16; Total Score at F7: 77', ()=>{ + scorecard.addFrame(6, 4); //Spare F8 + expect(scorecard.getFrameTotal(scorecard.frames[6])).toBe(16); + expect(scorecard.getTotalGameScoreAtFrame(7)).toBe(77); + }); + + test('Frame 8: [6,4] SPARE: FrameScore at F8: 10*; Total Score at F8: 87*', ()=>{ + expect(scorecard.frames).toEqual([ + [1, 4], + [4, 5], + [6, 4], + [5, 5], + [10, 0], + [0, 1], + [7, 3], + [6, 4] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[7])).toBe(10); + expect(scorecard.getTotalGameScoreAtFrame(8)).toBe(87); + expect(scorecard.getTotalGameScore()).toBe(87); + }); + + test('Frame 9: [10, 0] F8 SPARE BONUS => Framescore at F8: 20; Total Score at F8: 97', () =>{ + scorecard.addFrame(10, 0); //Strike F9 + expect(scorecard.getFrameTotal(scorecard.frames[7])).toBe(20); + expect(scorecard.getTotalGameScoreAtFrame(8)).toBe(97); + }); + + test('Frame 9: [10, 0] STRIKE => Framescore at F9: 10*; Total Score at F9: 107*', () =>{ + expect(scorecard.frames).toEqual([ + [1, 4], + [4, 5], + [6, 4], + [5, 5], + [10, 0], + [0, 1], + [7, 3], + [6, 4], + [10, 0] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(10); + expect(scorecard.getTotalGameScoreAtFrame(8)).toBe(97); + }); + + test('Frame 10: [2, 8, 6] F9 STRIKE BONUS => Framescore at F9: 20; Total Score at F9: 117', () =>{ + scorecard.add10thFrame(2, 8, 6); //10th Frame Spare + 6 on 3rd roll + expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(20); + expect(scorecard.getTotalGameScoreAtFrame(9)).toBe(117); + }) + + + test('Frame 10: [2, 8, 6] SPARE + 10th FRAME BONUS => Framescore at F10: 16; Total Score at F10: 133', () =>{ + expect(scorecard.frames).toEqual([ + [1, 4], + [4, 5], + [6, 4], + [5, 5], + [10, 0], + [0, 1], + [7, 3], + [6, 4], + [10, 0], + [2, 8, 6] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[9])).toBe(16); + expect(scorecard.getTotalGameScoreAtFrame(10)).toBe(133); + }); }) \ No newline at end of file From 1467d35e2dbbe8a01ec1e146cc5488907bcf164b Mon Sep 17 00:00:00 2001 From: ClairePeng Date: Wed, 1 Nov 2023 16:53:43 +0000 Subject: [PATCH 3/9] adds gutter game and perfect game. TODO failing perfect game score for second-last frame --- scorecard.test.js | 160 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 2 deletions(-) diff --git a/scorecard.test.js b/scorecard.test.js index 50c67bbb04..ec15627fc8 100644 --- a/scorecard.test.js +++ b/scorecard.test.js @@ -159,7 +159,7 @@ describe('Scorecard - example score', () => { [10, 0] ]); expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(10); - expect(scorecard.getTotalGameScoreAtFrame(8)).toBe(97); + expect(scorecard.getTotalGameScoreAtFrame(9)).toBe(107); }); test('Frame 10: [2, 8, 6] F9 STRIKE BONUS => Framescore at F9: 20; Total Score at F9: 117', () =>{ @@ -185,4 +185,160 @@ describe('Scorecard - example score', () => { expect(scorecard.getFrameTotal(scorecard.frames[9])).toBe(16); expect(scorecard.getTotalGameScoreAtFrame(10)).toBe(133); }); -}) \ No newline at end of file +}) + + +describe('Scorecard - Gutter Game', () => { + // arrange + const scorecard = new ScoreCard(); + + test('Frame 1: [0,0]: FrameScore at F1: 0; TotalScore at F1: 0;', () =>{ + scorecard.addFrame(0,0); //Open + expect(scorecard.frames).toEqual([ + [0, 0] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[0])).toBe(0); + expect(scorecard.getTotalGameScoreAtFrame(1)).toBe(0); + expect(scorecard.getTotalGameScore()).toBe(0); + }); + test('Frame 2: [0,0]: FrameScore at F2: 0; TotalScore at F2: 0;', () =>{ + scorecard.addFrame(0,0); //Open + expect(scorecard.frames).toEqual([ + [0, 0], + [0, 0] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[1])).toBe(0); + expect(scorecard.getTotalGameScoreAtFrame(2)).toBe(0); + expect(scorecard.getTotalGameScore()).toBe(0); + }); + test('Frame 3: [0,0]: FrameScore at 3: 0; TotalScore at F3: 0;', () =>{ + scorecard.addFrame(0,0); //Open + expect(scorecard.frames).toEqual([ + [0, 0], + [0, 0], + [0, 0] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[2])).toBe(0); + expect(scorecard.getTotalGameScoreAtFrame(3)).toBe(0); + expect(scorecard.getTotalGameScore()).toBe(0); + }); + test('Frame 4-9: [0,0]: FrameScore at F9: 0; TotalScore at F9: 0;', () =>{ + scorecard.addFrame(0,0); //Open F4 + scorecard.addFrame(0,0); //Open F5 + scorecard.addFrame(0,0); //Open F6 + scorecard.addFrame(0,0); //Open F7 + scorecard.addFrame(0,0); //Open F8 + scorecard.addFrame(0,0); //Open F9 + + expect(scorecard.frames).toEqual([ + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(0); + expect(scorecard.getTotalGameScoreAtFrame(9)).toBe(0); + expect(scorecard.getTotalGameScore()).toBe(0); + }); + test('Frame 10: [0,0]: FrameScore at 10: 0; TotalScore at 10: 0;', () =>{ + scorecard.addFrame(0,0); //Open F10 + + expect(scorecard.frames).toEqual([ + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0], + [0, 0] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[9])).toBe(0); + expect(scorecard.getTotalGameScoreAtFrame(10)).toBe(0); + expect(scorecard.getTotalGameScore()).toBe(0); + }); + +}); + +describe('Scorecard - Perfect Game', () => { + // arrange + const scorecard = new ScoreCard(); + + test('Frame 1: [10,0]: FrameScore at F1: 10; TotalScore at F1: 10;', () =>{ + scorecard.addFrame(10,0); //Strike F1 + expect(scorecard.frames).toEqual([ + [10, 0] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[0])).toBe(10); + expect(scorecard.getTotalGameScoreAtFrame(1)).toBe(10); + expect(scorecard.getTotalGameScore()).toBe(10); + }); + test('Frame 2-9: [10,0]: FS7: 30, FS8: 20; FS9: 10; TotalScore at F9: 230;', () =>{ + scorecard.addFrame(10,0); //Strike F2 + scorecard.addFrame(10,0); //Strike F3 + scorecard.addFrame(10,0); //Strike F4 + scorecard.addFrame(10,0); //Strike F5 + scorecard.addFrame(10,0); //Strike F6 + scorecard.addFrame(10,0); //Strike F7 + scorecard.addFrame(10,0); //Strike F8 + scorecard.addFrame(10,0); //Strike F9 + + expect(scorecard.frames).toEqual([ + [10, 0], + [10, 0], + [10, 0], + [10, 0], + [10, 0], + [10, 0], + [10, 0], + [10, 0], + [10, 0] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[0])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[1])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[2])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[3])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[4])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[5])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[6])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[7])).toBe(20); //only one roll ahead to count bonus + expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(10); //no rolls ahead to count bonus + expect(scorecard.getTotalGameScoreAtFrame(9)).toBe(230); + expect(scorecard.getTotalGameScore()).toBe(230); + }); + test('Frame 10: [10, 10, 10]: FS7: 30, FS8: 30; FS9: 30; TotalScore at F10: 300;', () =>{ + scorecard.add10thFrame(10, 10, 10); //Strike F10 + + expect(scorecard.frames).toEqual([ + [10, 0], + [10, 0], + [10, 0], + [10, 0], + [10, 0], + [10, 0], + [10, 0], + [10, 0], + [10, 0], + [10, 10, 10] + ]); + expect(scorecard.getFrameTotal(scorecard.frames[0])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[1])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[2])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[3])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[4])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[5])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[6])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[7])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[9])).toBe(30); + expect(scorecard.getTotalGameScoreAtFrame(10)).toBe(300); + expect(scorecard.getTotalGameScore()).toBe(300); + }); +}); From 07fe56535645e1f80e82f7b97d56111237a8e723 Mon Sep 17 00:00:00 2001 From: ClairePeng Date: Wed, 1 Nov 2023 16:54:21 +0000 Subject: [PATCH 4/9] adds gutter game and perfect game. TODO failing perfect game score for second-last frame --- scorecard.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scorecard.test.js b/scorecard.test.js index ec15627fc8..20646ce8c5 100644 --- a/scorecard.test.js +++ b/scorecard.test.js @@ -308,7 +308,7 @@ describe('Scorecard - Perfect Game', () => { expect(scorecard.getFrameTotal(scorecard.frames[4])).toBe(30); expect(scorecard.getFrameTotal(scorecard.frames[5])).toBe(30); expect(scorecard.getFrameTotal(scorecard.frames[6])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[7])).toBe(20); //only one roll ahead to count bonus + expect(scorecard.getFrameTotal(scorecard.frames[7])).toBe(20); //only one roll ahead to count bonus // ERROR, getting 10 instead of 30 expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(10); //no rolls ahead to count bonus expect(scorecard.getTotalGameScoreAtFrame(9)).toBe(230); expect(scorecard.getTotalGameScore()).toBe(230); @@ -336,7 +336,7 @@ describe('Scorecard - Perfect Game', () => { expect(scorecard.getFrameTotal(scorecard.frames[5])).toBe(30); expect(scorecard.getFrameTotal(scorecard.frames[6])).toBe(30); expect(scorecard.getFrameTotal(scorecard.frames[7])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(30); + expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(30); // ERROR, getting 10 instead of 30 expect(scorecard.getFrameTotal(scorecard.frames[9])).toBe(30); expect(scorecard.getTotalGameScoreAtFrame(10)).toBe(300); expect(scorecard.getTotalGameScore()).toBe(300); From a8ee599bfd62c71d162159818015af4a6d0ff6b2 Mon Sep 17 00:00:00 2001 From: ClairePeng Date: Thu, 2 Nov 2023 12:24:40 +0000 Subject: [PATCH 5/9] adds unit tested frame class --- frame.js | 124 ++++++++++++++++++++ frame.test.js | 129 +++++++++++++++++++++ scorecard.js => old/scorecard.js | 0 scorecard.test.js => old/scorecard.test.js | 0 4 files changed, 253 insertions(+) create mode 100644 frame.test.js rename scorecard.js => old/scorecard.js (100%) rename scorecard.test.js => old/scorecard.test.js (100%) diff --git a/frame.js b/frame.js index e69de29bb2..6c860d838b 100644 --- a/frame.js +++ b/frame.js @@ -0,0 +1,124 @@ +/* +10 Pin Scoring Rules: + +Every frame is 1-2 rolls + Open Frame(a, b) -> Less than 10 pins -> (a + b); + Spare(a, b = 10) -> 10 pins over 2 rolls -> (10) + (a); + Strike(a=10) -> 10 pins over 1 roll -> (10) + (a + b) or (10) + (10) + (b); + + For the 10th frame, if the player rolls a strike or spare, they can roll again for the bonus +*/ + +class Frame { + /** + * + * @param {number} roll1 // 0-10 + * @param {number} roll2 // 0-10, b <= 10-a + */ + constructor(roll1, roll2){ + // catch errors for construction: + if ((typeof roll1 !== 'number' || isNaN(roll1)) || (typeof roll2 !== 'number' || isNaN(roll2))) { + throw new Error('Rolls must be numbers and not empty.'); + } + + if (roll1 < 0 || roll1 > 10 || roll2 < 0 || roll2 > 10) { + throw new Error('Roll values must be between 0 and 10.'); + } + + if (roll1 + roll2 > 10) { + throw new Error('The sum of roll1 and roll2 cannot exceed 10.'); + } + + // initialization attributes: + this.rolls = [roll1, roll2]; + this.type = 'open'; + this.bonus = 0; + + // check and update type immediately on init. + this.checkType(); + } + // Get total before bonusses + getInitialTotal(){ + return this.rolls[0] + this.rolls[1]; + } + + // Return true if frame is a strike + isStrike(){ + return this.rolls[0] === 10; + } + // Return true if frame is a spare + isSpare(){ + return this.getInitialTotal() === 10 && !this.isStrike(); + } + // Checks if frame is a strike or spare and updates this.type + checkType(){ + if (this.isStrike()) { + this.type = 'strike'; + } else if (this.isSpare()) { + this.type = 'spare'; + } + } + + // Add bonus (calculated from the next 1-2 rolls in Scorecard) + addBonus(bonus){ + this.bonus += bonus + } + + // Get the current total, inclusive of any bonuses. + getCurrentTotal(){ + return this.getInitialTotal() + this.bonus; + } +} + + + +class TenthFrameSpecial { + constructor(roll1, roll2, roll3){ + // catch errors for construction: + if ( + (typeof roll1 !== 'number' || isNaN(roll1)) || + (typeof roll2 !== 'number' || isNaN(roll2)) || + (typeof roll3 !== 'number' || isNaN(roll3))) { + throw new Error('Rolls must be numbers and not empty.'); + } + + if (roll1 < 0 || roll1 > 10 || roll2 < 0 || roll2 > 10 || roll3 < 0 || roll3 > 10) { + throw new Error('Roll values must be between 0 and 10.'); + } + + // if not a strike, roll 1 & roll 2 cannot total more than 10; + // if (roll1 + roll2 > 10 && roll1 != 10){ + // throw new Error('This frame must be either a Strike or a Spare.'); + // } + + + this.rolls = [roll1, roll2, roll3]; + this.type = 'spare'; + + // check and update type immediately on init. + this.checkType(); + + + } + // Return true if frame is a strike + isStrike(){ + return this.rolls[0] === 10; + } + // Checks if frame is a strike or spare and updates this.type + // Default this.type is spare, so it only checks for strikes + checkType(){ + if (this.isStrike()) { + this.type = 'strike'; + } + } + // Using same method name as above so that ScoreCard use frame.getCurrentTotal() forEach frame in frames + getCurrentTotal(){ + // equivalent of sum(self.rolls) + return this.rolls.reduce((sum, roll) => sum + roll, 0); + } +} + +module.exports = { + Frame, + TenthFrameSpecial, +}; \ No newline at end of file diff --git a/frame.test.js b/frame.test.js new file mode 100644 index 0000000000..bb64784d2d --- /dev/null +++ b/frame.test.js @@ -0,0 +1,129 @@ +const { Frame, TenthFrameSpecial } = require('./frame'); + +/// =========== FOR FRAME ================ ///////// + +// OPEN FRAME +describe('Frame - open frame: [5, 3]', () => { + const frame = new Frame(5, 3); + test('construction values: rolls = [5,3]; type = open; bonus = 0', () => { + expect(frame.rolls).toEqual([5, 3]); + expect(frame.type).toBe('open'); + expect(frame.bonus).toBe(0); + }); + test('initial total: 8; current total: 8', () => { + expect(frame.getInitialTotal()).toBe(8); + expect(frame.getCurrentTotal()).toBe(8); + }); +}); + +// SPARE FRAME +describe('Frame - spare frame: [5,5]', () => { + const frame = new Frame(5, 5); + test('construction values: rolls = [5,5]; type = spare; bonus = 0', () => { + expect(frame.rolls).toEqual([5, 5]); + expect(frame.type).toBe('spare'); + expect(frame.bonus).toBe(0); + }); + test('initial total: 10; current total: 10', () => { + expect(frame.getInitialTotal()).toBe(10); + expect(frame.getCurrentTotal()).toBe(10); + }); + test('adding bonus of 4 updates the current total to 14', () => { + frame.addBonus(4); + expect(frame.bonus).toBe(4); + expect(frame.getInitialTotal()).toBe(10); + expect(frame.getCurrentTotal()).toBe(14); + }); +}); + +// STRIKE FRAME +describe('Frame - strike frame: [10, 0]', () => { + const frame = new Frame(10, 0); + test('construction values: rolls = [10, 0]; type = strike; bonus = 0', () => { + expect(frame.rolls).toEqual([10, 0]); + expect(frame.type).toBe('strike'); + expect(frame.bonus).toBe(0); + }); + test('initial total: 10; current total: 10', () => { + expect(frame.getInitialTotal()).toBe(10); + expect(frame.getCurrentTotal()).toBe(10); + }); + test('adding bonus of 4 updates the current total to 14', () => { + frame.addBonus(4); + expect(frame.bonus).toBe(4); + expect(frame.getInitialTotal()).toBe(10); + expect(frame.getCurrentTotal()).toBe(14); + }); + test('adding bonus of 5 updates the current total to 19', () => { + frame.addBonus(5); + expect(frame.bonus).toBe(9); + expect(frame.getInitialTotal()).toBe(10); + expect(frame.getCurrentTotal()).toBe(19); + }); +}); + +// GUTTER GAME FRAME [0,0] +describe('Frame - open frame: [0, 0]', () => { + const frame = new Frame(0, 0); + test('construction values: rolls = [0,0]; type = open; bonus = 0', () => { + expect(frame.rolls).toEqual([0,0]); + expect(frame.type).toBe('open'); + expect(frame.bonus).toBe(0); + }); + test('initial total: 0; current total: 0', () => { + expect(frame.getInitialTotal()).toBe(0); + expect(frame.getCurrentTotal()).toBe(0); + }); +}); + + +// PERFECT GAME FRAME [10,0] +describe('Frame - strike frame: [10, 0]', () => { + const frame = new Frame(10, 0); + test('construction values: rolls = [10, 0]; type = strike; bonus = 0', () => { + expect(frame.rolls).toEqual([10, 0]); + expect(frame.type).toBe('strike'); + expect(frame.bonus).toBe(0); + }); + test('initial total: 10; current total: 10', () => { + expect(frame.getInitialTotal()).toBe(10); + expect(frame.getCurrentTotal()).toBe(10); + }); + test('adding bonus of 10 updates the current total to 20', () => { + frame.addBonus(10); + expect(frame.bonus).toBe(10); + expect(frame.getInitialTotal()).toBe(10); + expect(frame.getCurrentTotal()).toBe(20); + }); + test('adding bonus of 10 updates the current total to 30', () => { + frame.addBonus(10); + expect(frame.bonus).toBe(20); + expect(frame.getInitialTotal()).toBe(10); + expect(frame.getCurrentTotal()).toBe(30); + }); + +}); + + + +// ERROR HANDLING +describe('Frame - Error Handling', () => { + test('throws an error when roll1 is not a number', () => { + expect(() => new Frame('', 3)).toThrowError('Rolls must be numbers and not empty.'); + }); + + test('throws an error when roll2 is not a number', () => { + expect(() => new Frame(5, null)).toThrowError('Rolls must be numbers and not empty.'); + }); + + test('throws an error when roll values are out of range', () => { + expect(() => new Frame(11, 3)).toThrowError('Roll values must be between 0 and 10.'); + }); + + test('throws an error when roll values exceed 10', () => { + expect(() => new Frame(7, 6)).toThrowError('The sum of roll1 and roll2 cannot exceed 10.'); + }); + +}); + + diff --git a/scorecard.js b/old/scorecard.js similarity index 100% rename from scorecard.js rename to old/scorecard.js diff --git a/scorecard.test.js b/old/scorecard.test.js similarity index 100% rename from scorecard.test.js rename to old/scorecard.test.js From ae74f407e0fa45e50c5c00dbadcbb541c34272b2 Mon Sep 17 00:00:00 2001 From: ClairePeng Date: Thu, 2 Nov 2023 16:16:14 +0000 Subject: [PATCH 6/9] adds tested scorecard, TODO: change frameScore to cumulative score at that frame --- frame.js | 55 +--- frame.test.js | 19 +- scorecard2.js | 182 +++++++++++ scorecard2.test.js | 788 +++++++++++++++++++++++++++++++++++++++++++++ tenthframe.js | 57 ++++ tenthframe.test.js | 73 +++++ 6 files changed, 1112 insertions(+), 62 deletions(-) create mode 100644 scorecard2.js create mode 100644 scorecard2.test.js create mode 100644 tenthframe.js create mode 100644 tenthframe.test.js diff --git a/frame.js b/frame.js index 6c860d838b..f24de703d2 100644 --- a/frame.js +++ b/frame.js @@ -60,8 +60,8 @@ class Frame { } // Add bonus (calculated from the next 1-2 rolls in Scorecard) - addBonus(bonus){ - this.bonus += bonus + updateBonus(bonus){ + this.bonus = bonus } // Get the current total, inclusive of any bonuses. @@ -72,53 +72,4 @@ class Frame { -class TenthFrameSpecial { - constructor(roll1, roll2, roll3){ - // catch errors for construction: - if ( - (typeof roll1 !== 'number' || isNaN(roll1)) || - (typeof roll2 !== 'number' || isNaN(roll2)) || - (typeof roll3 !== 'number' || isNaN(roll3))) { - throw new Error('Rolls must be numbers and not empty.'); - } - - if (roll1 < 0 || roll1 > 10 || roll2 < 0 || roll2 > 10 || roll3 < 0 || roll3 > 10) { - throw new Error('Roll values must be between 0 and 10.'); - } - - // if not a strike, roll 1 & roll 2 cannot total more than 10; - // if (roll1 + roll2 > 10 && roll1 != 10){ - // throw new Error('This frame must be either a Strike or a Spare.'); - // } - - - this.rolls = [roll1, roll2, roll3]; - this.type = 'spare'; - - // check and update type immediately on init. - this.checkType(); - - - } - // Return true if frame is a strike - isStrike(){ - return this.rolls[0] === 10; - } - // Checks if frame is a strike or spare and updates this.type - // Default this.type is spare, so it only checks for strikes - checkType(){ - if (this.isStrike()) { - this.type = 'strike'; - } - } - // Using same method name as above so that ScoreCard use frame.getCurrentTotal() forEach frame in frames - getCurrentTotal(){ - // equivalent of sum(self.rolls) - return this.rolls.reduce((sum, roll) => sum + roll, 0); - } -} - -module.exports = { - Frame, - TenthFrameSpecial, -}; \ No newline at end of file +module.exports = Frame; diff --git a/frame.test.js b/frame.test.js index bb64784d2d..ee34149bc1 100644 --- a/frame.test.js +++ b/frame.test.js @@ -1,4 +1,4 @@ -const { Frame, TenthFrameSpecial } = require('./frame'); +const Frame = require('./frame'); /// =========== FOR FRAME ================ ///////// @@ -29,7 +29,7 @@ describe('Frame - spare frame: [5,5]', () => { expect(frame.getCurrentTotal()).toBe(10); }); test('adding bonus of 4 updates the current total to 14', () => { - frame.addBonus(4); + frame.updateBonus(4); expect(frame.bonus).toBe(4); expect(frame.getInitialTotal()).toBe(10); expect(frame.getCurrentTotal()).toBe(14); @@ -49,13 +49,13 @@ describe('Frame - strike frame: [10, 0]', () => { expect(frame.getCurrentTotal()).toBe(10); }); test('adding bonus of 4 updates the current total to 14', () => { - frame.addBonus(4); + frame.updateBonus(4); expect(frame.bonus).toBe(4); expect(frame.getInitialTotal()).toBe(10); expect(frame.getCurrentTotal()).toBe(14); }); - test('adding bonus of 5 updates the current total to 19', () => { - frame.addBonus(5); + test('adding bonus of 4+5 updates the current total to 19', () => { + frame.updateBonus(4+5); expect(frame.bonus).toBe(9); expect(frame.getInitialTotal()).toBe(10); expect(frame.getCurrentTotal()).toBe(19); @@ -90,13 +90,13 @@ describe('Frame - strike frame: [10, 0]', () => { expect(frame.getCurrentTotal()).toBe(10); }); test('adding bonus of 10 updates the current total to 20', () => { - frame.addBonus(10); + frame.updateBonus(10); expect(frame.bonus).toBe(10); expect(frame.getInitialTotal()).toBe(10); expect(frame.getCurrentTotal()).toBe(20); }); - test('adding bonus of 10 updates the current total to 30', () => { - frame.addBonus(10); + test('adding bonus of 10+10 updates the current total to 30', () => { + frame.updateBonus(10+10); expect(frame.bonus).toBe(20); expect(frame.getInitialTotal()).toBe(10); expect(frame.getCurrentTotal()).toBe(30); @@ -105,7 +105,6 @@ describe('Frame - strike frame: [10, 0]', () => { }); - // ERROR HANDLING describe('Frame - Error Handling', () => { test('throws an error when roll1 is not a number', () => { @@ -123,7 +122,7 @@ describe('Frame - Error Handling', () => { test('throws an error when roll values exceed 10', () => { expect(() => new Frame(7, 6)).toThrowError('The sum of roll1 and roll2 cannot exceed 10.'); }); - + }); diff --git a/scorecard2.js b/scorecard2.js new file mode 100644 index 0000000000..8850d136fe --- /dev/null +++ b/scorecard2.js @@ -0,0 +1,182 @@ +const TenthFrameSpecial = require('./tenthframe'); +const Frame = require('./frame'); + + +/* +10 Pin Scoring Rules: + +Every frame is 1-2 rolls + Open Frame(a, b) -> Less than 10 pins -> (a + b); + Spare(a, b = 10) -> 10 pins over 2 rolls -> (10) + (a); + Strike(a=10) -> 10 pins over 1 roll -> (10) + (a + b) or (10) + (10) + (b); + + For the 10th frame, if the player rolls a strike or spare, they can roll again for the bonus +*/ + +class ScoreCard { + constructor(){ + this.frames = []; + }; + + // ADDING FRAMES: + /** + * + * @param {Frame | TenthFrameSpecial} frame + */ + addFrame(frame) { + this.frames.push(frame) + }; + + // GETTING SPARE BONUS: + getSpareBonus(frame) { + let bonus = 0; + // find the index of the current frame + const thisFrameIndex = this.frames.indexOf(frame); + + try { + // find the next frame, + const nextFrame = this.frames[thisFrameIndex + 1]; + // find the first roll of the next frame + bonus += nextFrame.rolls[0]; + // update the frame bonus + frame.updateBonus(bonus); + + } catch (error) { + // no bonus added if next roll hasn't happened yet. + if (error instanceof RangeError) { + // pass, no bonus to add + } else { + console.error('An error occured:', error.message); + } + } + return bonus; + }; + + // GETTING STRIKE BONUS: + getStrikeBonus(frame) { + let bonus = 0; + // find the index of the current frame + const thisFrameIndex = this.frames.indexOf(frame); + + // try to find the next frame: + try { + // find the next frame, + const nextFrame = this.frames[thisFrameIndex + 1]; + // find the first roll of the next frame + bonus += nextFrame.rolls[0]; + + // if the next frame is a strike AND is NOT frame 10 (thisFrame is NOT frame 9): + if (nextFrame.type === 'strike' && thisFrameIndex !== 8) { + + // try to find the next-next-frame: + // This allows the score to be updated for a frame sequence STRIKE, STRIKE, No roll yet. + try { + // find the next-next-frame, + const nextNextFrame = this.frames[thisFrameIndex + 2]; + // find the first roll of the next-next-frame + bonus += nextNextFrame.rolls[0]; + + } catch (error) { + // no bonus added if next-next-frame hasn't happened yet. + if (error instanceof RangeError) { + // pass, no bonus to add + } else { + console.error('An error occured:', error.message); + } + } + + // next frame is NOT a strike OR next frame IS a strike on frame 10: + } else { + // second bonus is from the second roll of the next frame + bonus += nextFrame.rolls[1] + } + + } catch (error) { + // no bonus added if next roll hasn't happened yet. + if (error instanceof RangeError) { + // pass, no bonus to add + } else { + console.error('An error occured:', error.message); + } + } + + // update the bonus of this frame with the cumulated bonus: + frame.updateBonus(bonus) + return bonus; + }; + + + + // CHECKING FOR BONUSES: + /** + * Updates the bonus of each frame depending on the frame type + * @param {Frame} frame // Use for frames 1-9. If 10th frame is special, just use frame.getCurrentTotal() (line 133) + */ + checkForBonus(frame) { + // if frame type is spare, try get spare bonus if the next roll has happened + if (frame.type === 'spare') { + this.getSpareBonus(frame) + + // if frame type is strike, try to get the bonus if the next 1 or 2 rolls have happened. + } else if (frame.type === 'strike') { + this.getStrikeBonus(frame) + } + }; + + // GET FRAME TOTAL: + /** + * + * @param {Frame | TenthFrameSpecial} frame + * @returns {number} + */ + getFrameTotal(frame) { + // If frame is frames 1-9, check for bonuses. If this is run on an open frame 10, nothing happens. + if (!(frame instanceof TenthFrameSpecial)) { + this.checkForBonus(frame) + } + // Get the total after any bonuses + return frame.getCurrentTotal(); + }; + + // GET GAME TOTAL: + /** + * + * @returns the total score for the game + */ + getGameTotal() { + let total = 0 + // getFrameTotal each frame from this.frames + // Add total of each frame + this.frames.forEach((frame) => { + total += this.getFrameTotal(frame); + }); + return total; + } + + // SCORECARD: + /** + * + * @returns a scorecard object + */ + showScoreCard() { + let scorecard = [] + this.frames.forEach((frame) => { + // const frameNumber = this.frames.indexOf(frame); + // const frameRolls = frame.rolls; + // const frameType = frame.type; + // const frameScore = this.frames.getFrameTotal(frame); + + const frameScoreCard = { + number: (this.frames.indexOf(frame)+1), + rolls: frame.rolls, + type: frame.type, + frameScore: this.getFrameTotal(frame) + } + scorecard.push(frameScoreCard) + }); + return scorecard; + } + +} + +module.exports = ScoreCard; \ No newline at end of file diff --git a/scorecard2.test.js b/scorecard2.test.js new file mode 100644 index 0000000000..2c3731d087 --- /dev/null +++ b/scorecard2.test.js @@ -0,0 +1,788 @@ +const TenthFrameSpecial = require('./tenthframe'); +const Frame = require('./frame'); +const ScoreCard = require('./scorecard2'); + +// INTEGRATION TESTS: +describe('Scorecard - Gutter Game', () => { + // arrange + const scorecard = new ScoreCard() + + test('Frame 1: [0,0]', () => { + scorecard.addFrame(new Frame(0, 0)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [0, 0], + type: 'open', + frameScore: 0 + } + ]) + expect(scorecard.getGameTotal()).toBe(0) + }) + test('Frame 2-9: [0,0]', () => { + scorecard.addFrame(new Frame(0, 0)); + scorecard.addFrame(new Frame(0, 0)); + scorecard.addFrame(new Frame(0, 0)); + scorecard.addFrame(new Frame(0, 0)); + scorecard.addFrame(new Frame(0, 0)); + scorecard.addFrame(new Frame(0, 0)); + scorecard.addFrame(new Frame(0, 0)); + scorecard.addFrame(new Frame(0, 0)); + + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 2, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 3, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 4, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 5, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 6, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 7, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 8, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 9, + rolls: [0, 0], + type: 'open', + frameScore: 0 + } + ]) + }) + test('Frame 10', () => { + scorecard.addFrame(new Frame(0, 0)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 2, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 3, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 4, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 5, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 6, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 7, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 8, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 9, + rolls: [0, 0], + type: 'open', + frameScore: 0 + }, + { + number: 10, + rolls: [0, 0], + type: 'open', + frameScore: 0 + } + + ]) + }) + +}) + + +describe('Scorecard - Perfect Game', () => { + // arrange + const scorecard = new ScoreCard() + test('Frame 1: [10,0]', () => { + scorecard.addFrame(new Frame(10,0)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [10, 0], + type: 'strike', + frameScore: 10 + } + ]) + expect(scorecard.getGameTotal()).toBe(10) + }) + test('Frame 2: [10,0]', () => { + secondFrame = new Frame(10,0) + scorecard.addFrame(secondFrame); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [10, 0], + type: 'strike', + frameScore: 20 + }, + { + number: 2, + rolls: [10, 0], + type: 'strike', + frameScore: 10 + } + ]) + expect(scorecard.getGameTotal()).toBe(30) + }) + test('Frame 3: [10,0]', () => { + scorecard.addFrame(new Frame(10,0)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [10, 0], + type: 'strike', + frameScore: 30 // returns 20 right now + }, + { + number: 2, + rolls: [10, 0], + type: 'strike', + frameScore: 20 // returns 30 right now + }, + { + number: 3, + rolls: [10, 0], + type: 'strike', + frameScore: 10 + } + ]) + expect(scorecard.getGameTotal()).toBe(60) + }) + + test('Frame 4: [10,0]', () => { + scorecard.addFrame(new Frame(10,0)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 2, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 3, + rolls: [10, 0], + type: 'strike', + frameScore: 20 // returns 30 right now + }, + { + number: 4, + rolls: [10, 0], + type: 'strike', + frameScore: 10 + } + ]) + expect(scorecard.getGameTotal()).toBe(90) + }) + + test('Frames 5-9: [10,0]', () => { + scorecard.addFrame(new Frame(10,0)); + scorecard.addFrame(new Frame(10,0)); + scorecard.addFrame(new Frame(10,0)); + scorecard.addFrame(new Frame(10,0)); + scorecard.addFrame(new Frame(10,0)); + + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 2, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 3, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 4, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 5, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 6, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 7, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 8, + rolls: [10, 0], + type: 'strike', + frameScore: 20 + }, + { + number: 9, + rolls: [10, 0], + type: 'strike', + frameScore: 10 + } + ]) + expect(scorecard.getGameTotal()).toBe(240) + }) + test('Frames 10: [10, 10, 10]', () => { + scorecard.addFrame(new TenthFrameSpecial(10,10,10)); + + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 2, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 3, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 4, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 5, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 6, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 7, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 8, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 9, + rolls: [10, 0], + type: 'strike', + frameScore: 30 + }, + { + number: 10, + rolls: [10, 10, 10], + type: 'strike', + frameScore: 30 + } + + ]) + expect(scorecard.getGameTotal()).toBe(300) + }) +}) + + + +describe('Scorecard - Example Game', () => { + // arrange + const scorecard = new ScoreCard() + + test('Frame 1-2: [1, 4], [4, 5]', () => { + // Frame 1 + scorecard.addFrame(new Frame(1, 4)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [1, 4], + type: 'open', + frameScore: 5 + } + ]) + expect(scorecard.getGameTotal()).toBe(5) + // Frame 2 + scorecard.addFrame(new Frame(4, 5)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [1, 4], + type: 'open', + frameScore: 5 + }, + { + number: 2, + rolls: [4, 5], + type: 'open', + frameScore: 9 + } + ]) + expect(scorecard.getGameTotal()).toBe(14) + }) + + test('Frame 3-6: [6,4], [5, 5], [10,0], [0, 1]', () => { + // Frame 3 + scorecard.addFrame(new Frame(6, 4)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [1, 4], + type: 'open', + frameScore: 5 + }, + { + number: 2, + rolls: [4, 5], + type: 'open', + frameScore: 9 + }, + { + number: 3, + rolls: [6, 4], + type: 'spare', + frameScore: 10 + } + ]) + expect(scorecard.getGameTotal()).toBe(24) + + // Frame 4 + scorecard.addFrame(new Frame(5, 5)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [1, 4], + type: 'open', + frameScore: 5 + }, + { + number: 2, + rolls: [4, 5], + type: 'open', + frameScore: 9 + }, + { + number: 3, + rolls: [6, 4], + type: 'spare', + frameScore: 15 + }, + { + number: 4, + rolls: [5, 5], + type: 'spare', + frameScore: 10 + } + ]) + expect(scorecard.getGameTotal()).toBe(39); + + // Frame 5 + scorecard.addFrame(new Frame(10, 0)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [1, 4], + type: 'open', + frameScore: 5 + }, + { + number: 2, + rolls: [4, 5], + type: 'open', + frameScore: 9 + }, + { + number: 3, + rolls: [6, 4], + type: 'spare', + frameScore: 15 + }, + { + number: 4, + rolls: [5, 5], + type: 'spare', + frameScore: 20 + }, + { + number: 5, + rolls: [10, 0], + type: 'strike', + frameScore: 10 + } + ]) + expect(scorecard.getGameTotal()).toBe(59); + + // Frame 6 + scorecard.addFrame(new Frame(0, 1)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [1, 4], + type: 'open', + frameScore: 5 + }, + { + number: 2, + rolls: [4, 5], + type: 'open', + frameScore: 9 + }, + { + number: 3, + rolls: [6, 4], + type: 'spare', + frameScore: 15 + }, + { + number: 4, + rolls: [5, 5], + type: 'spare', + frameScore: 20 + }, + { + number: 5, + rolls: [10, 0], + type: 'strike', + frameScore: 11 + }, + { + number: 6, + rolls: [0, 1], + type: 'open', + frameScore: 1 + } + ]) + expect(scorecard.getGameTotal()).toBe(61); + }) + + test('Frame 7-9: [7,3], [6,4], [10,0]', () => { + // Frame 7 + scorecard.addFrame(new Frame(7,3)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [1, 4], + type: 'open', + frameScore: 5 + }, + { + number: 2, + rolls: [4, 5], + type: 'open', + frameScore: 9 + }, + { + number: 3, + rolls: [6, 4], + type: 'spare', + frameScore: 15 + }, + { + number: 4, + rolls: [5, 5], + type: 'spare', + frameScore: 20 + }, + { + number: 5, + rolls: [10, 0], + type: 'strike', + frameScore: 11 + }, + { + number: 6, + rolls: [0, 1], + type: 'open', + frameScore: 1 + }, + { + number: 7, + rolls: [7, 3], + type: 'spare', + frameScore: 10 + } + ]) + expect(scorecard.getGameTotal()).toBe(71); + + // Frame 8 + scorecard.addFrame(new Frame(6, 4)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [1, 4], + type: 'open', + frameScore: 5 + }, + { + number: 2, + rolls: [4, 5], + type: 'open', + frameScore: 9 + }, + { + number: 3, + rolls: [6, 4], + type: 'spare', + frameScore: 15 + }, + { + number: 4, + rolls: [5, 5], + type: 'spare', + frameScore: 20 + }, + { + number: 5, + rolls: [10, 0], + type: 'strike', + frameScore: 11 + }, + { + number: 6, + rolls: [0, 1], + type: 'open', + frameScore: 1 + }, + { + number: 7, + rolls: [7, 3], + type: 'spare', + frameScore: 16 + }, + { + number: 8, + rolls: [6, 4], + type: 'spare', + frameScore: 10 + } + + ]) + expect(scorecard.getGameTotal()).toBe(87); + + + // Frame 9 + scorecard.addFrame(new Frame(10, 0)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [1, 4], + type: 'open', + frameScore: 5 + }, + { + number: 2, + rolls: [4, 5], + type: 'open', + frameScore: 9 + }, + { + number: 3, + rolls: [6, 4], + type: 'spare', + frameScore: 15 + }, + { + number: 4, + rolls: [5, 5], + type: 'spare', + frameScore: 20 + }, + { + number: 5, + rolls: [10, 0], + type: 'strike', + frameScore: 11 + }, + { + number: 6, + rolls: [0, 1], + type: 'open', + frameScore: 1 + }, + { + number: 7, + rolls: [7, 3], + type: 'spare', + frameScore: 16 + }, + { + number: 8, + rolls: [6, 4], + type: 'spare', + frameScore: 20 + }, + { + number: 9, + rolls: [10, 0], + type: 'strike', + frameScore: 10 + } + ]) + expect(scorecard.getGameTotal()).toBe(107); + }) + + test('Frame 10: [2, 8, 6]', () => { + // Frame 10 + scorecard.addFrame(new TenthFrameSpecial(2, 8, 6)); + expect(scorecard.showScoreCard()).toEqual([ + { + number: 1, + rolls: [1, 4], + type: 'open', + frameScore: 5 + }, + { + number: 2, + rolls: [4, 5], + type: 'open', + frameScore: 9 + }, + { + number: 3, + rolls: [6, 4], + type: 'spare', + frameScore: 15 + }, + { + number: 4, + rolls: [5, 5], + type: 'spare', + frameScore: 20 + }, + { + number: 5, + rolls: [10, 0], + type: 'strike', + frameScore: 11 + }, + { + number: 6, + rolls: [0, 1], + type: 'open', + frameScore: 1 + }, + { + number: 7, + rolls: [7, 3], + type: 'spare', + frameScore: 16 + }, + { + number: 8, + rolls: [6, 4], + type: 'spare', + frameScore: 20 + }, + { + number: 9, + rolls: [10, 0], + type: 'strike', + frameScore: 20 + }, + { + number: 10, + rolls: [2, 8, 6], + type: 'spare', + frameScore: 16 + } + ]) + expect(scorecard.getGameTotal()).toBe(133); + }) +}) diff --git a/tenthframe.js b/tenthframe.js new file mode 100644 index 0000000000..9d5d48b14d --- /dev/null +++ b/tenthframe.js @@ -0,0 +1,57 @@ + +class TenthFrameSpecial { + constructor(roll1, roll2, roll3){ + // catch errors for construction: + if ( + (typeof roll1 !== 'number' || isNaN(roll1)) || + (typeof roll2 !== 'number' || isNaN(roll2)) || + (typeof roll3 !== 'number' || isNaN(roll3))) { + throw new Error('Rolls must be numbers and not empty.'); + } + + if (roll1 < 0 || roll1 > 10 || roll2 < 0 || roll2 > 10 || roll3 < 0 || roll3 > 10) { + throw new Error('Roll values must be between 0 and 10.'); + } + + this.rolls = [roll1, roll2, roll3]; + this.type = ''; + + // check and update type immediately on init. + this.checkType(); + + + if (this.type !== 'strike' && roll1 + roll2 > 10) { + throw new Error('The sum of roll1 and roll2 cannot exceed 10 if roll1 is not a strike.') + } + + if (this.type === '') { + throw new Error('The initial frame must be a strike or a spare.'); + } + } + + // Return true if frame is a strike + isStrike(){ + return this.rolls[0] === 10; + } + // Return true if frame is a spare + isSpare(){ + return this.rolls[0] + this.rolls[1] === 10 && !this.isStrike(); + } + // Checks if frame is a strike or spare and updates this.type + // Default this.type is spare, so it only checks for strikes + checkType(){ + if (this.isStrike()) { + this.type = 'strike'; + } else if (this.isSpare()) { + this.type = 'spare'; + } + } + // Using same method name as above so that ScoreCard use frame.getCurrentTotal() forEach frame in frames + getCurrentTotal(){ + // equivalent of sum(self.rolls) + return this.rolls.reduce((sum, roll) => sum + roll, 0); + } +} + + +module.exports = TenthFrameSpecial; \ No newline at end of file diff --git a/tenthframe.test.js b/tenthframe.test.js new file mode 100644 index 0000000000..c239867579 --- /dev/null +++ b/tenthframe.test.js @@ -0,0 +1,73 @@ +const TenthFrameSpecial = require('./tenthframe'); + + +/// =========== FOR 10th FRAME ================ ///////// + + +// SPARE FRAME: +describe('10th Frame Special - Spare: [5, 5, 9]', () => { + const frame = new TenthFrameSpecial(5, 5, 9); + test('construction values: rolls = [5, 5, 9]; type = spare', () => { + expect(frame.rolls).toEqual([5, 5, 9]); + expect(frame.type).toBe('spare'); + }); + test('current total: 19', () => { + expect(frame.getCurrentTotal()).toBe(19); + }); +}); + +// STRIKE FRAME: +describe('10th Frame Special - Strike: [10, 2, 9]', () => { + const frame = new TenthFrameSpecial(10, 2, 9); + test('construction values: rolls = [10, 2, 9]; type = strike', () => { + expect(frame.rolls).toEqual([10, 2, 9]); + expect(frame.type).toBe('strike'); + }); + test('current total: 21', () => { + expect(frame.getCurrentTotal()).toBe(21); + }); +}); + + +// PERFECT GAME FRAME: [10,10,10] +describe('10th Frame Special - Perfect Game: [10, 10, 10]', () => { + const frame = new TenthFrameSpecial(10, 10, 10); + test('construction values: rolls = [10, 10, 10]; type = strike', () => { + expect(frame.rolls).toEqual([10, 10, 10]); + expect(frame.type).toBe('strike'); + }); + test('current total: 30', () => { + expect(frame.getCurrentTotal()).toBe(30); + }); +}); + + + +// ERROR HANDLING: +describe('TenthFrameSpecial - Error Handling', () => { + test('throws an error when roll1 is not a number', () => { + expect(() => new TenthFrameSpecial('', 3, 5)).toThrowError('Rolls must be numbers and not empty.'); + }); + + test('throws an error when roll2 is not a number', () => { + expect(() => new TenthFrameSpecial(5, null, 5)).toThrowError('Rolls must be numbers and not empty.'); + }); + + test('throws an error when roll3 is not a number', () => { + expect(() => new TenthFrameSpecial(5, 3, 'hello')).toThrowError('Rolls must be numbers and not empty.'); + }); + + test('throws an error when roll values are out of range', () => { + expect(() => new TenthFrameSpecial(11, 3, 5)).toThrowError('Roll values must be between 0 and 10.'); + }); + + test('throws an error when sum of roll1 and roll2 cannot exceed 10 if roll1 is not a strike', () => { + expect(() => new TenthFrameSpecial(7, 6, 5)).toThrowError('The sum of roll1 and roll2 cannot exceed 10 if roll1 is not a strike.'); + }); + + test('throws an error when the frame is not a strike or a spare', () => { + expect(() => new TenthFrameSpecial(7, 1, 5)).toThrowError('The initial frame must be a strike or a spare.'); + }); + + +}); \ No newline at end of file From 730cb6b61d834613012282842c14e3d6b78dd3c4 Mon Sep 17 00:00:00 2001 From: ClairePeng Date: Thu, 2 Nov 2023 16:43:28 +0000 Subject: [PATCH 7/9] last commit before re-org of try block --- scorecard2.js | 94 ++++++++++++++++-------------- scorecard2.test.js | 138 ++++++++++++++++++++++----------------------- 2 files changed, 121 insertions(+), 111 deletions(-) diff --git a/scorecard2.js b/scorecard2.js index 8850d136fe..f11ebe2c96 100644 --- a/scorecard2.js +++ b/scorecard2.js @@ -18,6 +18,8 @@ class ScoreCard { this.frames = []; }; + // ======= ADDING TO THE SCORECARD =============== // + // ADDING FRAMES: /** * @@ -27,6 +29,53 @@ class ScoreCard { this.frames.push(frame) }; + // ======= GET THE TOTAL SCORE ================= // + + // GET GAME TOTAL: + /** + * + * @returns the total score for the game + */ + getGameTotal() { + let total = 0 + // getFrameTotal each frame from this.frames + // Add total of each frame + this.frames.forEach((frame) => { + total += this.getFrameTotal(frame); + }); + return total; + } + + + // ======= SHOWING THE SCORECARD ================= // + + // SCORECARD: + /** + * + * @returns a scorecard object + */ + showScoreCard() { + let scorecard = []; + let cumulative_score = 0; + + this.frames.forEach((frame) => { + + // bowling scorecard shows the cumulative score after each frame. + cumulative_score += this.getFrameTotal(frame) + + const frameScoreCard = { + number: (this.frames.indexOf(frame)+1), + rolls: frame.rolls, + type: frame.type, + frameScore: cumulative_score + } + scorecard.push(frameScoreCard) + }); + return scorecard; + } + + // ------------- supportive functions: ---------------------- // + // GETTING SPARE BONUS: getSpareBonus(frame) { let bonus = 0; @@ -46,7 +95,7 @@ class ScoreCard { if (error instanceof RangeError) { // pass, no bonus to add } else { - console.error('An error occured:', error.message); + // console.error('An error occured:', error.message); // Cannot read properties of undefined (reading 'rolls') } } return bonus; @@ -81,7 +130,7 @@ class ScoreCard { if (error instanceof RangeError) { // pass, no bonus to add } else { - console.error('An error occured:', error.message); + // console.error('An error occured:', error.message); } } @@ -96,7 +145,7 @@ class ScoreCard { if (error instanceof RangeError) { // pass, no bonus to add } else { - console.error('An error occured:', error.message); + // console.error('An error occured:', error.message); } } @@ -106,7 +155,6 @@ class ScoreCard { }; - // CHECKING FOR BONUSES: /** * Updates the bonus of each frame depending on the frame type @@ -138,44 +186,6 @@ class ScoreCard { return frame.getCurrentTotal(); }; - // GET GAME TOTAL: - /** - * - * @returns the total score for the game - */ - getGameTotal() { - let total = 0 - // getFrameTotal each frame from this.frames - // Add total of each frame - this.frames.forEach((frame) => { - total += this.getFrameTotal(frame); - }); - return total; - } - - // SCORECARD: - /** - * - * @returns a scorecard object - */ - showScoreCard() { - let scorecard = [] - this.frames.forEach((frame) => { - // const frameNumber = this.frames.indexOf(frame); - // const frameRolls = frame.rolls; - // const frameType = frame.type; - // const frameScore = this.frames.getFrameTotal(frame); - - const frameScoreCard = { - number: (this.frames.indexOf(frame)+1), - rolls: frame.rolls, - type: frame.type, - frameScore: this.getFrameTotal(frame) - } - scorecard.push(frameScoreCard) - }); - return scorecard; - } } diff --git a/scorecard2.test.js b/scorecard2.test.js index 2c3731d087..85562b2d9b 100644 --- a/scorecard2.test.js +++ b/scorecard2.test.js @@ -185,7 +185,7 @@ describe('Scorecard - Perfect Game', () => { number: 2, rolls: [10, 0], type: 'strike', - frameScore: 10 + frameScore: 30 } ]) expect(scorecard.getGameTotal()).toBe(30) @@ -197,19 +197,19 @@ describe('Scorecard - Perfect Game', () => { number: 1, rolls: [10, 0], type: 'strike', - frameScore: 30 // returns 20 right now + frameScore: 30 }, { number: 2, rolls: [10, 0], type: 'strike', - frameScore: 20 // returns 30 right now + frameScore: 50 }, { number: 3, rolls: [10, 0], type: 'strike', - frameScore: 10 + frameScore: 60 } ]) expect(scorecard.getGameTotal()).toBe(60) @@ -228,19 +228,19 @@ describe('Scorecard - Perfect Game', () => { number: 2, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 60 }, { number: 3, rolls: [10, 0], type: 'strike', - frameScore: 20 // returns 30 right now + frameScore: 80 }, { number: 4, rolls: [10, 0], type: 'strike', - frameScore: 10 + frameScore: 90 } ]) expect(scorecard.getGameTotal()).toBe(90) @@ -264,49 +264,49 @@ describe('Scorecard - Perfect Game', () => { number: 2, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 60 }, { number: 3, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 90 }, { number: 4, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 120 }, { number: 5, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 150 }, { number: 6, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 180 }, { number: 7, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 210 }, { number: 8, rolls: [10, 0], type: 'strike', - frameScore: 20 + frameScore: 230 }, { number: 9, rolls: [10, 0], type: 'strike', - frameScore: 10 + frameScore: 240 } ]) expect(scorecard.getGameTotal()).toBe(240) @@ -325,55 +325,55 @@ describe('Scorecard - Perfect Game', () => { number: 2, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 60 }, { number: 3, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 90 }, { number: 4, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 120 }, { number: 5, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 150 }, { number: 6, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 180 }, { number: 7, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 210 }, { number: 8, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 240 }, { number: 9, rolls: [10, 0], type: 'strike', - frameScore: 30 + frameScore: 270 }, { number: 10, rolls: [10, 10, 10], type: 'strike', - frameScore: 30 + frameScore: 300 } ]) @@ -412,7 +412,7 @@ describe('Scorecard - Example Game', () => { number: 2, rolls: [4, 5], type: 'open', - frameScore: 9 + frameScore: 14 } ]) expect(scorecard.getGameTotal()).toBe(14) @@ -432,13 +432,13 @@ describe('Scorecard - Example Game', () => { number: 2, rolls: [4, 5], type: 'open', - frameScore: 9 + frameScore: 14 }, { number: 3, rolls: [6, 4], type: 'spare', - frameScore: 10 + frameScore: 24 } ]) expect(scorecard.getGameTotal()).toBe(24) @@ -456,19 +456,19 @@ describe('Scorecard - Example Game', () => { number: 2, rolls: [4, 5], type: 'open', - frameScore: 9 + frameScore: 14 }, { number: 3, rolls: [6, 4], type: 'spare', - frameScore: 15 + frameScore: 29 }, { number: 4, rolls: [5, 5], type: 'spare', - frameScore: 10 + frameScore: 39 } ]) expect(scorecard.getGameTotal()).toBe(39); @@ -486,25 +486,25 @@ describe('Scorecard - Example Game', () => { number: 2, rolls: [4, 5], type: 'open', - frameScore: 9 + frameScore: 14 }, { number: 3, rolls: [6, 4], type: 'spare', - frameScore: 15 + frameScore: 29 }, { number: 4, rolls: [5, 5], type: 'spare', - frameScore: 20 + frameScore: 49 }, { number: 5, rolls: [10, 0], type: 'strike', - frameScore: 10 + frameScore: 59 } ]) expect(scorecard.getGameTotal()).toBe(59); @@ -522,31 +522,31 @@ describe('Scorecard - Example Game', () => { number: 2, rolls: [4, 5], type: 'open', - frameScore: 9 + frameScore: 14 }, { number: 3, rolls: [6, 4], type: 'spare', - frameScore: 15 + frameScore: 29 }, { number: 4, rolls: [5, 5], type: 'spare', - frameScore: 20 + frameScore: 49 }, { number: 5, rolls: [10, 0], type: 'strike', - frameScore: 11 + frameScore: 60 }, { number: 6, rolls: [0, 1], type: 'open', - frameScore: 1 + frameScore: 61 } ]) expect(scorecard.getGameTotal()).toBe(61); @@ -566,37 +566,37 @@ describe('Scorecard - Example Game', () => { number: 2, rolls: [4, 5], type: 'open', - frameScore: 9 + frameScore: 14 }, { number: 3, rolls: [6, 4], type: 'spare', - frameScore: 15 + frameScore: 29 }, { number: 4, rolls: [5, 5], type: 'spare', - frameScore: 20 + frameScore: 49 }, { number: 5, rolls: [10, 0], type: 'strike', - frameScore: 11 + frameScore: 60 }, { number: 6, rolls: [0, 1], type: 'open', - frameScore: 1 + frameScore: 61 }, { number: 7, rolls: [7, 3], type: 'spare', - frameScore: 10 + frameScore: 71 } ]) expect(scorecard.getGameTotal()).toBe(71); @@ -614,43 +614,43 @@ describe('Scorecard - Example Game', () => { number: 2, rolls: [4, 5], type: 'open', - frameScore: 9 + frameScore: 14 }, { number: 3, rolls: [6, 4], type: 'spare', - frameScore: 15 + frameScore: 29 }, { number: 4, rolls: [5, 5], type: 'spare', - frameScore: 20 + frameScore: 49 }, { number: 5, rolls: [10, 0], type: 'strike', - frameScore: 11 + frameScore: 60 }, { number: 6, rolls: [0, 1], type: 'open', - frameScore: 1 + frameScore: 61 }, { number: 7, rolls: [7, 3], type: 'spare', - frameScore: 16 + frameScore: 77 }, { number: 8, rolls: [6, 4], type: 'spare', - frameScore: 10 + frameScore: 87 } ]) @@ -670,49 +670,49 @@ describe('Scorecard - Example Game', () => { number: 2, rolls: [4, 5], type: 'open', - frameScore: 9 + frameScore: 14 }, { number: 3, rolls: [6, 4], type: 'spare', - frameScore: 15 + frameScore: 29 }, { number: 4, rolls: [5, 5], type: 'spare', - frameScore: 20 + frameScore: 49 }, { number: 5, rolls: [10, 0], type: 'strike', - frameScore: 11 + frameScore: 60 }, { number: 6, rolls: [0, 1], type: 'open', - frameScore: 1 + frameScore: 61 }, { number: 7, rolls: [7, 3], type: 'spare', - frameScore: 16 + frameScore: 77 }, { number: 8, rolls: [6, 4], type: 'spare', - frameScore: 20 + frameScore: 97 }, { number: 9, rolls: [10, 0], type: 'strike', - frameScore: 10 + frameScore: 107 } ]) expect(scorecard.getGameTotal()).toBe(107); @@ -732,55 +732,55 @@ describe('Scorecard - Example Game', () => { number: 2, rolls: [4, 5], type: 'open', - frameScore: 9 + frameScore: 14 }, { number: 3, rolls: [6, 4], type: 'spare', - frameScore: 15 + frameScore: 29 }, { number: 4, rolls: [5, 5], type: 'spare', - frameScore: 20 + frameScore: 49 }, { number: 5, rolls: [10, 0], type: 'strike', - frameScore: 11 + frameScore: 60 }, { number: 6, rolls: [0, 1], type: 'open', - frameScore: 1 + frameScore: 61 }, { number: 7, rolls: [7, 3], type: 'spare', - frameScore: 16 + frameScore: 77 }, { number: 8, rolls: [6, 4], type: 'spare', - frameScore: 20 + frameScore: 97 }, { number: 9, rolls: [10, 0], type: 'strike', - frameScore: 20 + frameScore: 117 }, { number: 10, rolls: [2, 8, 6], type: 'spare', - frameScore: 16 + frameScore: 133 } ]) expect(scorecard.getGameTotal()).toBe(133); From c71091b14918b48e57b641a146195ad891b9b59b Mon Sep 17 00:00:00 2001 From: ClairePeng Date: Thu, 2 Nov 2023 17:19:58 +0000 Subject: [PATCH 8/9] updates organisation of scorecard2 --- scorecard2.js | 88 ++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 47 deletions(-) diff --git a/scorecard2.js b/scorecard2.js index f11ebe2c96..c681050ca2 100644 --- a/scorecard2.js +++ b/scorecard2.js @@ -64,10 +64,10 @@ class ScoreCard { cumulative_score += this.getFrameTotal(frame) const frameScoreCard = { - number: (this.frames.indexOf(frame)+1), - rolls: frame.rolls, - type: frame.type, - frameScore: cumulative_score + number: (this.frames.indexOf(frame)+1), // 1-10 + rolls: frame.rolls, + type: frame.type, // open, spare, strike + frameScore: cumulative_score } scorecard.push(frameScoreCard) }); @@ -81,23 +81,19 @@ class ScoreCard { let bonus = 0; // find the index of the current frame const thisFrameIndex = this.frames.indexOf(frame); + // find the next frame + const nextFrame = this.frames[thisFrameIndex + 1]; - try { - // find the next frame, - const nextFrame = this.frames[thisFrameIndex + 1]; + // If nextFrame has happened: + if (nextFrame !== undefined) { // find the first roll of the next frame bonus += nextFrame.rolls[0]; // update the frame bonus frame.updateBonus(bonus); - - } catch (error) { - // no bonus added if next roll hasn't happened yet. - if (error instanceof RangeError) { - // pass, no bonus to add - } else { - // console.error('An error occured:', error.message); // Cannot read properties of undefined (reading 'rolls') - } + + } else { // no bonus added if next roll hasn't happened yet. } + return bonus; }; @@ -106,47 +102,39 @@ class ScoreCard { let bonus = 0; // find the index of the current frame const thisFrameIndex = this.frames.indexOf(frame); + // find the next frame + const nextFrame = this.frames[thisFrameIndex + 1]; - // try to find the next frame: - try { - // find the next frame, - const nextFrame = this.frames[thisFrameIndex + 1]; - // find the first roll of the next frame + // If nextFrame has happened: + if (nextFrame !== undefined) { + // Add the first roll to the bonus. This is roll 1/2 of a strike bonus. bonus += nextFrame.rolls[0]; - // if the next frame is a strike AND is NOT frame 10 (thisFrame is NOT frame 9): + // ========= Finding roll 2/2 of the strike bonus:=========== + + // CASE 1: if the nextFrame is a strike AND is NOT frame 10 (thisFrame is NOT frame 9): if (nextFrame.type === 'strike' && thisFrameIndex !== 8) { - - // try to find the next-next-frame: + + // Try to find the nextNextFrame: // This allows the score to be updated for a frame sequence STRIKE, STRIKE, No roll yet. - try { - // find the next-next-frame, - const nextNextFrame = this.frames[thisFrameIndex + 2]; - // find the first roll of the next-next-frame + const nextNextFrame = this.frames[thisFrameIndex + 2]; + + // If the nextNextFrame has happened: + if (nextNextFrame !== undefined) { + // Add the first roll to the bonus. This is roll 2/2 of the strike bonus. bonus += nextNextFrame.rolls[0]; - - } catch (error) { - // no bonus added if next-next-frame hasn't happened yet. - if (error instanceof RangeError) { - // pass, no bonus to add - } else { - // console.error('An error occured:', error.message); - } + } else { + // no bonus added if the nextNextFrame hasn't happened yet. } - - // next frame is NOT a strike OR next frame IS a strike on frame 10: + + // CASE 2: nextFrame is NOT a strike OR nextFrame IS a strike on frame 10: + // If pattern is Strike + Spare || Strike + Open || Strike + 10th Frame special } else { - // second bonus is from the second roll of the next frame + // Add the second roll to the bonus. This is roll 2/2 of the strike bonus. bonus += nextFrame.rolls[1] } - - } catch (error) { - // no bonus added if next roll hasn't happened yet. - if (error instanceof RangeError) { - // pass, no bonus to add - } else { - // console.error('An error occured:', error.message); - } + + } else { // no bonus added if nextFrame hasn't happened yet. } // update the bonus of this frame with the cumulated bonus: @@ -178,10 +166,16 @@ class ScoreCard { * @returns {number} */ getFrameTotal(frame) { - // If frame is frames 1-9, check for bonuses. If this is run on an open frame 10, nothing happens. + // Checks for and adds bonuses for the following conditions: + // Frames 1-9: strike or spare + + // No bonus updates for the following conditions: + // Frames 1-10: open + // Frame 10: strike or spare if (!(frame instanceof TenthFrameSpecial)) { this.checkForBonus(frame) } + // Get the total after any bonuses return frame.getCurrentTotal(); }; From e62b5f3e4e5ab95b1510a638ef14e078d4b84d2c Mon Sep 17 00:00:00 2001 From: ClairePeng Date: Thu, 2 Nov 2023 17:38:50 +0000 Subject: [PATCH 9/9] organises project for submission and adds small readme --- README.md | 90 +---- docs/review.md | 235 ------------ frame.js => lib/frame.js | 0 scorecard2.js => lib/scorecard2.js | 7 +- tenthframe.js => lib/tenthframe.js | 0 old/scorecard.js | 164 --------- old/scorecard.test.js | 344 ------------------ frame.test.js => specs/frame.test.js | 2 +- .../scorecard2.test.js | 6 +- .../tenthframe.test.js | 3 +- 10 files changed, 17 insertions(+), 834 deletions(-) delete mode 100644 docs/review.md rename frame.js => lib/frame.js (100%) rename scorecard2.js => lib/scorecard2.js (96%) rename tenthframe.js => lib/tenthframe.js (100%) delete mode 100644 old/scorecard.js delete mode 100644 old/scorecard.test.js rename frame.test.js => specs/frame.test.js (99%) rename scorecard2.test.js => specs/scorecard2.test.js (99%) rename tenthframe.test.js => specs/tenthframe.test.js (97%) diff --git a/README.md b/README.md index ae8571b523..988ed69cf5 100644 --- a/README.md +++ b/README.md @@ -2,90 +2,14 @@ Bowling Challenge ================= -* Feel free to use google, your notes, books, etc. but work on your own -* If you refer to the solution of another coach or student, please put a link to that in your README -* If you have a partial solution, **still check in a partial solution** -* You must submit a pull request to this repo with your code by 9am Monday week +Submission for the bowling scorecard in JavaScript. +
+
+Includes tests for: -## The Task +* Gutter Game +* Perfect Game +* Example Game, please see image below. -**THIS IS NOT A BOWLING GAME, IT IS A BOWLING SCORECARD. DO NOT GENERATE RANDOM ROLLS. AN ACTUAL USER INTERFACE IS OPTIONAL** - -Count and sum the scores of a bowling game for one player (in JavaScript). - -A bowling game consists of 10 frames in which the player tries to knock down the 10 pins. In every frame the player can roll one or two times. The actual number depends on strikes and spares. The score of a frame is the number of knocked down pins plus bonuses for strikes and spares. After every frame the 10 pins are reset. - -Start by looking in detail at the rules and the example of scoring for a complete game given below. - -An example of how your code might be used could be: - -```javaScript -let scorecard = new Scorecard() -scorecard.calculateScore() // returns 0 -scorecard.addFrame(2, 5) -scorecard.addFrame(3, 5) -scorecard.calculateScore() // returns 15 -``` - -But feel free to add other methods if you think they are useful. - -As usual please start by - -* Forking this repo - -* Using test-driven development (if you decide to write a user interface, then make sure you have looked at the chapters on mocking). - -* Finally submit a pull request before Monday week at 9am with your solution or partial solution. However much or little amount of code you wrote please please please submit a pull request before Monday week at 9am. - -___STRONG HINT, IGNORE AT YOUR PERIL:___ Bowling is a deceptively complex game. Careful thought and thorough diagramming — both before and throughout — will save you literal hours of your life. - -### Optional Extras - -In any order you like: - -* Set up [Travis CI](https://travis-ci.org) to run your tests. -* Add [ESLint](http://eslint.org/) to your codebase and make your code conform. -* Create a UserInterface class, allowing you to run a game from the command line. - -You might even want to start with ESLint early on in your work — to help you -learn Javascript conventions as you go along. - -## Bowling — how does it work? - -### Strikes - -The player has a strike if he knocks down all 10 pins with the first roll in a frame. The frame ends immediately (since there are no pins left for a second roll). The bonus for that frame is the number of pins knocked down by the next two rolls. That would be the next frame, unless the player rolls another strike. - -### Spares - -The player has a spare if the knocks down all 10 pins with the two rolls of a frame. The bonus for that frame is the number of pins knocked down by the next roll (first roll of next frame). - -### 10th frame - -If the player rolls a strike or spare in the 10th frame they can roll the additional balls for the bonus. But they can never roll more than 3 balls in the 10th frame. The additional rolls only count for the bonus not for the regular frame count. - - 10, 10, 10 in the 10th frame gives 30 points (10 points for the regular first strike and 20 points for the bonus). - 1, 9, 10 in the 10th frame gives 20 points (10 points for the regular spare and 10 points for the bonus). - -### Gutter Game - -A Gutter Game is when the player never hits a pin (20 zero scores). - -### Perfect Game - -A Perfect Game is when the player rolls 12 strikes (10 regular strikes and 2 strikes for the bonus in the 10th frame). The Perfect Game scores 300 points. - -In the image below you can find some score examples. - -More about ten pin bowling here: http://en.wikipedia.org/wiki/Ten-pin_bowling ![Ten Pin Score Example](images/example_ten_pin_scoring.png) - -## Code Review - -In code review we'll be hoping to see: - -* All tests passing -* The code is elegant: every class has a clear responsibility, methods are short etc. - -Reviewers will potentially be using this [code review rubric](docs/review.md). Note that referring to this rubric in advance may make the challenge somewhat easier. You should be the judge of how much challenge you want. diff --git a/docs/review.md b/docs/review.md deleted file mode 100644 index 967eacfec4..0000000000 --- a/docs/review.md +++ /dev/null @@ -1,235 +0,0 @@ -# Introduction - -Welcome to the code review for the Bowling Challenge! Again, don't worry - you are not expected to have all the answers. The following is a code-review scaffold for Bowling Challenge that you can follow if you want to. These are common issues to look out for in this challenge - but you may decide to take your own route. - -# Step 0: Checkout and Run tests - -Please checkout your reviewee's code and run their tests. Read the code and try and use the app through the web interface (if they have made one). You can also experiment with the engine in the console. How easy is it to understand the structure of their code? How readable is their code? Did you need to make any cognitive leaps to 'get it'? Is it more complicated than it needs to be? - -# Step 1: How far did they get? - -* Features - * [ ] Gutter game - * [ ] One frame - * [ ] Multiple frames - * [ ] Spares - * [ ] Strikes - * [ ] Final Frame - -* Bonus Features - * [ ] UI - -The relevance of the subsequent steps may depend on how far the reviewee got with their challenge. - -# Step 2: Structure and supporting files - -## Installation/Usage Instructions in README - -As we have seen previously, the README is a great place to show the full story of how your app is used (from a user's perspective). Include instructions for how to download and run the tests, e.g.: - -```sh -$ git clone git@github.com:[USERNAME]/bowling-challenge.git -$ cd bowling-challenge -$ open SpecRunner.html -``` - -If you created a UI maybe include some screenshots? For more info on embedding images in a README: https://guides.github.com/features/mastering-markdown/ - -e.g.: -``` -![Screenshot](https://path_to_your_image) -``` - -You will need to host your images somewhere, e.g.: -* http://imgur.com/ -* http://dropbox.com/ - -## Read Over Your Pull Request Before Submitting - -Watch out for things like having any unnecessary files, e.g. your Bowling.js in both `src/` and `public/` folders. Remove all commented code. Remove all logging statements, e.g. `console.log` - -## Following Style Guidelines - -Hound uses [jshint](http://jshint.com/about/) to point out important style violations. Having your code follow style conventions is essential if you want to pass a tech test in order to get an interview with a company for a job, so look over the hound comments for issues like: - -- Inappropriate semi-colon use -- Deeply nested conditionals -- Consistent indentation - -# Step 3: Tests (\*Spec.js files) - -## Ensure tests are comprehensible and laid out correctly - -Tests should be organized under appropriate `describe` blocks, with descriptive titles and should be DRY. They are unDry if they are repeating themselves in the test in a way that could be extracted). Can you understand exactly how to use the solution solely by reading the tests? - -## Little or no testing of edge cases - -Many solutions rely on a 'virtuous consumer' - i.e. they do not validate inputs or check for out of range values etc. In the bowling challenge this includes checking for odd corner cases such as the gutter game and the perfect game, and odd combinations of strikes and spares. But also defending against non-numeric or meaningless values being passed in to the engine. - -# Step 4: Application code (\*.js files) - -## Not modeling the rules - -One of the commonest problems in the bowling challenge is not understanding and/or modeling the rules! Check that the code correctly handles spares, strikes and - as an added bonus - the final frame! - -## Poor Encapsulation - -Avoid relying on implementation details. It's common to see objects relying on the internals of other objects or their implementation of low-level types (particularly arrays). - -not so good - -```javascript -function Game(){ - this.frames = []; -} - -game = new Game(); -game.frames.push(new Frame()); -``` - -better - -```javascript -function Game(){ - this._frames = []; -} - -Games.prototype.addFrame = function(frame){ - this._frames.push(frame); -} - -game = new Game(); -game.addFrame(new Frame()); -``` - -## Poor function naming - -Function names should ideally start with a verb so it's clear that they _do something_ to something else. - -For example, a function that calculates the score should be named `calculateScore`. A function named `score` should probably only return a score that was already calculated. - -In all cases we should try to ensure that each function has a single responsibility that is clearly indicated by it's name. - -## Single Responsibility Principle and other SOLID issues - -Ensure your objects are [solid](https://github.com/makersacademy/course/blob/main/pills/code_reviews.md#oop---are-your-objects-solid)? - -For example, have you separated responsibilities of... - * knowing whether a frame is a strike / spare - * keeping track of the progress of a game - * calculating bonuses - -In particular you should avoid having a single monolithic object that does everything. - -## Unnecessary use of Exceptions - -Throw exceptions for exceptional behaviour, not for normal activity. E.g. - -```javascript -if(this.noFramesLeft()) { throw Error(this.GAMEOVER_ERROR); } -``` - -A game ending is a normal event, rather than an exceptional one. - -## Avoid long functions - -```javascript -Game.prototype.strikeBonus = function(index) { - var bonus = 0; - var frames = this.frames; - if (frames[index+1].outcome === 'X') { - if (frames[index+2].outcome === 'X') { - bonus = 20; - } else { - bonus = 10 + frames[index+2].firstBowl; - }; - } else { - bonus = frames[index+1].total; - }; - return bonus; -}; -``` - -A function like the above can be refactored like so: - -```javascript -Game.prototype.strikeBonus = function(index) { - var bonus = this.frames[index+1].total; - var frames = this.frames; - if (this.isAStrike(index+1)) { - bonus = isAStrike(index+2) ? 20 : 10 + this.frames[index+2].firstBowl; - } - return bonus; -} - -Game.prototype.isAStrike(index){ - return this.frames[index+1].outcome === 'X'; -} -``` - -Of course this would all be much easier to separate out if we were using a separate Frame object. - -## DRY things out - -```javascript -BowlingGame.prototype.currentMove = function(pins) { - if ( this.isFirstRoll() ) { - if ( this.isStrike() ) { - this.strikeScoring(pins); - } else if ( this.isSpare() ) { - this.spareScoring(pins); - } else { - this.incrementRoll(); - this.addToScore(pins); - } - } - else { - if ( this.isStrike() ) { - this.strikeScoring(pins); - } else if ( this.isSpare() ) { - this.spareScoring(pins); - } else { - this.addToScore(pins); - this.resetFrame(pins); - } - }; -}; -``` - -The above code has a lot of replication across the two branches of the if/else statement. We could refactor like so, pulling the outer if/else statement into the final element of the internal if/else statement. - -```javascript -BowlingGame.prototype.currentMove = function(pins) { - if ( this.isStrike() ) { - this.strikeScoring(pins); - } else if ( this.isSpare() ) { - this.spareScoring(pins); - } else { - this.addToScore(pins); - if ( this.isFirstRoll() ) { - this.incrementRoll(); - } else { - this.resetFrame(pins); - } - } -}; -``` - -## Monkey Patch carefully - -If you are adding new function to existing JavaScript objects then do check you are not overwriting an existing function. - -```javascript -if (!Array.prototype.last){ - Array.prototype.last = function(){ - return this[this.length - 1]; - }; -}; -``` - -## Example Solutions - -* [Leo](https://github.com/pitchinvasion/bowling) -* [Ben](https://github.com/silvabox/bowling_js) -* [Spike](https://github.com/spike01/bowlingJS) -* [Henry](https://github.com/henrygarner/BowlingNode) diff --git a/frame.js b/lib/frame.js similarity index 100% rename from frame.js rename to lib/frame.js diff --git a/scorecard2.js b/lib/scorecard2.js similarity index 96% rename from scorecard2.js rename to lib/scorecard2.js index c681050ca2..21e427eebf 100644 --- a/scorecard2.js +++ b/lib/scorecard2.js @@ -1,6 +1,7 @@ -const TenthFrameSpecial = require('./tenthframe'); -const Frame = require('./frame'); - +// const TenthFrameSpecial = require('./tenthframe'); +// const Frame = require('./frame'); +const TenthFrameSpecial = require('../lib/tenthframe'); +const Frame = require('../lib/frame'); /* 10 Pin Scoring Rules: diff --git a/tenthframe.js b/lib/tenthframe.js similarity index 100% rename from tenthframe.js rename to lib/tenthframe.js diff --git a/old/scorecard.js b/old/scorecard.js deleted file mode 100644 index 0c218c208c..0000000000 --- a/old/scorecard.js +++ /dev/null @@ -1,164 +0,0 @@ -/* -10 Pin Scoring Rules: - -Every frame is 1-2 rolls - Open Frame(a, b) -> Less than 10 pins -> (a + b); - Spare(a, b = 10) -> 10 pins over 2 rolls -> (10) + (a); - Strike(a=10) -> 10 pins over 1 roll -> (10) + (a + b) or (10) + (10) + (b); - - For the 10th frame, if the player rolls a strike or spare, they can roll again for the bonus -*/ - -class ScoreCard { - constructor(){ - this.frames = [] //empty list of frames - }; - // ADDING FRAMES - /** - * adds a single frame - * @param {number} a // first roll -- 0-10 - * @param {number} b // second roll -- 0-10; b <= 10-a - */ - addFrame(a,b) { - this.frames.push([a,b]); - }; - /** - * adds a special 10th frame with up to 3 rolls if the player scores a strike or spare in the 2-roll frame. - * @param {number} a - * @param {number} b - * @param {number} c - */ - add10thFrame(a, b, c) { - this.frames.push([a, b, c]); - }; - - // FINDING FRAME TYPE: - // takes single frames from self.frames. - isStrike(frame){ - return frame[0] === 10; - }; - isSpare(frame){ - return frame[0] + frame[1] === 10; - }; - - // GETTING FRAME SCORE NO BONUS - getFrameScoreNoBonus(frame){ - let sum = 0; - frame.forEach((roll) => { - sum += roll; - }); - return sum; - } - - // GETTING THE SPARE BONUS: - getSpareBonus(frame){ - let bonus = 0; - // find the index of the current frame - const frameNum = this.frames.indexOf(frame); - // find the next frame - const nextFrame = this.frames[frameNum + 1]; - // find the first roll of the next frame - bonus = nextFrame[0]; - return bonus; - } - - // GETTING THE STRIKE BONUS: - getStrikeBonus(frame){ - let bonus = 0; - // find the index of the current frame - const frameNum = this.frames.indexOf(frame); - // find the next frame - const nextFrame = this.frames[frameNum + 1]; - - // if next frame is also a Strike: - if (this.isStrike(nextFrame)) { - // find the next next frame's first roll. - const nextNextFrame = this.frames[frameNum + 2]; - bonus = nextFrame[0] + nextNextFrame[0]; - } else { - // find both rolls of the next frame. - bonus = nextFrame[0] + nextFrame[1]; - } - return bonus; - } - - // GETTING FRAME TOTAL: - getFrameTotal(frame){ - let score = 0; - const frameNum = this.frames.indexOf(frame); - - if (this.isStrike(frame) && frameNum != 10) { - // STRIKE & NOT LAST FRAME - console.log(`Frame ${frameNum}: Strike!`) - - try { - // Get the next two rolls - score += this.getStrikeBonus(frame); - - } catch (error) { - // catch range error for when the game is still ongoing - if (error instanceof RangeError) { - // no bonus added if next 2 rolls haven't happened yet. - } else { - console.error('An error occured:', error.message); - } - } - - } else if (this.isSpare(frame) && frameNum != 10) { - // SPARE & NOT LAST FRAME - console.log(`Frame ${frameNum}: Spare!`) - try { - // Get the next roll - score += this.getSpareBonus(frame); - - } catch (error) { - // catch range error for when the game is still ongoing - if (error instanceof RangeError) { - // no bonus added if next 1 roll hasn't happened yet. - } else { - console.error('An error occured:', error.message); - } - } - - } else { - if (this.isStrike(frame)){ - // 10th FRAME STRIKE - console.log(`Frame ${frameNum}: Strike!`) - } else if (this.isSpare(frame)){ - // 10th FRAME SPARE - console.log(`Frame ${frameNum}: Spare!`) - } else { - // OPEN FRAME - console.log(`Frame ${frameNum}: Open Frame!`) - } - }; - - score += this.getFrameScoreNoBonus(frame); - return score; - }; - - // Get the total score for the game - getTotalGameScore() { - let score = 0; - // for frame in frames: - this.frames.forEach((frame) => { - score += this.getFrameTotal(frame) - }); - return score; - }; - - // Get the total score at a certain frame for the game after the bonus rolls have occured. - getTotalGameScoreAtFrame(frameNumber){ - const frameIndex = frameNumber - 1 - let score = 0; - // for frame in frames up to frameIndex: - for (let i = 0; i <= frameIndex; i++ ){ - const currentFrame = this.frames[i]; - score += this.getFrameTotal(currentFrame); - } - return score; - } - -}; - -module.exports = ScoreCard; \ No newline at end of file diff --git a/old/scorecard.test.js b/old/scorecard.test.js deleted file mode 100644 index 20646ce8c5..0000000000 --- a/old/scorecard.test.js +++ /dev/null @@ -1,344 +0,0 @@ -const ScoreCard = require('./scorecard'); - - -describe('Scorecard - example score', () => { - // arrange - const scorecard = new ScoreCard(); - - test('Frame 1: [1, 4]; FrameScore: 5; TotalScore: 5', () => { - scorecard.addFrame(1, 4); //Open - expect(scorecard.frames).toEqual([ - [1, 4] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[0])).toBe(5); - expect(scorecard.getTotalGameScoreAtFrame(1)).toBe(5); - expect(scorecard.getTotalGameScore()).toBe(5); - }); - - test('Frame 2: [4, 5]; FrameScore: 9; TotalScore: 14', () => { - scorecard.addFrame(4, 5); //Open - expect(scorecard.frames).toEqual([ - [1, 4], - [4, 5] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[1])).toBe(9); - expect(scorecard.getTotalGameScoreAtFrame(2)).toBe(14); - expect(scorecard.getTotalGameScore()).toBe(14); - }); - - test('Frame 3: [6, 4] SPARE; FrameScore at F3: 10*; TotalScore at F3: 24*', () => { - scorecard.addFrame(6, 4); //Spare F3 - expect(scorecard.frames).toEqual([ - [1, 4], - [4, 5], - [6, 4] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[2])).toBe(10); - expect(scorecard.getTotalGameScoreAtFrame(3)).toBe(24); - expect(scorecard.getTotalGameScore()).toBe(24); - }); - - test('Frame 4: [5, 5] F3 SPARE BONUS => FrameScore at F3: 15; TotalScore at F3: 29', () => { - scorecard.addFrame(5, 5); //Spare F4 - // update the frame score for frame 3 to be 15 - expect(scorecard.getFrameTotal(scorecard.frames[2])).toBe(15); - // update the total score for frame 3 to be 29 - expect(scorecard.getTotalGameScoreAtFrame(3)).toBe(29); - }); - - test('Frame 4: [5, 5] SPARE; FrameScore at F4: 10*; TotalScore at F4: 39*', () => { - expect(scorecard.frames).toEqual([ - [1, 4], - [4, 5], - [6, 4], - [5, 5] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[3])).toBe(10); - expect(scorecard.getTotalGameScoreAtFrame(4)).toBe(39); - expect(scorecard.getTotalGameScore()).toBe(39); - }); - - - test('Frame 5: [10, 0] F4 SPARE BONUS => FrameScore at F4: 20; TotalScore at F4: 49', () => { - scorecard.addFrame(10, 0); //Strike F5 --- SHOULD I ADD NONE INSTEAD? - // update the frame score for frame 4 to be 15 - expect(scorecard.getFrameTotal(scorecard.frames[3])).toBe(20); - // update the total score for frame 4 to be 29 - expect(scorecard.getTotalGameScoreAtFrame(4)).toBe(49); - }); - - test('Frame 5: [10, 0] STRIKE; FrameScore at F5: 10*; TotalScore at F5: 59*', () => { - expect(scorecard.frames).toEqual([ - [1, 4], - [4, 5], - [6, 4], - [5, 5], - [10, 0] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[4])).toBe(10); - expect(scorecard.getTotalGameScoreAtFrame(5)).toBe(59); - expect(scorecard.getTotalGameScore()).toBe(59); - }); - - test('Frame 6: [0, 1] F5 STRIKE BONUS => FrameScore at F5: 11; TotalScore at F5: 60', () => { - scorecard.addFrame(0, 1); //Open F6 - // update the frame score for frame 5 to be 11 - expect(scorecard.getFrameTotal(scorecard.frames[4])).toBe(11); - // update the total score for frame 5 to be 60 - expect(scorecard.getTotalGameScoreAtFrame(5)).toBe(60); - }); - - test('Frame 6: [0, 1]; FrameScore at F6: 1; TotalScore at F6: 61', () => { - expect(scorecard.frames).toEqual([ - [1, 4], - [4, 5], - [6, 4], - [5, 5], - [10, 0], - [0, 1] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[5])).toBe(1); - expect(scorecard.getTotalGameScoreAtFrame(6)).toBe(61); - expect(scorecard.getTotalGameScore()).toBe(61); - }); - - test('Frame 7: [7, 3] SPARE; FrameScore at F7: 10*; TotalScore at F7: 71*', () => { - scorecard.addFrame(7, 3); //Spare F7 - expect(scorecard.frames).toEqual([ - [1, 4], - [4, 5], - [6, 4], - [5, 5], - [10, 0], - [0, 1], - [7, 3] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[6])).toBe(10); - expect(scorecard.getTotalGameScoreAtFrame(7)).toBe(71); - expect(scorecard.getTotalGameScore()).toBe(71); - }); - - test('Frame 8: [6,4] F7 SPARE BONUS => FrameScore at F7: 16; Total Score at F7: 77', ()=>{ - scorecard.addFrame(6, 4); //Spare F8 - expect(scorecard.getFrameTotal(scorecard.frames[6])).toBe(16); - expect(scorecard.getTotalGameScoreAtFrame(7)).toBe(77); - }); - - test('Frame 8: [6,4] SPARE: FrameScore at F8: 10*; Total Score at F8: 87*', ()=>{ - expect(scorecard.frames).toEqual([ - [1, 4], - [4, 5], - [6, 4], - [5, 5], - [10, 0], - [0, 1], - [7, 3], - [6, 4] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[7])).toBe(10); - expect(scorecard.getTotalGameScoreAtFrame(8)).toBe(87); - expect(scorecard.getTotalGameScore()).toBe(87); - }); - - test('Frame 9: [10, 0] F8 SPARE BONUS => Framescore at F8: 20; Total Score at F8: 97', () =>{ - scorecard.addFrame(10, 0); //Strike F9 - expect(scorecard.getFrameTotal(scorecard.frames[7])).toBe(20); - expect(scorecard.getTotalGameScoreAtFrame(8)).toBe(97); - }); - - test('Frame 9: [10, 0] STRIKE => Framescore at F9: 10*; Total Score at F9: 107*', () =>{ - expect(scorecard.frames).toEqual([ - [1, 4], - [4, 5], - [6, 4], - [5, 5], - [10, 0], - [0, 1], - [7, 3], - [6, 4], - [10, 0] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(10); - expect(scorecard.getTotalGameScoreAtFrame(9)).toBe(107); - }); - - test('Frame 10: [2, 8, 6] F9 STRIKE BONUS => Framescore at F9: 20; Total Score at F9: 117', () =>{ - scorecard.add10thFrame(2, 8, 6); //10th Frame Spare + 6 on 3rd roll - expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(20); - expect(scorecard.getTotalGameScoreAtFrame(9)).toBe(117); - }) - - - test('Frame 10: [2, 8, 6] SPARE + 10th FRAME BONUS => Framescore at F10: 16; Total Score at F10: 133', () =>{ - expect(scorecard.frames).toEqual([ - [1, 4], - [4, 5], - [6, 4], - [5, 5], - [10, 0], - [0, 1], - [7, 3], - [6, 4], - [10, 0], - [2, 8, 6] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[9])).toBe(16); - expect(scorecard.getTotalGameScoreAtFrame(10)).toBe(133); - }); -}) - - -describe('Scorecard - Gutter Game', () => { - // arrange - const scorecard = new ScoreCard(); - - test('Frame 1: [0,0]: FrameScore at F1: 0; TotalScore at F1: 0;', () =>{ - scorecard.addFrame(0,0); //Open - expect(scorecard.frames).toEqual([ - [0, 0] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[0])).toBe(0); - expect(scorecard.getTotalGameScoreAtFrame(1)).toBe(0); - expect(scorecard.getTotalGameScore()).toBe(0); - }); - test('Frame 2: [0,0]: FrameScore at F2: 0; TotalScore at F2: 0;', () =>{ - scorecard.addFrame(0,0); //Open - expect(scorecard.frames).toEqual([ - [0, 0], - [0, 0] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[1])).toBe(0); - expect(scorecard.getTotalGameScoreAtFrame(2)).toBe(0); - expect(scorecard.getTotalGameScore()).toBe(0); - }); - test('Frame 3: [0,0]: FrameScore at 3: 0; TotalScore at F3: 0;', () =>{ - scorecard.addFrame(0,0); //Open - expect(scorecard.frames).toEqual([ - [0, 0], - [0, 0], - [0, 0] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[2])).toBe(0); - expect(scorecard.getTotalGameScoreAtFrame(3)).toBe(0); - expect(scorecard.getTotalGameScore()).toBe(0); - }); - test('Frame 4-9: [0,0]: FrameScore at F9: 0; TotalScore at F9: 0;', () =>{ - scorecard.addFrame(0,0); //Open F4 - scorecard.addFrame(0,0); //Open F5 - scorecard.addFrame(0,0); //Open F6 - scorecard.addFrame(0,0); //Open F7 - scorecard.addFrame(0,0); //Open F8 - scorecard.addFrame(0,0); //Open F9 - - expect(scorecard.frames).toEqual([ - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [0, 0] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(0); - expect(scorecard.getTotalGameScoreAtFrame(9)).toBe(0); - expect(scorecard.getTotalGameScore()).toBe(0); - }); - test('Frame 10: [0,0]: FrameScore at 10: 0; TotalScore at 10: 0;', () =>{ - scorecard.addFrame(0,0); //Open F10 - - expect(scorecard.frames).toEqual([ - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [0, 0], - [0, 0] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[9])).toBe(0); - expect(scorecard.getTotalGameScoreAtFrame(10)).toBe(0); - expect(scorecard.getTotalGameScore()).toBe(0); - }); - -}); - -describe('Scorecard - Perfect Game', () => { - // arrange - const scorecard = new ScoreCard(); - - test('Frame 1: [10,0]: FrameScore at F1: 10; TotalScore at F1: 10;', () =>{ - scorecard.addFrame(10,0); //Strike F1 - expect(scorecard.frames).toEqual([ - [10, 0] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[0])).toBe(10); - expect(scorecard.getTotalGameScoreAtFrame(1)).toBe(10); - expect(scorecard.getTotalGameScore()).toBe(10); - }); - test('Frame 2-9: [10,0]: FS7: 30, FS8: 20; FS9: 10; TotalScore at F9: 230;', () =>{ - scorecard.addFrame(10,0); //Strike F2 - scorecard.addFrame(10,0); //Strike F3 - scorecard.addFrame(10,0); //Strike F4 - scorecard.addFrame(10,0); //Strike F5 - scorecard.addFrame(10,0); //Strike F6 - scorecard.addFrame(10,0); //Strike F7 - scorecard.addFrame(10,0); //Strike F8 - scorecard.addFrame(10,0); //Strike F9 - - expect(scorecard.frames).toEqual([ - [10, 0], - [10, 0], - [10, 0], - [10, 0], - [10, 0], - [10, 0], - [10, 0], - [10, 0], - [10, 0] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[0])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[1])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[2])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[3])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[4])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[5])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[6])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[7])).toBe(20); //only one roll ahead to count bonus // ERROR, getting 10 instead of 30 - expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(10); //no rolls ahead to count bonus - expect(scorecard.getTotalGameScoreAtFrame(9)).toBe(230); - expect(scorecard.getTotalGameScore()).toBe(230); - }); - test('Frame 10: [10, 10, 10]: FS7: 30, FS8: 30; FS9: 30; TotalScore at F10: 300;', () =>{ - scorecard.add10thFrame(10, 10, 10); //Strike F10 - - expect(scorecard.frames).toEqual([ - [10, 0], - [10, 0], - [10, 0], - [10, 0], - [10, 0], - [10, 0], - [10, 0], - [10, 0], - [10, 0], - [10, 10, 10] - ]); - expect(scorecard.getFrameTotal(scorecard.frames[0])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[1])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[2])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[3])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[4])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[5])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[6])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[7])).toBe(30); - expect(scorecard.getFrameTotal(scorecard.frames[8])).toBe(30); // ERROR, getting 10 instead of 30 - expect(scorecard.getFrameTotal(scorecard.frames[9])).toBe(30); - expect(scorecard.getTotalGameScoreAtFrame(10)).toBe(300); - expect(scorecard.getTotalGameScore()).toBe(300); - }); -}); diff --git a/frame.test.js b/specs/frame.test.js similarity index 99% rename from frame.test.js rename to specs/frame.test.js index ee34149bc1..5d5e88c405 100644 --- a/frame.test.js +++ b/specs/frame.test.js @@ -1,4 +1,4 @@ -const Frame = require('./frame'); +const Frame = require('../lib/frame'); /// =========== FOR FRAME ================ ///////// diff --git a/scorecard2.test.js b/specs/scorecard2.test.js similarity index 99% rename from scorecard2.test.js rename to specs/scorecard2.test.js index 85562b2d9b..b8ae1e8918 100644 --- a/scorecard2.test.js +++ b/specs/scorecard2.test.js @@ -1,6 +1,6 @@ -const TenthFrameSpecial = require('./tenthframe'); -const Frame = require('./frame'); -const ScoreCard = require('./scorecard2'); +const TenthFrameSpecial = require('../lib/tenthframe'); +const Frame = require('../lib/frame'); +const ScoreCard = require('../lib/scorecard2'); // INTEGRATION TESTS: describe('Scorecard - Gutter Game', () => { diff --git a/tenthframe.test.js b/specs/tenthframe.test.js similarity index 97% rename from tenthframe.test.js rename to specs/tenthframe.test.js index c239867579..5d9bb03b31 100644 --- a/tenthframe.test.js +++ b/specs/tenthframe.test.js @@ -1,4 +1,5 @@ -const TenthFrameSpecial = require('./tenthframe'); +const TenthFrameSpecial = require('../lib/tenthframe'); + /// =========== FOR 10th FRAME ================ /////////