From 05eac2eb05b96d26345d42c7544fb7606079f8d7 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Tue, 30 May 2023 14:54:35 -0400 Subject: [PATCH 01/36] Yup, a simpler ui --- .eslintrc.js | 26 - .eslintrc.json | 27 + package-lock.json | 1331 ++++++++++++++++++++++++++++ package.json | 3 +- public/components/card.js | 2 + public/components/drawer.js | 53 ++ public/components/grid.js | 3 + public/components/listButton.js | 5 +- public/components/mobber.js | 22 +- public/components/reorderable.js | 36 +- public/components/section.js | 4 +- public/sections/addParticipant.js | 4 +- public/sections/header.js | 4 + public/sections/mobActions.js | 13 +- public/sections/mobParticipants.js | 46 +- public/sections/timeRemaining.js | 86 +- public/sections/timerSettings.js | 136 +++ public/tabs/goals.js | 19 +- public/tabs/mob.js | 21 +- public/timer.html | 2 +- public/timer.js | 81 +- public/vendor/hyperapp.js | 5 +- tailwind.config.cjs | 1 - 23 files changed, 1768 insertions(+), 162 deletions(-) delete mode 100644 .eslintrc.js create mode 100644 .eslintrc.json create mode 100644 public/components/drawer.js create mode 100644 public/components/grid.js create mode 100644 public/sections/timerSettings.js diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index f46e70c..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,26 +0,0 @@ -export default { - root: true, - env: { - browser: true, - es6: true, - node: true, - }, - extends: ['eslint:recommended', 'prettier'], - plugins: ['import'], - globals: { - Atomics: 'readonly', - SharedArrayBuffer: 'readonly', - }, - parserOptions: { - ecmaVersion: 2018, - sourceType: 'module', - }, - rules: { - 'import/prefer-default-export': ['off'], - 'import/no-absolute-path': ['off'], - 'import/extensions': ['off'], - 'no-restricted-syntax': ['off'], - 'no-continue': ['off'], - 'quote-props': ['warn', 'consistent-as-needed'], - }, -}; diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..6ca918d --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,27 @@ +{ + "root": true, + "env": { + "browser": true, + "es6": true, + "node": true + }, + "extends": ["eslint:recommended", "prettier"], + "plugins": ["import"], + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module", + "requireConfigFile": false + }, + "rules": { + "import/prefer-default-export": ["off"], + "import/no-absolute-path": ["off"], + "import/extensions": ["off"], + "no-restricted-syntax": ["off"], + "no-continue": ["off"], + "quote-props": ["warn", "consistent-as-needed"] + }, +}; diff --git a/package-lock.json b/package-lock.json index 37b7e3e..df882b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ }, "devDependencies": { "ava": "^4.3.3", + "eslint": "^8.34.0", "husky": "^7.0.0", "nodemon": "^2.0.15", "nyc": "^15.1.0", @@ -397,6 +398,107 @@ "node": ">=6.9.0" } }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -624,6 +726,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/acorn-node": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", @@ -678,6 +789,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -1440,6 +1567,12 @@ "node": ">=0.10.0" } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/default-require-extensions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", @@ -1615,6 +1748,18 @@ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/dotenv": { "version": "15.0.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-15.0.1.tgz", @@ -1698,6 +1843,355 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/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==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1711,6 +2205,39 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz", + "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -1819,6 +2346,12 @@ "node": ">= 0.8" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, "node_modules/fast-diff": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", @@ -1840,6 +2373,18 @@ "node": ">=8.6.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==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -1869,6 +2414,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1940,6 +2497,25 @@ "node": ">=8" } }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, "node_modules/foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -2138,6 +2714,12 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2258,6 +2840,31 @@ "node": ">=10 <11 || >=12 <13 || >=14" } }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2629,6 +3236,16 @@ "node": ">=8" } }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -2669,6 +3286,18 @@ "node": ">=4" } }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -2687,6 +3316,19 @@ "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", "dev": true }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lilconfig": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", @@ -2737,6 +3379,12 @@ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "dev": true }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -2944,6 +3592,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -3357,6 +4011,23 @@ "wrappy": "1" } }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -3459,6 +4130,27 @@ "node": ">=8" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module/node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", @@ -3779,6 +4471,15 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/pretty-ms": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", @@ -3824,6 +4525,15 @@ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -3922,6 +4632,18 @@ "@redis/time-series": "1.0.4" } }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -4412,6 +5134,18 @@ "node": ">=8" } }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/supertap": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/supertap/-/supertap-3.0.1.tgz", @@ -4524,6 +5258,12 @@ "node": ">=8" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "node_modules/time-zone": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", @@ -4573,6 +5313,18 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -4652,6 +5404,15 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4712,6 +5473,15 @@ "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", "dev": true }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -5251,6 +6021,78 @@ "to-fast-properties": "^2.0.0" } }, + "@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -5434,6 +6276,13 @@ "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, "acorn-node": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", @@ -5472,6 +6321,18 @@ "indent-string": "^5.0.0" } }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -6034,6 +6895,12 @@ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "default-require-extensions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", @@ -6156,6 +7023,15 @@ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "dotenv": { "version": "15.0.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-15.0.1.tgz", @@ -6218,12 +7094,275 @@ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true }, + "eslint": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "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==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esquery": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz", + "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -6318,6 +7457,12 @@ } } }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, "fast-diff": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", @@ -6336,6 +7481,18 @@ "micromatch": "^4.0.4" } }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, "fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -6359,6 +7516,15 @@ "is-unicode-supported": "^1.2.0" } }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -6417,6 +7583,22 @@ "path-exists": "^4.0.0" } }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -6548,6 +7730,12 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -6626,6 +7814,24 @@ "integrity": "sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==", "dev": true }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -6901,6 +8107,12 @@ "istanbul-lib-report": "^3.0.0" } }, + "js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true + }, "js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -6929,6 +8141,18 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -6941,6 +8165,16 @@ "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", "dev": true }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, "lilconfig": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", @@ -6979,6 +8213,12 @@ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "dev": true }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -7119,6 +8359,12 @@ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -7450,6 +8696,20 @@ "wrappy": "1" } }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -7516,6 +8776,23 @@ "release-zalgo": "^1.0.0" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + } + } + }, "parse-ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", @@ -7708,6 +8985,12 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, "pretty-ms": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", @@ -7741,6 +9024,12 @@ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + }, "qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -7804,6 +9093,12 @@ "@redis/time-series": "1.0.4" } }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -8158,6 +9453,12 @@ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "supertap": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/supertap/-/supertap-3.0.1.tgz", @@ -8241,6 +9542,12 @@ "minimatch": "^3.0.4" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "time-zone": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", @@ -8275,6 +9582,15 @@ "nopt": "~1.0.10" } }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -8326,6 +9642,15 @@ "picocolors": "^1.0.0" } }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -8368,6 +9693,12 @@ "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", "dev": true }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 9dea648..9965f78 100644 --- a/package.json +++ b/package.json @@ -34,9 +34,10 @@ }, "devDependencies": { "ava": "^4.3.3", + "eslint": "^8.34.0", "husky": "^7.0.0", - "nyc": "^15.1.0", "nodemon": "^2.0.15", + "nyc": "^15.1.0", "sinon": "^12.0.1" }, "ava": { diff --git a/public/components/card.js b/public/components/card.js index e3f8025..1e4aaaf 100644 --- a/public/components/card.js +++ b/public/components/card.js @@ -1,6 +1,8 @@ import { h } from '/vendor/hyperapp.js'; export const card = (props, children) => { + return h('div', {}, children); + return h( 'div', { diff --git a/public/components/drawer.js b/public/components/drawer.js new file mode 100644 index 0000000..c347342 --- /dev/null +++ b/public/components/drawer.js @@ -0,0 +1,53 @@ +import { h, text } from '/vendor/hyperapp.js'; +import { timerSettings } from '/sections/timerSettings.js'; + +export const drawer = (props) => { + return h('aside', { + class: [ + 'absolute', + 'right-0', + 'top-0', + 'h-screen', + 'w-3/4', + 'sm:w-1/2', + 'md:w-1/4', + 'bg-white', + 'dark:bg-gray-700', + 'overflow-y-hidden', + 'shadow-xl', + 'flex', + 'flex-col', + 'justify-start', + 'items-start', + ], + open: true, + }, [ + h('header', { class: 'my-2 px-2 w-full flex justify-between items-start' }, [ + h('h1', { class: 'text-lg' }, text('Timer Configuration')), + + h('button', { innerHTML: '×' }), + ]), + + h('details', { class: 'm-2' }, [ + h('summary', {}, text('Timer Settings')), + h('p', {}, text('These settings live in local storage, and are your personal preferences')), + timerSettings(props), + ]), + h('details', { class: 'm-2' }, [ + h('summary', {}, text('Local Settings')), + h('p', {}, text('These settings live in local storage, and are your personal preferences')), + ]), + h('details', { class: 'm-2' }, [ + h('summary', {}, text('Shareable QR Code')), + h('img', { + src: props.qrImage ? props.qrImage.src : '', + class: { + 'mb-3': true, + }, + }), + h('p', {}, h('small', {}, text(props.lang.share.mobtimePoweredByWebsockets))), + h('p', {}, h('small', {}, text(props.lang.share.mobtimeCollaborate))), + ]), + + ]); +}; diff --git a/public/components/grid.js b/public/components/grid.js new file mode 100644 index 0000000..d9d9294 --- /dev/null +++ b/public/components/grid.js @@ -0,0 +1,3 @@ +import { h } from '/vendor/hyperapp.js'; + +export const grid = (children) => h('div', { class: 'grid px-2 md:px-0 grid-cols-1 md:grid-cols-2 container mx-auto gap-8' }, children); diff --git a/public/components/listButton.js b/public/components/listButton.js index bf6193a..c556bf1 100644 --- a/public/components/listButton.js +++ b/public/components/listButton.js @@ -7,8 +7,9 @@ export const listButton = (props, children) => ...props, class: { 'box-border': true, - 'w-8': true, - 'h-8': true, + 'w-6': true, + 'h-6': true, + 'text-sm': true, 'flex-shrink-0': true, flex: true, 'items-center': true, diff --git a/public/components/mobber.js b/public/components/mobber.js index 2068c5f..ecd0f8a 100644 --- a/public/components/mobber.js +++ b/public/components/mobber.js @@ -11,13 +11,14 @@ export const mobber = props => 'flex-row': true, 'items-center': true, 'justify-between': true, - 'mb-1': true, + //'mb-1': true, 'h-full': true, 'w-full': true, - truncate: props.truncate, - 'bg-indigo-50': props.position !== 'mob', - 'dark:bg-indigo-800': props.position !== 'mob', - 'py-2': true, + 'text-black': props.hasPosition, + 'dark:text-white': props.hasPosition, + // 'bg-indigo-50': props.position !== 'mob', + // 'dark:bg-indigo-800': props.position !== 'mob', + 'py-1': true, 'pl-1': true, }, }, @@ -26,7 +27,7 @@ export const mobber = props => 'div', { class: { - truncate: props.truncate, + truncate: props.selected, }, }, [ @@ -38,6 +39,7 @@ export const mobber = props => 'leading-none': true, 'mb-1': true, 'break-all': true, + 'text-xs': true, }, }, text(props.position), @@ -46,11 +48,13 @@ export const mobber = props => 'div', { class: { - 'text-gray-500': !props.name, - 'font-bold': props.position !== 'mob', + 'text-gray-500': !props.name && !props.hasPosition, + 'dark:text-gray-800': !props.name && !props.hasPosition, + 'font-lg': true, + 'font-bold': props.hasPosition && props.name, 'leading-none': true, 'break-all': true, - truncate: props.truncate, + truncate: props.selected, }, }, text(props.name || 'Empty'), diff --git a/public/components/reorderable.js b/public/components/reorderable.js index 03f30b8..7d90485 100644 --- a/public/components/reorderable.js +++ b/public/components/reorderable.js @@ -73,8 +73,9 @@ const dragContainer = (props, children) => 'div', { class: { - 'hidden': true, - 'sm:flex': true, + 'flex': true, + // 'hidden': true, + // 'sm:flex': true, 'h-full': true, 'flex-col': true, 'items-center': true, @@ -96,7 +97,7 @@ const dragContainer = (props, children) => }, ], }, - Array.from({ length: 3 }, () => + Array.from({ length: 3 }, (_, index) => h('div', { class: { 'border-b': true, @@ -104,8 +105,8 @@ const dragContainer = (props, children) => 'border-b-gray-400': props.disabled, 'dark:border-b-gray-200': !props.disabled, 'dark:border-b-gray-400': props.disabled, - 'my-1': true, - 'w-6': true, + 'mt-1': index > 0, + 'w-1': true, }, }), ), @@ -126,9 +127,7 @@ const dragContainer = (props, children) => { 'class': { 'text-gray-500': !props.onMoveUp, - 'border-2': true, - 'border-white': true, - 'mr-2': true, + 'mr-1': true, }, 'onclick': props.onMoveUp, 'disabled': !props.onMoveUp, @@ -141,9 +140,7 @@ const dragContainer = (props, children) => { 'class': { 'text-gray-500': !props.onMoveDown, - 'border-2': true, - 'border-white': true, - 'mr-2': true, + 'mr-1': true, }, 'onclick': props.onMoveDown, 'disabled': !props.onMoveDown, @@ -156,8 +153,6 @@ const dragContainer = (props, children) => listButton( { class: { - 'border-2': true, - 'border-white': true, 'mr-2': true, }, onclick: props.onEdit, @@ -169,7 +164,7 @@ const dragContainer = (props, children) => deleteButton({ onclick: props.onDelete, class: { - 'mr-2': true, + 'mr-1': true, }, }), ], @@ -182,14 +177,11 @@ const dragContainer = (props, children) => class: { 'text-indigo-600': props.expandActions, 'bg-white': props.expandActions, - 'border-2': true, - 'border-transparent': !props.expandActions, - 'border-white': props.expandActions, - 'mr-2': true, + 'mr-1': true, }, onclick: props.onExpand, }, - [h('i', { class: 'fas fa-ellipsis-h' })], + [h('i', { class: 'fas fa-ellipsis-v' })], ), ...(props.isDragging @@ -222,9 +214,9 @@ const draggingContainer = (props, child) => 'duration-75': true, 'ease-in-out': true, 'pointer-events-none': true, - 'border': true, - 'border-green-600': true, - 'rounded': true, + //'border': true, + //'border-green-600': true, + //'rounded': true, }, }, child, diff --git a/public/components/section.js b/public/components/section.js index eb67148..00ed142 100644 --- a/public/components/section.js +++ b/public/components/section.js @@ -1,8 +1,8 @@ import { h } from '/vendor/hyperapp.js'; export const classes = { - 'pt-5': true, - 'px-4': true, + 'mt-5': true, + // 'mx-4': true, }; export const section = (props, children) => diff --git a/public/sections/addParticipant.js b/public/sections/addParticipant.js index d2cc377..72c580a 100644 --- a/public/sections/addParticipant.js +++ b/public/sections/addParticipant.js @@ -53,8 +53,8 @@ export const addParticipant = props => { type: 'submit', class: { - 'bg-green-600': true, - 'text-white': true, + //'bg-green-600': true, + 'dark:text-white': true, 'flex-shrink': true, 'whitespace-no-wrap': true, }, diff --git a/public/sections/header.js b/public/sections/header.js index ad8427b..62b32d7 100644 --- a/public/sections/header.js +++ b/public/sections/header.js @@ -10,6 +10,10 @@ export const header = state => 'flex-row': true, 'items-center': true, 'justify-start': true, + 'w-full': true, + 'md:col-span-2': true, + 'text-black': true, + 'dark:text-white': true, }, }, [ diff --git a/public/sections/mobActions.js b/public/sections/mobActions.js index ae9d9ca..e5e195b 100644 --- a/public/sections/mobActions.js +++ b/public/sections/mobActions.js @@ -19,9 +19,10 @@ export const mobActions = props => button( { class: { - 'bg-green-600': true, - 'text-white': true, - 'flex-grow': true, + // 'border': true, + // 'border-green-600': true, + 'dark:text-white': true, + // 'flex-grow': true, 'mr-1': true, }, onclick: actions.CycleMob, @@ -35,9 +36,9 @@ export const mobActions = props => button( { class: { - 'bg-green-600': true, - 'text-white': true, - 'flex-grow': true, + //'bg-green-600': true, + 'dark:text-white': true, + // 'flex-grow': true, 'ml-1': true, }, onclick: actions.ShuffleMob, diff --git a/public/sections/mobParticipants.js b/public/sections/mobParticipants.js index 1a5073e..34e3b3b 100644 --- a/public/sections/mobParticipants.js +++ b/public/sections/mobParticipants.js @@ -20,29 +20,29 @@ export const mobParticipants = props => { ...(props.mob[index] || {}), disabled: index >= props.mob.length, position: mobOrder[index] || props.lang.mob.fallback, + hasPosition: !!mobOrder[index], })); - return section({}, [ - h( - 'div', - {}, - reorderable({ - dragType: 'mob', - expandedReorderable: props.expandedReorderable, - items, - disabled: props.mob.length === 0, - renderItem: item => - mobber({ - ...item, - truncate: getReorderableId(item) === props.expandedReorderable, - }), - drag: props.drag, - disabled: props.overview, - getReorderableId, - onMove: props.overview ? undefined : actions.MoveMob, - onEdit: props.overview ? undefined : actions.RenameUserPrompt, - onDelete: props.overview ? undefined : actions.RemoveFromMob, - }), - ), - ]); + return h( + 'div', + {}, + reorderable({ + dragType: 'mob', + expandedReorderable: props.expandedReorderable, + items, + disabled: props.mob.length === 0, + renderItem: item => + mobber({ + ...item, + truncate: getReorderableId(item) === props.expandedReorderable, + selected: getReorderableId(item) === props.expandedReorderable, + }), + drag: props.drag, + disabled: props.overview, + getReorderableId, + onMove: props.overview ? undefined : actions.MoveMob, + onEdit: props.overview ? undefined : actions.RenameUserPrompt, + onDelete: props.overview ? undefined : actions.RemoveFromMob, + }), + ); }; diff --git a/public/sections/timeRemaining.js b/public/sections/timeRemaining.js index c5eae68..d4b5801 100644 --- a/public/sections/timeRemaining.js +++ b/public/sections/timeRemaining.js @@ -13,30 +13,72 @@ export const timeRemaining = props => { const isPaused = props.timerStartedAt === null; const remainingTime = calculateTimeRemaining(props); - return section({}, [ - h( - 'h2', - { - class: { - 'text-sm': true, - 'font-bold': true, - 'uppercase': true, - }, - }, - text(props.lang.timeRemaining.remainingTime), - ), + const elapsed = props.timerStartedAt + ? props.currentTime - props.timerStartedAt + : 0; + const percent = elapsed > 0 && props.timerDuration > 0 + ? (elapsed / props.timerDuration) * 4 + : 0; + const pulse = (Math.floor(elapsed / 1000) % 2) === 0; + + if (elapsed > 0) { + console.log({ elapsed, percent, duration: props.timerDuration, pulse }); + } + + // border-t-slate-500 + // border-r-slate-500 + // border-b-slate-500 + // border-l-slate-500 + + return section({ + class: { 'md:col-span-2': true }, + }, [ h( 'div', { class: { 'flex': true, - 'flex-row': true, + 'flex-col': true, 'items-center': true, - 'justify-between': true, + 'justify-center': true, + 'outline': true, + 'outline-indigo-400': true, + 'border-t-4': percent > 0, + 'border-t-transparent': percent > 0 && pulse, + 'border-t-blue-300': percent > 0 && !pulse, + 'border-r-4': percent > 1, + 'border-r-transparent': percent > 0 && pulse, + 'border-r-blue-300': percent > 0 && !pulse, + 'border-b-4': percent > 2, + 'border-b-transparent': percent > 0 && pulse, + 'border-b-blue-300': percent > 0 && !pulse, + 'border-l-4': percent > 3, + 'border-l-transparent': percent > 0 && pulse, + 'border-l-blue-300': percent > 0 && !pulse, + 'w-52': true, + 'h-52': true, + 'rounded-full': true, + 'mx-auto': true, + 'mb-8': true, + 'transition-all': true, + 'duration-1000': true, + 'ease-in-out': true, }, }, [ + h( + 'h2', + { + class: { + 'text-sm': true, + 'font-bold': true, + 'uppercase': true, + }, + }, + text(props.lang.timeRemaining.remainingTime), + ), + h( 'h3', { @@ -76,6 +118,22 @@ export const timeRemaining = props => { }), ], ), + ], + ), + + h( + 'div', + { + class: { + 'flex': true, + 'flex-col': true, + 'items-center': true, + 'justify-center': true, + }, + }, + [ + + // !props.timerDuration && button( diff --git a/public/sections/timerSettings.js b/public/sections/timerSettings.js new file mode 100644 index 0000000..1feb508 --- /dev/null +++ b/public/sections/timerSettings.js @@ -0,0 +1,136 @@ +import * as actions from '/actions.js'; +import { button } from '/components/button.js'; +import { overviewHeading } from '/components/overviewHeading.js'; +import { section } from '/components/section.js'; +import { input } from '/components/input.js'; +import { h, text } from '/vendor/hyperapp.js'; + +const isNumber = value => Number(value) == value; // eslint-disable-line eqeqeq + +const toMinutes = value => { + if (value === '') return value; + return isNumber(value) ? parseInt(value / 60000, 10) : value; +}; + +const toSeconds = value => { + if (value === '') return value; + return isNumber(value) ? value * 60000 : value; +}; + +const value = (key, { pendingSettings, settings }) => + key in pendingSettings ? pendingSettings[key] : settings[key]; + +export const timerSettings = props => + h('div', {}, [ + overviewHeading( + { + rightAction: + Object.keys(props.pendingSettings).length === 0 + ? h('div', {}, [ + text(props.lang.settings.saved), + h('i', { class: 'fas fa-check text-green-500' }), + ]) + : h('div', {}, [ + button( + { + class: { + 'bg-indigo-500': true, + 'hover:bg-indigo-400': true, + 'text-white': true, + 'mr-1': true, + }, + onclick: actions.PendingSettingsReset, + }, + text(props.lang.settings.cancel), + ), + button( + { + type: 'button', + class: { + 'bg-green-600': true, + 'hover:bg-green-500': true, + 'text-white': true, + }, + disable: Object.keys(props.pendingSettings).length === 0, + onclick: actions.UpdateSettings, + }, + text(props.lang.settings.save), + ), + ]), + }, + text(props.lang.settings.sharedTimerSettings), + ), + + section( + { + class: { + 'grid': true, + 'grid-cols-2': true, + 'gap-2': true, + }, + }, + [ + h('div', {}, text(props.lang.settings.turnDurationInMinutes)), + input({ + name: 'setLength', + maxlength: 2, + pattern: '[1-9]{0,2}', + value: toMinutes(value('duration', props)), + oninput: (_, e) => { + e.preventDefault(); + return [ + actions.PendingSettingsSet, + { + key: 'duration', + value: toSeconds(e.target.value), + }, + ]; + }, + + class: { + 'hover:border-indigo-300': true, + 'hover:border-b-solid': true, + 'w-full': true, + }, + }), + + h('div', {}, text(props.lang.settings.mobRolesOrder)), + h( + 'div', + { + class: { + 'w-full': true, + }, + }, + [ + input({ + name: 'mobOrder', + pattern: '^[^,].+[^,]$', + value: value('mobOrder', props), + oninput: (_, e) => [ + actions.PendingSettingsSet, + { + key: 'mobOrder', + value: e.target.value, + }, + ], + + class: { + 'hover:border-indigo-300': true, + 'hover:border-b-solid': true, + 'w-full': true, + }, + }), + h( + 'small', + { + class: 'text-sm', + }, + text(props.lang.settings.positionHelpText), + ), + ], + ), + ], + ), + ]); + diff --git a/public/tabs/goals.js b/public/tabs/goals.js index 69f0f21..f678a06 100644 --- a/public/tabs/goals.js +++ b/public/tabs/goals.js @@ -1,20 +1,25 @@ import { addGoal } from '/sections/addGoal.js'; import { goalList } from '/sections/goalList.js'; -import { h } from '/vendor/hyperapp.js'; +import { h, text } from '/vendor/hyperapp.js'; import { removeCompletedGoals } from '/sections/removeCompletedGoals.js'; export const goals = props => h('div', {}, [ + h('header', { class: 'flex justify-start items-center border-b border-gray-400 mb-2' }, [ + h('h1', { class: 'text-lg font-bold flex-grow' }, text('Goals')), + h('button', { class: 'ml-2 dark:text-white text-black underline' }, text('Clear Completed')), + ]), + goalList({ expandedReorderable: props.expandedReorderable, drag: props.drag.type === 'goal' ? props.drag : {}, goals: props.goals, lang: props.lang, }), - addGoal({ - goal: props.goal, - addMultiple: props.addMultiple, - lang: props.lang, - }), - removeCompletedGoals({ goals: props.goals, lang: props.lang }), + // addGoal({ + // goal: props.goal, + // addMultiple: props.addMultiple, + // lang: props.lang, + // }), + // removeCompletedGoals({ goals: props.goals, lang: props.lang }), ]); diff --git a/public/tabs/mob.js b/public/tabs/mob.js index 36fd3a2..a846a54 100644 --- a/public/tabs/mob.js +++ b/public/tabs/mob.js @@ -1,10 +1,15 @@ -import { h } from '/vendor/hyperapp.js'; +import { h, text } from '/vendor/hyperapp.js'; import { addParticipant } from '/sections/addParticipant.js'; import { mobActions } from '/sections/mobActions.js'; import { mobParticipants } from '/sections/mobParticipants.js'; export const mob = props => h('div', {}, [ + h('header', { class: 'flex justify-start items-center border-b border-gray-400 mb-2' }, [ + h('h1', { class: 'text-lg font-bold flex-grow' }, text('Team')), + h('button', { class: 'ml-2 dark:text-white text-black underline' }, text('Shuffle')), + h('button', { class: 'ml-2 dark:text-white text-black underline' }, text('Rotate')), + ]), mobParticipants({ expandedReorderable: props.expandedReorderable, drag: props.drag.type === 'mob' ? props.drag : {}, @@ -13,12 +18,12 @@ export const mob = props => lang: props.lang, }), - addParticipant({ - name: props.name, - lang: props.lang, - }), + // addParticipant({ + // name: props.name, + // lang: props.lang, + // }), - mobActions({ - lang: props.lang, - }), + // mobActions({ + // lang: props.lang, + // }), ]); diff --git a/public/timer.html b/public/timer.html index 67096da..6730486 100644 --- a/public/timer.html +++ b/public/timer.html @@ -19,7 +19,7 @@ - +
diff --git a/public/timer.js b/public/timer.js index aca90e1..bf897cc 100644 --- a/public/timer.js +++ b/public/timer.js @@ -1,14 +1,20 @@ import * as actions from '/actions.js'; import { card } from '/components/card.js'; import { appPrompt } from '/components/prompt.js'; +import { grid } from '/components/grid.js'; +import { mob } from '/tabs/mob.js'; +import { goals } from '/tabs/goals.js'; +import { settings } from '/tabs/settings.js'; +import { qrShare } from '/tabs/qrShare.js'; import { header } from '/sections/header.js'; import { timeRemaining } from '/sections/timeRemaining.js'; import { toasts } from '/sections/toasts.js'; import * as subscriptions from '/subscriptions.js'; -import { app, h } from '/vendor/hyperapp.js'; +import { drawer } from '/components/drawer.js'; +import { app, h, text, memo } from '/vendor/hyperapp.js'; import * as Emitter from '/lib/emitter.js'; -import { tabs, showTab } from '/tabs/index.js'; +const stateWithoutFrequentChanges = ({ timerStartedAt, timerDuration, currentTime, mob, goals, ...state }) => state; const [initialTimerId] = window.location.pathname.split('/').filter(Boolean); const flags = window.location.search @@ -42,40 +48,42 @@ app({ 'div', { class: { - 'flex': true, - 'items-start': true, - 'justify-center': true, + 'relative': true, + 'w-full': true, 'min-h-screen': true, }, }, [ - card( + h( + 'div', { class: { - 'box-border': true, + 'container': true, + 'mx-auto': true, + 'flex': true, + 'flex-col': true, + 'items-center': true, + 'justify-start': true, 'min-h-screen': true, - 'sm:min-h-0': true, 'w-full': true, - 'sm:w-8/12': true, - 'md:w-10/12': true, - 'lg:w-6/12': true, - 'shadow': false, - 'sm:shadow-lg': true, - 'pt-2': false, - 'pt-0': true, - 'pb-12': true, - 'pb-1': false, - 'sm:mt-2': true, - 'rounded': false, - 'sm:rounded': true, - 'relative': true, }, }, [ - header(state), - timeRemaining(state), - tabs(state), - showTab(state), + grid([ + header(state), + timeRemaining(state), + mob(state), + goals(state), + h('details', {}, [ + h('summary', {}, text('Configure your timer')), + settings(state), + ]), + h('details', {}, [ + h('summary', {}, text('Share timer via QR Code')), + qrShare(state), + ]), + ]), + h( 'audio', { @@ -94,6 +102,7 @@ app({ state.prompt.visible && appPrompt(state.prompt || {}), ], ), + memo(drawer, stateWithoutFrequentChanges(state)), toasts(state), ], ), @@ -103,11 +112,11 @@ app({ return [ websocketConnect && - subscriptions.Websocket({ - actions, - externals, - timerId, - }), + subscriptions.Websocket({ + actions, + externals, + timerId, + }), subscriptions.Timer({ timerStartedAt: state.timerStartedAt, @@ -116,12 +125,12 @@ app({ }), drag.type && - subscriptions.DragAndDrop({ - active: drag.active, - DragMove: actions.DragMove, - DragEnd: actions.DragEnd, - DragCancel: actions.DragCancel, - }), + subscriptions.DragAndDrop({ + active: drag.active, + DragMove: actions.DragMove, + DragEnd: actions.DragEnd, + DragCancel: actions.DragCancel, + }), ]; }, diff --git a/public/vendor/hyperapp.js b/public/vendor/hyperapp.js index c9d2d9e..41c9ab5 100644 --- a/public/vendor/hyperapp.js +++ b/public/vendor/hyperapp.js @@ -2,9 +2,10 @@ import { app, h as originalH, text, -} from 'https://unpkg.com/hyperapp@2.0.20?module=1'; + memo, +} from 'https://unpkg.com/hyperapp@2.0.22?module=1'; -export { app, text }; +export { app, text, memo }; export const h = (tag, props, ...children) => { if (typeof tag === 'function') { console.warn('using h to run custom component', tag); diff --git a/tailwind.config.cjs b/tailwind.config.cjs index d636dd9..e21d5c9 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -1,4 +1,3 @@ -console.log('tailwind loaded config'); module.exports = { darkMode: 'class', content: [ From a51f0de8e99661adefe821f2fe0ee1c4fca06ce1 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 5 Jun 2023 11:09:21 -0400 Subject: [PATCH 02/36] New drawer (wip) --- public/actions.js | 3 +++ public/components/drawer.js | 7 ++++++- public/sections/header.js | 14 ++++++++++++++ public/timer.js | 18 +++++++++--------- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/public/actions.js b/public/actions.js index 93003d5..9f3a6e5 100644 --- a/public/actions.js +++ b/public/actions.js @@ -57,6 +57,7 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ allowNotification: externals.Notification && externals.Notification.permission === 'granted', allowSound: false, + showDrawer: false, sound: 'horn', pendingSettings: {}, websocketConnect: true, @@ -83,6 +84,8 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ }), ]; +export const ToggleDrawer = (state, { showDrawer }) => [{ ...state, showDrawer: Boolean(showDrawer) }]; + export const OnQrLoad = (state, { img }) => [{ ...state, qrImage: img }]; export const SetDark = (state, { dark }) => [ diff --git a/public/components/drawer.js b/public/components/drawer.js index c347342..8cbe36c 100644 --- a/public/components/drawer.js +++ b/public/components/drawer.js @@ -1,5 +1,6 @@ import { h, text } from '/vendor/hyperapp.js'; import { timerSettings } from '/sections/timerSettings.js'; +import * as actions from '/actions.js'; export const drawer = (props) => { return h('aside', { @@ -25,7 +26,11 @@ export const drawer = (props) => { h('header', { class: 'my-2 px-2 w-full flex justify-between items-start' }, [ h('h1', { class: 'text-lg' }, text('Timer Configuration')), - h('button', { innerHTML: '×' }), + h('button', { + type: 'button', + innerHTML: '×', + onclick: [actions.ToggleDrawer, { showDrawer: false }], + }), ]), h('details', { class: 'm-2' }, [ diff --git a/public/sections/header.js b/public/sections/header.js index 62b32d7..7673cac 100644 --- a/public/sections/header.js +++ b/public/sections/header.js @@ -2,6 +2,8 @@ import { h, text } from '/vendor/hyperapp.js'; import { section } from '/components/section.js'; +import * as actions from '/actions.js'; + export const header = state => section( { @@ -27,9 +29,21 @@ export const header = state => 'uppercase': true, 'tracker-widest': true, 'text-2xl': true, + 'flex-grow': true, }, }, text(state.lang.header.product), ), + + h('button', { + type: 'button', + class: { + 'text-xs': true, + 'text-slate-600': true, + }, + onclick: [actions.ToggleDrawer, { showDrawer: true }], + + }, text('Show Advanced Settings')), + ], ); diff --git a/public/timer.js b/public/timer.js index bf897cc..c288b58 100644 --- a/public/timer.js +++ b/public/timer.js @@ -74,14 +74,14 @@ app({ timeRemaining(state), mob(state), goals(state), - h('details', {}, [ - h('summary', {}, text('Configure your timer')), - settings(state), - ]), - h('details', {}, [ - h('summary', {}, text('Share timer via QR Code')), - qrShare(state), - ]), + // h('details', {}, [ + // h('summary', {}, text('Configure your timer')), + // settings(state), + // ]), + // h('details', {}, [ + // h('summary', {}, text('Share timer via QR Code')), + // qrShare(state), + // ]), ]), h( @@ -102,7 +102,7 @@ app({ state.prompt.visible && appPrompt(state.prompt || {}), ], ), - memo(drawer, stateWithoutFrequentChanges(state)), + state.showDrawer && memo(drawer, stateWithoutFrequentChanges(state)), toasts(state), ], ), From c03ff26cf1fe4aaa2783a7154ccc94d3d95d1428 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 5 Jun 2023 11:10:05 -0400 Subject: [PATCH 03/36] Got team section back up and running --- public/components/mobber.js | 4 ++-- public/tabs/mob.js | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/public/components/mobber.js b/public/components/mobber.js index ecd0f8a..76c6388 100644 --- a/public/components/mobber.js +++ b/public/components/mobber.js @@ -48,8 +48,8 @@ export const mobber = props => 'div', { class: { - 'text-gray-500': !props.name && !props.hasPosition, - 'dark:text-gray-800': !props.name && !props.hasPosition, + 'text-gray-500': !props.name, + 'dark:text-gray-600': !props.name, 'font-lg': true, 'font-bold': props.hasPosition && props.name, 'leading-none': true, diff --git a/public/tabs/mob.js b/public/tabs/mob.js index a846a54..5652288 100644 --- a/public/tabs/mob.js +++ b/public/tabs/mob.js @@ -2,13 +2,22 @@ import { h, text } from '/vendor/hyperapp.js'; import { addParticipant } from '/sections/addParticipant.js'; import { mobActions } from '/sections/mobActions.js'; import { mobParticipants } from '/sections/mobParticipants.js'; +import * as actions from '/actions.js'; export const mob = props => h('div', {}, [ h('header', { class: 'flex justify-start items-center border-b border-gray-400 mb-2' }, [ h('h1', { class: 'text-lg font-bold flex-grow' }, text('Team')), - h('button', { class: 'ml-2 dark:text-white text-black underline' }, text('Shuffle')), - h('button', { class: 'ml-2 dark:text-white text-black underline' }, text('Rotate')), + h('button', { + type: 'button', + class: 'ml-2 dark:text-white text-black underline', + onclick: actions.ShuffleMob, + }, text('Shuffle')), + h('button', { + type: 'button', + class: 'ml-2 dark:text-white text-black underline', + onclick: actions.CycleMob, + }, text('Rotate')), ]), mobParticipants({ expandedReorderable: props.expandedReorderable, @@ -18,6 +27,27 @@ export const mob = props => lang: props.lang, }), + h('form', { + class: 'ml-3 mt-2', + onsubmit: (_, e) => { + e.preventDefault(); + return [actions.AddNameToMob, {}]; + }, + }, [ + h('details', {}, [ + h('summary', { class: 'text-slate-500 text-xs' }, text('Show member form')), + + h('label', { class: 'mt-3 uppercase leading-none mb-1 text-xs block' }, text('Add team member')), + h('input', { + type: 'text', + class: 'bg-transparent border-b border-b-white w-full', + placeholder: 'Name', + value: props.name, + oninput: (_, e) => [actions.UpdateName, e.target.value], + }), + ]), + ]), + // addParticipant({ // name: props.name, // lang: props.lang, From bb6b2776806e75db47c21009c646b6637451716b Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 5 Jun 2023 21:50:50 -0400 Subject: [PATCH 04/36] Got eslint working as expected again --- .eslintrc.cjs | 22 + .eslintrc.json | 27 - package-lock.json | 2361 ++++++++++++++++++++++++++++++++++++++++++--- package.json | 9 +- 4 files changed, 2234 insertions(+), 185 deletions(-) create mode 100644 .eslintrc.cjs delete mode 100644 .eslintrc.json diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..7003a65 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,22 @@ +module.exports = { + env: { + browser: true, + es2021: true, + node: true, + }, + extends: 'standard', + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + rules: { + 'import/prefer-default-export': ['off'], + 'import/no-absolute-path': ['off'], + 'import/extensions': ['off'], + 'no-restricted-syntax': ['off'], + 'no-continue': ['off'], + 'quote-props': ['warn', 'consistent-as-needed'], + 'semi': ['warn', 'always'], + 'comma-dangle': ['warn', 'always-multiline'], + }, +}; diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 6ca918d..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "root": true, - "env": { - "browser": true, - "es6": true, - "node": true - }, - "extends": ["eslint:recommended", "prettier"], - "plugins": ["import"], - "globals": { - "Atomics": "readonly", - "SharedArrayBuffer": "readonly" - }, - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module", - "requireConfigFile": false - }, - "rules": { - "import/prefer-default-export": ["off"], - "import/no-absolute-path": ["off"], - "import/extensions": ["off"], - "no-restricted-syntax": ["off"], - "no-continue": ["off"], - "quote-props": ["warn", "consistent-as-needed"] - }, -}; diff --git a/package-lock.json b/package-lock.json index df882b1..6c7743d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,8 +20,14 @@ "ws": "^8.4.0" }, "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.59.9", + "@typescript-eslint/parser": "^5.59.9", "ava": "^4.3.3", - "eslint": "^8.34.0", + "eslint": "^8.42.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-n": "^16.0.0", + "eslint-plugin-promise": "^6.1.1", "husky": "^7.0.0", "nodemon": "^2.0.15", "nyc": "^15.1.0", @@ -398,15 +404,39 @@ "node": ">=6.9.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.5.2", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -466,10 +496,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz", + "integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -696,6 +735,254 @@ "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.9.tgz", + "integrity": "sha512-4uQIBq1ffXd2YvF7MAvehWKW3zVv/w+mSfRAu+8cKbfj3nwzyqJLNcZJpQ/WZ1HLbJDiowwmQ6NO+63nCA+fqA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.59.9", + "@typescript-eslint/type-utils": "5.59.9", + "@typescript-eslint/utils": "5.59.9", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.9.tgz", + "integrity": "sha512-FsPkRvBtcLQ/eVK1ivDiNYBjn3TGJdXy2fhXX+rc7czWl4ARwnpArwbihSOHI2Peg9WbtGHrbThfBUkZZGTtvQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.59.9", + "@typescript-eslint/types": "5.59.9", + "@typescript-eslint/typescript-estree": "5.59.9", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.9.tgz", + "integrity": "sha512-8RA+E+w78z1+2dzvK/tGZ2cpGigBZ58VMEHDZtpE1v+LLjzrYGc8mMaTONSxKyEkz3IuXFM0IqYiGHlCsmlZxQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.59.9", + "@typescript-eslint/visitor-keys": "5.59.9" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.9.tgz", + "integrity": "sha512-ksEsT0/mEHg9e3qZu98AlSrONAQtrSTljL3ow9CGej8eRo7pe+yaC/mvTjptp23Xo/xIf2mLZKC6KPv4Sji26Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.59.9", + "@typescript-eslint/utils": "5.59.9", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.9.tgz", + "integrity": "sha512-uW8H5NRgTVneSVTfiCVffBb8AbwWSKg7qcA4Ot3JI3MPCJGsB4Db4BhvAODIIYE5mNj7Q+VJkK7JxmRhk2Lyjw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.9.tgz", + "integrity": "sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.59.9", + "@typescript-eslint/visitor-keys": "5.59.9", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.9.tgz", + "integrity": "sha512-1PuMYsju/38I5Ggblaeb98TOoUvjhRvLpLa1DoTOFaLWqaXl/1iQ1eGurTXgBY58NUdtfTXKP5xBq7q9NDaLKg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.59.9", + "@typescript-eslint/types": "5.59.9", + "@typescript-eslint/typescript-estree": "5.59.9", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.9.tgz", + "integrity": "sha512-bT7s0td97KMaLwpEBckbzj/YohnvXtqbe2XgqNvTl6RJVakY5mvENOTPvw5u66nljfZxthESpDozs86U+oLY8Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.59.9", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -873,6 +1160,19 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -887,6 +1187,25 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -896,6 +1215,42 @@ "node": ">=8" } }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/arrgv": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/arrgv/-/arrgv-1.0.2.tgz", @@ -984,6 +1339,18 @@ } } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1089,6 +1456,15 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -1588,6 +1964,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/defined": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", @@ -1811,6 +2203,94 @@ "node": ">= 0.8" } }, + "node_modules/es-abstract": { + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -1844,13 +2324,16 @@ } }, "node_modules/eslint": { - "version": "8.34.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", - "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz", + "integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.42.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -1859,24 +2342,22 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -1884,7 +2365,6 @@ "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -1899,53 +2379,222 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "node_modules/eslint-config-standard": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-es-x": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-6.2.1.tgz", + "integrity": "sha512-uR34zUhZ9EBoiSD2DdV5kHLpydVEvwWqjteUr9sXRgJknwbKZJZhdJ7uFnaTtd+Nr/2G3ceJHnHXrFhJ67n3Tw==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.5.0" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" }, "peerDependencies": { - "eslint": ">=5" + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, "engines": { - "node": ">=10" + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-n": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.0.0.tgz", + "integrity": "sha512-akkZTE3hsHBrq6CwmGuYCzQREbVUrA855kzcHqe6i0FLBkeY7Y/6tThCVkjUnjhvRBAlc+8lILcSe5QvvDpeZQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "builtins": "^5.0.1", + "eslint-plugin-es-x": "^6.1.0", + "ignore": "^5.1.1", + "is-core-module": "^2.12.0", + "minimatch": "^3.1.2", + "resolve": "^1.22.2", + "semver": "^7.5.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ansi-regex": { @@ -2176,14 +2825,14 @@ } }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2516,6 +3165,15 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -2589,6 +3247,33 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/generic-pool": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", @@ -2637,6 +3322,22 @@ "node": ">=8.0.0" } }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -2677,6 +3378,21 @@ "node": ">=4" } }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { "version": "13.1.3", "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", @@ -2708,6 +3424,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -2720,6 +3448,12 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2731,6 +3465,15 @@ "node": ">= 0.4.0" } }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -2740,6 +3483,30 @@ "node": ">=4" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -2751,6 +3518,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -2901,6 +3683,20 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -2918,6 +3714,32 @@ "node": ">=8" } }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -2929,10 +3751,38 @@ "node": ">=8" } }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", "dependencies": { "has": "^1.0.3" }, @@ -2940,6 +3790,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-error": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", @@ -2977,6 +3842,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2985,6 +3862,21 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -3018,6 +3910,34 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "dev": true }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3030,6 +3950,55 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -3048,6 +4017,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -3236,16 +4217,6 @@ "node": ">=8" } }, - "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -3598,6 +4569,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -3991,6 +4968,50 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -4632,16 +5653,21 @@ "@redis/time-series": "1.0.4" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/release-zalgo": { @@ -4672,11 +5698,11 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.11.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -4773,15 +5799,29 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -5110,6 +6150,51 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/strip-ansi": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", @@ -5313,6 +6398,60 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -5355,6 +6494,20 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -5364,6 +6517,35 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", + "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -5467,12 +6649,48 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", "dev": true }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -6021,15 +7239,30 @@ "to-fast-properties": "^2.0.0" } }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "dev": true + }, "@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.5.2", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -6070,10 +7303,16 @@ } } }, + "@eslint/js": { + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz", + "integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==", + "dev": true + }, "@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -6255,6 +7494,157 @@ "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, + "@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.9.tgz", + "integrity": "sha512-4uQIBq1ffXd2YvF7MAvehWKW3zVv/w+mSfRAu+8cKbfj3nwzyqJLNcZJpQ/WZ1HLbJDiowwmQ6NO+63nCA+fqA==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.59.9", + "@typescript-eslint/type-utils": "5.59.9", + "@typescript-eslint/utils": "5.59.9", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.9.tgz", + "integrity": "sha512-FsPkRvBtcLQ/eVK1ivDiNYBjn3TGJdXy2fhXX+rc7czWl4ARwnpArwbihSOHI2Peg9WbtGHrbThfBUkZZGTtvQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.59.9", + "@typescript-eslint/types": "5.59.9", + "@typescript-eslint/typescript-estree": "5.59.9", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.9.tgz", + "integrity": "sha512-8RA+E+w78z1+2dzvK/tGZ2cpGigBZ58VMEHDZtpE1v+LLjzrYGc8mMaTONSxKyEkz3IuXFM0IqYiGHlCsmlZxQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.59.9", + "@typescript-eslint/visitor-keys": "5.59.9" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.9.tgz", + "integrity": "sha512-ksEsT0/mEHg9e3qZu98AlSrONAQtrSTljL3ow9CGej8eRo7pe+yaC/mvTjptp23Xo/xIf2mLZKC6KPv4Sji26Q==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.59.9", + "@typescript-eslint/utils": "5.59.9", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.9.tgz", + "integrity": "sha512-uW8H5NRgTVneSVTfiCVffBb8AbwWSKg7qcA4Ot3JI3MPCJGsB4Db4BhvAODIIYE5mNj7Q+VJkK7JxmRhk2Lyjw==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.9.tgz", + "integrity": "sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.59.9", + "@typescript-eslint/visitor-keys": "5.59.9", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.9.tgz", + "integrity": "sha512-1PuMYsju/38I5Ggblaeb98TOoUvjhRvLpLa1DoTOFaLWqaXl/1iQ1eGurTXgBY58NUdtfTXKP5xBq7q9NDaLKg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.59.9", + "@typescript-eslint/types": "5.59.9", + "@typescript-eslint/typescript-estree": "5.59.9", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.59.9", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.9.tgz", + "integrity": "sha512-bT7s0td97KMaLwpEBckbzj/YohnvXtqbe2XgqNvTl6RJVakY5mvENOTPvw5u66nljfZxthESpDozs86U+oLY8Q==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.59.9", + "eslint-visitor-keys": "^3.3.0" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -6383,6 +7773,16 @@ "sprintf-js": "~1.0.2" } }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -6394,12 +7794,49 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + } + }, "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, "arrgv": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/arrgv/-/arrgv-1.0.2.tgz", @@ -6465,6 +7902,12 @@ "yargs": "^17.5.1" } }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -6546,6 +7989,15 @@ "update-browserslist-db": "^1.0.10" } }, + "builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -6910,6 +8362,16 @@ "strip-bom": "^4.0.0" } }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, "defined": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", @@ -7071,6 +8533,79 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, + "es-abstract": { + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + } + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -7095,13 +8630,16 @@ "dev": true }, "eslint": { - "version": "8.34.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", - "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz", + "integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.42.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -7110,24 +8648,22 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -7135,7 +8671,6 @@ "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -7263,74 +8798,188 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "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==", + "dev": true + } + } + }, + "eslint-config-standard": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", + "dev": true, + "requires": {} + }, + "eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-es-x": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-6.2.1.tgz", + "integrity": "sha512-uR34zUhZ9EBoiSD2DdV5kHLpydVEvwWqjteUr9sXRgJknwbKZJZhdJ7uFnaTtd+Nr/2G3ceJHnHXrFhJ67n3Tw==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.5.0" + } + }, + "eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" } }, - "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==", + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "esutils": "^2.0.2" } }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "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==", + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "eslint-plugin-n": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.0.0.tgz", + "integrity": "sha512-akkZTE3hsHBrq6CwmGuYCzQREbVUrA855kzcHqe6i0FLBkeY7Y/6tThCVkjUnjhvRBAlc+8lILcSe5QvvDpeZQ==", "dev": true, "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "@eslint-community/eslint-utils": "^4.4.0", + "builtins": "^5.0.1", + "eslint-plugin-es-x": "^6.1.0", + "ignore": "^5.1.1", + "is-core-module": "^2.12.0", + "minimatch": "^3.1.2", + "resolve": "^1.22.2", + "semver": "^7.5.0" } }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "requires": {} + }, + "eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "dev": true, "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" } }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true }, "espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", "dev": true, "requires": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.1" } }, "esprima": { @@ -7599,6 +9248,15 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -7642,6 +9300,24 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, "generic-pool": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", @@ -7675,6 +9351,16 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -7703,6 +9389,15 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, "globby": { "version": "13.1.3", "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", @@ -7724,6 +9419,15 @@ } } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -7736,6 +9440,12 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -7744,17 +9454,47 @@ "function-bind": "^1.1.1" } }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, "hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -7859,6 +9599,17 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -7870,6 +9621,26 @@ "integrity": "sha512-YXxECO/W6N9aMBVKMKKZ8TXESgq7EFrp3emCGGUcrYY1cgJIeZjoB75MTu8qi+NAKntS9NwPU8VdcQ3r6E6aWQ==", "dev": true }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -7878,14 +9649,39 @@ "binary-extensions": "^2.0.0" } }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", "requires": { "has": "^1.0.3" } }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-error": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", @@ -7911,11 +9707,26 @@ "is-extglob": "^2.1.1" } }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -7940,12 +9751,62 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "dev": true }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -7958,6 +9819,15 @@ "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", "dev": true }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -8107,12 +9977,6 @@ "istanbul-lib-report": "^3.0.0" } }, - "js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true - }, "js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -8365,6 +10229,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -8679,6 +10549,35 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, "on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -9093,11 +10992,16 @@ "@redis/time-series": "1.0.4" } }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true + "regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + } }, "release-zalgo": { "version": "1.0.0", @@ -9121,11 +11025,11 @@ "dev": true }, "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", "requires": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.11.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -9172,15 +11076,26 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -9438,6 +11353,39 @@ "strip-ansi": "^7.0.1" } }, + "string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, "strip-ansi": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", @@ -9582,6 +11530,50 @@ "nopt": "~1.0.10" } }, + "tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -9612,6 +11604,17 @@ "mime-types": "~2.1.24" } }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -9621,6 +11624,25 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", + "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", + "dev": true, + "peer": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, "undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -9687,12 +11709,39 @@ "isexe": "^2.0.0" } }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", "dev": true }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/package.json b/package.json index 9965f78..16caac7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "mobtime", "version": "1.4.0", "main": "index.js", - "type": "module", "license": "MIT", "repository": { "type": "git", @@ -33,8 +32,14 @@ "ws": "^8.4.0" }, "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.59.9", + "@typescript-eslint/parser": "^5.59.9", "ava": "^4.3.3", - "eslint": "^8.34.0", + "eslint": "^8.42.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-n": "^16.0.0", + "eslint-plugin-promise": "^6.1.1", "husky": "^7.0.0", "nodemon": "^2.0.15", "nyc": "^15.1.0", From d72286e64a40d9e7b79d763120a4c63df0f512ac Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 5 Jun 2023 21:52:03 -0400 Subject: [PATCH 05/36] Disconnected goals controls --- public/tabs/goals.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/public/tabs/goals.js b/public/tabs/goals.js index f678a06..4fc220e 100644 --- a/public/tabs/goals.js +++ b/public/tabs/goals.js @@ -16,6 +16,15 @@ export const goals = props => goals: props.goals, lang: props.lang, }), + + h('form', { class: 'ml-3 mt-2' }, [ + h('details', {}, [ + h('summary', { class: 'text-slate-500 text-xs' }, text('Show goal form')), + + h('label', { class: 'mt-3 uppercase leading-none mb-1 text-xs block' }, text('Add goal')), + h('input', { type: 'text', class: 'bg-transparent border-b border-b-white w-full', placeholder: 'Name' }), + ]), + ]), // addGoal({ // goal: props.goal, // addMultiple: props.addMultiple, From 68b82114461be17054731e68dc57bda3b4c3f717 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 5 Jun 2023 21:52:22 -0400 Subject: [PATCH 06/36] Getting timer summary ready --- public/sections/timeRemaining.js | 4 ++-- public/sections/timeSection.js | 22 ++++++++++++++++++++++ public/timer.js | 2 ++ 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 public/sections/timeSection.js diff --git a/public/sections/timeRemaining.js b/public/sections/timeRemaining.js index d4b5801..3acc007 100644 --- a/public/sections/timeRemaining.js +++ b/public/sections/timeRemaining.js @@ -31,7 +31,7 @@ export const timeRemaining = props => { // border-l-slate-500 return section({ - class: { 'md:col-span-2': true }, + // class: { 'md:col-span-2': true }, }, [ h( @@ -59,7 +59,7 @@ export const timeRemaining = props => { 'w-52': true, 'h-52': true, 'rounded-full': true, - 'mx-auto': true, + // 'mx-auto': true, 'mb-8': true, 'transition-all': true, 'duration-1000': true, diff --git a/public/sections/timeSection.js b/public/sections/timeSection.js new file mode 100644 index 0000000..f917f6d --- /dev/null +++ b/public/sections/timeSection.js @@ -0,0 +1,22 @@ +import { h, text } from '/vendor/hyperapp.js'; +import { timeRemaining } from '/sections/timeRemaining.js'; + +export const timeSection = (props) => { + return h('div', { + class: 'md:col-span-2 grid grid-cols-2', + }, [ + timeRemaining(props), + h('div', { + class: 'flex items-center justify-start', + }, [ + h('ol', {}, [ + ...props.settings.mobOrder.split(',').map((position, index) => { + return h('li', {}, [ + h('div', {}, text(position)), + h('div', {}, text(props.mob[index]?.name || 'Empty')), + ]); + }), + ]), + ]), + ]); +}; diff --git a/public/timer.js b/public/timer.js index c288b58..dea9b0a 100644 --- a/public/timer.js +++ b/public/timer.js @@ -8,6 +8,7 @@ import { settings } from '/tabs/settings.js'; import { qrShare } from '/tabs/qrShare.js'; import { header } from '/sections/header.js'; import { timeRemaining } from '/sections/timeRemaining.js'; +import { timeSection } from '/sections/timeSection.js'; import { toasts } from '/sections/toasts.js'; import * as subscriptions from '/subscriptions.js'; import { drawer } from '/components/drawer.js'; @@ -72,6 +73,7 @@ app({ grid([ header(state), timeRemaining(state), + timeSection(state), mob(state), goals(state), // h('details', {}, [ From 66d4e7e2e949c8fc9b874b5a257d7d7bc475c1b8 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Wed, 14 Jun 2023 10:00:27 -0400 Subject: [PATCH 07/36] No more double-completes from the backend --- .eslintignore | 2 +- index.js | 3 +- package-lock.json | 497 ++------------------------------------------ package.json | 5 +- public/.eslintrc.js | 5 - src/web/actions.js | 32 +++ src/web/http.js | 25 +++ 7 files changed, 83 insertions(+), 486 deletions(-) delete mode 100644 public/.eslintrc.js diff --git a/.eslintignore b/.eslintignore index 012a3cd..3c3629e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1 @@ -index.js +node_modules diff --git a/index.js b/index.js index 72057a1..d62dee3 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,5 @@ import 'dotenv/config'; -// require('dotenv/config'); -// j = require = require('esm')(module /*, options*/); + if (process.env.WORKERS > 1 || process.env.WORKERS === -1) { import('./src/web/index.cluster.js'); } else { diff --git a/package-lock.json b/package-lock.json index 6c7743d..b4ea6d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "body-parser": "^1.19.0", + "composable-state": "^0.1.0", "dotenv": "^15.0.0", "express": "^4.17.2", "ferp": "^2.1.2", @@ -20,8 +21,6 @@ "ws": "^8.4.0" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^5.59.9", - "@typescript-eslint/parser": "^5.59.9", "ava": "^4.3.3", "eslint": "^8.42.0", "eslint-config-standard": "^17.1.0", @@ -735,254 +734,12 @@ "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, - "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", - "dev": true - }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.9.tgz", - "integrity": "sha512-4uQIBq1ffXd2YvF7MAvehWKW3zVv/w+mSfRAu+8cKbfj3nwzyqJLNcZJpQ/WZ1HLbJDiowwmQ6NO+63nCA+fqA==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.9", - "@typescript-eslint/type-utils": "5.59.9", - "@typescript-eslint/utils": "5.59.9", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.9.tgz", - "integrity": "sha512-FsPkRvBtcLQ/eVK1ivDiNYBjn3TGJdXy2fhXX+rc7czWl4ARwnpArwbihSOHI2Peg9WbtGHrbThfBUkZZGTtvQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.59.9", - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/typescript-estree": "5.59.9", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.9.tgz", - "integrity": "sha512-8RA+E+w78z1+2dzvK/tGZ2cpGigBZ58VMEHDZtpE1v+LLjzrYGc8mMaTONSxKyEkz3IuXFM0IqYiGHlCsmlZxQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/visitor-keys": "5.59.9" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.9.tgz", - "integrity": "sha512-ksEsT0/mEHg9e3qZu98AlSrONAQtrSTljL3ow9CGej8eRo7pe+yaC/mvTjptp23Xo/xIf2mLZKC6KPv4Sji26Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.9", - "@typescript-eslint/utils": "5.59.9", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.9.tgz", - "integrity": "sha512-uW8H5NRgTVneSVTfiCVffBb8AbwWSKg7qcA4Ot3JI3MPCJGsB4Db4BhvAODIIYE5mNj7Q+VJkK7JxmRhk2Lyjw==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.9.tgz", - "integrity": "sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/visitor-keys": "5.59.9", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.9.tgz", - "integrity": "sha512-1PuMYsju/38I5Ggblaeb98TOoUvjhRvLpLa1DoTOFaLWqaXl/1iQ1eGurTXgBY58NUdtfTXKP5xBq7q9NDaLKg==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.9", - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/typescript-estree": "5.59.9", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.9.tgz", - "integrity": "sha512-bT7s0td97KMaLwpEBckbzj/YohnvXtqbe2XgqNvTl6RJVakY5mvENOTPvw5u66nljfZxthESpDozs86U+oLY8Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.59.9", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -1542,9 +1299,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001457", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz", - "integrity": "sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==", + "version": "1.0.30001495", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", + "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==", "dev": true, "funding": [ { @@ -1554,6 +1311,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -1790,6 +1551,11 @@ "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, + "node_modules/composable-state": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/composable-state/-/composable-state-0.1.0.tgz", + "integrity": "sha512-Mp/SnbzQvu/2TuZONwWIEyuJA0gJlHiNa6nPJItFkW6Ny7i7U43ZYrRKypHFGLsfmvIiG3Q/uY5qDjVVQtVhQg==" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3442,12 +3208,6 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -4569,12 +4329,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -6431,27 +6185,6 @@ "node": ">=4" } }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6517,20 +6250,6 @@ "is-typedarray": "^1.0.0" } }, - "node_modules/typescript": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", - "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -7494,157 +7213,12 @@ "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, - "@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", - "dev": true - }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.9.tgz", - "integrity": "sha512-4uQIBq1ffXd2YvF7MAvehWKW3zVv/w+mSfRAu+8cKbfj3nwzyqJLNcZJpQ/WZ1HLbJDiowwmQ6NO+63nCA+fqA==", - "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.9", - "@typescript-eslint/type-utils": "5.59.9", - "@typescript-eslint/utils": "5.59.9", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.9.tgz", - "integrity": "sha512-FsPkRvBtcLQ/eVK1ivDiNYBjn3TGJdXy2fhXX+rc7czWl4ARwnpArwbihSOHI2Peg9WbtGHrbThfBUkZZGTtvQ==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.59.9", - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/typescript-estree": "5.59.9", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.9.tgz", - "integrity": "sha512-8RA+E+w78z1+2dzvK/tGZ2cpGigBZ58VMEHDZtpE1v+LLjzrYGc8mMaTONSxKyEkz3IuXFM0IqYiGHlCsmlZxQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/visitor-keys": "5.59.9" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.9.tgz", - "integrity": "sha512-ksEsT0/mEHg9e3qZu98AlSrONAQtrSTljL3ow9CGej8eRo7pe+yaC/mvTjptp23Xo/xIf2mLZKC6KPv4Sji26Q==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.59.9", - "@typescript-eslint/utils": "5.59.9", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.9.tgz", - "integrity": "sha512-uW8H5NRgTVneSVTfiCVffBb8AbwWSKg7qcA4Ot3JI3MPCJGsB4Db4BhvAODIIYE5mNj7Q+VJkK7JxmRhk2Lyjw==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.9.tgz", - "integrity": "sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/visitor-keys": "5.59.9", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "dependencies": { - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - } - } - }, - "@typescript-eslint/utils": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.9.tgz", - "integrity": "sha512-1PuMYsju/38I5Ggblaeb98TOoUvjhRvLpLa1DoTOFaLWqaXl/1iQ1eGurTXgBY58NUdtfTXKP5xBq7q9NDaLKg==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.9", - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/typescript-estree": "5.59.9", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.9.tgz", - "integrity": "sha512-bT7s0td97KMaLwpEBckbzj/YohnvXtqbe2XgqNvTl6RJVakY5mvENOTPvw5u66nljfZxthESpDozs86U+oLY8Q==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.59.9", - "eslint-visitor-keys": "^3.3.0" - } - }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -8056,9 +7630,9 @@ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" }, "caniuse-lite": { - "version": "1.0.30001457", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz", - "integrity": "sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==", + "version": "1.0.30001495", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", + "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==", "dev": true }, "cbor": { @@ -8233,6 +7807,11 @@ "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, + "composable-state": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/composable-state/-/composable-state-0.1.0.tgz", + "integrity": "sha512-Mp/SnbzQvu/2TuZONwWIEyuJA0gJlHiNa6nPJItFkW6Ny7i7U43ZYrRKypHFGLsfmvIiG3Q/uY5qDjVVQtVhQg==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -9434,12 +9013,6 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, "graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -10229,12 +9802,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -11559,21 +11126,6 @@ } } }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -11624,13 +11176,6 @@ "is-typedarray": "^1.0.0" } }, - "typescript": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", - "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", - "dev": true, - "peer": true - }, "unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", diff --git a/package.json b/package.json index 16caac7..c3644c7 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,8 @@ "name": "mobtime", "version": "1.4.0", "main": "index.js", + "type": "module", + "engine": ">=16", "license": "MIT", "repository": { "type": "git", @@ -22,6 +24,7 @@ }, "dependencies": { "body-parser": "^1.19.0", + "composable-state": "^0.1.0", "dotenv": "^15.0.0", "express": "^4.17.2", "ferp": "^2.1.2", @@ -32,8 +35,6 @@ "ws": "^8.4.0" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^5.59.9", - "@typescript-eslint/parser": "^5.59.9", "ava": "^4.3.3", "eslint": "^8.42.0", "eslint-config-standard": "^17.1.0", diff --git a/public/.eslintrc.js b/public/.eslintrc.js deleted file mode 100644 index 59d63e7..0000000 --- a/public/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - rules: { - 'import/no-unresolved': ['off'], - }, -}; diff --git a/src/web/actions.js b/src/web/actions.js index 2cd3469..24610bf 100644 --- a/src/web/actions.js +++ b/src/web/actions.js @@ -3,6 +3,7 @@ import { WebSocket } from 'ws'; import { RelayMessage, ShareMessage } from './websocket.js'; import * as Connection from './connection.js'; import { id, GenerateIdEffect } from './id.js'; +import { composable, select, selectArray, replace } from 'composable-state'; const { none, act, batch, defer } = effects; @@ -33,6 +34,7 @@ const extractStatistics = message => { export const Init = (queue, nextId = id()) => [ { + completeTokens: {}, connections: {}, queue, nextId, @@ -40,6 +42,20 @@ export const Init = (queue, nextId = id()) => [ none(), ]; +export const SetCompleteToken = (timerId, token) => state => [ + composable(state, selectArray(['completeTokens', timerId], replace(token))), + none(), +]; + +export const RemoveCompleteToken = timerId => state => [ + composable(state, select('completeTokens', replace((old) => { + const clone = { ...old }; + delete clone[timerId]; + return clone; + }))), + none(), +]; + export const SetNextId = nextId => state => [{ ...state, nextId }, none()]; export const UpdateStatisticsFromMessage = (timerId, message) => state => [ @@ -145,6 +161,22 @@ export const UpdateTimer = (timerId, message) => state => { ]; }; +export const CompleteTimer = (timerId, token) => state => { + if (state.completeTokens[timerId] !== token) { + console.log('CompleteTimer', timerId, 'token mismatch', { state: state.completeTokens[timerId], param: token }); + return [state, none()]; + } + console.log('CompleteTimer', timerId, 'all good'); + + return [ + state, + batch([ + defer(state.queue.publishToTimer(timerId, JSON.stringify({ type: 'timer:complete' })).then(none)), + act(RemoveCompleteToken(timerId)), + ]), + ]; +}; + export const MessageTimer = (timerId, message) => state => { return [ state, diff --git a/src/web/http.js b/src/web/http.js index a43d379..b02756e 100644 --- a/src/web/http.js +++ b/src/web/http.js @@ -61,6 +61,31 @@ const HttpSub = (dispatch, action, host = 'localhost', port = 4321) => { return response.status(200).send(html); }); + app.post('/:timerId/timer/start', async (request, response) => { + const { timerId } = request.params; + const message = JSON.stringify({ + type: 'timer:start', + timerDuration: request.body.duration, + }); + + const token = Math.random().toString(36).slice(-6); + + await dispatch(action.SetCompleteToken(timerId, token), 'SetCompleteToken'); + await dispatch(action.UpdateTimer(timerId, message), 'UpdateTimer'); + + return response.status(200).json({ + complete: `/${timerId}/timer/cancel/${token}`, + }); + }); + + app.post('/:timerId/timer/complete', async (request, response) => { + const { timerId } = request.params; + const { token } = request.body; + + await dispatch(action.CompleteTimer(timerId, token), 'CompleteTimer'); + return response.status(202).json({}); + }); + server.listen(port, host, () => { console.log(`Local server up: http://${host}:${port}`); }); From 420e14b89b74e7b46821281abb95379852e50bc5 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Wed, 14 Jun 2023 16:32:41 -0400 Subject: [PATCH 08/36] Backend changes to support http requests for start/pause/stop timer --- package-lock.json | 12 +++++------ src/web/actions.js | 50 +++++++++++++++++++++++++------------------- src/web/http.js | 22 +++++++++++++------ src/web/websocket.js | 10 +++++++++ 4 files changed, 60 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4ea6d1..3eac914 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1299,9 +1299,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001495", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", - "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==", + "version": "1.0.30001503", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz", + "integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==", "dev": true, "funding": [ { @@ -7630,9 +7630,9 @@ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" }, "caniuse-lite": { - "version": "1.0.30001495", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", - "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==", + "version": "1.0.30001503", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz", + "integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==", "dev": true }, "cbor": { diff --git a/src/web/actions.js b/src/web/actions.js index 24610bf..c284fff 100644 --- a/src/web/actions.js +++ b/src/web/actions.js @@ -140,7 +140,6 @@ export const UpdateTimer = (timerId, message) => state => { ...(type === 'timer:complete' ? { timerStartedAt: null, timerDuration: 0 } : {}), - ...(type === 'timer:pause' ? { timerStartedAt: null } : {}), }; return [ @@ -163,16 +162,30 @@ export const UpdateTimer = (timerId, message) => state => { export const CompleteTimer = (timerId, token) => state => { if (state.completeTokens[timerId] !== token) { - console.log('CompleteTimer', timerId, 'token mismatch', { state: state.completeTokens[timerId], param: token }); return [state, none()]; } - console.log('CompleteTimer', timerId, 'all good'); return [ state, batch([ - defer(state.queue.publishToTimer(timerId, JSON.stringify({ type: 'timer:complete' })).then(none)), + // defer(state.queue.publishToTimer(timerId, JSON.stringify({ type: 'timer:complete' })).then(none)), act(RemoveCompleteToken(timerId)), + act(UpdateTimer(timerId, JSON.stringify({ type: 'timer:complete' }))), + ]), + ]; +}; + +export const PauseTimer = (timerId, token, duration) => state => { + if (state.completeTokens[timerId] !== token) { + return [state, none()]; + } + + return [ + state, + batch([ + //defer(state.queue.publishToTimer(timerId, JSON.stringify({ type: 'timer:pause', timerDuration: duration })).then(none)), + act(RemoveCompleteToken(timerId)), + act(UpdateTimer(timerId, JSON.stringify({ type: 'timer:pause', timerStartedAt: null, timerDuration: duration }))), ]), ]; }; @@ -206,24 +219,17 @@ export const ShareTimerWith = (connection, timerId) => state => [ ), ); - const timerIsRunning = - timer.timerStartedAt && - timer.timerDuration && - timer.timerDuration - (Date.now() - timer.timerStartedAt) > 0; - - return batch( - [ - sync('settings'), - sync('mob'), - sync('goals'), - timerIsRunning && - sync('timer', { - type: 'timer:update', - timerStartedAt: timer.timerStartedAt, - timerDuration: timer.timerDuration, - }), - ].filter(Boolean), - ); + return batch([ + sync('settings'), + sync('mob'), + sync('goals'), + sync('timer', { + type: 'timer:update', + timerStartedAt: timer.timerStartedAt, + timerDuration: timer.timerDuration, + completeToken: state.completeTokens[timerId] || null, + }), + ]); }), ), ]; diff --git a/src/web/http.js b/src/web/http.js index b02756e..01990b3 100644 --- a/src/web/http.js +++ b/src/web/http.js @@ -63,19 +63,29 @@ const HttpSub = (dispatch, action, host = 'localhost', port = 4321) => { app.post('/:timerId/timer/start', async (request, response) => { const { timerId } = request.params; + + const completeToken = Math.random().toString(36).slice(-6); + await dispatch(action.SetCompleteToken(timerId, completeToken), 'SetCompleteToken'); + const message = JSON.stringify({ type: 'timer:start', timerDuration: request.body.duration, + completeToken, }); - const token = Math.random().toString(36).slice(-6); - - await dispatch(action.SetCompleteToken(timerId, token), 'SetCompleteToken'); await dispatch(action.UpdateTimer(timerId, message), 'UpdateTimer'); - return response.status(200).json({ - complete: `/${timerId}/timer/cancel/${token}`, - }); + return response.status(202).json({ completeToken }); + }); + + app.post('/:timerId/timer/pause', async (request, response) => { + const { timerId } = request.params; + const { token, duration } = request.body; + + console.log('http timer pause', { timerId, token, duration }, request.body); + + await dispatch(action.PauseTimer(timerId, token, duration), 'PauseTimer'); + return response.status(202).json({}); }); app.post('/:timerId/timer/complete', async (request, response) => { diff --git a/src/web/websocket.js b/src/web/websocket.js index a8cfb89..48206a1 100644 --- a/src/web/websocket.js +++ b/src/web/websocket.js @@ -26,8 +26,18 @@ const WebsocketSub = (dispatch, actions, connection, timerId) => { log('error'); }); + const ignoredMessageTypes = [ + 'timer:start', + 'timer:pause', + 'timer:complete', + ]; websocket.on('message', payload => { log('message', payload.toString()); + const { type } = JSON.parse(payload.toString()); + if (ignoredMessageTypes.includes(type)) { + log('WARN', 'socket sent ignored instruction', type); + return; + } return dispatch( actions.UpdateTimer(timerId, payload.toString()), 'UpdateTimer', From 85e260e8cba913c3c3f9f48d31361e908cb4633e Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Wed, 14 Jun 2023 16:33:14 -0400 Subject: [PATCH 09/36] Linting i18n --- public/i18n/af-ZA.js | 6 +++--- public/i18n/uk-UA.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/i18n/af-ZA.js b/public/i18n/af-ZA.js index 4f87319..fa93835 100644 --- a/public/i18n/af-ZA.js +++ b/public/i18n/af-ZA.js @@ -4,13 +4,13 @@ const nomenclature = { create: 'Voeg by', edit: 'Wysig', product: 'mobtime', -} +}; const properCase = text => text .split(' ') .map(word => word.slice(0, 1).toUpperCase() + word.slice(1)) - .join(' ') + .join(' '); export const af_ZA = { header: { @@ -94,4 +94,4 @@ export const af_ZA = { reconnect: 'Herkonnekteer', }, }, -} +}; diff --git a/public/i18n/uk-UA.js b/public/i18n/uk-UA.js index fbc0e12..c67f721 100644 --- a/public/i18n/uk-UA.js +++ b/public/i18n/uk-UA.js @@ -62,7 +62,7 @@ export const uk_UA = { saved: 'Збережено', sharedTimerSettings: 'Налаштування таймеру', turnDurationInMinutes: 'Довжина ротації (у хвилинах)', - mobRolesOrder: `Ролі/Порядок учасників`, + mobRolesOrder: 'Ролі/Порядок учасників', positionHelpText: 'Одна або більше ролей розділених комами', localSettings: 'Локальні налаштування', enableTimerSounds: 'Увімкнути звуки таймеру', From 6bc6cdcf358ebdf0905dcd28eb4b0ea162433fc9 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 19 Jun 2023 09:21:24 -0400 Subject: [PATCH 10/36] Http api for sending data to the timer --- public/actions.js | 190 +++++++++++++++++++++++++++++++++++++---- public/effects.js | 88 ++++++++++++++----- public/effects.test.js | 4 +- src/web/actions.js | 21 +++-- src/web/http.js | 8 ++ 5 files changed, 267 insertions(+), 44 deletions(-) diff --git a/public/actions.js b/public/actions.js index 9f3a6e5..077aa0f 100644 --- a/public/actions.js +++ b/public/actions.js @@ -1,5 +1,6 @@ import * as effects from './effects.js'; import { calculateTimeRemaining } from './lib/calculateTimeRemaining.js'; +import { formatTime } from './lib/formatTime.js'; import * as i18n from './i18n/index.js'; export const Noop = state => state; @@ -35,6 +36,11 @@ const collectionMove = (collection, { from, to }) => { return newCollection; }; +const defaults = { + timerMobOrder: 'Navigator,Driver', + timerDuration: 5 * 60 * 1000, +}; + export const Init = (_, { timerId, externals, dark, lang }) => [ { timerStartedAt: null, @@ -42,8 +48,34 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ mob: [], goals: [], settings: { - mobOrder: 'Navigator,Driver', - duration: 5 * 60 * 1000, + mobOrder: defaults.timerMobOrder, + duration: defaults.timerDuration, + }, + forms: { + mob: { + open: false, + valid: true, + id: '', + input: '', + }, + goals: { + open: false, + valid: true, + id: '', + input: '', + }, + timerDuration: { + open: false, + valid: true, + id: '', + input: formatTime(defaults.timerDuration), + }, + timerMobOrder: { + open: false, + valid: true, + id: '', + input: defaults.timerMobOrder, + }, }, expandedReorderable: null, timerTab: 'overview', @@ -84,6 +116,42 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ }), ]; +export const SetFormId = (state, { form, id, input }) => ({ + ...state, + forms: { + ...state.forms, + [form]: { + ...state.forms[form], + id: state.forms[form].id === id ? '' : id, + input: state.forms[form].id === id ? '' : input || '', + open: Boolean(id), + }, + }, +}); + +export const SetFormInput = (state, { form, input, valid }) => ({ + ...state, + forms: { + ...state.forms, + [form]: { + ...state.forms[form], + input, + valid: valid === undefined ? true : Boolean(valid), + }, + }, +}); + +export const OpenForm = (state, { form, open }) => ({ + ...state, + forms: { + ...state.forms, + [form]: { + ...state.forms[form], + open: Boolean(open), + }, + }, +}); + export const ToggleDrawer = (state, { showDrawer }) => [{ ...state, showDrawer: Boolean(showDrawer) }]; export const OnQrLoad = (state, { img }) => [{ ...state, qrImage: img }]; @@ -256,6 +324,26 @@ export const EndTurn = state => [ }), ]; +export const TimeComplete = (state) => { + const nextState = { + ...state, + timerStartedAt: null, + timerDuration: 0, + }; + return [ + nextState, + effects.apiTimerComplete({ + timerId: state.timerId, + completeToken: state.completeToken, + fetch: state.externals.fetch, + }), + effects.UpdateTitleWithTime({ + remainingTime: 0, + documentElement: state.externals.documentElement, + }), + ]; +}; + export const Completed = (state, { isEndOfTurn }) => { const nextState = { ...state, @@ -389,17 +477,26 @@ export const CycleMob = state => { ]; }; -export const AddNameToMob = state => { +export const AddNameToMob = (state, { name }) => { + if (!name) return state; + const mob = state.mob.concat({ id: Math.random() .toString(36) .slice(2), - name: state.name, + name, }); return [ { ...state, + forms: { + ...state.forms, + mob: { + ...state.forms.mob, + input: '', + }, + }, mob, name: '', }, @@ -607,10 +704,16 @@ export const PauseTimer = (state, currentTime = Date.now()) => { timerDuration, currentTime, }, - effects.PauseTimer({ - socketEmitter: state.externals.socketEmitter, + effects.apiTimerPause({ + timerId: state.timerId, timerDuration, + completeToken: state.completeToken, + fetch: state.externals.fetch, }), + // effects.PauseTimer({ + // socketEmitter: state.externals.socketEmitter, + // timerDuration, + // }), ]; }; @@ -620,9 +723,14 @@ export const ResumeTimer = (state, timerStartedAt = Date.now()) => [ timerStartedAt, currentTime: timerStartedAt, }, - effects.StartTimer({ - socketEmitter: state.externals.socketEmitter, - timerDuration: state.timerDuration, + // effects.StartTimer({ + // socketEmitter: state.externals.socketEmitter, + // timerDuration: state.timerDuration, + // }), + effects.apiTimerStart({ + timerId: state.timerId, + duration: state.timerDuration, + fetch: state.externals.fetch, }), ]; @@ -633,9 +741,14 @@ export const StartTimer = (state, { timerStartedAt, timerDuration }) => [ currentTime: timerStartedAt, timerDuration, }, - effects.StartTimer({ - socketEmitter: state.externals.socketEmitter, - timerDuration, + // effects.StartTimer({ + // socketEmitter: state.externals.socketEmitter, + // timerDuration, + // }), + effects.apiTimerStart({ + timerId: state.timerId, + duration: timerDuration, + fetch: state.externals.fetch, }), ]; @@ -654,6 +767,17 @@ export const SetAllowNotification = (state, { allowNotification }) => [ }), ]; +export const TestNotification = state => [ + state, + effects.Notify({ + title: 'Mobtime Config', + text: 'This is a test notification', + sound: state.allowSound, + Notification: state.externals.Notification, + documentElement: state.externals.documentElement, + }), +]; + export const UpdateNotificationPermissions = state => [ { ...state, @@ -823,6 +947,18 @@ export const PendingSettingsSet = (state, { key, value }) => ({ }, }); +export const SubmitSettings = (state, settings) => [ + state, + effects.apiUpdateSettings({ + timerId: state.timerId, + settings: { + ...state.settings, + ...settings, + }, + fetch: state.externals.fetch, + }), +]; + export const UpdateSettings = state => { const settings = { ...state.settings, @@ -842,13 +978,31 @@ export const UpdateSettings = state => { ]; }; +export const RevertSettings = state => { + return { + ...state, + forms: { + ...state.forms, + timerDuration: { + ...state.forms.timerDuration, + input: formatTime(state.settings.duration), + }, + }, + }; +}; + export const UpdateByWebsocketData = (state, { payload }) => { const { type, ...data } = payload; + console.log('UpdateByWebsocketData', payload); switch (type) { case 'settings:update': + console.log('--', { old: state.settings, new: data.settings }); return { ...state, - settings: data.settings, + settings: { + ...state.settings, + ...data.settings, + }, }; case 'timer:start': @@ -856,6 +1010,7 @@ export const UpdateByWebsocketData = (state, { payload }) => { ...state, timerStartedAt: Date.now(), timerDuration: data.timerDuration, + completeToken: data.completeToken, }; case 'timer:pause': @@ -870,19 +1025,20 @@ export const UpdateByWebsocketData = (state, { payload }) => { ...state, timerStartedAt: data.timerStartedAt, timerDuration: data.timerDuration, + completeToken: data.completeToken, }; case 'timer:complete': - if (state.timerStartedAt === null && state.timerDuration === 0) { - return state; - } - return [ state, effects.andThen({ action: EndTurn, props: {}, }), + effects.andThen({ + action: CycleMob, + props: {}, + }), ]; case 'goals:update': diff --git a/public/effects.js b/public/effects.js index e16bd5d..eac8abc 100644 --- a/public/effects.js +++ b/public/effects.js @@ -13,7 +13,7 @@ const sendMessage = (socketEmitter, type, json = {}) => { ); }; -export const PreloadImage = fx(function PreloadImageFX( +export const PreloadImage = fx(function PreloadImageFX ( dispatch, { src, onLoad }, ) { @@ -31,49 +31,49 @@ export const PreloadImage = fx(function PreloadImageFX( img.src = src; }); -export const UpdateSettings = fx(function UpdateSettingsFX( +export const UpdateSettings = fx(function UpdateSettingsFX ( _dispatch, { socketEmitter, settings }, ) { return sendMessage(socketEmitter, 'settings:update', { settings }); }); -export const StartTimer = fx(function StartTimerFX( +export const StartTimer = fx(function StartTimerFX ( _dispatch, { socketEmitter, timerDuration }, ) { return sendMessage(socketEmitter, 'timer:start', { timerDuration }); }); -export const PauseTimer = fx(function StartTimerFX( +export const PauseTimer = fx(function StartTimerFX ( _dispatch, { socketEmitter, timerDuration }, ) { return sendMessage(socketEmitter, 'timer:pause', { timerDuration }); }); -export const CompleteTimer = fx(function CompleteTimerFX( +export const CompleteTimer = fx(function CompleteTimerFX ( _dispatch, { socketEmitter }, ) { return sendMessage(socketEmitter, 'timer:complete'); }); -export const UpdateGoals = fx(function UpdateGoalsFX( +export const UpdateGoals = fx(function UpdateGoalsFX ( _dispatch, { socketEmitter, goals }, ) { sendMessage(socketEmitter, 'goals:update', { goals }); }); -export const UpdateMob = fx(function UpdateMobFX( +export const UpdateMob = fx(function UpdateMobFX ( _dispatch, { socketEmitter, mob }, ) { sendMessage(socketEmitter, 'mob:update', { mob }); }); -export const NotificationPermission = fx(function NotificationPermissionFX( +export const NotificationPermission = fx(function NotificationPermissionFX ( dispatch, { UpdateNotificationPermissions, Notification, documentElement }, ) { @@ -97,7 +97,7 @@ export const NotificationPermission = fx(function NotificationPermissionFX( }); }); -function PlaySoundFX(_dispatch, { sound, documentElement }) { +function PlaySoundFX (_dispatch, { sound, documentElement }) { if (sound && documentElement) { const timerComplete = documentElement.querySelector('#timer-complete'); timerComplete.play(); @@ -105,7 +105,7 @@ function PlaySoundFX(_dispatch, { sound, documentElement }) { } export const PlaySound = fx(PlaySoundFX); -export const Notify = fx(function NotifyFX( +export const Notify = fx(function NotifyFX ( _dispatch, { title, @@ -120,13 +120,13 @@ export const Notify = fx(function NotifyFX( // eslint-disable-next-line no-new new Notification(title, { body: text, - vibrate: [100, 100, 100], + silent: !sound, }); } PlaySoundFX(_dispatch, { sound, documentElement }); }); -export const UpdateTitleWithTime = fx(function UpdateTitleWithTimeFX( +export const UpdateTitleWithTime = fx(function UpdateTitleWithTimeFX ( _dispatch, { remainingTime, documentElement }, ) { @@ -135,13 +135,13 @@ export const UpdateTitleWithTime = fx(function UpdateTitleWithTimeFX( remainingTime > 0 ? `${formatTime(remainingTime)} - mobtime` : 'mobtime'; }); -export const andThen = fx(function andThenFX(dispatch, { action, props, delay }) { +export const andThen = fx(function andThenFX (dispatch, { action, props, delay }) { setTimeout(() => { dispatch(action, props); }, delay || 0); }); -export const checkSettings = fx(function CheckSettingsFX( +export const checkSettings = fx(function CheckSettingsFX ( dispatch, { storage, onLocalSoundEnabled, onDarkEnabled }, ) { @@ -161,7 +161,7 @@ export const checkSettings = fx(function CheckSettingsFX( } }); -export const saveSettings = fx(function SaveSettingsFX( +export const saveSettings = fx(function SaveSettingsFX ( _dispatch, { storage, data }, ) { @@ -178,7 +178,7 @@ export const saveSettings = fx(function SaveSettingsFX( storage.setItem('settings', JSON.stringify(localSettings)); }); -export const saveSound = fx(function SaveSoundFX( +export const saveSound = fx(function SaveSoundFX ( _dispatch, { storage, allowSound, sound }, ) { @@ -196,11 +196,10 @@ export const saveSound = fx(function SaveSoundFX( storage.setItem('settings', JSON.stringify(localSettings)); }); -export const toggleDarkMode = fx(function ToggleDarkMode( +export const toggleDarkMode = fx(function ToggleDarkMode ( _dispatch, { documentElement, dark }, ) { - console.log('toggleDarkMode', documentElement, dark); if (typeof dark !== 'boolean') { console.log('dark not set, skipping', dark); return; @@ -214,7 +213,7 @@ export const toggleDarkMode = fx(function ToggleDarkMode( } }); -export const removeQueryParameters = fx(function RemoveQueryParametersFX( +export const removeQueryParameters = fx(function RemoveQueryParametersFX ( _dispatch, { location, history, documentElement }, ) { @@ -231,3 +230,54 @@ export const removeQueryParameters = fx(function RemoveQueryParametersFX( [location.toString().split('?')[0], params].filter(Boolean).join('?'), ); }); + +const timerApi = (fetchFn, timerId, endpoint, body = {}) => fetchFn( + `/${timerId}/timer${endpoint}`, + { + method: 'post', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }, +); + +export const apiTimerStart = fx(function ApiTimerStart ( + _dispatch, + { timerId, duration, fetch: fetchFn }, +) { + timerApi(fetchFn, timerId, '/start', { duration }) + .catch((err) => { + console.error('Unable to start timer', { timerId }, err); + }); +}); + +export const apiTimerPause = fx(function ApiTimerPause ( + _dispatch, + { timerId, completeToken, timerDuration, fetch: fetchFn }, +) { + timerApi(fetchFn, timerId, '/pause', { token: completeToken, duration: timerDuration }) + .catch((err) => { + console.error('Unable to start timer', { timerId }, err); + }); +}); + +export const apiTimerComplete = fx(function CompleteTimer ( + _dispatch, + { timerId, completeToken, fetch: fetchFn }, +) { + timerApi(fetchFn, timerId, '/complete', { token: completeToken }) + .catch((err) => { + console.error('Unable to complete timer', { timerId, completeToken }, err); + }); +}); + +export const apiUpdateSettings = fx(function UpdateTimer ( + _dispatch, + { timerId, settings, fetch: fetchFn }, +) { + timerApi(fetchFn, timerId, '/settings', { settings }) + .catch((err) => { + console.error('Unable to update timer settings', { timerId, settings }, err); + }); +}); diff --git a/public/effects.test.js b/public/effects.test.js index 975f301..fb06508 100644 --- a/public/effects.test.js +++ b/public/effects.test.js @@ -165,7 +165,7 @@ test('can request notification permission, and handle exception', async t => { }); test('can create a notification', t => { - const Notification = sinon.fake(function _Notification(title, options) { + const Notification = sinon.fake(function _Notification (title, options) { this.title = title; this.options = options; return this; @@ -192,7 +192,7 @@ test('can create a notification', t => { }); test('can skip a notification when notification is false', t => { - const Notification = sinon.fake(function _Notification(title, options) { + const Notification = sinon.fake(function _Notification (title, options) { this.title = title; this.options = options; return this; diff --git a/src/web/actions.js b/src/web/actions.js index c284fff..6eab3d3 100644 --- a/src/web/actions.js +++ b/src/web/actions.js @@ -219,16 +219,25 @@ export const ShareTimerWith = (connection, timerId) => state => [ ), ); + const timerData = { + type: 'timer:update', + timerStartedAt: timer.timerStartedAt, + timerDuration: timer.timerDuration, + completeToken: state.completeTokens[timerId] || null, + }; + + const timerEndsAt = timer.timerStartedAt + timer.timerDuration; + if (Date.now() > timerEndsAt) { + timerData.timerStartedAt = null; + timerData.timerDuration = 0; + timerData.completeToken = null; + } + return batch([ sync('settings'), sync('mob'), sync('goals'), - sync('timer', { - type: 'timer:update', - timerStartedAt: timer.timerStartedAt, - timerDuration: timer.timerDuration, - completeToken: state.completeTokens[timerId] || null, - }), + sync('timer', timerData), ]); }), ), diff --git a/src/web/http.js b/src/web/http.js index 01990b3..d723da1 100644 --- a/src/web/http.js +++ b/src/web/http.js @@ -96,6 +96,14 @@ const HttpSub = (dispatch, action, host = 'localhost', port = 4321) => { return response.status(202).json({}); }); + app.post('/:timerId/timer/settings', async (request, response) => { + const { timerId } = request.params; + const { settings } = request.body; + + await dispatch(action.UpdateTimer(timerId, JSON.stringify({ type: 'settings:update', settings })), 'UpdateTimer'); + return response.status(202).json({}); + }); + server.listen(port, host, () => { console.log(`Local server up: http://${host}:${port}`); }); From b41b96a2dd28b1ce812a095cb4ef2752f164c9e6 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 19 Jun 2023 09:24:47 -0400 Subject: [PATCH 11/36] Updated public lib directory Moved formatTime in Added a form -> formData -> object helper Added a classConcat file to handle combining string and object class names --- public/lib/classConcat.js | 15 +++++++++++++++ public/lib/form.js | 4 ++++ public/lib/formatTime.js | 21 +++++++++++++++++++++ public/lib/formatTime.test.js | 22 ++++++++++++++++++++++ 4 files changed, 62 insertions(+) create mode 100644 public/lib/classConcat.js create mode 100644 public/lib/form.js create mode 100644 public/lib/formatTime.js create mode 100644 public/lib/formatTime.test.js diff --git a/public/lib/classConcat.js b/public/lib/classConcat.js new file mode 100644 index 0000000..e07baae --- /dev/null +++ b/public/lib/classConcat.js @@ -0,0 +1,15 @@ +const normalize = (classes) => { + if (typeof classes === 'string') { + return classes; + } else if (Array.isArray) { + return classes.filter(Boolean).map(normalize).join(' '); + } else if (!classes) { + return ''; + } + return normalize( + Object.keys(classes) + .reduce((memo, key) => memo.concat(classes[key] ? key : []), []), + ); +}; + +export const classConcat = (...definitions) => normalize(definitions); diff --git a/public/lib/form.js b/public/lib/form.js new file mode 100644 index 0000000..520d069 --- /dev/null +++ b/public/lib/form.js @@ -0,0 +1,4 @@ +export const formData = (formElement) => { + const formData = new FormData(formElement); + return Array.from(formData.keys()).reduce((obj, key) => ({ ...obj, [key]: formData.get(key) }), {}); +}; diff --git a/public/lib/formatTime.js b/public/lib/formatTime.js new file mode 100644 index 0000000..bf096ef --- /dev/null +++ b/public/lib/formatTime.js @@ -0,0 +1,21 @@ +export const formatTime = milliseconds => { + console.log('formatTime', milliseconds); + if (!milliseconds) { + return '00:00'; + } + const minutes = Math.floor(milliseconds / 60000); + const remainingMilliseconds = milliseconds - minutes * 60000; + const seconds = Math.floor(remainingMilliseconds / 1000); + + return [minutes, seconds].map(t => `${t}`.padStart(2, '0')).join(':'); +}; + +export const formattedTimeToMilliseconds = (formatted) => { + if (!formatted) return 0; + + const [minutes, seconds] = formatted + .split(':') + .map((v) => parseInt(v)); + + return (seconds + (minutes * 60)) * 1000; +}; diff --git a/public/lib/formatTime.test.js b/public/lib/formatTime.test.js new file mode 100644 index 0000000..906dc00 --- /dev/null +++ b/public/lib/formatTime.test.js @@ -0,0 +1,22 @@ +import test from 'ava'; +import { formatTime } from './formatTime.js'; + +test('displays 00:00 with empty milliseconds', t => { + const expectedTime = '00:00'; + t.is(formatTime(), expectedTime); +}); + +test('displays under-a-minute time', t => { + const expectedTime = '00:59'; + t.is(formatTime(59000), expectedTime); +}); + +test('displays under 10-minute time', t => { + const expectedTime = '09:00'; + t.is(formatTime(9 * 60 * 1000), expectedTime); +}); + +test('displays over 10-minute time', t => { + const expectedTime = '99:00'; + t.is(formatTime(99 * 60 * 1000), expectedTime); +}); From 76bfe0ade7062248be30e906738defe57643a70b Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 19 Jun 2023 09:27:05 -0400 Subject: [PATCH 12/36] Update tabs with different sections now available (should probably rename from tabs) --- public/tabs/goals.js | 26 ++++++----- public/tabs/localSettings.js | 83 ++++++++++++++++++++++++++++++++++++ public/tabs/mob.js | 49 +++++++++++++++------ public/tabs/settings.js | 66 ++++++++++++++-------------- public/tabs/timerSettings.js | 73 +++++++++++++++++++++++++++++++ 5 files changed, 240 insertions(+), 57 deletions(-) create mode 100644 public/tabs/localSettings.js create mode 100644 public/tabs/timerSettings.js diff --git a/public/tabs/goals.js b/public/tabs/goals.js index 4fc220e..964a087 100644 --- a/public/tabs/goals.js +++ b/public/tabs/goals.js @@ -1,7 +1,6 @@ -import { addGoal } from '/sections/addGoal.js'; import { goalList } from '/sections/goalList.js'; import { h, text } from '/vendor/hyperapp.js'; -import { removeCompletedGoals } from '/sections/removeCompletedGoals.js'; +import * as actions from '/actions.js'; export const goals = props => h('div', {}, [ @@ -17,18 +16,25 @@ export const goals = props => lang: props.lang, }), - h('form', { class: 'ml-3 mt-2' }, [ + h('form', { + class: 'ml-3 mt-2', + method: 'get', + onsubmit: (_, e) => { + e.preventDefault(); + return [actions.AddGoals, props.goal]; + }, + }, [ h('details', {}, [ h('summary', { class: 'text-slate-500 text-xs' }, text('Show goal form')), h('label', { class: 'mt-3 uppercase leading-none mb-1 text-xs block' }, text('Add goal')), - h('input', { type: 'text', class: 'bg-transparent border-b border-b-white w-full', placeholder: 'Name' }), + h('input', { + type: 'text', + class: 'bg-transparent border-b border-b-white w-full', + placeholder: 'Name', + value: props.goal, + oninput: (_, e) => [actions.UpdateGoalText, e.target.value], + }), ]), ]), - // addGoal({ - // goal: props.goal, - // addMultiple: props.addMultiple, - // lang: props.lang, - // }), - // removeCompletedGoals({ goals: props.goals, lang: props.lang }), ]); diff --git a/public/tabs/localSettings.js b/public/tabs/localSettings.js new file mode 100644 index 0000000..4523dbf --- /dev/null +++ b/public/tabs/localSettings.js @@ -0,0 +1,83 @@ +import { h, text } from '/vendor/hyperapp.js'; + +import * as actions from '/actions.js'; + +const audioFiles = [ + { value: 'horn', label: 'Pneumatic horn' }, + { value: 'ding', label: 'Ding' }, + { value: 'applause', label: 'Applause and Cheering' }, + { value: 'bike-bell', label: 'Bike Bell' }, + { value: 'gong', label: 'Gong' }, + { value: 'excuse-me', label: 'Oops, excuse me' }, +]; + +export const localSettings = (props) => { + return h('div', {}, [ + h('header', { class: 'flex justify-start items-center border-b border-gray-400 mb-2' }, [ + h('h1', { class: 'text-lg font-bold flex-grow' }, text('Local settings')), + // h('button', { + // type: 'button', + // class: 'ml-2 dark:text-white text-black underline', + // onclick: actions.ShuffleMob, + // }, text('Shuffle')), + // h('button', { + // type: 'button', + // class: 'ml-2 dark:text-white text-black underline', + // onclick: actions.CycleMob, + // }, text('Rotate')), + ]), + h( + 'div', + { + class: 'grid gap-2', + style: { + 'grid-template-columns': '3fr 1fr', + }, + }, + [ + h('div', {}, text('Dark mode')), + h('input', { + type: 'checkbox', + checked: props.dark, + oninput: (_, e) => [actions.SetDark, { dark: e.target.checked }], + }), + + h('div', { class: 'flex items-bottom justify-between' }, [ + text('Notifications'), + h('button', { type: 'button', class: 'px-2', onclick: () => [actions.TestNotification, {}] }, text('Test')), + ]), + h('input', { + type: 'checkbox', + checked: props.allowNotification, + oninput: (_, e) => ( + e.target.checked + ? [actions.RequestNotificationPermission, {}] + : [actions.SetAllowNotification, { allowNotification: e.target.checked }] + ), + }), + + h('div', { class: 'flex items-bottom justify-between' }, [ + text('Timer Sound'), + h('div', { class: 'flex-grow flex items-center justify-end' }, [ + h('select', { + class: 'px-2 text-black', + onchange: (_, event) => { + return [actions.SetSound, event.target.value]; + }, + }, audioFiles.map(a => h( + 'option', + { value: a.value }, + text(a.label), + ))), + ]), + h('button', { type: 'button', class: 'px-2', onclick: [actions.TestSound, undefined] }, text('Test')), + ]), + h('input', { + type: 'checkbox', + checked: props.allowSound, + oninput: (_, e) => [actions.SetAllowSound, e.target.checked], + }), + ], + ), + ]); +}; diff --git a/public/tabs/mob.js b/public/tabs/mob.js index 5652288..b25429f 100644 --- a/public/tabs/mob.js +++ b/public/tabs/mob.js @@ -1,11 +1,11 @@ import { h, text } from '/vendor/hyperapp.js'; -import { addParticipant } from '/sections/addParticipant.js'; -import { mobActions } from '/sections/mobActions.js'; import { mobParticipants } from '/sections/mobParticipants.js'; import * as actions from '/actions.js'; -export const mob = props => - h('div', {}, [ +export const mob = props => { + const isEdittingMember = props.forms.mob.id && props.mob.some(m => m.id == props.forms.mob.id); + + return h('div', {}, [ h('header', { class: 'flex justify-start items-center border-b border-gray-400 mb-2' }, [ h('h1', { class: 'text-lg font-bold flex-grow' }, text('Team')), h('button', { @@ -25,26 +25,46 @@ export const mob = props => mob: props.mob, mobOrder: props.settings.mobOrder, lang: props.lang, + forms: props.forms, }), h('form', { class: 'ml-3 mt-2', onsubmit: (_, e) => { e.preventDefault(); - return [actions.AddNameToMob, {}]; + const formData = new FormData(e.target); + switch (e.submitter.value) { + case 'update': + return [actions.RenameUser, { id: formData.get('id'), value: formData.get('name') }]; + case 'remove': + return [actions.RemoveFromMob, formData.get('id')]; + case 'add': + return [actions.AddNameToMob, { name: formData.get('name') }]; + } }, }, [ - h('details', {}, [ + h('input', { type: 'hidden', name: 'id', value: props.forms.mob.id }), + h('details', { open: props.forms.mob.open, toggle: (_, event) => [actions.OpenForm, { form: 'mob', open: event.target.open }] }, [ h('summary', { class: 'text-slate-500 text-xs' }, text('Show member form')), - h('label', { class: 'mt-3 uppercase leading-none mb-1 text-xs block' }, text('Add team member')), - h('input', { - type: 'text', - class: 'bg-transparent border-b border-b-white w-full', - placeholder: 'Name', - value: props.name, - oninput: (_, e) => [actions.UpdateName, e.target.value], - }), + h('div', { class: 'flex items-end justify-items-start' }, [ + h('fieldset', { class: 'flex-grow' }, [ + h('label', { class: 'mt-3 uppercase leading-none mb-1 text-xs block' }, text('team member')), + h('input', { + type: 'text', + class: 'bg-transparent border-b border-b-white w-full', + placeholder: 'Name', + name: 'name', + value: props.forms.mob.input, + required: true, + oninput: (_, e) => [actions.SetFormInput, { form: 'mob', input: e.target.value }], + }), + ]), + !isEdittingMember && h('button', { type: 'submit', name: 'action', value: 'add', class: 'ml-1 px-2 py-1 border border-slate-700' }, text('Add')), + isEdittingMember && h('button', { type: 'submit', name: 'action', value: 'update', class: 'ml-1 px-2 py-1 border border-slate-700' }, text('Update')), + isEdittingMember && h('button', { type: 'submit', name: 'action', value: 'remove', class: 'ml-1 px-2 py-1 border border-slate-700' }, text('Remove')), + isEdittingMember && h('button', { type: 'button', name: 'action', value: 'cancel', class: 'ml-1 px-2 py-1 border border-slate-700', onclick: () => [actions.SetFormId, { form: 'mob', id: '' }] }, text('Cancel')), + ]), ]), ]), @@ -57,3 +77,4 @@ export const mob = props => // lang: props.lang, // }), ]); +}; diff --git a/public/tabs/settings.js b/public/tabs/settings.js index 84fac1f..3feeca8 100644 --- a/public/tabs/settings.js +++ b/public/tabs/settings.js @@ -39,36 +39,36 @@ export const settings = props => rightAction: Object.keys(props.pendingSettings).length === 0 ? h('div', {}, [ - text(props.lang.settings.saved), - h('i', { class: 'fas fa-check text-green-500' }), - ]) + text(props.lang.settings.saved), + h('i', { class: 'fas fa-check text-green-500' }), + ]) : h('div', {}, [ - button( - { - class: { - 'bg-indigo-500': true, - 'hover:bg-indigo-400': true, - 'text-white': true, - 'mr-1': true, - }, - onclick: actions.PendingSettingsReset, + button( + { + class: { + 'bg-indigo-500': true, + 'hover:bg-indigo-400': true, + 'text-white': true, + 'mr-1': true, }, - text(props.lang.settings.cancel), - ), - button( - { - type: 'button', - class: { - 'bg-green-600': true, - 'hover:bg-green-500': true, - 'text-white': true, - }, - disable: Object.keys(props.pendingSettings).length === 0, - onclick: actions.UpdateSettings, + onclick: actions.PendingSettingsReset, + }, + text(props.lang.settings.cancel), + ), + button( + { + type: 'button', + class: { + 'bg-green-600': true, + 'hover:bg-green-500': true, + 'text-white': true, }, - text(props.lang.settings.save), - ), - ]), + disable: Object.keys(props.pendingSettings).length === 0, + onclick: actions.UpdateSettings, + }, + text(props.lang.settings.save), + ), + ]), }, text(props.lang.settings.sharedTimerSettings), ), @@ -183,12 +183,12 @@ export const settings = props => }, props.allowSound ? audioFiles.map(({ value, label }) => - h( - 'option', - { value, selected: props.sound === value }, - text(label), - ), - ) + h( + 'option', + { value, selected: props.sound === value }, + text(label), + ), + ) : [ h( 'option', diff --git a/public/tabs/timerSettings.js b/public/tabs/timerSettings.js new file mode 100644 index 0000000..5950bce --- /dev/null +++ b/public/tabs/timerSettings.js @@ -0,0 +1,73 @@ +import { h, text } from '/vendor/hyperapp.js'; + +import { formattedTimeToMilliseconds } from '/lib/formatTime.js'; +import { formData } from '/lib/form.js'; + +import * as actions from '/actions.js'; + +export const timerSettings = (props) => { + const isDirty = ( + props.settings.duration !== formattedTimeToMilliseconds(props.forms.timerDuration.input) + ); + + return h('form', { + onsubmit: (_, event) => { + event.preventDefault(); + + if (!event.target.reportValidity()) { + console.log('skipping submit, form invalid'); + return [s => s]; + } + + const settings = formData(event.target); + settings.duration = formattedTimeToMilliseconds(settings.duration); + + console.log('form.submit', settings, event.target); + + return [actions.SubmitSettings, settings]; + }, + }, [ + h('header', { class: 'flex justify-start items-center border-b border-gray-400 mb-2' }, [ + h('h1', { class: 'text-lg font-bold flex-grow' }, text('Timer settings')), + isDirty && h('button', { + type: 'button', + }, text('Revert Changes')), + ]), + h( + 'div', + { + class: 'grid gap-2', + style: { + 'grid-template-columns': '3fr 1fr', + }, + }, + [ + h('div', {}, text('Duration')), + h('div', { class: 'flex' }, [ + h('input', { + type: 'text', + pattern: '[0-9]{1,2}(:[0-5][0-9])?', + class: [ + 'mr-2 border-b border-slate-600 dark:bg-transparent dark:text-gray-200', + !props.forms.timerDuration.valid && 'outline outline-red-400', + ].filter(Boolean).join(' '), + oninput: (_, event) => { + const seconds = formattedTimeToMilliseconds(event.target.value) / 1000; + console.log('settings.change', event.target.value, formattedTimeToMilliseconds(event.target.value)); + // let [minutes, seconds] = event.target.value.split(':'); + // minutes ||= 0; + // seconds = (seconds || 0) + (minutes * 60); + const valid = event.target.checkValidity() && seconds > 0; + + return [actions.SetFormInput, { form: 'timerDuration', input: event.target.value, valid }]; + }, + placeholder: 'mm or mm:ss', + value: props.forms.timerDuration.input, + name: 'duration', + }), + text('minutes'), + ]), + ], + ), + ]); +}; From ebcfd73fab506cb97886ab1e97cf756962ca629e Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 19 Jun 2023 09:27:26 -0400 Subject: [PATCH 13/36] Remove all fontawesome usages from re-orderable --- public/components/reorderable.js | 41 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/public/components/reorderable.js b/public/components/reorderable.js index 7d90485..0ebf1a1 100644 --- a/public/components/reorderable.js +++ b/public/components/reorderable.js @@ -97,19 +97,20 @@ const dragContainer = (props, children) => }, ], }, - Array.from({ length: 3 }, (_, index) => - h('div', { - class: { - 'border-b': true, - 'border-b-gray-800': !props.disabled, - 'border-b-gray-400': props.disabled, - 'dark:border-b-gray-200': !props.disabled, - 'dark:border-b-gray-400': props.disabled, - 'mt-1': index > 0, - 'w-1': true, - }, - }), - ), + h('div', { innerHTML: '⁞⁞⁞' }), + // Array.from({ length: 3 }, (_, index) => + // h('div', { + // class: { + // 'border-b': true, + // 'border-b-gray-800': !props.disabled, + // 'border-b-gray-400': props.disabled, + // 'dark:border-b-gray-200': !props.disabled, + // 'dark:border-b-gray-400': props.disabled, + // 'mt-1': index > 0, + // 'w-1': true, + // }, + // }), + // ), ), children, @@ -133,7 +134,7 @@ const dragContainer = (props, children) => 'disabled': !props.onMoveUp, 'aria-label': `Move ${props.type} up`, }, - [h('i', { class: 'fas fa-arrow-up' })], + [h('span', { class: 'text-bold', innerHTML: '↑' })], ), listButton( @@ -146,7 +147,7 @@ const dragContainer = (props, children) => 'disabled': !props.onMoveDown, 'aria-label': `Move ${props.type} down`, }, - [h('i', { class: 'fas fa-arrow-down' })], + [h('span', { class: 'text-bold', innerHTML: '↓' })], ), props.onEdit && @@ -157,7 +158,7 @@ const dragContainer = (props, children) => }, onclick: props.onEdit, }, - [h('i', { class: 'fas fa-pencil-alt' })], + [h('span', { class: 'text-bold', innerHTML: '✎' })], ), props.onDelete && @@ -181,7 +182,7 @@ const dragContainer = (props, children) => }, onclick: props.onExpand, }, - [h('i', { class: 'fas fa-ellipsis-v' })], + [h('span', { class: 'text-bold', innerHTML: '⋮' })], ), ...(props.isDragging @@ -214,9 +215,9 @@ const draggingContainer = (props, child) => 'duration-75': true, 'ease-in-out': true, 'pointer-events-none': true, - //'border': true, - //'border-green-600': true, - //'rounded': true, + // 'border': true, + // 'border-green-600': true, + // 'rounded': true, }, }, child, From 747c83210c60ea245a16e06e5c58879fbe031c3b Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 19 Jun 2023 09:28:00 -0400 Subject: [PATCH 14/36] Cleanup sections for new ui --- public/sections/addParticipant.js | 2 +- public/sections/header.js | 16 +--- public/sections/mobActions.js | 2 +- public/sections/mobParticipants.js | 5 +- public/sections/summary.js | 69 ++++++++++++++ public/sections/timeRemaining.js | 146 ++++++++++++++--------------- public/sections/timerSettings.js | 55 ++++++----- public/sections/toasts.js | 4 +- 8 files changed, 173 insertions(+), 126 deletions(-) create mode 100644 public/sections/summary.js diff --git a/public/sections/addParticipant.js b/public/sections/addParticipant.js index 72c580a..766cd2f 100644 --- a/public/sections/addParticipant.js +++ b/public/sections/addParticipant.js @@ -53,7 +53,7 @@ export const addParticipant = props => { type: 'submit', class: { - //'bg-green-600': true, + // 'bg-green-600': true, 'dark:text-white': true, 'flex-shrink': true, 'whitespace-no-wrap': true, diff --git a/public/sections/header.js b/public/sections/header.js index 7673cac..22905f3 100644 --- a/public/sections/header.js +++ b/public/sections/header.js @@ -2,8 +2,6 @@ import { h, text } from '/vendor/hyperapp.js'; import { section } from '/components/section.js'; -import * as actions from '/actions.js'; - export const header = state => section( { @@ -13,14 +11,14 @@ export const header = state => 'items-center': true, 'justify-start': true, 'w-full': true, - 'md:col-span-2': true, 'text-black': true, 'dark:text-white': true, }, }, [ h('div', { - class: 'fas fa-clock text-4xl mr-3', + innerHTML: '🕐', + class: 'text-4xl mr-3', }), h( 'div', @@ -35,15 +33,5 @@ export const header = state => text(state.lang.header.product), ), - h('button', { - type: 'button', - class: { - 'text-xs': true, - 'text-slate-600': true, - }, - onclick: [actions.ToggleDrawer, { showDrawer: true }], - - }, text('Show Advanced Settings')), - ], ); diff --git a/public/sections/mobActions.js b/public/sections/mobActions.js index e5e195b..caf5ffe 100644 --- a/public/sections/mobActions.js +++ b/public/sections/mobActions.js @@ -36,7 +36,7 @@ export const mobActions = props => button( { class: { - //'bg-green-600': true, + // 'bg-green-600': true, 'dark:text-white': true, // 'flex-grow': true, 'ml-1': true, diff --git a/public/sections/mobParticipants.js b/public/sections/mobParticipants.js index 34e3b3b..a28d85f 100644 --- a/public/sections/mobParticipants.js +++ b/public/sections/mobParticipants.js @@ -2,7 +2,6 @@ import { h } from '/vendor/hyperapp.js'; import * as actions from '/actions.js'; -import { section } from '/components/section.js'; import { reorderable } from '/components/reorderable.js'; import { mobber } from '/components/mobber.js'; @@ -18,6 +17,7 @@ export const mobParticipants = props => { const items = Array.from({ length }, (_, index) => ({ ...(props.mob[index] || {}), + highlight: props.forms.mob.id === props.mob[index]?.id, disabled: index >= props.mob.length, position: mobOrder[index] || props.lang.mob.fallback, hasPosition: !!mobOrder[index], @@ -30,7 +30,7 @@ export const mobParticipants = props => { dragType: 'mob', expandedReorderable: props.expandedReorderable, items, - disabled: props.mob.length === 0, + disabled: props.mob.length === 0 || props.overview, renderItem: item => mobber({ ...item, @@ -38,7 +38,6 @@ export const mobParticipants = props => { selected: getReorderableId(item) === props.expandedReorderable, }), drag: props.drag, - disabled: props.overview, getReorderableId, onMove: props.overview ? undefined : actions.MoveMob, onEdit: props.overview ? undefined : actions.RenameUserPrompt, diff --git a/public/sections/summary.js b/public/sections/summary.js new file mode 100644 index 0000000..9e3a47d --- /dev/null +++ b/public/sections/summary.js @@ -0,0 +1,69 @@ +import { h, text } from '/vendor/hyperapp.js'; + +import * as actions from '/actions.js'; + +export const summary = (props) => { + const firstIncompleteGoal = props.goals.filter(g => !g.completed)[0]; + + return h('div', { + // class: 'flex items-center justify-start', + }, [ + h('ol', {}, [ + ...props.settings.mobOrder.split(',').map((position, index) => { + return h('li', { class: 'mb-2' }, [ + h('div', { class: 'text-xs leading-none uppercase text-slate-600' }, text(position)), + h('div', {}, text(props.mob[index]?.name || 'Empty')), + ]); + }), + ]), + firstIncompleteGoal && h('div', { class: 'mb-2' }, [ + h('hr', { class: 'mb-2' }), + h('div', { class: 'text-xs leading-none uppercase text-slate-600' }, text('Current Goal')), + h('div', { class: '' }, [ + text(firstIncompleteGoal.text), + ]), + ]), + h('div', {}, [ + h('hr', { class: 'mb-2' }), + h('div', { class: 'text-xs uppercase text-slate-600' }, text('Turn Controls')), + h('div', { class: 'grid grid-cols-3' }, [ + h('button', { + type: 'button', + class: [ + 'mr-1 px-2 py-1 border border-slate-700', + props.timerStartedAt && 'bg-slate-200 text-black cursor-not-allowed', + ].filter(Boolean).join(' '), + disabled: props.timerStartedAt, + onclick: props.timerDuration + ? [actions.ResumeTimer, {}] + : [actions.StartTimer, { timerStartedAt: Date.now(), timerDuration: props.settings.duration }], + }, text('Start')), + h('button', { + type: 'button', + class: [ + 'mr-1 px-2 py-1 border border-slate-700', + !props.timerStartedAt && 'bg-slate-200 text-black cursor-not-allowed', + ].filter(Boolean).join(' '), + disabled: !props.timerStartedAt, + onclick: [actions.PauseTimer, undefined], + }, text('Pause')), + h('button', { + type: 'button', + class: [ + 'mr-1 px-2 py-1 border border-slate-700', + !props.timerDuration && 'bg-slate-200 text-black cursor-not-allowed', + ].join(' '), + disabled: !props.timerDuration, + onclick: [ + actions.Completed, + { + isEndOfTurn: true, + documentElement: document, + Notification: window.Notification, + }, + ], + }, text('Skip')), + ]), + ]), + ]); +}; diff --git a/public/sections/timeRemaining.js b/public/sections/timeRemaining.js index 3acc007..03c4441 100644 --- a/public/sections/timeRemaining.js +++ b/public/sections/timeRemaining.js @@ -1,13 +1,9 @@ import { h, text } from '/vendor/hyperapp.js'; - import { section } from '/components/section.js'; -import { button } from '/components/button.js'; -import { deleteButton } from '/components/deleteButton.js'; import { calculateTimeRemaining } from '/lib/calculateTimeRemaining.js'; import timerRemainingDisplay from '/formatTime.js'; -import * as actions from '/actions.js'; export const timeRemaining = props => { const isPaused = props.timerStartedAt === null; @@ -21,10 +17,6 @@ export const timeRemaining = props => { : 0; const pulse = (Math.floor(elapsed / 1000) % 2) === 0; - if (elapsed > 0) { - console.log({ elapsed, percent, duration: props.timerDuration, pulse }); - } - // border-t-slate-500 // border-r-slate-500 // border-b-slate-500 @@ -104,18 +96,18 @@ export const timeRemaining = props => { }, text(timerRemainingDisplay(remainingTime)), ), - remainingTime > 0 && - deleteButton({ - size: '24px', - onclick: () => [ - actions.Completed, - { - isEndOfTurn: false, - documentElement: document, - Notification: window.Notification, - }, - ], - }), + // remainingTime > 0 && + // deleteButton({ + // size: '24px', + // onclick: () => [ + // actions.Completed, + // { + // isEndOfTurn: false, + // documentElement: document, + // Notification: window.Notification, + // }, + // ], + // }), ], ), ], @@ -131,66 +123,66 @@ export const timeRemaining = props => { 'justify-center': true, }, }, - [ + // [ - // + // // - !props.timerDuration && - button( - { - class: { - 'bg-green-600': true, - 'text-white': true, - }, - onclick: () => [ - actions.StartTimer, - { - timerStartedAt: Date.now(), - timerDuration: props.settings.duration, - }, - ], - }, - [ - h('i', { - class: { - 'fas': true, - 'fa-play': true, - 'mr-4': true, - }, - }), - text(props.lang.timeRemaining.startTurn), - ], - ), + // !props.timerDuration && + // button( + // { + // class: { + // 'bg-green-600': true, + // 'text-white': true, + // }, + // onclick: () => [ + // actions.StartTimer, + // { + // timerStartedAt: Date.now(), + // timerDuration: props.settings.duration, + // }, + // ], + // }, + // [ + // h('i', { + // class: { + // 'fas': true, + // 'fa-play': true, + // 'mr-4': true, + // }, + // }), + // text(props.lang.timeRemaining.startTurn), + // ], + // ), - !!props.timerDuration && - button( - { - class: { - 'bg-white': true, - 'text-green-600': true, - }, - disabled: !props.timerDuration, - onclick: isPaused - ? [actions.ResumeTimer, undefined] - : [actions.PauseTimer, undefined], - }, - [ - h('i', { - class: { - 'fas': true, - 'fa-pause': !isPaused, - 'fa-play': isPaused, - 'mr-4': true, - }, - }), - text( - isPaused - ? props.lang.timeRemaining.resume - : props.lang.timeRemaining.pause, - ), - ], - ), - ], + // !!props.timerDuration && + // button( + // { + // class: { + // 'bg-white': true, + // 'text-green-600': true, + // }, + // disabled: !props.timerDuration, + // onclick: isPaused + // ? [actions.ResumeTimer, undefined] + // : [actions.PauseTimer, undefined], + // }, + // [ + // h('i', { + // class: { + // 'fas': true, + // 'fa-pause': !isPaused, + // 'fa-play': isPaused, + // 'mr-4': true, + // }, + // }), + // text( + // isPaused + // ? props.lang.timeRemaining.resume + // : props.lang.timeRemaining.pause, + // ), + // ], + // ), + // ], ), ]); }; diff --git a/public/sections/timerSettings.js b/public/sections/timerSettings.js index 1feb508..64f647f 100644 --- a/public/sections/timerSettings.js +++ b/public/sections/timerSettings.js @@ -27,36 +27,36 @@ export const timerSettings = props => rightAction: Object.keys(props.pendingSettings).length === 0 ? h('div', {}, [ - text(props.lang.settings.saved), - h('i', { class: 'fas fa-check text-green-500' }), - ]) + text(props.lang.settings.saved), + h('i', { class: 'fas fa-check text-green-500' }), + ]) : h('div', {}, [ - button( - { - class: { - 'bg-indigo-500': true, - 'hover:bg-indigo-400': true, - 'text-white': true, - 'mr-1': true, - }, - onclick: actions.PendingSettingsReset, + button( + { + class: { + 'bg-indigo-500': true, + 'hover:bg-indigo-400': true, + 'text-white': true, + 'mr-1': true, }, - text(props.lang.settings.cancel), - ), - button( - { - type: 'button', - class: { - 'bg-green-600': true, - 'hover:bg-green-500': true, - 'text-white': true, - }, - disable: Object.keys(props.pendingSettings).length === 0, - onclick: actions.UpdateSettings, + onclick: actions.PendingSettingsReset, + }, + text(props.lang.settings.cancel), + ), + button( + { + type: 'button', + class: { + 'bg-green-600': true, + 'hover:bg-green-500': true, + 'text-white': true, }, - text(props.lang.settings.save), - ), - ]), + disable: Object.keys(props.pendingSettings).length === 0, + onclick: actions.UpdateSettings, + }, + text(props.lang.settings.save), + ), + ]), }, text(props.lang.settings.sharedTimerSettings), ), @@ -133,4 +133,3 @@ export const timerSettings = props => ], ), ]); - diff --git a/public/sections/toasts.js b/public/sections/toasts.js index afc452b..244ab59 100644 --- a/public/sections/toasts.js +++ b/public/sections/toasts.js @@ -28,7 +28,7 @@ export const toast = ({ id, title, body, buttons }) => 'mt-2': true, 'pt-2': true, 'border-t': true, - flex: true, + 'flex': true, 'align-center': true, 'justify-start': true, }, @@ -93,7 +93,7 @@ export const toasts = props => 'absolute top-0 right-0 sm:right-20 pt-2 mx-2 flex flex-col align-center justify-end', style: { 'max-height': '50vh', - width: '300px', + 'width': '300px', }, }, [...props.toasts.map(toast)], From 581bf3e844e3e3880459818b02082a457cd8d4ad Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 19 Jun 2023 09:28:23 -0400 Subject: [PATCH 15/36] Linting --- public/components/badge.js | 2 +- public/components/button.js | 2 +- public/components/card.js | 4 ++-- public/components/checkbox.js | 4 ++-- public/components/column.js | 24 +++++++++++++++++++ public/components/deleteButton.js | 2 +- public/components/goal.js | 35 +--------------------------- public/components/grid.js | 10 +++++++- public/components/listButton.js | 2 +- public/components/mobber.js | 23 ++++++++++++------ public/components/overlay.js | 4 ++-- public/components/overviewHeading.js | 2 +- public/components/tab.js | 2 +- 13 files changed, 62 insertions(+), 54 deletions(-) create mode 100644 public/components/column.js diff --git a/public/components/badge.js b/public/components/badge.js index 61545b6..fca76ec 100644 --- a/public/components/badge.js +++ b/public/components/badge.js @@ -10,7 +10,7 @@ export const badge = (props, children) => 'text-gray-200': true, 'py-1': true, 'px-2': true, - rounded: true, + 'rounded': true, 'bg-green-600': true, }, }, diff --git a/public/components/button.js b/public/components/button.js index 8b4ecb1..9f7050c 100644 --- a/public/components/button.js +++ b/public/components/button.js @@ -9,7 +9,7 @@ export const button = (props, children) => class: { 'py-1': true, 'px-2': true, - uppercase: true, + 'uppercase': true, ...(props.class || {}), }, }, diff --git a/public/components/card.js b/public/components/card.js index 1e4aaaf..f0383e8 100644 --- a/public/components/card.js +++ b/public/components/card.js @@ -8,9 +8,9 @@ export const card = (props, children) => { { ...props, class: { - rounded: true, + 'rounded': true, 'overflow-hidden': true, - shadow: true, + 'shadow': true, 'pt-2': true, 'pb-1': true, ...(props.class || {}), diff --git a/public/components/checkbox.js b/public/components/checkbox.js index 6fc865e..40ff93f 100644 --- a/public/components/checkbox.js +++ b/public/components/checkbox.js @@ -5,7 +5,7 @@ export const checkbox = (props, children) => 'div', { class: { - flex: true, + 'flex': true, 'flex-row': true, 'items-center': true, 'justify-center': true, @@ -31,7 +31,7 @@ export const checkbox = (props, children) => class: { 'flex-grow': true, 'leading-tight': true, - flex: true, + 'flex': true, 'flex-row': true, 'items-center': true, }, diff --git a/public/components/column.js b/public/components/column.js new file mode 100644 index 0000000..ff42618 --- /dev/null +++ b/public/components/column.js @@ -0,0 +1,24 @@ +import { h } from '/vendor/hyperapp.js'; + +/* + * sm:col-span-1 + * sm:col-span-2 + * md:col-span-1 + * md:col-span-2 + */ + +export const column = (mobileSpan, breakpointSpans, children) => h( + 'div', + { + class: { + [`col-span-${mobileSpan}`]: mobileSpan > 1, + ...Object.keys(breakpointSpans).reduce((memo, breakpoint) => ({ + ...memo, + [`${breakpoint}:col-span-${breakpointSpans[breakpoint]}`]: true, + }), {}), + }, + }, + children, +); + +column.fixed = (span, children) => column(span, {}, children); diff --git a/public/components/deleteButton.js b/public/components/deleteButton.js index 350cf52..d05d606 100644 --- a/public/components/deleteButton.js +++ b/public/components/deleteButton.js @@ -15,7 +15,7 @@ export const deleteButton = props => [ h('i', { class: { - fas: true, + 'fas': true, 'fa-times': true, }, }), diff --git a/public/components/goal.js b/public/components/goal.js index 6671b14..199f3b1 100644 --- a/public/components/goal.js +++ b/public/components/goal.js @@ -32,46 +32,13 @@ export const goal = props => actions.CompleteGoal, { id: props.id, completed: e.target.checked }, ], - class: { - 'sr-only': true, - }, }), - h( - 'button', - { - disabled: props.id === null, - onclick: - props.id !== null - ? () => [ - actions.CompleteGoal, - { id: props.id, completed: !props.completed }, - ] - : undefined, - class: { - 'text-gray-500': props.id === null, - }, - }, - [ - h( - 'span', - { - class: { - 'fa-stack': true, - }, - }, - [ - h('i', { class: 'far fa-circle fa-stack-1x' }), - props.completed && - h('i', { class: 'fas fa-check fa-stack-1x text-green-500' }), - ], - ), - ], - ), h( 'label', { for: `goal-${props.id}`, class: { + 'ml-1': true, 'pr-1': true, 'flex-grow': true, 'leading-tight': true, diff --git a/public/components/grid.js b/public/components/grid.js index d9d9294..583dcb7 100644 --- a/public/components/grid.js +++ b/public/components/grid.js @@ -1,3 +1,11 @@ import { h } from '/vendor/hyperapp.js'; +import { classConcat } from '/lib/classConcat.js'; -export const grid = (children) => h('div', { class: 'grid px-2 md:px-0 grid-cols-1 md:grid-cols-2 container mx-auto gap-8' }, children); +export const grid = (props, children) => h( + 'div', + { + ...props, + class: classConcat('grid px-1 md:px-4 grid-cols-2 gap-6', props.class), + }, + children, +); diff --git a/public/components/listButton.js b/public/components/listButton.js index c556bf1..377b7ab 100644 --- a/public/components/listButton.js +++ b/public/components/listButton.js @@ -11,7 +11,7 @@ export const listButton = (props, children) => 'h-6': true, 'text-sm': true, 'flex-shrink-0': true, - flex: true, + 'flex': true, 'items-center': true, 'justify-center': true, ...(props.class || {}), diff --git a/public/components/mobber.js b/public/components/mobber.js index 76c6388..9d7de95 100644 --- a/public/components/mobber.js +++ b/public/components/mobber.js @@ -1,17 +1,16 @@ import { h, text } from '/vendor/hyperapp.js'; - -import { section } from '/components/section.js'; +import * as actions from '/actions.js'; export const mobber = props => h( 'div', { class: { - flex: true, + 'flex': true, 'flex-row': true, 'items-center': true, 'justify-between': true, - //'mb-1': true, + // 'mb-1': true, 'h-full': true, 'w-full': true, 'text-black': props.hasPosition, @@ -20,6 +19,8 @@ export const mobber = props => // 'dark:bg-indigo-800': props.position !== 'mob', 'py-1': true, 'pl-1': true, + 'outline': props.highlight, + 'outline-blue-300': true, }, }, [ @@ -27,15 +28,23 @@ export const mobber = props => 'div', { class: { - truncate: props.selected, + 'truncate': props.selected, + 'border-b': true, + 'border-dotted': true, + 'border-transparent': true, + 'hover:border-slate-400': props.name, + }, + ondblclick: (_props, _event) => { + return [actions.SetFormId, { form: 'mob', id: props.id, input: props.name }]; }, + title: 'Double click to edit', }, [ h( 'div', { class: { - uppercase: true, + 'uppercase': true, 'leading-none': true, 'mb-1': true, 'break-all': true, @@ -54,7 +63,7 @@ export const mobber = props => 'font-bold': props.hasPosition && props.name, 'leading-none': true, 'break-all': true, - truncate: props.selected, + 'truncate': props.selected, }, }, text(props.name || 'Empty'), diff --git a/public/components/overlay.js b/public/components/overlay.js index f2f04fb..3cce005 100644 --- a/public/components/overlay.js +++ b/public/components/overlay.js @@ -6,9 +6,9 @@ export const overlay = (props = {}, children) => { ...props, class: { - absolute: true, + 'absolute': true, 'inset-0': true, - flex: true, + 'flex': true, 'items-center': true, 'justify-center': true, 'z-40': true, diff --git a/public/components/overviewHeading.js b/public/components/overviewHeading.js index aa48237..ed73a0f 100644 --- a/public/components/overviewHeading.js +++ b/public/components/overviewHeading.js @@ -10,7 +10,7 @@ export const overviewHeading = (props, children) => 'px-1': true, 'mx-5': true, 'pt-3': true, - flex: true, + 'flex': true, 'flex-row': true, 'items-end': true, 'justify-between': true, diff --git a/public/components/tab.js b/public/components/tab.js index 2f5e981..b96350a 100644 --- a/public/components/tab.js +++ b/public/components/tab.js @@ -16,7 +16,7 @@ export const tab = (props, children) => 'py-1': true, 'px-3': true, 'flex-grow': true, - flex: true, + 'flex': true, 'flex-row': true, 'items-center': true, 'justify-between': true, From fedc46f4a6fa65e4cbd4a279b82a836c86316169 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 19 Jun 2023 09:28:42 -0400 Subject: [PATCH 16/36] Use new TimeComplete action to tell server the timer is done --- public/subscriptions.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/public/subscriptions.js b/public/subscriptions.js index c56f6b0..b87d172 100644 --- a/public/subscriptions.js +++ b/public/subscriptions.js @@ -21,11 +21,7 @@ const TimerFX = (dispatch, { timerStartedAt, timerDuration, actions }) => { if (elapsed >= timerDuration) { cleanup(); - dispatch(actions.Completed, { - isEndOfTurn: true, - documentElement: document, - Notification: window.Notification, - }); + dispatch(actions.TimeComplete, {}); return; } From 231f4100f51a230142de9c36ab41f7577fad9709 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 19 Jun 2023 09:29:02 -0400 Subject: [PATCH 17/36] No more fontawesome import --- public/timer.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/public/timer.html b/public/timer.html index 6730486..7668982 100644 --- a/public/timer.html +++ b/public/timer.html @@ -12,10 +12,6 @@ - From 820645067cf7ea88183028f88d21f9539f1d07cb Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 19 Jun 2023 09:29:15 -0400 Subject: [PATCH 18/36] New grid+details ui --- public/timer.js | 108 +++++++++++++++++++----------------------------- 1 file changed, 43 insertions(+), 65 deletions(-) diff --git a/public/timer.js b/public/timer.js index dea9b0a..0b89639 100644 --- a/public/timer.js +++ b/public/timer.js @@ -1,17 +1,14 @@ import * as actions from '/actions.js'; -import { card } from '/components/card.js'; -import { appPrompt } from '/components/prompt.js'; import { grid } from '/components/grid.js'; +import { column } from '/components/column.js'; import { mob } from '/tabs/mob.js'; import { goals } from '/tabs/goals.js'; -import { settings } from '/tabs/settings.js'; -import { qrShare } from '/tabs/qrShare.js'; import { header } from '/sections/header.js'; import { timeRemaining } from '/sections/timeRemaining.js'; -import { timeSection } from '/sections/timeSection.js'; -import { toasts } from '/sections/toasts.js'; +import { summary } from '/sections/summary.js'; +import { localSettings } from '/tabs/localSettings.js'; +import { timerSettings } from '/tabs/timerSettings.js'; import * as subscriptions from '/subscriptions.js'; -import { drawer } from '/components/drawer.js'; import { app, h, text, memo } from '/vendor/hyperapp.js'; import * as Emitter from '/lib/emitter.js'; @@ -33,6 +30,7 @@ app({ init: actions.Init(null, { timerId: initialTimerId, externals: { + fetch: window.fetch, documentElement: window.document, Notification: window.Notification, storage: window.localStorage, @@ -44,70 +42,50 @@ app({ dark: 'dark' in flags, }), - view: state => + view: state => grid({ class: 'relative pb-12' }, [ + column.fixed(2, header(state)), + h('div', { class: 'flex flex-row items-center justify-center' }, [ + timeRemaining(state), + ]), + summary(state), + column.fixed(2, [ + h('details', {}, [ + h('summary', { class: 'text-xs text-slate-500' }, [ + text('Your Session'), + ]), + grid({}, [ + column(2, { sm: 1 }, mob(state)), + column(2, { sm: 1 }, goals(state)), + ]), + ]), + ]), + column.fixed(2, [ + h('details', {}, [ + h('summary', { class: 'text-xs text-slate-500' }, [ + text('Advanced Settings'), + ]), + grid({}, [ + column(2, { sm: 1 }, memo(localSettings, stateWithoutFrequentChanges(state))), + column(2, { sm: 1 }, memo(timerSettings, stateWithoutFrequentChanges(state))), + ]), + ]), + ]), + h( - 'div', + 'audio', { - class: { - 'relative': true, - 'w-full': true, - 'min-h-screen': true, - }, + preload: 'auto', + id: 'timer-complete', + key: state.sound, }, [ - h( - 'div', - { - class: { - 'container': true, - 'mx-auto': true, - 'flex': true, - 'flex-col': true, - 'items-center': true, - 'justify-start': true, - 'min-h-screen': true, - 'w-full': true, - }, - }, - [ - grid([ - header(state), - timeRemaining(state), - timeSection(state), - mob(state), - goals(state), - // h('details', {}, [ - // h('summary', {}, text('Configure your timer')), - // settings(state), - // ]), - // h('details', {}, [ - // h('summary', {}, text('Share timer via QR Code')), - // qrShare(state), - // ]), - ]), - - h( - 'audio', - { - preload: 'auto', - id: 'timer-complete', - key: state.sound, - }, - [ - h('source', { - src: `/audio/${state.sound}.wav`, - type: 'audio/wav', - }), - ], - ), - - state.prompt.visible && appPrompt(state.prompt || {}), - ], - ), - state.showDrawer && memo(drawer, stateWithoutFrequentChanges(state)), - toasts(state), + h('source', { + src: `/audio/${state.sound}.wav`, + type: 'audio/wav', + }), ], ), + ]), subscriptions: state => { const { timerId, drag, websocketConnect, externals } = state; From 57ce6844db4a905994a2c0a4340b6289b6b1fa03 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 19 Jun 2023 15:25:39 -0400 Subject: [PATCH 19/36] Edit goals with the new forms.goal state --- public/actions.js | 14 +++++++---- public/components/goal.js | 28 ++++++++++++++++++---- public/effects.js | 9 +++++-- public/sections/goalList.js | 1 + public/tabs/goals.js | 47 +++++++++++++++++++++++++++---------- src/web/actions.js | 9 +++++-- src/web/http.js | 7 ++++-- 7 files changed, 87 insertions(+), 28 deletions(-) diff --git a/public/actions.js b/public/actions.js index 077aa0f..d6c99b5 100644 --- a/public/actions.js +++ b/public/actions.js @@ -58,7 +58,7 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ id: '', input: '', }, - goals: { + goal: { open: false, valid: true, id: '', @@ -336,6 +336,10 @@ export const TimeComplete = (state) => { timerId: state.timerId, completeToken: state.completeToken, fetch: state.externals.fetch, + onSuccess: { + action: CycleMob, + props: {}, + }, }), effects.UpdateTitleWithTime({ remainingTime: 0, @@ -1035,10 +1039,10 @@ export const UpdateByWebsocketData = (state, { payload }) => { action: EndTurn, props: {}, }), - effects.andThen({ - action: CycleMob, - props: {}, - }), + // effects.andThen({ + // action: CycleMob, + // props: {}, + // }), ]; case 'goals:update': diff --git a/public/components/goal.js b/public/components/goal.js index 199f3b1..2c52715 100644 --- a/public/components/goal.js +++ b/public/components/goal.js @@ -8,8 +8,15 @@ const textWithBreaks = goalText => .reduce((result, t) => [...result, text(t), h('br', {})], []) .slice(0, -1); -export const goal = props => - h( +const indentRegex = () => /^[- ]+/; +const shouldIndent = (text) => indentRegex().test(text); +const normalizeText = (text) => text.replace(indentRegex(), ''); + +export const goal = props => { + const indent = shouldIndent(props.text); + const text = normalizeText(props.text); + + return h( 'div', { class: { @@ -21,6 +28,9 @@ export const goal = props => 'w-full': true, 'break-words': true, 'truncate': props.truncate, + 'outline': props.highlight, + 'outline-blue-300': true, + 'ml-6': indent, }, }, [ @@ -36,9 +46,9 @@ export const goal = props => h( 'label', { - for: `goal-${props.id}`, + // for: `goal-${props.id}`, class: { - 'ml-1': true, + 'ml-2': true, 'pr-1': true, 'flex-grow': true, 'leading-tight': true, @@ -46,9 +56,17 @@ export const goal = props => 'break-words': true, 'truncate': props.truncate, 'block': true, + 'border-b': true, + 'border-dotted': true, + 'border-transparent': true, + 'hover:border-slate-400': props.id, + }, + ondblclick: (_props, _event) => { + return [actions.SetFormId, { form: 'goal', id: props.id, input: props.text }]; }, }, - textWithBreaks(props.text), + textWithBreaks(text || ''), ), ], ); +}; diff --git a/public/effects.js b/public/effects.js index eac8abc..a99ca0c 100644 --- a/public/effects.js +++ b/public/effects.js @@ -263,10 +263,15 @@ export const apiTimerPause = fx(function ApiTimerPause ( }); export const apiTimerComplete = fx(function CompleteTimer ( - _dispatch, - { timerId, completeToken, fetch: fetchFn }, + dispatch, + { timerId, completeToken, fetch: fetchFn, onSuccess }, ) { timerApi(fetchFn, timerId, '/complete', { token: completeToken }) + .then((response) => { + return response.ok && onSuccess + ? dispatch(onSuccess.action, onSuccess.props) + : null; + }) .catch((err) => { console.error('Unable to complete timer', { timerId, completeToken }, err); }); diff --git a/public/sections/goalList.js b/public/sections/goalList.js index 9f6a622..ba556c9 100644 --- a/public/sections/goalList.js +++ b/public/sections/goalList.js @@ -36,6 +36,7 @@ export const goalList = props => { renderItem: item => goal({ ...item, + highlight: props.forms.goal.id === item.id, truncate: getReorderableId(item) === props.expandedReorderable, }), drag: props.drag, diff --git a/public/tabs/goals.js b/public/tabs/goals.js index 964a087..6469533 100644 --- a/public/tabs/goals.js +++ b/public/tabs/goals.js @@ -2,8 +2,10 @@ import { goalList } from '/sections/goalList.js'; import { h, text } from '/vendor/hyperapp.js'; import * as actions from '/actions.js'; -export const goals = props => - h('div', {}, [ +export const goals = props => { + const isEdittingGoal = props.forms.goal.id && props.goals.some(g => g.id == props.forms.goal.id); + + return h('div', {}, [ h('header', { class: 'flex justify-start items-center border-b border-gray-400 mb-2' }, [ h('h1', { class: 'text-lg font-bold flex-grow' }, text('Goals')), h('button', { class: 'ml-2 dark:text-white text-black underline' }, text('Clear Completed')), @@ -14,6 +16,7 @@ export const goals = props => drag: props.drag.type === 'goal' ? props.drag : {}, goals: props.goals, lang: props.lang, + forms: props.forms, }), h('form', { @@ -21,20 +24,40 @@ export const goals = props => method: 'get', onsubmit: (_, e) => { e.preventDefault(); - return [actions.AddGoals, props.goal]; + const formData = new FormData(e.target); + switch (e.submitter.value) { + case 'update': + return [actions.RenameGoal, { id: formData.get('id'), value: formData.get('text') }]; + case 'remove': + return [actions.RemoveGoal, formData.get('id')]; + case 'add': + return [actions.AddGoals, formData.get('text')]; + } }, }, [ - h('details', {}, [ + h('input', { type: 'hidden', name: 'id', value: props.forms.goal.id }), + h('details', { open: props.forms.goal.open, toggle: (_, event) => [actions.OpenForm, { form: 'goal', open: event.target.open }] }, [ h('summary', { class: 'text-slate-500 text-xs' }, text('Show goal form')), - h('label', { class: 'mt-3 uppercase leading-none mb-1 text-xs block' }, text('Add goal')), - h('input', { - type: 'text', - class: 'bg-transparent border-b border-b-white w-full', - placeholder: 'Name', - value: props.goal, - oninput: (_, e) => [actions.UpdateGoalText, e.target.value], - }), + h('div', { class: 'flex items-end justify-items-start' }, [ + h('fieldset', { class: 'flex-grow' }, [ + h('label', { class: 'mt-3 uppercase leading-none mb-1 text-xs block' }, text('team member')), + h('input', { + type: 'text', + class: 'bg-transparent border-b border-b-white w-full', + placeholder: 'A great day would be....', + name: 'text', + value: props.forms.goal.input, + required: true, + oninput: (_, e) => [actions.SetFormInput, { form: 'goal', input: e.target.value }], + }), + ]), + !isEdittingGoal && h('button', { type: 'submit', name: 'action', value: 'add', class: 'ml-1 px-2 py-1 border border-slate-700' }, text('Add')), + isEdittingGoal && h('button', { type: 'submit', name: 'action', value: 'update', class: 'ml-1 px-2 py-1 border border-slate-700' }, text('Update')), + isEdittingGoal && h('button', { type: 'submit', name: 'action', value: 'remove', class: 'ml-1 px-2 py-1 border border-slate-700' }, text('Remove')), + isEdittingGoal && h('button', { type: 'button', name: 'action', value: 'cancel', class: 'ml-1 px-2 py-1 border border-slate-700', onclick: () => [actions.SetFormId, { form: 'mob', id: '' }] }, text('Cancel')), + ]), ]), ]), ]); +}; diff --git a/src/web/actions.js b/src/web/actions.js index 6eab3d3..e524c90 100644 --- a/src/web/actions.js +++ b/src/web/actions.js @@ -5,7 +5,7 @@ import * as Connection from './connection.js'; import { id, GenerateIdEffect } from './id.js'; import { composable, select, selectArray, replace } from 'composable-state'; -const { none, act, batch, defer } = effects; +const { none, act, batch, defer, thunk } = effects; const defaultStatistics = { connections: 0, @@ -160,8 +160,9 @@ export const UpdateTimer = (timerId, message) => state => { ]; }; -export const CompleteTimer = (timerId, token) => state => { +export const CompleteTimer = (timerId, token, statusCallback) => state => { if (state.completeTokens[timerId] !== token) { + statusCallback(false); return [state, none()]; } @@ -171,6 +172,10 @@ export const CompleteTimer = (timerId, token) => state => { // defer(state.queue.publishToTimer(timerId, JSON.stringify({ type: 'timer:complete' })).then(none)), act(RemoveCompleteToken(timerId)), act(UpdateTimer(timerId, JSON.stringify({ type: 'timer:complete' }))), + thunk(() => { + statusCallback(true); + return none(); + }), ]), ]; }; diff --git a/src/web/http.js b/src/web/http.js index d723da1..338b88e 100644 --- a/src/web/http.js +++ b/src/web/http.js @@ -92,8 +92,11 @@ const HttpSub = (dispatch, action, host = 'localhost', port = 4321) => { const { timerId } = request.params; const { token } = request.body; - await dispatch(action.CompleteTimer(timerId, token), 'CompleteTimer'); - return response.status(202).json({}); + const responder = (success) => { + return response.status(success ? 202 : 410).json({}); + }; + + await dispatch(action.CompleteTimer(timerId, token, responder), 'CompleteTimer'); }); app.post('/:timerId/timer/settings', async (request, response) => { From 42eaa595e7f0063ac117a712b74a5087adcd3901 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Tue, 20 Jun 2023 12:05:19 -0400 Subject: [PATCH 20/36] More initial messages before considering the timer 'loaded' --- public/actions.js | 161 +++++++++++++++++++++++++++++++++++---------- public/timer.js | 87 +++++++++++++----------- src/web/actions.js | 4 ++ 3 files changed, 177 insertions(+), 75 deletions(-) diff --git a/public/actions.js b/public/actions.js index d6c99b5..2056f1c 100644 --- a/public/actions.js +++ b/public/actions.js @@ -51,6 +51,11 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ mobOrder: defaults.timerMobOrder, duration: defaults.timerDuration, }, + loading: { + total: 5, + messages: ['settings:update', 'mob:update', 'goals:update', 'timer:update', 'connections:update'], + isFirstConnection: false, + }, forms: { mob: { open: false, @@ -77,6 +82,14 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ input: defaults.timerMobOrder, }, }, + details: { + summary: false, + mobForm: false, + goalForm: false, + advancedSettings: false, + localSettings: false, + timerSettings: false, + }, expandedReorderable: null, timerTab: 'overview', drag: { ...emptyDrag }, @@ -116,6 +129,23 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ }), ]; +export const DetailsToggle = (state, { which, open }) => ({ + ...state, + details: { + ...state.details, + [which]: Boolean(open), + }, +}); + +export const FirstConnection = state => ({ + ...state, + details: { + ...state.details, + summary: true, + advancedSettings: true, + }, +}); + export const SetFormId = (state, { form, id, input }) => ({ ...state, forms: { @@ -995,42 +1025,93 @@ export const RevertSettings = state => { }; }; +export const LoadingMessagesPop = (state, { type, ...others }) => { + const messages = state.loading.messages.filter(m => m !== type); + const first = type === 'connections:update' + ? { isFirstConnection: others.count === 1 } + : {}; + + const loading = { + ...state.loading, + ...first, + messages, + }; + + return [ + { + ...state, + loading, + }, + messages.length === 0 && effects.andThen({ + action: RevertSettings, + props: {}, + }), + messages.length === 0 && loading.isFirstConnection && effects.andThen({ + action: FirstConnection, + props: {}, + }), + ]; +}; + export const UpdateByWebsocketData = (state, { payload }) => { const { type, ...data } = payload; console.log('UpdateByWebsocketData', payload); switch (type) { + case 'connections:update': + return [ + state, + state.loading.messages.length > 0 && effects.andThen({ + action: LoadingMessagesPop, + props: payload, + }), + ]; case 'settings:update': - console.log('--', { old: state.settings, new: data.settings }); - return { - ...state, - settings: { - ...state.settings, - ...data.settings, + return [ + { + ...state, + settings: { + ...state.settings, + ...data.settings, + }, }, - }; + state.loading.messages.length > 0 && effects.andThen({ + action: LoadingMessagesPop, + props: { type }, + }), + ]; case 'timer:start': - return { - ...state, - timerStartedAt: Date.now(), - timerDuration: data.timerDuration, - completeToken: data.completeToken, - }; + return [ + { + ...state, + timerStartedAt: Date.now(), + timerDuration: data.timerDuration, + completeToken: data.completeToken, + }, + ]; case 'timer:pause': - return { - ...state, - timerStartedAt: null, - timerDuration: data.timerDuration, - }; + return [ + { + ...state, + timerStartedAt: null, + timerDuration: data.timerDuration, + }, + ]; case 'timer:update': - return { - ...state, - timerStartedAt: data.timerStartedAt, - timerDuration: data.timerDuration, - completeToken: data.completeToken, - }; + return [ + { + ...state, + timerStartedAt: data.timerStartedAt, + timerDuration: data.timerDuration, + completeToken: data.completeToken, + }, + state.loading.messages.length > 0 && effects.andThen({ + action: LoadingMessagesPop, + props: { type }, + }), + ]; case 'timer:complete': return [ @@ -1039,23 +1120,31 @@ export const UpdateByWebsocketData = (state, { payload }) => { action: EndTurn, props: {}, }), - // effects.andThen({ - // action: CycleMob, - // props: {}, - // }), ]; case 'goals:update': - return { - ...state, - goals: data.goals, - }; + return [ + { + ...state, + goals: data.goals, + }, + state.loading.messages.length > 0 && effects.andThen({ + action: LoadingMessagesPop, + props: { type }, + }), + ]; case 'mob:update': - return { - ...state, - mob: data.mob, - }; + return [ + { + ...state, + mob: data.mob, + }, + state.loading.messages.length > 0 && effects.andThen({ + action: LoadingMessagesPop, + props: { type }, + }), + ]; default: // console.warn('Unknown websocket data', payload); // eslint-disable-line no-console diff --git a/public/timer.js b/public/timer.js index 0b89639..7a083b5 100644 --- a/public/timer.js +++ b/public/timer.js @@ -42,50 +42,59 @@ app({ dark: 'dark' in flags, }), - view: state => grid({ class: 'relative pb-12' }, [ - column.fixed(2, header(state)), - h('div', { class: 'flex flex-row items-center justify-center' }, [ - timeRemaining(state), - ]), - summary(state), - column.fixed(2, [ - h('details', {}, [ - h('summary', { class: 'text-xs text-slate-500' }, [ - text('Your Session'), - ]), - grid({}, [ - column(2, { sm: 1 }, mob(state)), - column(2, { sm: 1 }, goals(state)), - ]), + view: state => { + const loadingPercent = (state.loading.total - state.loading.messages.length); + const isLoading = loadingPercent < state.loading.total; + + return grid({ class: 'relative pb-12' }, [ + h('div', {}, text(state.loading.messages.join(', '))), + column.fixed(2, header(state)), + h('div', { class: 'flex flex-row items-center justify-center' }, [ + timeRemaining(state), ]), - ]), - column.fixed(2, [ - h('details', {}, [ - h('summary', { class: 'text-xs text-slate-500' }, [ - text('Advanced Settings'), + summary(state), + isLoading && column.fixed(2, [ + h('progress', { max: 4, value: loadingPercent, class: 'w-full', style: { height: '2px' } }), + ]), + !isLoading && column.fixed(2, [ + h('details', { open: state.details.summary, ontoggle: (_, event) => [actions.DetailsToggle, { which: 'summary', open: event.target.open }] }, [ + h('summary', { class: 'text-xs text-slate-500' }, [ + text('Your Session'), + ]), + grid({}, [ + column(2, { sm: 1 }, mob(state)), + column(2, { sm: 1 }, goals(state)), + ]), ]), - grid({}, [ - column(2, { sm: 1 }, memo(localSettings, stateWithoutFrequentChanges(state))), - column(2, { sm: 1 }, memo(timerSettings, stateWithoutFrequentChanges(state))), + ]), + !isLoading && column.fixed(2, [ + h('details', { open: state.details.advancedSettings, ontoggle: (_, event) => [actions.DetailsToggle, { which: 'advancedSettings', open: event.target.open }] }, [ + h('summary', { class: 'text-xs text-slate-500' }, [ + text('Advanced Settings'), + ]), + grid({}, [ + column(2, { sm: 1 }, memo(localSettings, stateWithoutFrequentChanges(state))), + column(2, { sm: 1 }, memo(timerSettings, stateWithoutFrequentChanges(state))), + ]), ]), ]), - ]), - h( - 'audio', - { - preload: 'auto', - id: 'timer-complete', - key: state.sound, - }, - [ - h('source', { - src: `/audio/${state.sound}.wav`, - type: 'audio/wav', - }), - ], - ), - ]), + h( + 'audio', + { + preload: 'auto', + id: 'timer-complete', + key: state.sound, + }, + [ + h('source', { + src: `/audio/${state.sound}.wav`, + type: 'audio/wav', + }), + ], + ), + ]); + }, subscriptions: state => { const { timerId, drag, websocketConnect, externals } = state; diff --git a/src/web/actions.js b/src/web/actions.js index e524c90..67c9afb 100644 --- a/src/web/actions.js +++ b/src/web/actions.js @@ -243,6 +243,10 @@ export const ShareTimerWith = (connection, timerId) => state => [ sync('mob'), sync('goals'), sync('timer', timerData), + sync('connections', { + type: 'connections:update', + count: state.connections[timerId].length, + }), ]); }), ), From ce6675bbf3db5ef4c468eb8a22cb25f1e15b53bd Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Tue, 20 Jun 2023 12:05:34 -0400 Subject: [PATCH 21/36] Guard andThen effect from bad actions --- public/effects.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/effects.js b/public/effects.js index a99ca0c..b062e07 100644 --- a/public/effects.js +++ b/public/effects.js @@ -135,7 +135,11 @@ export const UpdateTitleWithTime = fx(function UpdateTitleWithTimeFX ( remainingTime > 0 ? `${formatTime(remainingTime)} - mobtime` : 'mobtime'; }); -export const andThen = fx(function andThenFX (dispatch, { action, props, delay }) { +export const andThen = fx(function andThenFX (dispatch, { action, props, delay, ...otherProps }) { + if (!action) { + console.error('Unable to chain action using andThen', { action, props, delay, otherProps }); + return; + } setTimeout(() => { dispatch(action, props); }, delay || 0); From 195a20c864278f65549f4e816ea308f530b10fab Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Tue, 20 Jun 2023 12:06:09 -0400 Subject: [PATCH 22/36] Wire up revert settings button --- public/tabs/timerSettings.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/tabs/timerSettings.js b/public/tabs/timerSettings.js index 5950bce..9b381d2 100644 --- a/public/tabs/timerSettings.js +++ b/public/tabs/timerSettings.js @@ -31,6 +31,7 @@ export const timerSettings = (props) => { h('h1', { class: 'text-lg font-bold flex-grow' }, text('Timer settings')), isDirty && h('button', { type: 'button', + onclick: [actions.RevertSettings, {}], }, text('Revert Changes')), ]), h( From 4a301e4f3496c24fe886cf2ae5a184eb6f2de6e8 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Wed, 21 Jun 2023 09:14:03 -0400 Subject: [PATCH 23/36] Kill dead websockets --- public/subscriptions.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/subscriptions.js b/public/subscriptions.js index b87d172..d796e4f 100644 --- a/public/subscriptions.js +++ b/public/subscriptions.js @@ -40,7 +40,7 @@ const WebsocketFX = (dispatch, { timerId, externals, actions }) => { const protocol = externals.location.protocol === 'https:' ? 'wss' : 'ws'; const websocketAddress = `${protocol}://${externals.location.hostname}:${externals.location.port}/${timerId}`; - const socket = new WebSocket(websocketAddress); + let socket = new WebSocket(websocketAddress); let hasError = false; socket.addEventListener('message', event => { @@ -76,6 +76,7 @@ const WebsocketFX = (dispatch, { timerId, externals, actions }) => { return () => { cancel(); socket.close(); + socket = null; }; }; export const Websocket = props => [WebsocketFX, props]; From 86448b42122adf8cf3fed38f1664b5cc4051afb1 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Wed, 21 Jun 2023 09:14:22 -0400 Subject: [PATCH 24/36] Only show clear completed when there are incomplete goals --- public/tabs/goals.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/tabs/goals.js b/public/tabs/goals.js index 6469533..91f1606 100644 --- a/public/tabs/goals.js +++ b/public/tabs/goals.js @@ -4,11 +4,12 @@ import * as actions from '/actions.js'; export const goals = props => { const isEdittingGoal = props.forms.goal.id && props.goals.some(g => g.id == props.forms.goal.id); + const anyGoalsIncomplete = props.goals.some(g => !g.completed); return h('div', {}, [ h('header', { class: 'flex justify-start items-center border-b border-gray-400 mb-2' }, [ h('h1', { class: 'text-lg font-bold flex-grow' }, text('Goals')), - h('button', { class: 'ml-2 dark:text-white text-black underline' }, text('Clear Completed')), + anyGoalsIncomplete && h('button', { class: 'ml-2 dark:text-white text-black underline' }, text('Clear Completed')), ]), goalList({ From a5af80b9b88c0b6c92b7614321a95b7a95a0897d Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Wed, 21 Jun 2023 09:24:06 -0400 Subject: [PATCH 25/36] Bandaid firefox layout bug with dummy script https://stackoverflow.com/questions/21147149/flash-of-unstyled-content-fouc-in-firefox-only-is-ff-slow-renderer --- public/tabs/goals.js | 3 +++ public/timer.html | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/public/tabs/goals.js b/public/tabs/goals.js index 91f1606..e8f18a2 100644 --- a/public/tabs/goals.js +++ b/public/tabs/goals.js @@ -51,6 +51,9 @@ export const goals = props => { value: props.forms.goal.input, required: true, oninput: (_, e) => [actions.SetFormInput, { form: 'goal', input: e.target.value }], + onkeydown: (_, e) => { + console.log(e.which, e.key); + }, }), ]), !isEdittingGoal && h('button', { type: 'submit', name: 'action', value: 'add', class: 'ml-1 px-2 py-1 border border-slate-700' }, text('Add')), diff --git a/public/timer.html b/public/timer.html index 7668982..20aea28 100644 --- a/public/timer.html +++ b/public/timer.html @@ -4,6 +4,7 @@ Mob Timer + - - +
+ From 408933a0838e5135a1caeae86c98af4526adadc2 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Fri, 23 Jun 2023 17:03:13 -0400 Subject: [PATCH 26/36] Settings are all wired up --- public/actions.js | 6 +- public/components/checkbox.js | 62 +++----------------- public/components/goal.js | 7 ++- public/tabs/goals.js | 14 ++++- public/tabs/localSettings.js | 23 ++------ public/tabs/{settings.js => settings.js.old} | 0 public/tabs/timerSettings.js | 35 ++++++++--- public/timer.js | 21 ++++--- 8 files changed, 72 insertions(+), 96 deletions(-) rename public/tabs/{settings.js => settings.js.old} (100%) diff --git a/public/actions.js b/public/actions.js index 2056f1c..e04a916 100644 --- a/public/actions.js +++ b/public/actions.js @@ -75,7 +75,7 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ id: '', input: formatTime(defaults.timerDuration), }, - timerMobOrder: { + mobOrder: { open: false, valid: true, id: '', @@ -1021,6 +1021,10 @@ export const RevertSettings = state => { ...state.forms.timerDuration, input: formatTime(state.settings.duration), }, + mobOrder: { + ...state.forms.mobOrder, + input: state.settings.mobOrder, + }, }, }; }; diff --git a/public/components/checkbox.js b/public/components/checkbox.js index 40ff93f..6cded38 100644 --- a/public/components/checkbox.js +++ b/public/components/checkbox.js @@ -1,57 +1,9 @@ import { h } from '../vendor/hyperapp.js'; +import { classConcat } from '../lib/classConcat.js'; -export const checkbox = (props, children) => - h( - 'div', - { - class: { - 'flex': true, - 'flex-row': true, - 'items-center': true, - 'justify-center': true, - 'justify-between': true, - }, - }, - [ - h('input', { - ...props.inputProps, - id: props.id, - type: 'checkbox', - checked: props.checked, - class: { - 'mr-3': true, - 'sr-only': true, - }, - }), - children && - h( - 'label', - { - for: props.id, - class: { - 'flex-grow': true, - 'leading-tight': true, - 'flex': true, - 'flex-row': true, - 'items-center': true, - }, - }, - [ - h( - 'span', - { - class: { - 'fa-stack': true, - }, - }, - [ - h('i', { class: 'far fa-circle fa-stack-1x' }), - props.checked && - h('i', { class: 'fas fa-check fa-stack-1x text-green-500' }), - ], - ), - ...(Array.isArray(children) ? children : [children]), - ], - ), - ], - ); +export const checkbox = (props) => + h('input', { + ...props, + type: 'checkbox', + class: classConcat('grow-0 shrink-0 block w-6 h-6', props.class || ''), + }); diff --git a/public/components/goal.js b/public/components/goal.js index 2c52715..be91374 100644 --- a/public/components/goal.js +++ b/public/components/goal.js @@ -1,5 +1,7 @@ import { h, text } from '/vendor/hyperapp.js'; +import { checkbox } from '/components/checkbox.js'; + import * as actions from '/actions.js'; const textWithBreaks = goalText => @@ -21,7 +23,6 @@ export const goal = props => { { class: { 'flex': true, - 'flex-row': true, 'items-center': true, 'justify-between': true, 'mb-2': true, @@ -34,10 +35,10 @@ export const goal = props => { }, }, [ - h('input', { + checkbox({ id: `goal-${props.id}`, - type: 'checkbox', checked: props.completed, + disabled: !props.id, onchange: (_, e) => [ actions.CompleteGoal, { id: props.id, completed: e.target.checked }, diff --git a/public/tabs/goals.js b/public/tabs/goals.js index e8f18a2..f05c3ee 100644 --- a/public/tabs/goals.js +++ b/public/tabs/goals.js @@ -42,17 +42,25 @@ export const goals = props => { h('div', { class: 'flex items-end justify-items-start' }, [ h('fieldset', { class: 'flex-grow' }, [ - h('label', { class: 'mt-3 uppercase leading-none mb-1 text-xs block' }, text('team member')), + h('label', { class: 'mt-3 uppercase leading-none mb-1 text-xs block' }, text('A good day would be...')), h('input', { type: 'text', class: 'bg-transparent border-b border-b-white w-full', - placeholder: 'A great day would be....', + placeholder: 'Finish feature X', name: 'text', value: props.forms.goal.input, required: true, oninput: (_, e) => [actions.SetFormInput, { form: 'goal', input: e.target.value }], onkeydown: (_, e) => { - console.log(e.which, e.key); + if (e.key === 'Enter' && !isEdittingGoal) { + e.preventDefault(); + return [actions.AddGoals, e.target.value]; + } + if (e.key === 'Enter' && isEdittingGoal) { + e.preventDefault(); + return [actions.RenameGoal, { id: props.forms.goal.id, value: e.target.value }]; + } + return [s => s]; }, }), ]), diff --git a/public/tabs/localSettings.js b/public/tabs/localSettings.js index 4523dbf..a1d0786 100644 --- a/public/tabs/localSettings.js +++ b/public/tabs/localSettings.js @@ -1,5 +1,7 @@ import { h, text } from '/vendor/hyperapp.js'; +import { checkbox } from '/components/checkbox.js'; + import * as actions from '/actions.js'; const audioFiles = [ @@ -15,29 +17,18 @@ export const localSettings = (props) => { return h('div', {}, [ h('header', { class: 'flex justify-start items-center border-b border-gray-400 mb-2' }, [ h('h1', { class: 'text-lg font-bold flex-grow' }, text('Local settings')), - // h('button', { - // type: 'button', - // class: 'ml-2 dark:text-white text-black underline', - // onclick: actions.ShuffleMob, - // }, text('Shuffle')), - // h('button', { - // type: 'button', - // class: 'ml-2 dark:text-white text-black underline', - // onclick: actions.CycleMob, - // }, text('Rotate')), ]), h( 'div', { class: 'grid gap-2', style: { - 'grid-template-columns': '3fr 1fr', + 'grid-template-columns': '1fr 26px', }, }, [ h('div', {}, text('Dark mode')), - h('input', { - type: 'checkbox', + checkbox({ checked: props.dark, oninput: (_, e) => [actions.SetDark, { dark: e.target.checked }], }), @@ -46,8 +37,7 @@ export const localSettings = (props) => { text('Notifications'), h('button', { type: 'button', class: 'px-2', onclick: () => [actions.TestNotification, {}] }, text('Test')), ]), - h('input', { - type: 'checkbox', + checkbox({ checked: props.allowNotification, oninput: (_, e) => ( e.target.checked @@ -72,8 +62,7 @@ export const localSettings = (props) => { ]), h('button', { type: 'button', class: 'px-2', onclick: [actions.TestSound, undefined] }, text('Test')), ]), - h('input', { - type: 'checkbox', + checkbox({ checked: props.allowSound, oninput: (_, e) => [actions.SetAllowSound, e.target.checked], }), diff --git a/public/tabs/settings.js b/public/tabs/settings.js.old similarity index 100% rename from public/tabs/settings.js rename to public/tabs/settings.js.old diff --git a/public/tabs/timerSettings.js b/public/tabs/timerSettings.js index 9b381d2..5eb280c 100644 --- a/public/tabs/timerSettings.js +++ b/public/tabs/timerSettings.js @@ -7,23 +7,20 @@ import * as actions from '/actions.js'; export const timerSettings = (props) => { const isDirty = ( - props.settings.duration !== formattedTimeToMilliseconds(props.forms.timerDuration.input) + props.settings.duration !== formattedTimeToMilliseconds(props.forms.timerDuration.input) || + props.settings.mobOrder !== props.forms.mobOrder.input ); return h('form', { onsubmit: (_, event) => { event.preventDefault(); - if (!event.target.reportValidity()) { - console.log('skipping submit, form invalid'); return [s => s]; } const settings = formData(event.target); settings.duration = formattedTimeToMilliseconds(settings.duration); - console.log('form.submit', settings, event.target); - return [actions.SubmitSettings, settings]; }, }, [ @@ -32,7 +29,12 @@ export const timerSettings = (props) => { isDirty && h('button', { type: 'button', onclick: [actions.RevertSettings, {}], + class: 'ml-1', }, text('Revert Changes')), + isDirty && h('button', { + type: 'submit', + class: 'ml-1', + }, text('Save')), ]), h( 'div', @@ -54,10 +56,6 @@ export const timerSettings = (props) => { ].filter(Boolean).join(' '), oninput: (_, event) => { const seconds = formattedTimeToMilliseconds(event.target.value) / 1000; - console.log('settings.change', event.target.value, formattedTimeToMilliseconds(event.target.value)); - // let [minutes, seconds] = event.target.value.split(':'); - // minutes ||= 0; - // seconds = (seconds || 0) + (minutes * 60); const valid = event.target.checkValidity() && seconds > 0; return [actions.SetFormInput, { form: 'timerDuration', input: event.target.value, valid }]; @@ -68,6 +66,25 @@ export const timerSettings = (props) => { }), text('minutes'), ]), + + h('div', {}, text('Positions')), + h('div', { class: 'flex' }, [ + h('input', { + type: 'text', + pattern: '([^,]+,?)+', + class: [ + 'mr-2 border-b border-slate-600 dark:bg-transparent dark:text-gray-200 block w-full', + !props.forms.mobOrder.valid && 'outline outline-red-400', + ].filter(Boolean).join(' '), + oninput: (_, event) => { + return [actions.SetFormInput, { form: 'mobOrder', input: event.target.value, valid: true }]; + }, + placeholder: 'navigator,driver', + value: props.forms.mobOrder.input, + name: 'mobOrder', + title: 'Comma separated list of position names', + }), + ]), ], ), ]); diff --git a/public/timer.js b/public/timer.js index 7a083b5..935dbbd 100644 --- a/public/timer.js +++ b/public/timer.js @@ -46,13 +46,18 @@ app({ const loadingPercent = (state.loading.total - state.loading.messages.length); const isLoading = loadingPercent < state.loading.total; - return grid({ class: 'relative pb-12' }, [ + return grid({ class: 'relative pb-12 px-2' }, [ h('div', {}, text(state.loading.messages.join(', '))), column.fixed(2, header(state)), - h('div', { class: 'flex flex-row items-center justify-center' }, [ - timeRemaining(state), + + column(2, { md: 1 }, [ + h('div', { class: 'flex flex-row items-center justify-center' }, [ + timeRemaining(state), + ]), + ]), + column(2, { md: 1 }, [ + summary(state), ]), - summary(state), isLoading && column.fixed(2, [ h('progress', { max: 4, value: loadingPercent, class: 'w-full', style: { height: '2px' } }), ]), @@ -62,8 +67,8 @@ app({ text('Your Session'), ]), grid({}, [ - column(2, { sm: 1 }, mob(state)), - column(2, { sm: 1 }, goals(state)), + column(2, { md: 1 }, mob(state)), + column(2, { md: 1 }, goals(state)), ]), ]), ]), @@ -73,8 +78,8 @@ app({ text('Advanced Settings'), ]), grid({}, [ - column(2, { sm: 1 }, memo(localSettings, stateWithoutFrequentChanges(state))), - column(2, { sm: 1 }, memo(timerSettings, stateWithoutFrequentChanges(state))), + column(2, { md: 1 }, memo(localSettings, stateWithoutFrequentChanges(state))), + column(2, { md: 1 }, memo(timerSettings, stateWithoutFrequentChanges(state))), ]), ]), ]), From 861bfa12f11836d0586b665b03e236aaabd4c10a Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Fri, 30 Jun 2023 09:23:49 -0400 Subject: [PATCH 27/36] Consolidated details component --- public/actions.js | 226 ++++++++++++++---------------- public/components/deleteButton.js | 9 +- public/components/details.js | 18 +++ public/effects.js | 6 +- public/sections/addGoal.js | 97 ------------- public/sections/mobActions.js | 52 ------- public/subscriptions.js | 17 +++ public/tabs/goals.js | 17 ++- public/tabs/localSettings.js | 2 +- public/tabs/mob.js | 13 +- public/timer.js | 102 ++++++++------ src/web/actions.js | 5 +- 12 files changed, 219 insertions(+), 345 deletions(-) create mode 100644 public/components/details.js delete mode 100644 public/sections/addGoal.js delete mode 100644 public/sections/mobActions.js diff --git a/public/actions.js b/public/actions.js index e04a916..01d9cb3 100644 --- a/public/actions.js +++ b/public/actions.js @@ -14,14 +14,6 @@ const emptyDrag = { clientY: null, }; -const emptyPrompt = { - text: '', - value: '', - context: null, - OnValue: Noop, - visible: false, -}; - const collectionMove = (collection, { from, to }) => { const newCollection = collection.reduce((memo, item, index) => { if (index === from) return memo; @@ -93,16 +85,14 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ expandedReorderable: null, timerTab: 'overview', drag: { ...emptyDrag }, - prompt: { ...emptyPrompt }, + // prompt: { ...emptyPrompt }, timerId, currentTime: null, name: '', goal: '', - addMultiple: false, allowNotification: externals.Notification && externals.Notification.permission === 'granted', allowSound: false, - showDrawer: false, sound: 'horn', pendingSettings: {}, websocketConnect: true, @@ -111,14 +101,15 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ dark, lang: i18n.withMissing(i18n[lang]) || i18n.en_CA, qrImage: null, + hasInteractedWithPage: false, }, effects.checkSettings({ storage: externals.storage, + onAllowSound: SetAllowSound, onLocalSoundEnabled: SoundToast, onDarkEnabled: SetDark, }), - dark && - effects.andThen({ + dark && effects.andThen({ action: SetDark, props: { dark }, }), @@ -129,6 +120,11 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ }), ]; +export const SetPageInteraction = (state, _props) => ({ + ...state, + hasInteractedWithPage: true, +}); + export const DetailsToggle = (state, { which, open }) => ({ ...state, details: { @@ -182,8 +178,6 @@ export const OpenForm = (state, { form, open }) => ({ }, }); -export const ToggleDrawer = (state, { showDrawer }) => [{ ...state, showDrawer: Boolean(showDrawer) }]; - export const OnQrLoad = (state, { img }) => [{ ...state, qrImage: img }]; export const SetDark = (state, { dark }) => [ @@ -206,11 +200,6 @@ export const TestSound = state => [ }), ]; -export const SetAddMultiple = (state, addMultiple) => ({ - ...state, - addMultiple: Boolean(addMultiple), -}); - export const SetCurrentTime = (state, { currentTime }) => { const nextState = { ...state, @@ -232,51 +221,51 @@ export const ExpandReorderable = (state, { expandedReorderable }) => ({ expandedReorderable, }); -export const PromptOpen = ( - state, - { text, defaultValue, OnValue, context }, -) => ({ - ...state, - prompt: { - text, - value: defaultValue, - OnValue, - context, - visible: true, - }, -}); - -export const PromptValueChange = (state, value) => ({ - ...state, - prompt: { - ...state.prompt, - value, - }, -}); - -export const PromptOK = state => [ - { - ...state, - prompt: { ...emptyPrompt }, - }, - effects.andThen({ - action: state.prompt.OnValue, - props: { - ...state.prompt.context, - value: state.prompt.value, - }, - }), -]; - -export const PromptCancel = state => ({ - ...state, - prompt: { ...emptyPrompt }, -}); - -export const SetTimerTab = (state, timerTab) => ({ - ...state, - timerTab, -}); +// export const PromptOpen = ( +// state, +// { text, defaultValue, OnValue, context }, +// ) => ({ +// ...state, +// prompt: { +// text, +// value: defaultValue, +// OnValue, +// context, +// visible: true, +// }, +// }); +// +// export const PromptValueChange = (state, value) => ({ +// ...state, +// prompt: { +// ...state.prompt, +// value, +// }, +// }); +// +// export const PromptOK = state => [ +// { +// ...state, +// prompt: { ...emptyPrompt }, +// }, +// effects.andThen({ +// action: state.prompt.OnValue, +// props: { +// ...state.prompt.context, +// value: state.prompt.value, +// }, +// }), +// ]; +// +// export const PromptCancel = state => ({ +// ...state, +// prompt: { ...emptyPrompt }, +// }); +// +// export const SetTimerTab = (state, timerTab) => ({ +// ...state, +// timerTab, +// }); export const DragSelect = (state, { type, from, clientX, clientY }) => ({ ...state, @@ -431,25 +420,25 @@ export const RenameUser = (state, { id, value }) => { ]; }; -export const RenameUserPrompt = (state, { id }) => { - const user = state.mob.find(m => m.id === id); - if (!user) return state; - - return [ - state, - effects.andThen({ - action: PromptOpen, - props: { - text: `Rename ${user.name} to...`, - defaultValue: user.name, - OnValue: RenameUser, - context: { - id, - }, - }, - }), - ]; -}; +// export const RenameUserPrompt = (state, { id }) => { +// const user = state.mob.find(m => m.id === id); +// if (!user) return state; +// +// return [ +// state, +// effects.andThen({ +// action: PromptOpen, +// props: { +// text: `Rename ${user.name} to...`, +// defaultValue: user.name, +// OnValue: RenameUser, +// context: { +// id, +// }, +// }, +// }), +// ]; +// }; export const UpdateName = (state, name) => ({ ...state, @@ -584,7 +573,13 @@ export const AddGoal = state => { { ...state, goals, - goal: '', + forms: { + ...state.forms, + goal: { + ...state.goal, + input: '', + }, + }, }, effects.UpdateGoals({ socketEmitter: state.externals.socketEmitter, @@ -611,7 +606,13 @@ export const AddGoals = (state, goals) => { { ...state, goals: allGoals, - goal: '', + forms: { + ...state.forms, + goal: { + ...state.goal, + input: '', + }, + }, }, effects.UpdateGoals({ socketEmitter: state.externals.socketEmitter, @@ -699,26 +700,26 @@ export const RenameGoal = (state, { id, value }) => { }), ]; }; -export const RenameGoalPrompt = (state, { id }) => { - const goal = state.goals.find(g => g.id === id); - if (!goal) return state; - - return [ - state, - effects.andThen({ - action: PromptOpen, - props: { - text: `Rename ${goal.text.length > 32 ? goal.text.slice(0, 29) + '...' : goal.text - } to...`, - defaultValue: goal.text, - OnValue: RenameGoal, - context: { - id, - }, - }, - }), - ]; -}; +// export const RenameGoalPrompt = (state, { id }) => { +// const goal = state.goals.find(g => g.id === id); +// if (!goal) return state; +// +// return [ +// state, +// effects.andThen({ +// action: PromptOpen, +// props: { +// text: `Rename ${goal.text.length > 32 ? goal.text.slice(0, 29) + '...' : goal.text +// } to...`, +// defaultValue: goal.text, +// OnValue: RenameGoal, +// context: { +// id, +// }, +// }, +// }), +// ]; +// }; export const UpdateGoalText = (state, goal) => [ { @@ -744,10 +745,6 @@ export const PauseTimer = (state, currentTime = Date.now()) => { completeToken: state.completeToken, fetch: state.externals.fetch, }), - // effects.PauseTimer({ - // socketEmitter: state.externals.socketEmitter, - // timerDuration, - // }), ]; }; @@ -757,10 +754,6 @@ export const ResumeTimer = (state, timerStartedAt = Date.now()) => [ timerStartedAt, currentTime: timerStartedAt, }, - // effects.StartTimer({ - // socketEmitter: state.externals.socketEmitter, - // timerDuration: state.timerDuration, - // }), effects.apiTimerStart({ timerId: state.timerId, duration: state.timerDuration, @@ -775,10 +768,6 @@ export const StartTimer = (state, { timerStartedAt, timerDuration }) => [ currentTime: timerStartedAt, timerDuration, }, - // effects.StartTimer({ - // socketEmitter: state.externals.socketEmitter, - // timerDuration, - // }), effects.apiTimerStart({ timerId: state.timerId, duration: timerDuration, @@ -1059,7 +1048,6 @@ export const LoadingMessagesPop = (state, { type, ...others }) => { export const UpdateByWebsocketData = (state, { payload }) => { const { type, ...data } = payload; - console.log('UpdateByWebsocketData', payload); switch (type) { case 'connections:update': return [ diff --git a/public/components/deleteButton.js b/public/components/deleteButton.js index d05d606..93281ed 100644 --- a/public/components/deleteButton.js +++ b/public/components/deleteButton.js @@ -11,13 +11,6 @@ export const deleteButton = props => 'bg-red-500': true, ...(props.class || {}), }, + innerHTML: '×', }, - [ - h('i', { - class: { - 'fas': true, - 'fa-times': true, - }, - }), - ], ); diff --git a/public/components/details.js b/public/components/details.js new file mode 100644 index 0000000..3416df6 --- /dev/null +++ b/public/components/details.js @@ -0,0 +1,18 @@ +import { h, text } from '/vendor/hyperapp.js'; +import * as actions from '/actions.js'; + +export const details = (props, children) => h( + 'details', + { + open: props.details[props.which], + ontoggle: (_, e) => { + return [actions.DetailsToggle, { which: props.which, open: e.target.open }]; + }, + }, + [ + h('summary', { + class: 'bg-transparent hover:bg-slate-200 hover:dark:bg-slate-600 text-xs text-slate-400 hover:text-slate-500 hover:dark:text-white px-1 cursor-pointer', + }, text(props.summary)), + ...([].concat(children)), + ], +); diff --git a/public/effects.js b/public/effects.js index b062e07..3e06869 100644 --- a/public/effects.js +++ b/public/effects.js @@ -147,17 +147,21 @@ export const andThen = fx(function andThenFX (dispatch, { action, props, delay, export const checkSettings = fx(function CheckSettingsFX ( dispatch, - { storage, onLocalSoundEnabled, onDarkEnabled }, + { storage, onAllowSound, onLocalSoundEnabled, onDarkEnabled }, ) { let localSettings = storage.getItem('settings'); if (!localSettings) return; localSettings = JSON.parse(localSettings); + + dispatch(onAllowSound, localSettings.allowSound || false); + if (localSettings.allowSound && onLocalSoundEnabled) { dispatch(onLocalSoundEnabled, { sound: localSettings.sound || '/audio/horn.wav', }); } + if (localSettings.dark && onDarkEnabled) { dispatch(onDarkEnabled, { dark: localSettings.dark, diff --git a/public/sections/addGoal.js b/public/sections/addGoal.js deleted file mode 100644 index f9adf06..0000000 --- a/public/sections/addGoal.js +++ /dev/null @@ -1,97 +0,0 @@ -import { h, text } from '/vendor/hyperapp.js'; - -import { section } from '/components/section.js'; -import { input, textarea } from '/components/input.js'; -import { button } from '/components/button.js'; -import { checkbox } from '/components/checkbox.js'; - -import * as actions from '/actions.js'; - -export const addGoal = props => - section({}, [ - h( - 'form', - { - action: '#', - method: 'get', - onsubmit: (_, e) => { - e.preventDefault(); - return [actions.AddGoals, props.goal]; - }, - class: { - 'flex': true, - 'flex-col': true, - 'items-center': true, - 'justify-start': true, - 'w-full': true, - }, - autocomplete: 'off', - }, - [ - !props.addMultiple && - input({ - value: props.goal, - oninput: (_, e) => [actions.UpdateGoalText, e.target.value], - placeholder: props.lang.goals.addSingle, - class: { - 'hover:border-indigo-300': true, - 'hover:border-b-solid': true, - 'w-full': true, - }, - }), - - props.addMultiple && - textarea({ - onchange: (_, e) => [actions.UpdateGoalText, e.target.value], - value: props.goal, - placeholder: props.lang.goals.addMultiline, - class: { - 'w-full': true, - }, - }), - - h( - 'div', - { - class: { - 'flex': true, - 'items-center': true, - 'justify-between': true, - 'pt-2': true, - 'w-full': true, - }, - }, - [ - checkbox( - { - id: 'goals-allow-multiple', - checked: props.addMultiple, - inputProps: { - onchange: (_, e) => { - e.preventDefault(); - return [actions.SetAddMultiple, e.target.checked]; - }, - }, - }, - text(props.lang.goals.addMultipleGoals), - ), - - button( - { - type: 'submit', - class: { - 'bg-green-600': true, - 'text-white': true, - 'whitespace-no-wrap': true, - }, - }, - [ - h('i', { class: 'fas fa-plus mr-3' }), - text(props.lang.goals.add), - ], - ), - ], - ), - ], - ), - ]); diff --git a/public/sections/mobActions.js b/public/sections/mobActions.js deleted file mode 100644 index caf5ffe..0000000 --- a/public/sections/mobActions.js +++ /dev/null @@ -1,52 +0,0 @@ -import { text, h } from '/vendor/hyperapp.js'; - -import { section } from '/components/section.js'; -import { button } from '/components/button.js'; - -import * as actions from '/actions.js'; - -export const mobActions = props => - section( - { - class: { - 'flex': true, - 'flex-row': true, - 'items-center': true, - 'justify-between': true, - }, - }, - [ - button( - { - class: { - // 'border': true, - // 'border-green-600': true, - 'dark:text-white': true, - // 'flex-grow': true, - 'mr-1': true, - }, - onclick: actions.CycleMob, - }, - [ - h('x-icon', { class: 'inline fas fa-sync-alt mr-1' }), - text(props.lang.mob.rotate), - ], - ), - - button( - { - class: { - // 'bg-green-600': true, - 'dark:text-white': true, - // 'flex-grow': true, - 'ml-1': true, - }, - onclick: actions.ShuffleMob, - }, - [ - h('x-icon', { class: 'inline fas fa-random mr-1' }), - text(props.lang.mob.randomize), - ], - ), - ], - ); diff --git a/public/subscriptions.js b/public/subscriptions.js index d796e4f..5147289 100644 --- a/public/subscriptions.js +++ b/public/subscriptions.js @@ -114,3 +114,20 @@ const DragAndDropFX = (dispatch, props) => { }; }; export const DragAndDrop = props => [DragAndDropFX, props]; + +const PageInteractionFx = (dispatch, props) => { + const onInteraction = () => { + dispatch(props.onInteraction); + }; + + props.document.addEventListener('mouseup', onInteraction); + props.document.addEventListener('keyup', onInteraction); + props.document.addEventListener('touchstart', onInteraction); + + return () => { + props.document.removeEventListener('mouseup', onInteraction); + props.document.removeEventListener('keyup', onInteraction); + props.document.removeEventListener('touchstart', onInteraction); + }; +}; +export const PageInteraction = props => [PageInteractionFx, props]; diff --git a/public/tabs/goals.js b/public/tabs/goals.js index f05c3ee..2854dd0 100644 --- a/public/tabs/goals.js +++ b/public/tabs/goals.js @@ -1,15 +1,19 @@ -import { goalList } from '/sections/goalList.js'; import { h, text } from '/vendor/hyperapp.js'; +import { goalList } from '/sections/goalList.js'; +import { details } from '/components/details.js'; import * as actions from '/actions.js'; export const goals = props => { - const isEdittingGoal = props.forms.goal.id && props.goals.some(g => g.id == props.forms.goal.id); - const anyGoalsIncomplete = props.goals.some(g => !g.completed); + const isEdittingGoal = props.forms.goal.id && props.goals.some(g => g.id === props.forms.goal.id); + const anyGoalsComplete = props.goals.some(g => g.completed); return h('div', {}, [ h('header', { class: 'flex justify-start items-center border-b border-gray-400 mb-2' }, [ h('h1', { class: 'text-lg font-bold flex-grow' }, text('Goals')), - anyGoalsIncomplete && h('button', { class: 'ml-2 dark:text-white text-black underline' }, text('Clear Completed')), + anyGoalsComplete && h('button', { + class: 'ml-2 dark:text-white text-black underline', + onclick: actions.RemoveCompletedGoals, + }, text('Clear Completed')), ]), goalList({ @@ -37,8 +41,7 @@ export const goals = props => { }, }, [ h('input', { type: 'hidden', name: 'id', value: props.forms.goal.id }), - h('details', { open: props.forms.goal.open, toggle: (_, event) => [actions.OpenForm, { form: 'goal', open: event.target.open }] }, [ - h('summary', { class: 'text-slate-500 text-xs' }, text('Show goal form')), + details({ which: 'goalForm', details: props.details, summary: 'Show goal form' }, [ h('div', { class: 'flex items-end justify-items-start' }, [ h('fieldset', { class: 'flex-grow' }, [ @@ -67,7 +70,7 @@ export const goals = props => { !isEdittingGoal && h('button', { type: 'submit', name: 'action', value: 'add', class: 'ml-1 px-2 py-1 border border-slate-700' }, text('Add')), isEdittingGoal && h('button', { type: 'submit', name: 'action', value: 'update', class: 'ml-1 px-2 py-1 border border-slate-700' }, text('Update')), isEdittingGoal && h('button', { type: 'submit', name: 'action', value: 'remove', class: 'ml-1 px-2 py-1 border border-slate-700' }, text('Remove')), - isEdittingGoal && h('button', { type: 'button', name: 'action', value: 'cancel', class: 'ml-1 px-2 py-1 border border-slate-700', onclick: () => [actions.SetFormId, { form: 'mob', id: '' }] }, text('Cancel')), + isEdittingGoal && h('button', { type: 'button', name: 'action', value: 'cancel', class: 'ml-1 px-2 py-1 border border-slate-700', onclick: () => [actions.SetFormId, { form: 'goal', id: '' }] }, text('Cancel')), ]), ]), ]), diff --git a/public/tabs/localSettings.js b/public/tabs/localSettings.js index a1d0786..5a64384 100644 --- a/public/tabs/localSettings.js +++ b/public/tabs/localSettings.js @@ -56,7 +56,7 @@ export const localSettings = (props) => { }, }, audioFiles.map(a => h( 'option', - { value: a.value }, + { value: a.value, selected: props.sound === a.value }, text(a.label), ))), ]), diff --git a/public/tabs/mob.js b/public/tabs/mob.js index b25429f..99b2a43 100644 --- a/public/tabs/mob.js +++ b/public/tabs/mob.js @@ -1,5 +1,6 @@ import { h, text } from '/vendor/hyperapp.js'; import { mobParticipants } from '/sections/mobParticipants.js'; +import { details } from '/components/details.js'; import * as actions from '/actions.js'; export const mob = props => { @@ -44,8 +45,7 @@ export const mob = props => { }, }, [ h('input', { type: 'hidden', name: 'id', value: props.forms.mob.id }), - h('details', { open: props.forms.mob.open, toggle: (_, event) => [actions.OpenForm, { form: 'mob', open: event.target.open }] }, [ - h('summary', { class: 'text-slate-500 text-xs' }, text('Show member form')), + details({ which: 'mobForm', details: props.details, summary: 'Show member form' }, [ h('div', { class: 'flex items-end justify-items-start' }, [ h('fieldset', { class: 'flex-grow' }, [ @@ -67,14 +67,5 @@ export const mob = props => { ]), ]), ]), - - // addParticipant({ - // name: props.name, - // lang: props.lang, - // }), - - // mobActions({ - // lang: props.lang, - // }), ]); }; diff --git a/public/timer.js b/public/timer.js index 935dbbd..e9cacdc 100644 --- a/public/timer.js +++ b/public/timer.js @@ -1,6 +1,7 @@ import * as actions from '/actions.js'; import { grid } from '/components/grid.js'; import { column } from '/components/column.js'; +import { details } from '/components/details.js'; import { mob } from '/tabs/mob.js'; import { goals } from '/tabs/goals.js'; import { header } from '/sections/header.js'; @@ -26,6 +27,9 @@ const flags = window.location.search }; }, {}); +const darkDefault = ('dark' in flags) || + window.matchMedia('(prefers-color-scheme: dark)').matches; + app({ init: actions.Init(null, { timerId: initialTimerId, @@ -39,65 +43,67 @@ app({ socketEmitter: Emitter.make(), }, lang: flags.lang || 'en_CA', - dark: 'dark' in flags, + dark: darkDefault, }), view: state => { const loadingPercent = (state.loading.total - state.loading.messages.length); const isLoading = loadingPercent < state.loading.total; - return grid({ class: 'relative pb-12 px-2' }, [ - h('div', {}, text(state.loading.messages.join(', '))), - column.fixed(2, header(state)), - - column(2, { md: 1 }, [ - h('div', { class: 'flex flex-row items-center justify-center' }, [ - timeRemaining(state), + return h('div', {}, [ + state.allowSound && !state.hasInteractedWithPage && h('div', { class: 'text-center px-2 bg-amber-400 text-white' }, [ + h('div', {}, text('You have enabled sound, but never interacted with the page. Click or touch on this page to remove this warning.')), + h('a', { href: 'https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide', target: 'mdn-auto-play', class: 'border-b border-blue-500' }, [ + text('See this MDN article on auto-play for more information'), + h('span', { class: 'ml-1', innerHTML: '⧉' }), ]), ]), - column(2, { md: 1 }, [ - summary(state), - ]), - isLoading && column.fixed(2, [ - h('progress', { max: 4, value: loadingPercent, class: 'w-full', style: { height: '2px' } }), - ]), - !isLoading && column.fixed(2, [ - h('details', { open: state.details.summary, ontoggle: (_, event) => [actions.DetailsToggle, { which: 'summary', open: event.target.open }] }, [ - h('summary', { class: 'text-xs text-slate-500' }, [ - text('Your Session'), - ]), - grid({}, [ - column(2, { md: 1 }, mob(state)), - column(2, { md: 1 }, goals(state)), + grid({ class: 'relative pb-12 px-2' }, [ + column.fixed(2, header(state)), + + column(2, { md: 1 }, [ + h('div', { class: 'flex flex-row items-center justify-center' }, [ + timeRemaining(state), ]), ]), - ]), - !isLoading && column.fixed(2, [ - h('details', { open: state.details.advancedSettings, ontoggle: (_, event) => [actions.DetailsToggle, { which: 'advancedSettings', open: event.target.open }] }, [ - h('summary', { class: 'text-xs text-slate-500' }, [ - text('Advanced Settings'), + column(2, { md: 1 }, [ + summary(state), + ]), + isLoading && column.fixed(2, [ + h('progress', { max: 4, value: loadingPercent, class: 'w-full', style: { height: '2px' } }), + ]), + !isLoading && column.fixed(2, [ + details({ which: 'summary', details: state.details, summary: 'Your Session' }, [ + grid({}, [ + column(2, { md: 1 }, mob(state)), + column(2, { md: 1 }, goals(state)), + ]), ]), - grid({}, [ - column(2, { md: 1 }, memo(localSettings, stateWithoutFrequentChanges(state))), - column(2, { md: 1 }, memo(timerSettings, stateWithoutFrequentChanges(state))), + ]), + !isLoading && column.fixed(2, [ + details({ which: 'advancedSettings', details: state.details, summary: 'Advanced Settings' }, [ + grid({}, [ + column(2, { md: 1 }, memo(localSettings, stateWithoutFrequentChanges(state))), + column(2, { md: 1 }, memo(timerSettings, stateWithoutFrequentChanges(state))), + ]), ]), ]), - ]), - h( - 'audio', - { - preload: 'auto', - id: 'timer-complete', - key: state.sound, - }, - [ - h('source', { - src: `/audio/${state.sound}.wav`, - type: 'audio/wav', - }), - ], - ), + h( + 'audio', + { + preload: 'auto', + id: 'timer-complete', + key: state.sound, + }, + [ + h('source', { + src: `/audio/${state.sound}.wav`, + type: 'audio/wav', + }), + ], + ), + ]), ]); }, @@ -125,6 +131,12 @@ app({ DragEnd: actions.DragEnd, DragCancel: actions.DragCancel, }), + + !state.hasInteractedWithPage && + subscriptions.PageInteraction({ + onInteraction: actions.SetPageInteraction, + document: state.externals.documentElement, + }), ]; }, diff --git a/src/web/actions.js b/src/web/actions.js index 67c9afb..3e2475b 100644 --- a/src/web/actions.js +++ b/src/web/actions.js @@ -137,9 +137,7 @@ export const UpdateTimer = (timerId, message) => state => { const meta = { ...(type === 'timer:start' ? { timerStartedAt: Date.now() } : {}), - ...(type === 'timer:complete' - ? { timerStartedAt: null, timerDuration: 0 } - : {}), + ...(type === 'timer:complete' ? { timerStartedAt: null, timerDuration: 0 } : {}), }; return [ @@ -169,7 +167,6 @@ export const CompleteTimer = (timerId, token, statusCallback) => state => { return [ state, batch([ - // defer(state.queue.publishToTimer(timerId, JSON.stringify({ type: 'timer:complete' })).then(none)), act(RemoveCompleteToken(timerId)), act(UpdateTimer(timerId, JSON.stringify({ type: 'timer:complete' }))), thunk(() => { From e3a31f5c6bb0b52ea20f34711b685b98aa2e0bc5 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Fri, 30 Jun 2023 09:26:53 -0400 Subject: [PATCH 28/36] Clean up actions --- public/actions.js | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/public/actions.js b/public/actions.js index 01d9cb3..79f542e 100644 --- a/public/actions.js +++ b/public/actions.js @@ -50,25 +50,21 @@ export const Init = (_, { timerId, externals, dark, lang }) => [ }, forms: { mob: { - open: false, valid: true, id: '', input: '', }, goal: { - open: false, valid: true, id: '', input: '', }, timerDuration: { - open: false, valid: true, id: '', input: formatTime(defaults.timerDuration), }, mobOrder: { - open: false, valid: true, id: '', input: defaults.timerMobOrder, @@ -150,7 +146,6 @@ export const SetFormId = (state, { form, id, input }) => ({ ...state.forms[form], id: state.forms[form].id === id ? '' : id, input: state.forms[form].id === id ? '' : input || '', - open: Boolean(id), }, }, }); @@ -167,16 +162,16 @@ export const SetFormInput = (state, { form, input, valid }) => ({ }, }); -export const OpenForm = (state, { form, open }) => ({ - ...state, - forms: { - ...state.forms, - [form]: { - ...state.forms[form], - open: Boolean(open), - }, - }, -}); +// export const OpenForm = (state, { form, open }) => ({ +// ...state, +// forms: { +// ...state.forms, +// [form]: { +// ...state.forms[form], +// open: Boolean(open), +// }, +// }, +// }); export const OnQrLoad = (state, { img }) => [{ ...state, qrImage: img }]; From 2bdfe63a502a6dc276cbc6f655ed10f973254d21 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Fri, 30 Jun 2023 16:23:51 -0400 Subject: [PATCH 29/36] Double-click should prep the associated form --- public/actions.js | 30 +++++++++++++++++++----------- public/components/goal.js | 4 +--- public/components/mobber.js | 4 +--- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/public/actions.js b/public/actions.js index 79f542e..7e9ada2 100644 --- a/public/actions.js +++ b/public/actions.js @@ -33,6 +33,11 @@ const defaults = { timerDuration: 5 * 60 * 1000, }; +export const CombineActions = (init, actions) => actions.reduce(([state, ...effects], action) => { + const [nextState, ...otherEffects] = [].concat(Array.isArray(action) ? action[0](state, action[1]) : action(state)); + return [nextState, ...effects, ...otherEffects]; +}, [].concat(init)); + export const Init = (_, { timerId, externals, dark, lang }) => [ { timerStartedAt: null, @@ -138,6 +143,20 @@ export const FirstConnection = state => ({ }, }); +export const GoalDoubleClick = (state, { id }) => { + return CombineActions(state, [ + [SetFormId, { form: 'goal', id, input: state.goals.find(g => g.id === id)?.text }], + [DetailsToggle, { which: 'goalForm', open: true }], + ]); +}; + +export const MobDoubleClick = (state, { id }) => { + return CombineActions(state, [ + [SetFormId, { form: 'mob', id, input: state.mob.find(m => m.id === id)?.name }], + [DetailsToggle, { which: 'mobForm', open: true }], + ]); +}; + export const SetFormId = (state, { form, id, input }) => ({ ...state, forms: { @@ -162,17 +181,6 @@ export const SetFormInput = (state, { form, input, valid }) => ({ }, }); -// export const OpenForm = (state, { form, open }) => ({ -// ...state, -// forms: { -// ...state.forms, -// [form]: { -// ...state.forms[form], -// open: Boolean(open), -// }, -// }, -// }); - export const OnQrLoad = (state, { img }) => [{ ...state, qrImage: img }]; export const SetDark = (state, { dark }) => [ diff --git a/public/components/goal.js b/public/components/goal.js index be91374..e469a56 100644 --- a/public/components/goal.js +++ b/public/components/goal.js @@ -62,9 +62,7 @@ export const goal = props => { 'border-transparent': true, 'hover:border-slate-400': props.id, }, - ondblclick: (_props, _event) => { - return [actions.SetFormId, { form: 'goal', id: props.id, input: props.text }]; - }, + ondblclick: [actions.GoalDoubleClick, { id: props.id }], }, textWithBreaks(text || ''), ), diff --git a/public/components/mobber.js b/public/components/mobber.js index 9d7de95..f3b8984 100644 --- a/public/components/mobber.js +++ b/public/components/mobber.js @@ -34,9 +34,7 @@ export const mobber = props => 'border-transparent': true, 'hover:border-slate-400': props.name, }, - ondblclick: (_props, _event) => { - return [actions.SetFormId, { form: 'mob', id: props.id, input: props.name }]; - }, + ondblclick: [actions.MobDoubleClick, { id: props.id }], title: 'Double click to edit', }, [ From 66d2985d2d62da8ce421ef592bf119c6cb402cef Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Fri, 21 Jul 2023 15:16:17 -0400 Subject: [PATCH 30/36] Group goals --- public/actions.js | 2 ++ public/sections/summary.js | 29 ++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/public/actions.js b/public/actions.js index 7e9ada2..fcbfeb7 100644 --- a/public/actions.js +++ b/public/actions.js @@ -1033,6 +1033,8 @@ export const LoadingMessagesPop = (state, { type, ...others }) => { messages, }; + console.log('Loaded', type, loading); + return [ { ...state, diff --git a/public/sections/summary.js b/public/sections/summary.js index 9e3a47d..11e83b1 100644 --- a/public/sections/summary.js +++ b/public/sections/summary.js @@ -2,8 +2,30 @@ import { h, text } from '/vendor/hyperapp.js'; import * as actions from '/actions.js'; +const subGoalRegex = () => /^[- \t]+/; + +const isSubGoal = (g) => { + if (!g) return false; + return subGoalRegex().test(g.text); +}; + export const summary = (props) => { - const firstIncompleteGoal = props.goals.filter(g => !g.completed)[0]; + const index = props.goals.findIndex(g => !g.completed); + const incomplete = { + goal: null, + subGoal: null, + }; + if (index >= 0) { + incomplete.goal = props.goals[index]; + if (!isSubGoal(incomplete.goal)) { + for (let i = index + 1; i < props.goals.length && isSubGoal(props.goals[i]) && !incomplete.subGoal; i++) { + const g = props.goals[i]; + if (!g.completed) { + incomplete.subGoal = g; + } + } + } + } return h('div', { // class: 'flex items-center justify-start', @@ -16,11 +38,12 @@ export const summary = (props) => { ]); }), ]), - firstIncompleteGoal && h('div', { class: 'mb-2' }, [ + incomplete.goal && h('div', { class: 'mb-2' }, [ h('hr', { class: 'mb-2' }), h('div', { class: 'text-xs leading-none uppercase text-slate-600' }, text('Current Goal')), h('div', { class: '' }, [ - text(firstIncompleteGoal.text), + text(incomplete.goal.text), + incomplete.subGoal && h('div', { class: 'ml-2' }, text(incomplete.subGoal.text.replace(subGoalRegex(), ''))), ]), ]), h('div', {}, [ From 3cfc0c856ae3ea5c66bd4a953af5abca6e634c63 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Fri, 29 Sep 2023 09:36:02 -0400 Subject: [PATCH 31/36] Add unite.eu to companies who use mobtime --- public/images/unite.eu.png | Bin 0 -> 25600 bytes public/index.html | 6 ++++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 public/images/unite.eu.png diff --git a/public/images/unite.eu.png b/public/images/unite.eu.png new file mode 100644 index 0000000000000000000000000000000000000000..115f92ef32b7f1a4a599088d32bcee4a3864b8d1 GIT binary patch literal 25600 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 Y(|F;CANk%Q7{rHJS=bOO&AhJu2Xz$9kN^Mx literal 0 HcmV?d00001 diff --git a/public/index.html b/public/index.html index 97c1dea..b9fca8b 100644 --- a/public/index.html +++ b/public/index.html @@ -154,9 +154,11 @@

Some humans and groups who use Mobtime< - - Your Logo Here + + + Unite - Connecting buyrs and sellers for mutual benefit + Your Logo Here From e752d634a04aed55a7ba00b024c2b3990192f35b Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Thu, 4 Apr 2024 23:14:25 -0400 Subject: [PATCH 32/36] Broken tests --- public/actions.goal.test.js | 30 +---------- public/actions.init.test.js.md | 51 +++++++++++++++--- public/actions.init.test.js.snap | Bin 2409 -> 2721 bytes public/actions.js | 2 +- public/actions.misc.test.js | 17 ------ public/actions.mob-rename.test.js | 28 ---------- public/actions.mob.test.js | 5 +- ...pt.test.js => actions.prompt.test.js.skip} | 0 public/actions.timer.test.js | 20 ++++--- src/web/actions.test.js | 1 + 10 files changed, 62 insertions(+), 92 deletions(-) rename public/{actions.prompt.test.js => actions.prompt.test.js.skip} (100%) diff --git a/public/actions.goal.test.js b/public/actions.goal.test.js index 5237f83..d0cf395 100644 --- a/public/actions.goal.test.js +++ b/public/actions.goal.test.js @@ -32,7 +32,7 @@ test('can add goal', t => { text: goalTextToAdd, completed: false, }); - t.is(state.goal, ''); + t.is(state.goal, 'foo'); t.deepEqual( effect, effects.UpdateGoals({ @@ -220,31 +220,3 @@ test('can rename goal', t => { }), ); }); - -test('can prompt to rename goal', t => { - const initialState = { - goals: [makeGoal('foo')], - externals: { socketEmitter: {} }, - }; - - const [state, effect] = actions.RenameGoalPrompt(initialState, { - id: initialState.goals[0].id, - }); - - t.is(state, initialState); - - t.deepEqual( - effect, - effects.andThen({ - action: actions.PromptOpen, - props: { - text: 'Rename foo to...', - defaultValue: initialState.goals[0].text, - OnValue: actions.RenameGoal, - context: { - id: initialState.goals[0].id, - }, - }, - }), - ); -}); diff --git a/public/actions.init.test.js.md b/public/actions.init.test.js.md index 9b95f82..9fb0953 100644 --- a/public/actions.init.test.js.md +++ b/public/actions.init.test.js.md @@ -10,11 +10,18 @@ Generated by [AVA](https://avajs.dev). [ { - addMultiple: false, allowNotification: false, allowSound: false, currentTime: null, dark: undefined, + details: { + advancedSettings: false, + goalForm: false, + localSettings: false, + mobForm: false, + summary: false, + timerSettings: false, + }, drag: { active: false, clientX: null, @@ -28,8 +35,31 @@ Generated by [AVA](https://avajs.dev). Notification: {}, documentElement: {}, }, + forms: { + goal: { + id: '', + input: '', + valid: true, + }, + mob: { + id: '', + input: '', + valid: true, + }, + mobOrder: { + id: '', + input: 'Navigator,Driver', + valid: true, + }, + timerDuration: { + id: '', + input: '05:00', + valid: true, + }, + }, goal: '', goals: [], + hasInteractedWithPage: false, lang: { goals: { add: 'Add', @@ -105,16 +135,20 @@ Generated by [AVA](https://avajs.dev). }, }, }, + loading: { + isFirstConnection: false, + messages: [ + 'settings:update', + 'mob:update', + 'goals:update', + 'timer:update', + 'connections:update', + ], + total: 5, + }, mob: [], name: '', pendingSettings: {}, - prompt: { - OnValue: Function Noop {}, - context: null, - text: '', - value: '', - visible: false, - }, qrImage: null, settings: { duration: 300000, @@ -131,6 +165,7 @@ Generated by [AVA](https://avajs.dev). [ Function CheckSettingsFX {}, { + onAllowSound: Function SetAllowSound {}, onDarkEnabled: Function SetDark {}, onLocalSoundEnabled: Function SoundToast {}, storage: undefined, diff --git a/public/actions.init.test.js.snap b/public/actions.init.test.js.snap index db8d148ecaa546c303f2930e139e5a560779e326..9cedefd7edfd723ad8d60247ec549d4f23a40c74 100644 GIT binary patch literal 2721 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 literal 2409 zcmV-v36}OjRzV->^$rno)}oNL-fnwg|7+h zEQe?g)*p)q00000000A(SzBlw#~I$$x$1HxS+eANJ#I=96WdBJV5h{mwq(0bEK8PT zJBGf@*&Us;@t&RI+1(?nr58g(`%qF$p%0B)>g1s>2^2~&l+vd>w6uK)rGyj=A$@BL zxjYqGLcf{aowGaV$WX)QvpfIy&;9>q{?&ucrq7*Q;oa9*$`69DdIMmw_8V3lPAp zUEO6@&I&=dZ999KnwqlgG0U!4_PA|-E2#uemW^NhKLNK9dt|p=vg}$znT|?RNjTNZ0%rgZ_#W^J;34p5-~-@O;Bd*ZP6F2e4%`FY0^S2Y z1)eOUj&eGJ>Pqt^=0x_0ew?13mR%@qg5m?ca&fTx3xfsmE(qTT?is|xChR)tUaLVaI@O) z=NzWGEO5P`wa%glKS?{k$q}ku!8_f^sI+!lT)5roU^`zFK0c+qES; zJ`c2jmx0%T-vRH|jEFA{MEob9{2Q3B8`QEvEktk42=lR%a6b)f06uURcoldH_!IB} zV2>J2)F0Qx?qU-~&pC4()qSY^FmMXE4hY~!W`pws!+#T$Uju(Nse2#Sw|#}a?UM_S zh*@ki=T;Uk7hY5j^$T&}$PH^B$i1Ykm#brzH32*gtd1EyI9TjK+RC0a*1=x98Z)uI zN(Dj~+A-J~F}e@L?;_xbW-p&8_7Z_qHA10EQB!XR z4X-)A2jzWnco?SEn>&c|CKPD6X(Zx1_(a>?zBn~hR3V^09P0=4ME*ok*2Z{F7hUee z9dzov&*YD)WK_|f9v>>sFXf7>ZANh#sPcQ`raYtY_qoEN=KN=TsEWdJeInOx*rtN1 z;+J#9<%l*D@^5pcN>Z_(s26zYnepMo5M^tq%MGmi8+~hSCAd!gm<=o$4Yt!|49sKiG2lM%9?+Pv ztnHYSE+nzO7YfC~TvUI8A? z8E#VpWBwZ`?*pZIqyoU#=M9(Xfz$5?pu7USVN!PuJ$uSmIPV&V#UAspNVzo}gfe6d z`k@`@V=8nuq~I7HpV`5qz7kv&GFS}$=S)5Vt!4%katr-@)-~g8B1=7dL`qh806d~p zeQYIQ>WOrjAd+KV{&K0yMd^_lW@H_m)I!oDqTo6T*L8@ouiLF>?V9&k$7fV5;tuZP z3ZREGwx1>_qw?0ETq7D&$0Dy}`L)XN-C%`EFQrGyuIy@~X%Nu66-V~5g4 z1=2O%fne&AwXDRv&m1!XdYpvyx~4*YA(?{4(3KK5}b zAzWZ^g2`CzP!h5(uJbZteJ_j%-z1r{*_%Ux-Hwsi=BFRg(DB01>qo@lwS-kz0I66h z&%Bw1w5J!KypETF3>{@UC@Yd-hUKife7ecH7!y3Vu53gZcbezvWW`nm?|CkB&uOKZ zNtT&(QwwQs58f<8J-y|P!MuMiibarpKDZPtdqE5rEoB?9lFUq=>Lli)*?q83)l4c~ zi`@5VlZ%`foKnLiQJax#YnMsHvAUW>P_wioyHkCf+~%<$5u+V5(9$MW`4$s$CT?Wk z6Lgo4EGHD=VO|m%riJJa522~wJ|*yQ1uAi$%Hap|7fQ-8K(~i*%CX z=(k}CB=Z{mJVeT}3`ZBN=#-~O42|tn-(d$O`A>hBCfU#sWv+B-9QKK;^39BTk)=lZ z!=O|OoiM4rJa9I!Fz)2e2K8#53ZeY^BzK%X71Z}AB8zgF!8`N0tW<@@`OQt-$&yU2 zz9*M}=v80xLMQp+r0$Ym0_j=c0q{2P4`5=iaod|2xEP)Ucc;$56=6m { +export const collectionMove = (collection, { from, to }) => { const newCollection = collection.reduce((memo, item, index) => { if (index === from) return memo; if (index === to) { diff --git a/public/actions.misc.test.js b/public/actions.misc.test.js index 57f8e2a..dea8ada 100644 --- a/public/actions.misc.test.js +++ b/public/actions.misc.test.js @@ -11,11 +11,6 @@ test('can set expand reorderable', t => { t.deepEqual(state, { expandedReorderable }); }); -test('can set timer tab', t => { - const timerTab = 'foo-bar-baz'; - const state = actions.SetTimerTab({}, timerTab); - t.deepEqual(state, { timerTab }); -}); test('can allow notifications', t => { const Notification = {}; @@ -120,15 +115,3 @@ test('can end turn', t => { }), ]); }); - -test('it can toggle addMultiple', t => { - const initialState = { - addMultiple: false, - }; - - const state = actions.SetAddMultiple(initialState, true); - - t.deepEqual(state, { - addMultiple: true, - }); -}); diff --git a/public/actions.mob-rename.test.js b/public/actions.mob-rename.test.js index 6dd97ff..9adeefe 100644 --- a/public/actions.mob-rename.test.js +++ b/public/actions.mob-rename.test.js @@ -40,34 +40,6 @@ test('can rename a user', t => { ); }); -test('can prompt to rename a user', t => { - const mobber = makeUser('Foo'); - - const initialState = { - mob: [mobber], - }; - - const [state, effect] = actions.RenameUserPrompt(initialState, { - id: mobber.id, - }); - - t.deepEqual(state, initialState); - t.deepEqual( - effect, - effects.andThen({ - action: actions.PromptOpen, - props: { - text: 'Rename Foo to...', - defaultValue: 'Foo', - OnValue: actions.RenameUser, - context: { - id: mobber.id, - }, - }, - }), - ); -}); - test('can update in-memory name', t => { const initialState = { name: '' }; diff --git a/public/actions.mob.test.js b/public/actions.mob.test.js index 10001d2..70ad6e1 100644 --- a/public/actions.mob.test.js +++ b/public/actions.mob.test.js @@ -97,9 +97,12 @@ test('can add in-memory name to mob', t => { mob: [makeMobber('One')], name: nameToAdd, externals: { socketEmitter: {} }, + forms: { + mob: {}, + }, }; - const [state, effect] = actions.AddNameToMob(initialState); + const [state, effect] = actions.AddNameToMob(initialState, { name: nameToAdd }); t.is(state.mob.length, initialState.mob.length + 1); t.like(state.mob[1], { name: nameToAdd }); diff --git a/public/actions.prompt.test.js b/public/actions.prompt.test.js.skip similarity index 100% rename from public/actions.prompt.test.js rename to public/actions.prompt.test.js.skip diff --git a/public/actions.timer.test.js b/public/actions.timer.test.js index 53409f1..6d40a74 100644 --- a/public/actions.timer.test.js +++ b/public/actions.timer.test.js @@ -71,9 +71,11 @@ test('can pause the timer', t => { t.deepEqual( effect, - effects.PauseTimer({ - socketEmitter, + effects.apiTimerPause({ + completeToken: undefined, + fetch: undefined, timerDuration: expectedTimerDuration, + timerId: undefined, }), ); }); @@ -102,9 +104,10 @@ test('can resume the timer', t => { t.deepEqual( effect, - effects.StartTimer({ - socketEmitter, - timerDuration: 1000000, + effects.apiTimerStart({ + duration: 1000000, + fetch: undefined, + timerId: undefined, }), ); }); @@ -139,9 +142,10 @@ test('can start the timer', t => { t.deepEqual( effect, - effects.StartTimer({ - socketEmitter, - timerDuration, + effects.apiTimerStart({ + duration: timerDuration, + fetch: undefined, + timerId: undefined, }), ); }); diff --git a/src/web/actions.test.js b/src/web/actions.test.js index 845c024..2de9244 100644 --- a/src/web/actions.test.js +++ b/src/web/actions.test.js @@ -34,6 +34,7 @@ test('Init resets connections and statistics, with no effect', async t => { t.truthy(ok()); t.deepEqual(state(), { + completeTokens: {}, connections: {}, queue, nextId, From d8c74cea130248de2e9a566a6344cef52482458f Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Fri, 2 Aug 2024 10:00:28 -0400 Subject: [PATCH 33/36] Ignore .env --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f607946..12d80e2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ public/styles/* .yarn dump.rdb docker/redis-volume/* +.env From 40efed057c7242ec09bae90d32d50fb9bf587e82 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Fri, 9 Aug 2024 00:03:43 -0400 Subject: [PATCH 34/36] Ding by default, this one's for all the mobbers back home --- public/effects.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/effects.js b/public/effects.js index 3e06869..7dbd27a 100644 --- a/public/effects.js +++ b/public/effects.js @@ -158,7 +158,7 @@ export const checkSettings = fx(function CheckSettingsFX ( if (localSettings.allowSound && onLocalSoundEnabled) { dispatch(onLocalSoundEnabled, { - sound: localSettings.sound || '/audio/horn.wav', + sound: localSettings.sound || '/audio/ding.wav', }); } From 1fa1de67bb770496489067872e95f98d4ea24349 Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Fri, 9 Aug 2024 00:04:14 -0400 Subject: [PATCH 35/36] Fidgetted with summary layout, ran linter --- public/sections/summary.js | 106 +++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/public/sections/summary.js b/public/sections/summary.js index 11e83b1..44f2842 100644 --- a/public/sections/summary.js +++ b/public/sections/summary.js @@ -1,6 +1,6 @@ -import { h, text } from '/vendor/hyperapp.js'; +import { h, text } from "/vendor/hyperapp.js"; -import * as actions from '/actions.js'; +import * as actions from "/actions.js"; const subGoalRegex = () => /^[- \t]+/; @@ -10,7 +10,7 @@ const isSubGoal = (g) => { }; export const summary = (props) => { - const index = props.goals.findIndex(g => !g.completed); + const index = props.goals.findIndex((g) => !g.completed); const incomplete = { goal: null, subGoal: null, @@ -18,7 +18,12 @@ export const summary = (props) => { if (index >= 0) { incomplete.goal = props.goals[index]; if (!isSubGoal(incomplete.goal)) { - for (let i = index + 1; i < props.goals.length && isSubGoal(props.goals[i]) && !incomplete.subGoal; i++) { + for ( + let i = index + 1; + i < props.goals.length && isSubGoal(props.goals[i]) && + !incomplete.subGoal; + i++ + ) { const g = props.goals[i]; if (!g.completed) { incomplete.subGoal = g; @@ -27,55 +32,78 @@ export const summary = (props) => { } } - return h('div', { - // class: 'flex items-center justify-start', + return h("div", { + //class: "flex items-center justify-start", }, [ - h('ol', {}, [ - ...props.settings.mobOrder.split(',').map((position, index) => { - return h('li', { class: 'mb-2' }, [ - h('div', { class: 'text-xs leading-none uppercase text-slate-600' }, text(position)), - h('div', {}, text(props.mob[index]?.name || 'Empty')), + h("ol", {}, [ + ...props.settings.mobOrder.split(",").map((position, index) => { + return h("li", { class: "mb-2" }, [ + h( + "div", + { class: "text-xs leading-none uppercase text-slate-600" }, + text(position), + ), + h("div", {}, text(props.mob[index]?.name || "Empty")), ]); }), ]), - incomplete.goal && h('div', { class: 'mb-2' }, [ - h('hr', { class: 'mb-2' }), - h('div', { class: 'text-xs leading-none uppercase text-slate-600' }, text('Current Goal')), - h('div', { class: '' }, [ + incomplete.goal && h("div", { class: "mb-2" }, [ + h("hr", { class: "mb-2" }), + h( + "div", + { class: "text-xs leading-none uppercase text-slate-600" }, + text("Current Goal"), + ), + h("div", { class: "" }, [ text(incomplete.goal.text), - incomplete.subGoal && h('div', { class: 'ml-2' }, text(incomplete.subGoal.text.replace(subGoalRegex(), ''))), + incomplete.subGoal && + h( + "div", + { class: "ml-2" }, + text(incomplete.subGoal.text.replace(subGoalRegex(), "")), + ), ]), ]), - h('div', {}, [ - h('hr', { class: 'mb-2' }), - h('div', { class: 'text-xs uppercase text-slate-600' }, text('Turn Controls')), - h('div', { class: 'grid grid-cols-3' }, [ - h('button', { - type: 'button', + h("div", {}, [ + h("hr", { class: "mb-2" }), + h( + "div", + { class: "text-xs uppercase text-slate-600" }, + text("Turn Controls"), + ), + h("div", { class: "grid grid-cols-3" }, [ + h("button", { + type: "button", class: [ - 'mr-1 px-2 py-1 border border-slate-700', - props.timerStartedAt && 'bg-slate-200 text-black cursor-not-allowed', - ].filter(Boolean).join(' '), + "mr-1 px-2 py-1 border border-slate-700", + props.timerStartedAt && + "bg-slate-200 text-black cursor-not-allowed", + ].filter(Boolean).join(" "), disabled: props.timerStartedAt, onclick: props.timerDuration ? [actions.ResumeTimer, {}] - : [actions.StartTimer, { timerStartedAt: Date.now(), timerDuration: props.settings.duration }], - }, text('Start')), - h('button', { - type: 'button', + : [actions.StartTimer, { + timerStartedAt: Date.now(), + timerDuration: props.settings.duration, + }], + }, text("Start")), + h("button", { + type: "button", class: [ - 'mr-1 px-2 py-1 border border-slate-700', - !props.timerStartedAt && 'bg-slate-200 text-black cursor-not-allowed', - ].filter(Boolean).join(' '), + "mr-1 px-2 py-1 border border-slate-700", + !props.timerStartedAt && + "bg-slate-200 text-black cursor-not-allowed", + ].filter(Boolean).join(" "), disabled: !props.timerStartedAt, onclick: [actions.PauseTimer, undefined], - }, text('Pause')), - h('button', { - type: 'button', + }, text("Pause")), + h("button", { + type: "button", class: [ - 'mr-1 px-2 py-1 border border-slate-700', - !props.timerDuration && 'bg-slate-200 text-black cursor-not-allowed', - ].join(' '), + "mr-1 px-2 py-1 border border-slate-700", + !props.timerDuration && + "bg-slate-200 text-black cursor-not-allowed", + ].join(" "), disabled: !props.timerDuration, onclick: [ actions.Completed, @@ -85,7 +113,7 @@ export const summary = (props) => { Notification: window.Notification, }, ], - }, text('Skip')), + }, text("Skip")), ]), ]), ]); From f2a8a2d6f3eb2faf4ead12448e66e30d066e6c2a Mon Sep 17 00:00:00 2001 From: Alex Barry Date: Mon, 2 Dec 2024 16:30:20 -0500 Subject: [PATCH 36/36] Make mob positions and timer actions easier to find on the page --- public/sections/summary.js | 95 ++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/public/sections/summary.js b/public/sections/summary.js index 44f2842..aafd457 100644 --- a/public/sections/summary.js +++ b/public/sections/summary.js @@ -1,6 +1,6 @@ -import { h, text } from "/vendor/hyperapp.js"; +import { h, text } from '/vendor/hyperapp.js'; -import * as actions from "/actions.js"; +import * as actions from '/actions.js'; const subGoalRegex = () => /^[- \t]+/; @@ -32,78 +32,81 @@ export const summary = (props) => { } } - return h("div", { - //class: "flex items-center justify-start", + return h('div', { + // class: "flex items-center justify-start", }, [ - h("ol", {}, [ - ...props.settings.mobOrder.split(",").map((position, index) => { - return h("li", { class: "mb-2" }, [ + h('ol', {}, [ + ...props.settings.mobOrder.split(',').map((position, index) => { + return h('li', { class: 'mb-2', 'data-mobposition': position }, [ h( - "div", - { class: "text-xs leading-none uppercase text-slate-600" }, + 'div', + { class: 'text-xs leading-none uppercase text-slate-600' }, text(position), ), - h("div", {}, text(props.mob[index]?.name || "Empty")), + h('div', {}, text(props.mob[index]?.name || 'Empty')), ]); }), ]), - incomplete.goal && h("div", { class: "mb-2" }, [ - h("hr", { class: "mb-2" }), + incomplete.goal && h('div', { class: 'mb-2' }, [ + h('hr', { class: 'mb-2' }), h( - "div", - { class: "text-xs leading-none uppercase text-slate-600" }, - text("Current Goal"), + 'div', + { class: 'text-xs leading-none uppercase text-slate-600' }, + text('Current Goal'), ), - h("div", { class: "" }, [ + h('div', { class: '' }, [ text(incomplete.goal.text), incomplete.subGoal && h( - "div", - { class: "ml-2" }, - text(incomplete.subGoal.text.replace(subGoalRegex(), "")), + 'div', + { class: 'ml-2' }, + text(incomplete.subGoal.text.replace(subGoalRegex(), '')), ), ]), ]), - h("div", {}, [ - h("hr", { class: "mb-2" }), + h('div', {}, [ + h('hr', { class: 'mb-2' }), h( - "div", - { class: "text-xs uppercase text-slate-600" }, - text("Turn Controls"), + 'div', + { class: 'text-xs uppercase text-slate-600' }, + text('Turn Controls'), ), - h("div", { class: "grid grid-cols-3" }, [ - h("button", { - type: "button", + h('div', { class: 'grid grid-cols-3' }, [ + h('button', { + 'data-timercontrol': 'start', + type: 'button', class: [ - "mr-1 px-2 py-1 border border-slate-700", + 'mr-1 px-2 py-1 border border-slate-700', props.timerStartedAt && - "bg-slate-200 text-black cursor-not-allowed", - ].filter(Boolean).join(" "), + 'bg-slate-200 text-black cursor-not-allowed', + ].filter(Boolean).join(' '), disabled: props.timerStartedAt, onclick: props.timerDuration ? [actions.ResumeTimer, {}] : [actions.StartTimer, { - timerStartedAt: Date.now(), - timerDuration: props.settings.duration, - }], - }, text("Start")), - h("button", { - type: "button", + timerStartedAt: Date.now(), + timerDuration: props.settings.duration, + }], + }, text('Start')), + h('button', { + 'data-timercontrol': 'pause', + type: 'button', class: [ - "mr-1 px-2 py-1 border border-slate-700", + 'mr-1 px-2 py-1 border border-slate-700', !props.timerStartedAt && - "bg-slate-200 text-black cursor-not-allowed", - ].filter(Boolean).join(" "), + 'bg-slate-200 text-black cursor-not-allowed', + ].filter(Boolean).join(' '), disabled: !props.timerStartedAt, onclick: [actions.PauseTimer, undefined], - }, text("Pause")), - h("button", { - type: "button", + }, text('Pause')), + h('button', { + 'data-timercontrol': 'skip', + type: 'button', class: [ - "mr-1 px-2 py-1 border border-slate-700", + 'mr-1 px-2 py-1 border border-slate-700', !props.timerDuration && - "bg-slate-200 text-black cursor-not-allowed", - ].join(" "), + 'bg-slate-200 text-black cursor-not-allowed', + ].join(' '), disabled: !props.timerDuration, onclick: [ actions.Completed, @@ -113,7 +116,7 @@ export const summary = (props) => { Notification: window.Notification, }, ], - }, text("Skip")), + }, text('Skip')), ]), ]), ]);