diff --git a/.all-contributorsrc b/.all-contributorsrc
index 492cac3d..ef6eb129 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -339,6 +339,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "suddenlyGiovanni",
+ "name": "Giovanni Ravalico",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/15946771?v=4",
+ "profile": "https://suddenlyGiovanni.dev",
+ "contributions": [
+ "ideas"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index d81452c1..ee8fd431 100644
--- a/README.md
+++ b/README.md
@@ -219,6 +219,7 @@ Thanks goes to these wonderful people
Jakub Majorek 💻
+ Giovanni Ravalico 🤔
diff --git a/package-lock.json b/package-lock.json
index c865e646..00d80ec2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"@babel/code-frame": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
- "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
+ "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
"requires": {
"@babel/highlight": "^7.10.4"
}
@@ -42,11 +42,11 @@
}
},
"@babel/generator": {
- "version": "7.12.10",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz",
- "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==",
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz",
+ "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==",
"requires": {
- "@babel/types": "^7.12.10",
+ "@babel/types": "^7.12.11",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
@@ -70,27 +70,6 @@
"@babel/types": "^7.10.4"
}
},
- "@babel/helper-builder-react-jsx": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.10.4.tgz",
- "integrity": "sha512-5nPcIZ7+KKDxT1427oBivl9V9YTal7qk0diccnh7RrcgrT/pGFOjgGw1dgryyx1GvHEpXVfoDF6Ak3rTiWh8Rg==",
- "dev": true,
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.10.4",
- "@babel/types": "^7.10.4"
- }
- },
- "@babel/helper-builder-react-jsx-experimental": {
- "version": "7.12.10",
- "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.12.10.tgz",
- "integrity": "sha512-3Kcr2LGpL7CTRDTTYm1bzeor9qZbxbvU2AxsLA6mUG9gYarSfIKMK0UlU+azLWI+s0+BH768bwyaziWB2NOJlQ==",
- "dev": true,
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.12.10",
- "@babel/helper-module-imports": "^7.12.5",
- "@babel/types": "^7.12.10"
- }
- },
"@babel/helper-compilation-targets": {
"version": "7.12.5",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz",
@@ -147,13 +126,13 @@
}
},
"@babel/helper-function-name": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz",
- "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==",
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz",
+ "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==",
"requires": {
- "@babel/helper-get-function-arity": "^7.10.4",
- "@babel/template": "^7.10.4",
- "@babel/types": "^7.10.4"
+ "@babel/helper-get-function-arity": "^7.12.10",
+ "@babel/template": "^7.12.7",
+ "@babel/types": "^7.12.11"
}
},
"@babel/helper-get-function-arity": {
@@ -230,14 +209,14 @@
}
},
"@babel/helper-replace-supers": {
- "version": "7.12.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz",
- "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==",
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz",
+ "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==",
"requires": {
- "@babel/helper-member-expression-to-functions": "^7.12.1",
- "@babel/helper-optimise-call-expression": "^7.10.4",
- "@babel/traverse": "^7.12.5",
- "@babel/types": "^7.12.5"
+ "@babel/helper-member-expression-to-functions": "^7.12.7",
+ "@babel/helper-optimise-call-expression": "^7.12.10",
+ "@babel/traverse": "^7.12.10",
+ "@babel/types": "^7.12.11"
}
},
"@babel/helper-simple-access": {
@@ -258,22 +237,22 @@
}
},
"@babel/helper-split-export-declaration": {
- "version": "7.11.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz",
- "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==",
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz",
+ "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==",
"requires": {
- "@babel/types": "^7.11.0"
+ "@babel/types": "^7.12.11"
}
},
"@babel/helper-validator-identifier": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
- "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw=="
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
+ "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
},
"@babel/helper-validator-option": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz",
- "integrity": "sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==",
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz",
+ "integrity": "sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw==",
"dev": true
},
"@babel/helper-wrap-function": {
@@ -321,14 +300,14 @@
}
},
"@babel/parser": {
- "version": "7.12.10",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz",
- "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA=="
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz",
+ "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg=="
},
"@babel/plugin-proposal-async-generator-functions": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz",
- "integrity": "sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A==",
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.12.tgz",
+ "integrity": "sha512-nrz9y0a4xmUrRq51bYkWJIO5SBZyG2ys2qinHsN0zHDHVsUaModrkpyWWWXfGqYQmOL3x9sQIcTNN/pBGpo09A==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.10.4",
@@ -658,9 +637,9 @@
}
},
"@babel/plugin-transform-block-scoping": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz",
- "integrity": "sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==",
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.12.tgz",
+ "integrity": "sha512-VOEPQ/ExOVqbukuP7BYJtI5ZxxsmegTwzZ04j1aF0dkSypGo9XpDHuOrABsJu+ie+penpSJheDJ11x1BEZNiyQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.10.4"
@@ -886,26 +865,25 @@
}
},
"@babel/plugin-transform-react-jsx": {
- "version": "7.12.10",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.10.tgz",
- "integrity": "sha512-MM7/BC8QdHXM7Qc1wdnuk73R4gbuOpfrSUgfV/nODGc86sPY1tgmY2M9E9uAnf2e4DOIp8aKGWqgZfQxnTNGuw==",
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.12.tgz",
+ "integrity": "sha512-JDWGuzGNWscYcq8oJVCtSE61a5+XAOos+V0HrxnDieUus4UMnBEosDnY1VJqU5iZ4pA04QY7l0+JvHL1hZEfsw==",
"dev": true,
"requires": {
- "@babel/helper-builder-react-jsx": "^7.10.4",
- "@babel/helper-builder-react-jsx-experimental": "^7.12.10",
+ "@babel/helper-annotate-as-pure": "^7.12.10",
+ "@babel/helper-module-imports": "^7.12.5",
"@babel/helper-plugin-utils": "^7.10.4",
- "@babel/plugin-syntax-jsx": "^7.12.1"
+ "@babel/plugin-syntax-jsx": "^7.12.1",
+ "@babel/types": "^7.12.12"
}
},
"@babel/plugin-transform-react-jsx-development": {
- "version": "7.12.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.7.tgz",
- "integrity": "sha512-Rs3ETtMtR3VLXFeYRChle5SsP/P9Jp/6dsewBQfokDSzKJThlsuFcnzLTDRALiUmTC48ej19YD9uN1mupEeEDg==",
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.12.tgz",
+ "integrity": "sha512-i1AxnKxHeMxUaWVXQOSIco4tvVvvCxMSfeBMnMM06mpaJt3g+MpxYQQrDfojUQldP1xxraPSJYSMEljoWM/dCg==",
"dev": true,
"requires": {
- "@babel/helper-builder-react-jsx-experimental": "^7.12.4",
- "@babel/helper-plugin-utils": "^7.10.4",
- "@babel/plugin-syntax-jsx": "^7.12.1"
+ "@babel/plugin-transform-react-jsx": "^7.12.12"
}
},
"@babel/plugin-transform-react-jsx-self": {
@@ -1043,16 +1021,16 @@
}
},
"@babel/preset-env": {
- "version": "7.12.10",
- "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.10.tgz",
- "integrity": "sha512-Gz9hnBT/tGeTE2DBNDkD7BiWRELZt+8lSysHuDwmYXUIvtwZl0zI+D6mZgXZX0u8YBlLS4tmai9ONNY9tjRgRA==",
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.11.tgz",
+ "integrity": "sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw==",
"dev": true,
"requires": {
"@babel/compat-data": "^7.12.7",
"@babel/helper-compilation-targets": "^7.12.5",
"@babel/helper-module-imports": "^7.12.5",
"@babel/helper-plugin-utils": "^7.10.4",
- "@babel/helper-validator-option": "^7.12.1",
+ "@babel/helper-validator-option": "^7.12.11",
"@babel/plugin-proposal-async-generator-functions": "^7.12.1",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-dynamic-import": "^7.12.1",
@@ -1081,7 +1059,7 @@
"@babel/plugin-transform-arrow-functions": "^7.12.1",
"@babel/plugin-transform-async-to-generator": "^7.12.1",
"@babel/plugin-transform-block-scoped-functions": "^7.12.1",
- "@babel/plugin-transform-block-scoping": "^7.12.1",
+ "@babel/plugin-transform-block-scoping": "^7.12.11",
"@babel/plugin-transform-classes": "^7.12.1",
"@babel/plugin-transform-computed-properties": "^7.12.1",
"@babel/plugin-transform-destructuring": "^7.12.1",
@@ -1111,7 +1089,7 @@
"@babel/plugin-transform-unicode-escapes": "^7.12.1",
"@babel/plugin-transform-unicode-regex": "^7.12.1",
"@babel/preset-modules": "^0.1.3",
- "@babel/types": "^7.12.10",
+ "@babel/types": "^7.12.11",
"core-js-compat": "^3.8.0",
"semver": "^5.5.0"
}
@@ -1180,27 +1158,27 @@
}
},
"@babel/traverse": {
- "version": "7.12.10",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz",
- "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==",
- "requires": {
- "@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.10",
- "@babel/helper-function-name": "^7.10.4",
- "@babel/helper-split-export-declaration": "^7.11.0",
- "@babel/parser": "^7.12.10",
- "@babel/types": "^7.12.10",
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz",
+ "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==",
+ "requires": {
+ "@babel/code-frame": "^7.12.11",
+ "@babel/generator": "^7.12.11",
+ "@babel/helper-function-name": "^7.12.11",
+ "@babel/helper-split-export-declaration": "^7.12.11",
+ "@babel/parser": "^7.12.11",
+ "@babel/types": "^7.12.12",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
}
},
"@babel/types": {
- "version": "7.12.10",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz",
- "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==",
+ "version": "7.12.12",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz",
+ "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==",
"requires": {
- "@babel/helper-validator-identifier": "^7.10.4",
+ "@babel/helper-validator-identifier": "^7.12.11",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
@@ -1315,9 +1293,9 @@
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
},
"@eslint/eslintrc": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz",
- "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==",
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz",
+ "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
@@ -1327,7 +1305,7 @@
"ignore": "^4.0.6",
"import-fresh": "^3.2.1",
"js-yaml": "^3.13.1",
- "lodash": "^4.17.19",
+ "lodash": "^4.17.20",
"minimatch": "^3.0.4",
"strip-json-comments": "^3.1.1"
},
@@ -1745,18 +1723,20 @@
}
},
"@kentcdodds/react-workshop-app": {
- "version": "2.20.0",
- "resolved": "https://registry.npmjs.org/@kentcdodds/react-workshop-app/-/react-workshop-app-2.20.0.tgz",
- "integrity": "sha512-rTVbNGY3L7WMgW/pNKh68yCQeuuY1htF+iOb37o4uxdmuqi2SiwggE3jxUUXZZt4FdWk3eZsm5Wdr4U+x88v+w==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@kentcdodds/react-workshop-app/-/react-workshop-app-3.0.0.tgz",
+ "integrity": "sha512-5uUQoc8QBxJ6Q3r9U0W5Y4cpcBHpMicOuVXVbPL60CM0O2ul72YMISvvprte0FAPjAN3rBLqsGzHn4LXFxMbdQ==",
"requires": {
"@babel/runtime": "^7.12.5",
"@emotion/core": "^10.0.35",
- "@reach/tabs": "^0.11.2",
- "@reach/tooltip": "^0.11.2",
- "@testing-library/jest-dom": "^5.11.6",
- "@testing-library/react": "^11.1.2",
+ "@reach/tabs": "^0.12.1",
+ "@reach/tooltip": "^0.12.1",
+ "@testing-library/jest-dom": "^5.11.9",
+ "@testing-library/react": "^11.2.3",
+ "@types/react": "^17.0.0",
+ "@types/react-dom": "^17.0.0",
"chalk": "^4.1.0",
- "codegen.macro": "^4.0.0",
+ "codegen.macro": "^4.1.0",
"cross-env": "^7.0.3",
"cross-spawn": "^7.0.3",
"emotion-theming": "^10.0.27",
@@ -1767,11 +1747,12 @@
"inquirer": "^7.3.3",
"is-ci": "^2.0.0",
"mdx-loader": "^3.0.2",
- "msw": "^0.21.3",
+ "mq-polyfill": "^1.1.8",
+ "msw": "^0.25.0",
"node-match-path": "^0.6.0",
"normalize.css": "^8.0.1",
"raw-loader": "^4.0.2",
- "react-error-boundary": "^3.0.2",
+ "react-error-boundary": "^3.1.0",
"react-icons": "^3.11.0",
"react-router-dom": "^5.2.0",
"replace-in-file": "^6.1.0"
@@ -1826,38 +1807,39 @@
"integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA=="
},
"@nodelib/fs.scandir": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
- "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
+ "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
"dev": true,
"requires": {
- "@nodelib/fs.stat": "2.0.3",
+ "@nodelib/fs.stat": "2.0.4",
"run-parallel": "^1.1.9"
}
},
"@nodelib/fs.stat": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
- "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
+ "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
"dev": true
},
"@nodelib/fs.walk": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
- "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
+ "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
"dev": true,
"requires": {
- "@nodelib/fs.scandir": "2.1.3",
+ "@nodelib/fs.scandir": "2.1.4",
"fastq": "^1.6.0"
}
},
"@npmcli/move-file": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz",
- "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.1.tgz",
+ "integrity": "sha512-LtWTicuF2wp7PNTuyCwABx7nNG+DnzSE8gN0iWxkC6mpgm/iOPu0ZMTkXuCxmJxtWFsDxUaixM9COSNJEMUfuQ==",
"dev": true,
"requires": {
- "mkdirp": "^1.0.4"
+ "mkdirp": "^1.0.4",
+ "rimraf": "^3.0.2"
},
"dependencies": {
"mkdirp": {
@@ -1907,20 +1889,20 @@
}
},
"@reach/auto-id": {
- "version": "0.11.2",
- "resolved": "https://registry.npmjs.org/@reach/auto-id/-/auto-id-0.11.2.tgz",
- "integrity": "sha512-YZ21b0Kb88wJ0t7QjSznWOYskARQMnmXY9Y2XZ5RyYcZ2krT4s3+ghghpfaPs6BKcrZDonZCrU65OFDJPa1jAw==",
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/@reach/auto-id/-/auto-id-0.12.1.tgz",
+ "integrity": "sha512-s8cdY6dF0hEBB/28BbidB2EX6JfEBVIWLP6S2Jg0Xqq2H3xijL+zrsjL40jACwXRkignjuP+CvYsuFuO0+/GRA==",
"requires": {
- "@reach/utils": "0.11.2",
+ "@reach/utils": "0.12.1",
"tslib": "^2.0.0"
}
},
"@reach/descendants": {
- "version": "0.11.2",
- "resolved": "https://registry.npmjs.org/@reach/descendants/-/descendants-0.11.2.tgz",
- "integrity": "sha512-63Wdx32/RyjGRJc4UZKK7F1sIrb6jeGkDwvQH0hv0lRAhEjsiSQ1t2JTYDml3testFP48J0B2xS7JzNeY0zoQw==",
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/@reach/descendants/-/descendants-0.12.1.tgz",
+ "integrity": "sha512-lvpyQ2EixbN7GvT8LyjZfHWQZz/cKwa/p7E26YQOT8nvxm4ABKRGxaSTwUA7D+MLOX6NtHo2qyZ9wippaXB5sQ==",
"requires": {
- "@reach/utils": "0.11.2",
+ "@reach/utils": "0.12.1",
"tslib": "^2.0.0"
}
},
@@ -1930,55 +1912,55 @@
"integrity": "sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ=="
},
"@reach/portal": {
- "version": "0.11.2",
- "resolved": "https://registry.npmjs.org/@reach/portal/-/portal-0.11.2.tgz",
- "integrity": "sha512-/53A/rY5oX2Y7D5TpvsP+V5cSd+4MPY6f21mAmVn4DCVwpkCFOlJ059ZL7ixS85M0Jz48YQnnvBJUqwkxqUG/g==",
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/@reach/portal/-/portal-0.12.1.tgz",
+ "integrity": "sha512-Lhmtd2Qw1DzNZ2m0GHNzCu+2TYUf6kBREPSQJf44AP6kThRs02p1clntbJcmW/rrpYFYgFNbgf5Lso7NyW9ZXg==",
"requires": {
- "@reach/utils": "0.11.2",
+ "@reach/utils": "0.12.1",
"tslib": "^2.0.0"
}
},
"@reach/rect": {
- "version": "0.11.2",
- "resolved": "https://registry.npmjs.org/@reach/rect/-/rect-0.11.2.tgz",
- "integrity": "sha512-eoUWayAADi1ITtrc+8jN9NsBTUkfpORkOs5bQb4RnR6UA/3zlxo5VPuxWgWAG0BCohZlqsxg7NpvckNAyaiAAQ==",
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/@reach/rect/-/rect-0.12.1.tgz",
+ "integrity": "sha512-c+EjKc+9ud832MpmYKsxu+2R0/XHyXk47ik/N+DIHsugIgKJn2B34r4r9benqsaHncUO1IQk5rTv40D7x+yR0g==",
"requires": {
"@reach/observe-rect": "1.2.0",
- "@reach/utils": "0.11.2",
+ "@reach/utils": "0.12.1",
"prop-types": "^15.7.2",
"tslib": "^2.0.0"
}
},
"@reach/tabs": {
- "version": "0.11.2",
- "resolved": "https://registry.npmjs.org/@reach/tabs/-/tabs-0.11.2.tgz",
- "integrity": "sha512-iVDXfmdpJmBavyyiJbm9sUddlelra+x5MaF5Y4QwV7Q+w3t9RLqTePQAOX+2MX0BJgvasX/YItMBO2JumWxGPQ==",
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/@reach/tabs/-/tabs-0.12.1.tgz",
+ "integrity": "sha512-k9piLoajPhIpM6BlHDSTMaBK9dGYDB9Ri+Ic+o+BqLzO1Lm0mC3ghXeYJcwyTzGA47dOYklI65TW/RxYqtT38g==",
"requires": {
- "@reach/auto-id": "0.11.2",
- "@reach/descendants": "0.11.2",
- "@reach/utils": "0.11.2",
+ "@reach/auto-id": "0.12.1",
+ "@reach/descendants": "0.12.1",
+ "@reach/utils": "0.12.1",
"prop-types": "^15.7.2",
"tslib": "^2.0.0"
}
},
"@reach/tooltip": {
- "version": "0.11.2",
- "resolved": "https://registry.npmjs.org/@reach/tooltip/-/tooltip-0.11.2.tgz",
- "integrity": "sha512-aTi3aLkRZMHrNiHt84vnyTWNj84rPdGYkxAfaFpxgkaKpos3XmaOPiR+n/3YzQUoJXISuw8mZezcrDtsSpr3aA==",
- "requires": {
- "@reach/auto-id": "0.11.2",
- "@reach/portal": "0.11.2",
- "@reach/rect": "0.11.2",
- "@reach/utils": "0.11.2",
- "@reach/visually-hidden": "0.11.1",
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/@reach/tooltip/-/tooltip-0.12.1.tgz",
+ "integrity": "sha512-9qk7WcgAjN/2tFEHN3Oi1m7BrSsL+MBFTFaxTaNqQacXYIKO3jNVFzLxkDVgyFP82h6EMJ5CkAJjOMi4aNyicQ==",
+ "requires": {
+ "@reach/auto-id": "0.12.1",
+ "@reach/portal": "0.12.1",
+ "@reach/rect": "0.12.1",
+ "@reach/utils": "0.12.1",
+ "@reach/visually-hidden": "0.12.0",
"prop-types": "^15.7.2",
"tslib": "^2.0.0"
}
},
"@reach/utils": {
- "version": "0.11.2",
- "resolved": "https://registry.npmjs.org/@reach/utils/-/utils-0.11.2.tgz",
- "integrity": "sha512-fBTolYj+rKTROXmf0zHO0rCWSvw7J0ALmYj5QxW4DmITMOH5uyRuWDWOfqohIGFbOtF/sum50WTB3tvx76d+Aw==",
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/@reach/utils/-/utils-0.12.1.tgz",
+ "integrity": "sha512-5uH4OgO+GupAzZuf3b6Wv/9uC6NdMBlxS6FSKD6YqSxP4QJ0vjD34RVon6N/RMRORacCLyD/aaZIA7283YgeOg==",
"requires": {
"@types/warning": "^3.0.0",
"tslib": "^2.0.0",
@@ -1986,9 +1968,9 @@
}
},
"@reach/visually-hidden": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/@reach/visually-hidden/-/visually-hidden-0.11.1.tgz",
- "integrity": "sha512-TZZNSttor2jG6ZPGI35s/8G0FNSz49QrJIhAZbnUqHyPf3+jtNqAC0dOWW8Nuk+mApDDDVYd2KZ9P2vnzllNnQ==",
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/@reach/visually-hidden/-/visually-hidden-0.12.0.tgz",
+ "integrity": "sha512-VXtyR36WOS0FHmFQ/BzfswwPyBXICl/YjmTPtx/I0Vy5C6djjhD9kDsE+h/FpHzP3ugTdqdqiPBVElIZTSwOSA==",
"requires": {
"tslib": "^2.0.0"
}
@@ -2036,9 +2018,9 @@
}
},
"@sinonjs/commons": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz",
- "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==",
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz",
+ "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==",
"dev": true,
"requires": {
"type-detect": "4.0.8"
@@ -2236,9 +2218,9 @@
}
},
"@testing-library/dom": {
- "version": "7.29.0",
- "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.29.0.tgz",
- "integrity": "sha512-0hhuJSmw/zLc6ewR9cVm84TehuTd7tbqBX9pRNSp8znJ9gTmSgesdbiGZtt8R6dL+2rgaPFp9Yjr7IU1HWm49w==",
+ "version": "7.29.4",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.29.4.tgz",
+ "integrity": "sha512-CtrJRiSYEfbtNGtEsd78mk1n1v2TUbeABlNIcOCJdDfkN5/JTOwQEbbQpoSRxGqzcWPgStMvJ4mNolSuBRv1NA==",
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
@@ -2251,9 +2233,9 @@
}
},
"@testing-library/jest-dom": {
- "version": "5.11.6",
- "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.11.6.tgz",
- "integrity": "sha512-cVZyUNRWwUKI0++yepYpYX7uhrP398I+tGz4zOlLVlUYnZS+Svuxv4fwLeCIy7TnBYKXUaOlQr3vopxL8ZfEnA==",
+ "version": "5.11.9",
+ "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.11.9.tgz",
+ "integrity": "sha512-Mn2gnA9d1wStlAIT2NU8J15LNob0YFBVjs2aEQ3j8rsfRQo+lAs7/ui1i2TGaJjapLmuNPLTsrm+nPjmZDwpcQ==",
"requires": {
"@babel/runtime": "^7.9.2",
"@types/testing-library__jest-dom": "^5.9.1",
@@ -2311,20 +2293,20 @@
}
},
"@testing-library/react": {
- "version": "11.2.2",
- "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.2.tgz",
- "integrity": "sha512-jaxm0hwUjv+hzC+UFEywic7buDC9JQ1q3cDsrWVSDAPmLotfA6E6kUHlYm/zOeGCac6g48DR36tFHxl7Zb+N5A==",
+ "version": "11.2.3",
+ "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.3.tgz",
+ "integrity": "sha512-BirBUGPkTW28ULuCwIbYo0y2+0aavHczBT6N9r3LrsswEW3pg25l1wgoE7I8QBIy1upXWkwKpYdWY7NYYP0Bxw==",
"requires": {
"@babel/runtime": "^7.12.5",
"@testing-library/dom": "^7.28.1"
}
},
"@testing-library/user-event": {
- "version": "12.5.0",
- "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.5.0.tgz",
- "integrity": "sha512-9uXr4+OwjHVUxzdfYZ2yCnF3xlEzr8cZOdqjGnqD8Qb1NoCJrm7UXxG3RUpL2QqcqZ1eqVuxkFJTCky5Yit+XQ==",
+ "version": "12.6.2",
+ "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.6.2.tgz",
+ "integrity": "sha512-4OsiTSo2vbQm+eOnm1un8b9i2Re4mn+D7d7ET6HXtzYKY7vPe3O01iYKRmSW9vS5mNrQcCLwvRhVq1gWs5YGKA==",
"requires": {
- "@babel/runtime": "^7.10.2"
+ "@babel/runtime": "^7.12.5"
}
},
"@types/anymatch": {
@@ -2334,9 +2316,9 @@
"dev": true
},
"@types/aria-query": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz",
- "integrity": "sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A=="
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz",
+ "integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg=="
},
"@types/babel__core": {
"version": "7.1.12",
@@ -2395,9 +2377,9 @@
}
},
"@types/estree": {
- "version": "0.0.45",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz",
- "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==",
+ "version": "0.0.46",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz",
+ "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==",
"dev": true
},
"@types/glob": {
@@ -2455,18 +2437,18 @@
}
},
"@types/jest": {
- "version": "26.0.19",
- "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.19.tgz",
- "integrity": "sha512-jqHoirTG61fee6v6rwbnEuKhpSKih0tuhqeFbCmMmErhtu3BYlOZaXWjffgOstMM4S/3iQD31lI5bGLTrs97yQ==",
+ "version": "26.0.20",
+ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.20.tgz",
+ "integrity": "sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==",
"requires": {
"jest-diff": "^26.0.0",
"pretty-format": "^26.0.0"
}
},
"@types/json-schema": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
- "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw=="
+ "version": "7.0.7",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
+ "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA=="
},
"@types/json5": {
"version": "0.0.29",
@@ -2489,9 +2471,9 @@
"dev": true
},
"@types/node": {
- "version": "14.14.12",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.12.tgz",
- "integrity": "sha512-ASH8OPHMNlkdjrEdmoILmzFfsJICvhBsFfAum4aKZ/9U4B6M6tTmTPh+f3ttWdD74CEGV5XvXWkbyfSdXaTd7g=="
+ "version": "14.14.22",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz",
+ "integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw=="
},
"@types/normalize-package-data": {
"version": "2.4.0",
@@ -2510,16 +2492,15 @@
"integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw=="
},
"@types/prettier": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.5.tgz",
- "integrity": "sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==",
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.6.tgz",
+ "integrity": "sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA==",
"dev": true
},
"@types/prop-types": {
"version": "15.7.3",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
- "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
- "dev": true
+ "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
},
"@types/q": {
"version": "1.5.4",
@@ -2531,17 +2512,15 @@
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.0.tgz",
"integrity": "sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==",
- "dev": true,
"requires": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
},
"dependencies": {
"csstype": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz",
- "integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==",
- "dev": true
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz",
+ "integrity": "sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw=="
}
}
},
@@ -2549,7 +2528,6 @@
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.0.tgz",
"integrity": "sha512-lUqY7OlkF/RbNtD5nIq7ot8NquXrdFrjSOR6+w9a9RFQevGi1oZO1dcJbXMeONAPKtZ2UrZOEJ5UOCVsxbLk/g==",
- "dev": true,
"requires": {
"@types/react": "*"
}
@@ -2617,9 +2595,9 @@
"integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI="
},
"@types/webpack": {
- "version": "4.41.25",
- "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.25.tgz",
- "integrity": "sha512-cr6kZ+4m9lp86ytQc1jPOJXgINQyz3kLLunZ57jznW+WIAL0JqZbGubQk4GlD42MuQL5JGOABrxdpqqWeovlVQ==",
+ "version": "4.41.26",
+ "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.26.tgz",
+ "integrity": "sha512-7ZyTfxjCRwexh+EJFwRUM+CDB2XvgHl4vfuqf1ZKrgGvcS5BrNvPQqJh3tsZ0P6h6Aa1qClVHaJZszLPzpqHeA==",
"dev": true,
"requires": {
"@types/anymatch": "*",
@@ -2658,28 +2636,29 @@
}
},
"@types/yargs": {
- "version": "15.0.11",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.11.tgz",
- "integrity": "sha512-jfcNBxHFYJ4nPIacsi3woz1+kvUO6s1CyeEhtnDHBjHUMNj5UlW2GynmnSgiJJEdNg9yW5C8lfoNRZrHGv5EqA==",
+ "version": "15.0.13",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
+ "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==",
"requires": {
"@types/yargs-parser": "*"
}
},
"@types/yargs-parser": {
- "version": "15.0.0",
- "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz",
- "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw=="
+ "version": "20.2.0",
+ "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz",
+ "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
},
"@typescript-eslint/eslint-plugin": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.9.1.tgz",
- "integrity": "sha512-QRLDSvIPeI1pz5tVuurD+cStNR4sle4avtHhxA+2uyixWGFjKzJ+EaFVRW6dA/jOgjV5DTAjOxboQkRDE8cRlQ==",
+ "version": "4.14.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.14.1.tgz",
+ "integrity": "sha512-5JriGbYhtqMS1kRcZTQxndz1lKMwwEXKbwZbkUZNnp6MJX0+OVXnG0kOlBZP4LUAxEyzu3cs+EXd/97MJXsGfw==",
"dev": true,
"requires": {
- "@typescript-eslint/experimental-utils": "4.9.1",
- "@typescript-eslint/scope-manager": "4.9.1",
+ "@typescript-eslint/experimental-utils": "4.14.1",
+ "@typescript-eslint/scope-manager": "4.14.1",
"debug": "^4.1.1",
"functional-red-black-tree": "^1.0.1",
+ "lodash": "^4.17.15",
"regexpp": "^3.0.0",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
@@ -2697,55 +2676,55 @@
}
},
"@typescript-eslint/experimental-utils": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.9.1.tgz",
- "integrity": "sha512-c3k/xJqk0exLFs+cWSJxIjqLYwdHCuLWhnpnikmPQD2+NGAx9KjLYlBDcSI81EArh9FDYSL6dslAUSwILeWOxg==",
+ "version": "4.14.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.14.1.tgz",
+ "integrity": "sha512-2CuHWOJwvpw0LofbyG5gvYjEyoJeSvVH2PnfUQSn0KQr4v8Dql2pr43ohmx4fdPQ/eVoTSFjTi/bsGEXl/zUUQ==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.3",
- "@typescript-eslint/scope-manager": "4.9.1",
- "@typescript-eslint/types": "4.9.1",
- "@typescript-eslint/typescript-estree": "4.9.1",
+ "@typescript-eslint/scope-manager": "4.14.1",
+ "@typescript-eslint/types": "4.14.1",
+ "@typescript-eslint/typescript-estree": "4.14.1",
"eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0"
}
},
"@typescript-eslint/parser": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.9.1.tgz",
- "integrity": "sha512-Gv2VpqiomvQ2v4UL+dXlQcZ8zCX4eTkoIW+1aGVWT6yTO+6jbxsw7yQl2z2pPl/4B9qa5JXeIbhJpONKjXIy3g==",
+ "version": "4.14.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.14.1.tgz",
+ "integrity": "sha512-mL3+gU18g9JPsHZuKMZ8Z0Ss9YP1S5xYZ7n68Z98GnPq02pYNQuRXL85b9GYhl6jpdvUc45Km7hAl71vybjUmw==",
"dev": true,
"requires": {
- "@typescript-eslint/scope-manager": "4.9.1",
- "@typescript-eslint/types": "4.9.1",
- "@typescript-eslint/typescript-estree": "4.9.1",
+ "@typescript-eslint/scope-manager": "4.14.1",
+ "@typescript-eslint/types": "4.14.1",
+ "@typescript-eslint/typescript-estree": "4.14.1",
"debug": "^4.1.1"
}
},
"@typescript-eslint/scope-manager": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.9.1.tgz",
- "integrity": "sha512-sa4L9yUfD/1sg9Kl8OxPxvpUcqxKXRjBeZxBuZSSV1v13hjfEJkn84n0An2hN8oLQ1PmEl2uA6FkI07idXeFgQ==",
+ "version": "4.14.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.14.1.tgz",
+ "integrity": "sha512-F4bjJcSqXqHnC9JGUlnqSa3fC2YH5zTtmACS1Hk+WX/nFB0guuynVK5ev35D4XZbdKjulXBAQMyRr216kmxghw==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "4.9.1",
- "@typescript-eslint/visitor-keys": "4.9.1"
+ "@typescript-eslint/types": "4.14.1",
+ "@typescript-eslint/visitor-keys": "4.14.1"
}
},
"@typescript-eslint/types": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.9.1.tgz",
- "integrity": "sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA==",
+ "version": "4.14.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.14.1.tgz",
+ "integrity": "sha512-SkhzHdI/AllAgQSxXM89XwS1Tkic7csPdndUuTKabEwRcEfR8uQ/iPA3Dgio1rqsV3jtqZhY0QQni8rLswJM2w==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.9.1.tgz",
- "integrity": "sha512-bzP8vqwX6Vgmvs81bPtCkLtM/Skh36NE6unu6tsDeU/ZFoYthlTXbBmpIrvosgiDKlWTfb2ZpPELHH89aQjeQw==",
+ "version": "4.14.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.14.1.tgz",
+ "integrity": "sha512-M8+7MbzKC1PvJIA8kR2sSBnex8bsR5auatLCnVlNTJczmJgqRn8M+sAlQfkEq7M4IY3WmaNJ+LJjPVRrREVSHQ==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "4.9.1",
- "@typescript-eslint/visitor-keys": "4.9.1",
+ "@typescript-eslint/types": "4.14.1",
+ "@typescript-eslint/visitor-keys": "4.14.1",
"debug": "^4.1.1",
"globby": "^11.0.1",
"is-glob": "^4.0.1",
@@ -2766,12 +2745,12 @@
}
},
"@typescript-eslint/visitor-keys": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.1.tgz",
- "integrity": "sha512-9gspzc6UqLQHd7lXQS7oWs+hrYggspv/rk6zzEMhCbYwPE/sF7oxo7GAjkS35Tdlt7wguIG+ViWCPtVZHz/ybQ==",
+ "version": "4.14.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.1.tgz",
+ "integrity": "sha512-TAblbDXOI7bd0C/9PE1G+AFo7R5uc+ty1ArDoxmrC1ah61Hn6shURKy7gLdRb1qKJmjHkqu5Oq+e4Kt0jwf1IA==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "4.9.1",
+ "@typescript-eslint/types": "4.14.1",
"eslint-visitor-keys": "^2.0.0"
}
},
@@ -3309,9 +3288,9 @@
"dev": true
},
"astral-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
- "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
"dev": true
},
"async": {
@@ -3480,13 +3459,37 @@
}
},
"babel-plugin-codegen": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-codegen/-/babel-plugin-codegen-4.0.1.tgz",
- "integrity": "sha512-cehTkKAGgENw+ftEngX/zVfFqMxFFItsatwmLHfxVLJCnkJvREQhsCb5/WNrNdP7L3tbwGgd5JQt9dFth+p24g==",
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-codegen/-/babel-plugin-codegen-4.1.4.tgz",
+ "integrity": "sha512-WWqjrCgi/+bOA9Vnx0k6tbuyDVzJaMFcBlzBpw02r9yrW8W4qWu+ObZE8lbM1g57IX+tHHS4WbO0zW40sDLGPA==",
"requires": {
- "@babel/runtime": "^7.9.2",
- "babel-plugin-macros": "^2.8.0",
+ "@babel/runtime": "^7.12.5",
+ "babel-plugin-macros": "^3.0.1",
"require-from-string": "^2.0.2"
+ },
+ "dependencies": {
+ "babel-plugin-macros": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.0.1.tgz",
+ "integrity": "sha512-CKt4+Oy9k2wiN+hT1uZzOw7d8zb1anbQpf7KLwaaXRCi/4pzKdFKHf7v5mvoPmjkmxshh7eKZQuRop06r5WP4w==",
+ "requires": {
+ "@babel/runtime": "^7.12.5",
+ "cosmiconfig": "^7.0.0",
+ "resolve": "^1.19.0"
+ }
+ },
+ "cosmiconfig": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
+ "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
+ "requires": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ }
+ }
}
},
"babel-plugin-dynamic-import-node": {
@@ -3592,9 +3595,9 @@
"dev": true
},
"babel-preset-current-node-syntax": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.0.tgz",
- "integrity": "sha512-mGkvkpocWJes1CmMKtgGUwCeeq0pOhALyymozzDWYomHTbDLwueDYG6p4TK1YOeYHCzBzYPsWkgTto10JubI1Q==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
+ "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
"dev": true,
"requires": {
"@babel/plugin-syntax-async-generators": "^7.8.4",
@@ -3923,9 +3926,9 @@
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="
},
"binary-extensions": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
- "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ=="
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
},
"bindings": {
"version": "1.5.0",
@@ -4127,16 +4130,16 @@
}
},
"browserslist": {
- "version": "4.16.0",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz",
- "integrity": "sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==",
+ "version": "4.16.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz",
+ "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==",
"dev": true,
"requires": {
- "caniuse-lite": "^1.0.30001165",
+ "caniuse-lite": "^1.0.30001173",
"colorette": "^1.2.1",
- "electron-to-chromium": "^1.3.621",
+ "electron-to-chromium": "^1.3.634",
"escalade": "^3.1.1",
- "node-releases": "^1.1.67"
+ "node-releases": "^1.1.69"
}
},
"bser": {
@@ -4186,9 +4189,9 @@
"dev": true
},
"builtin-modules": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
- "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
+ "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
"dev": true
},
"builtin-status-codes": {
@@ -4254,13 +4257,13 @@
}
},
"call-bind": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz",
- "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dev": true,
"requires": {
"function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.0"
+ "get-intrinsic": "^1.0.2"
}
},
"caller-callsite": {
@@ -4326,9 +4329,9 @@
}
},
"caniuse-lite": {
- "version": "1.0.30001165",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001165.tgz",
- "integrity": "sha512-8cEsSMwXfx7lWSUMA2s08z9dIgsnR5NAqjXP23stdsU3AUWkCr/rr4s4OFtHXn5XXr6+7kam3QFVoYyXNPdJPA==",
+ "version": "1.0.30001181",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001181.tgz",
+ "integrity": "sha512-m5ul/ARCX50JB8BSNM+oiPmQrR5UmngaQ3QThTTp5HcIIQGP/nPBs82BYLE+tigzm3VW+F4BJIhUyaVtEweelQ==",
"dev": true
},
"capture-exit": {
@@ -4460,13 +4463,13 @@
"dev": true
},
"chokidar": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
- "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
+ "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
"requires": {
"anymatch": "~3.1.1",
"braces": "~3.0.2",
- "fsevents": "~2.1.2",
+ "fsevents": "~2.3.1",
"glob-parent": "~5.1.0",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
@@ -4640,11 +4643,11 @@
}
},
"codegen.macro": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/codegen.macro/-/codegen.macro-4.0.0.tgz",
- "integrity": "sha512-7K7BXVLmsO4shE/+2KhzCjP7uPbqwbkY4o5EJaJouncVY7IkZozpnbUex8xjWB9AzEV9aWpnXe0+oLbEuPj9Ew==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/codegen.macro/-/codegen.macro-4.1.0.tgz",
+ "integrity": "sha512-T0A8vdX9SkhT00cd7nWQwlg8CT2qQwp1o2+ZD7Wqx38ABK0kJvhk/IJTjNgnE1W35dE98+OzLr1zluVREz5bPg==",
"requires": {
- "babel-plugin-codegen": "^4.0.0"
+ "babel-plugin-codegen": "^4.1.0"
}
},
"collapse-white-space": {
@@ -4955,18 +4958,18 @@
"dev": true
},
"core-js": {
- "version": "3.8.1",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.1.tgz",
- "integrity": "sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg==",
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.3.tgz",
+ "integrity": "sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q==",
"dev": true
},
"core-js-compat": {
- "version": "3.8.1",
- "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.1.tgz",
- "integrity": "sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ==",
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.3.tgz",
+ "integrity": "sha512-1sCb0wBXnBIL16pfFG1Gkvei6UzvKyTNYpiC41yrdjEv0UoJoq9E/abTMzyYJ6JpTkAj15dLjbqifIzEBDVvog==",
"dev": true,
"requires": {
- "browserslist": "^4.15.0",
+ "browserslist": "^4.16.1",
"semver": "7.0.0"
},
"dependencies": {
@@ -4979,9 +4982,9 @@
}
},
"core-js-pure": {
- "version": "3.8.1",
- "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.8.1.tgz",
- "integrity": "sha512-Se+LaxqXlVXGvmexKGPvnUIYC1jwXu1H6Pkyb3uBM5d8/NELMYCHs/4/roD7721NxrTLyv7e5nXd5/QLBO+10g=="
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.8.3.tgz",
+ "integrity": "sha512-V5qQZVAr9K0xu7jXg1M7qTEwuxUgqr7dUOezGaNa7i+Xn9oXAU/d1fzqD9ObuwpVQOaorO5s70ckyi1woP9lVA=="
},
"core-util-is": {
"version": "1.0.2",
@@ -6021,9 +6024,9 @@
"dev": true
},
"electron-to-chromium": {
- "version": "1.3.622",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.622.tgz",
- "integrity": "sha512-AJT0Fm1W0uZlMVVkkJrcCVvczDuF8tPm3bwzQf5WO8AaASB2hwTRP7B8pU5rqjireH+ib6am8+hH5/QkXzzYKw==",
+ "version": "1.3.649",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.649.tgz",
+ "integrity": "sha512-ojGDupQ3UMkvPWcTICe4JYe17+o9OLiFMPoduoR72Zp2ILt1mRVeqnxBEd6s/ptekrnsFU+0A4lStfBe/wyG/A==",
"dev": true
},
"elliptic": {
@@ -6096,9 +6099,9 @@
}
},
"enhanced-resolve": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz",
- "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
+ "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
@@ -6158,15 +6161,15 @@
}
},
"entities": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
- "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"dev": true
},
"errno": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
- "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
+ "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
"dev": true,
"requires": {
"prr": "~1.0.1"
@@ -6190,23 +6193,25 @@
}
},
"es-abstract": {
- "version": "1.18.0-next.1",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
- "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
+ "version": "1.18.0-next.2",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz",
+ "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==",
"dev": true,
"requires": {
+ "call-bind": "^1.0.2",
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.2.2",
- "is-negative-zero": "^2.0.0",
+ "is-negative-zero": "^2.0.1",
"is-regex": "^1.1.1",
- "object-inspect": "^1.8.0",
+ "object-inspect": "^1.9.0",
"object-keys": "^1.1.1",
- "object.assign": "^4.1.1",
- "string.prototype.trimend": "^1.0.1",
- "string.prototype.trimstart": "^1.0.1"
+ "object.assign": "^4.1.2",
+ "string.prototype.trimend": "^1.0.3",
+ "string.prototype.trimstart": "^1.0.3"
}
},
"es-to-primitive": {
@@ -6330,13 +6335,13 @@
}
},
"eslint": {
- "version": "7.15.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.15.0.tgz",
- "integrity": "sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA==",
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz",
+ "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
- "@eslint/eslintrc": "^0.2.2",
+ "@eslint/eslintrc": "^0.3.0",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
@@ -6360,7 +6365,7 @@
"js-yaml": "^3.13.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
- "lodash": "^4.17.19",
+ "lodash": "^4.17.20",
"minimatch": "^3.0.4",
"natural-compare": "^1.4.0",
"optionator": "^0.9.1",
@@ -6369,7 +6374,7 @@
"semver": "^7.2.1",
"strip-ansi": "^6.0.0",
"strip-json-comments": "^3.1.0",
- "table": "^5.2.3",
+ "table": "^6.0.4",
"text-table": "^0.2.0",
"v8-compile-cache": "^2.0.3"
},
@@ -6620,17 +6625,17 @@
},
"dependencies": {
"emoji-regex": {
- "version": "9.2.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.0.tgz",
- "integrity": "sha512-DNc3KFPK18bPdElMJnf/Pkv5TXhxFU3YFDEuGLDRtPmV4rkmCjBkCSEp22u6rBHdSN9Vlp/GK7k98prmE1Jgug==",
+ "version": "9.2.1",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.1.tgz",
+ "integrity": "sha512-117l1H6U4X3Krn+MrzYrL57d5H7siRHWraBs7s+LjRuFK7Fe7hJqnJ0skWlinqsycVLU5YAo6L8CsEYQ0V5prg==",
"dev": true
}
}
},
"eslint-plugin-react": {
- "version": "7.21.5",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz",
- "integrity": "sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g==",
+ "version": "7.22.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz",
+ "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==",
"dev": true,
"requires": {
"array-includes": "^3.1.1",
@@ -6767,9 +6772,9 @@
"dev": true
},
"eslint-webpack-plugin": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-2.4.1.tgz",
- "integrity": "sha512-cj8iPWZKuAiVD8MMgTSunyMCAvxQxp5mxoPHZl1UMGkApFXaXJHdCFcCR+oZEJbBNhReNa5SjESIn34uqUbBtg==",
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-2.4.3.tgz",
+ "integrity": "sha512-+15ifHFkGn0gB7lQBe+xgyKcjelxv9xlTutGHEPYBUUj+1Rjrjq3+1REJLJpyAHgpQTatpqkRY1z8gQuyn3Aww==",
"dev": true,
"requires": {
"@types/eslint": "^7.2.4",
@@ -7243,9 +7248,9 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-glob": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
- "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
+ "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.2",
@@ -7268,9 +7273,9 @@
"dev": true
},
"fastq": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz",
- "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==",
+ "version": "1.10.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.1.tgz",
+ "integrity": "sha512-AWuv6Ery3pM+dY7LYS8YIaCiQvUaos9OB1RyNgaOWnaX+Tik7Onvcsf8x8c+YtDeT0maYLniBip2hox5KtEXXA==",
"dev": true,
"requires": {
"reusify": "^1.0.4"
@@ -7470,12 +7475,12 @@
}
},
"find-versions": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz",
- "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz",
+ "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==",
"dev": true,
"requires": {
- "semver-regex": "^2.0.0"
+ "semver-regex": "^3.1.2"
}
},
"flat-cache": {
@@ -7489,9 +7494,9 @@
}
},
"flatted": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz",
- "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz",
+ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==",
"dev": true
},
"flatten": {
@@ -7548,9 +7553,9 @@
"integrity": "sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ=="
},
"follow-redirects": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
- "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==",
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz",
+ "integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==",
"dev": true
},
"for-in": {
@@ -7798,15 +7803,15 @@
}
},
"fs-extra": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
- "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"dev": true,
"requires": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
- "universalify": "^1.0.0"
+ "universalify": "^2.0.0"
}
},
"fs-minipass": {
@@ -7868,9 +7873,9 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"fsevents": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
- "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.1.tgz",
+ "integrity": "sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw==",
"optional": true
},
"function-bind": {
@@ -7895,9 +7900,9 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"get-intrinsic": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz",
- "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.0.tgz",
+ "integrity": "sha512-M11rgtQp5GZMZzDL7jLTNxbDfurpzuau5uqRWDPvlHjfvg3TdScAZo96GLvhMjImrmR8uAt0FS2RLoMrfWGKlg==",
"dev": true,
"requires": {
"function-bind": "^1.1.1",
@@ -8014,9 +8019,9 @@
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
},
"globby": {
- "version": "11.0.1",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
- "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
+ "version": "11.0.2",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz",
+ "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==",
"dev": true,
"requires": {
"array-union": "^2.1.0",
@@ -8043,9 +8048,9 @@
"dev": true
},
"graphql": {
- "version": "15.4.0",
- "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.4.0.tgz",
- "integrity": "sha512-EB3zgGchcabbsU9cFe1j+yxdzKQKAbGUWRb13DsrsMN1yyfmmIq+2+L5MqVWcDCE4V89R5AyUOi7sMOGxdsYtA=="
+ "version": "15.5.0",
+ "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.5.0.tgz",
+ "integrity": "sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA=="
},
"gray-matter": {
"version": "4.0.2",
@@ -8437,9 +8442,9 @@
}
},
"html-entities": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz",
- "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz",
+ "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==",
"dev": true
},
"html-escaper": {
@@ -8792,18 +8797,18 @@
"dev": true
},
"husky": {
- "version": "4.3.5",
- "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.5.tgz",
- "integrity": "sha512-E5S/1HMoDDaqsH8kDF5zeKEQbYqe3wL9zJDyqyYqc8I4vHBtAoxkDBGXox0lZ9RI+k5GyB728vZdmnM4bYap+g==",
+ "version": "4.3.8",
+ "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz",
+ "integrity": "sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow==",
"dev": true,
"requires": {
"chalk": "^4.0.0",
"ci-info": "^2.0.0",
"compare-versions": "^3.6.0",
"cosmiconfig": "^7.0.0",
- "find-versions": "^3.2.0",
+ "find-versions": "^4.0.0",
"opencollective-postinstall": "^2.0.2",
- "pkg-dir": "^4.2.0",
+ "pkg-dir": "^5.0.0",
"please-upgrade-node": "^3.2.0",
"slash": "^3.0.0",
"which-pm-runs": "^1.0.0"
@@ -8884,9 +8889,9 @@
}
},
"import-fresh": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz",
- "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
"requires": {
"parent-module": "^1.0.0",
"resolve-from": "^4.0.0"
@@ -8917,6 +8922,17 @@
"requires": {
"pkg-dir": "^4.2.0",
"resolve-cwd": "^3.0.0"
+ },
+ "dependencies": {
+ "pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "requires": {
+ "find-up": "^4.0.0"
+ }
+ }
}
},
"imurmurhash": {
@@ -8957,9 +8973,9 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ini": {
- "version": "1.3.7",
- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz",
- "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==",
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"dev": true
},
"inline-style-parser": {
@@ -8998,35 +9014,14 @@
}
},
"internal-slot": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz",
- "integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
+ "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
"dev": true,
"requires": {
- "es-abstract": "^1.17.0-next.1",
+ "get-intrinsic": "^1.1.0",
"has": "^1.0.3",
- "side-channel": "^1.0.2"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.17.7",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
- "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
- "dev": true,
- "requires": {
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1",
- "is-callable": "^1.2.2",
- "is-regex": "^1.1.1",
- "object-inspect": "^1.8.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.1",
- "string.prototype.trimend": "^1.0.1",
- "string.prototype.trimstart": "^1.0.1"
- }
- }
+ "side-channel": "^1.0.4"
}
},
"ip": {
@@ -10650,14 +10645,6 @@
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
- },
- "dependencies": {
- "universalify": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
- "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
- "dev": true
- }
}
},
"jsprim": {
@@ -10673,13 +10660,13 @@
}
},
"jsx-ast-utils": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.1.0.tgz",
- "integrity": "sha512-d4/UOjg+mxAWxCiF0c5UTSwyqbchkbqCvK87aBovhnh8GtysTjWmgC63tY0cJx/HzGgm9qnA147jVBdpOiQ2RA==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
+ "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==",
"dev": true,
"requires": {
- "array-includes": "^3.1.1",
- "object.assign": "^4.1.1"
+ "array-includes": "^3.1.2",
+ "object.assign": "^4.1.2"
}
},
"killable": {
@@ -11371,18 +11358,18 @@
"dev": true
},
"mime-db": {
- "version": "1.44.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
- "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
+ "version": "1.45.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
+ "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==",
"dev": true
},
"mime-types": {
- "version": "2.1.27",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
- "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
+ "version": "2.1.28",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
+ "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
"dev": true,
"requires": {
- "mime-db": "1.44.0"
+ "mime-db": "1.45.0"
}
},
"mimic-fn": {
@@ -11584,29 +11571,23 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"msw": {
- "version": "0.21.3",
- "resolved": "https://registry.npmjs.org/msw/-/msw-0.21.3.tgz",
- "integrity": "sha512-voPc/EJsjarvi454vSEuozZQQqLG4AUHT6qQL5Ah47lq7sGCpc7icByeUlfvEj5+MvaugN0c7JwXyCa2rxu8cA==",
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/msw/-/msw-0.25.0.tgz",
+ "integrity": "sha512-KWW9Qwf4ecw7lgf7KM0gRfFLvfmUPw0ljCvii2IluhObZggoN/dBMFe5YJf1utnW7q9qHBc4oMNLrd8zFE6BfQ==",
"requires": {
"@open-draft/until": "^1.0.3",
"@types/cookie": "^0.4.0",
"chalk": "^4.1.0",
"chokidar": "^3.4.2",
"cookie": "^0.4.1",
- "graphql": "^15.3.0",
+ "graphql": "^15.4.0",
"headers-utils": "^1.2.0",
"node-fetch": "^2.6.1",
- "node-match-path": "^0.4.4",
- "node-request-interceptor": "^0.5.1",
+ "node-match-path": "^0.6.0",
+ "node-request-interceptor": "^0.6.3",
"statuses": "^2.0.0",
- "yargs": "^16.0.3"
- },
- "dependencies": {
- "node-match-path": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/node-match-path/-/node-match-path-0.4.4.tgz",
- "integrity": "sha512-pBq9gp7TG0r0VXuy/oeZmQsjBSnYQo7G886Ly/B3azRwZuEtHCY155dzmfoKWcDPGgyfIGD8WKVC7h3+6y7yTg=="
- }
+ "strict-event-emitter": "^0.1.0",
+ "yargs": "^16.2.0"
}
},
"multicast-dns": {
@@ -11827,9 +11808,9 @@
}
},
"node-match-path": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/node-match-path/-/node-match-path-0.6.0.tgz",
- "integrity": "sha512-mld1LbiLaufULAYFPAWgNEG4P0ccL49otlL/nbF5VBQLATuzfS1BGYV1rjRMsxbc0vcnasikFqGHoKDFMQylMw=="
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/node-match-path/-/node-match-path-0.6.1.tgz",
+ "integrity": "sha512-5KjUxG0fUqiIB4HXVatTYGNXf0fD/ZIC88P2w5izFrk6jz45hgavoVuIERsTqb+lMPMuvvL3rxvFWwpnJzN/wQ=="
},
"node-modules-regexp": {
"version": "1.0.0",
@@ -11838,9 +11819,9 @@
"dev": true
},
"node-notifier": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.0.tgz",
- "integrity": "sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz",
+ "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==",
"dev": true,
"optional": true,
"requires": {
@@ -11865,19 +11846,20 @@
}
},
"node-releases": {
- "version": "1.1.67",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz",
- "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==",
+ "version": "1.1.70",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.70.tgz",
+ "integrity": "sha512-Slf2s69+2/uAD79pVVQo8uSiC34+g8GWY8UH2Qtqv34ZfhYrxpYpfzs9Js9d6O0mbDmALuxaTlplnBTnSELcrw==",
"dev": true
},
"node-request-interceptor": {
- "version": "0.5.9",
- "resolved": "https://registry.npmjs.org/node-request-interceptor/-/node-request-interceptor-0.5.9.tgz",
- "integrity": "sha512-M1a3aulCW/kqajDn/w+qBX86G4So7utJGlrODAjQ1piz/kR8ZaDfd/wrJnsuPtUM12F0YxsnXG8qRKFkIEIxsw==",
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/node-request-interceptor/-/node-request-interceptor-0.6.3.tgz",
+ "integrity": "sha512-8I2V7H2Ch0NvW7qWcjmS0/9Lhr0T6x7RD6PDirhvWEkUQvy83x8BA4haYMr09r/rig7hcgYSjYh6cd4U7G1vLA==",
"requires": {
"@open-draft/until": "^1.0.3",
"debug": "^4.3.0",
- "headers-utils": "^1.2.0"
+ "headers-utils": "^1.2.0",
+ "strict-event-emitter": "^0.1.0"
}
},
"normalize-package-data": {
@@ -12216,9 +12198,9 @@
}
},
"open": {
- "version": "7.3.0",
- "resolved": "https://registry.npmjs.org/open/-/open-7.3.0.tgz",
- "integrity": "sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw==",
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/open/-/open-7.3.1.tgz",
+ "integrity": "sha512-f2wt9DCBKKjlFbjzGb8MOAW8LH8F0mrs1zc7KTjAJ9PZNQbfenzWbNP1VZJvw6ICMG9r14Ah6yfwPn7T7i646A==",
"dev": true,
"requires": {
"is-docker": "^2.0.0",
@@ -12435,9 +12417,9 @@
}
},
"parse-json": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz",
- "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"requires": {
"@babel/code-frame": "^7.0.0",
"error-ex": "^1.3.1",
@@ -12596,12 +12578,51 @@
}
},
"pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz",
+ "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==",
"dev": true,
"requires": {
- "find-up": "^4.0.0"
+ "find-up": "^5.0.0"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "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"
+ }
+ }
}
},
"pkg-up": {
@@ -13704,9 +13725,9 @@
},
"dependencies": {
"postcss": {
- "version": "8.2.1",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.1.tgz",
- "integrity": "sha512-RhsqOOAQzTgh1UB/IZdca7F9WDb7SUCR2Vnv1x7DbvuuggQIpoDwjK+q0rzoPffhYvWNKX5JSwS4so4K3UC6vA==",
+ "version": "8.2.4",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.4.tgz",
+ "integrity": "sha512-kRFftRoExRVXZlwUuay9iC824qmXPcQQVzAjbCCgjpXnkdMCJYBu2gTwAaFBzv8ewND6O8xFb3aELmEkh9zTzg==",
"dev": true,
"requires": {
"colorette": "^1.2.1",
@@ -13733,9 +13754,9 @@
}
},
"postcss-selector-not": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.0.tgz",
- "integrity": "sha512-W+bkBZRhqJaYN8XAnbbZPLWMvZD1wKTu0UxtFKdhtGjWYmxhkUneoeOhRJKdAE5V7ZTlnbHfCR+6bNwK9e1dTQ==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz",
+ "integrity": "sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
@@ -13821,9 +13842,9 @@
"dev": true
},
"pretty-bytes": {
- "version": "5.4.1",
- "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.4.1.tgz",
- "integrity": "sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==",
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.5.0.tgz",
+ "integrity": "sha512-p+T744ZyjjiaFlMUZZv6YPC5JrkNj8maRmPaQCWFJFplUAzpIUTRaTcS+7wmZtUoFXHtESJb23ISliaWyz3SHA==",
"dev": true
},
"pretty-error": {
@@ -13876,9 +13897,9 @@
}
},
"prismjs": {
- "version": "1.22.0",
- "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.22.0.tgz",
- "integrity": "sha512-lLJ/Wt9yy0AiSYBf212kK3mM5L8ycwlyTlSxHBAneXLR0nzFMlZ5y7riFPF3E33zXOF2IH95xdY5jIyZbM9z/w==",
+ "version": "1.23.0",
+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz",
+ "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==",
"requires": {
"clipboard": "^2.0.0"
}
@@ -14196,6 +14217,15 @@
"text-table": "0.2.0"
},
"dependencies": {
+ "@babel/code-frame": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
"browserslist": {
"version": "4.14.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.2.tgz",
@@ -14233,6 +14263,20 @@
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
"dev": true
},
+ "globby": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
+ "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
+ "dev": true,
+ "requires": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.1.1",
+ "ignore": "^5.1.4",
+ "merge2": "^1.3.0",
+ "slash": "^3.0.0"
+ }
+ },
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
@@ -14593,9 +14637,9 @@
}
},
"reading-time": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.2.1.tgz",
- "integrity": "sha512-a27kU9sCJzx4JklmKFMXgMoCWlhBi75DFTbU7+M3rjh5SXRWyacYt02il3muYaA+SUQ7tg5gMQn7GC8zOxTt/g=="
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.3.0.tgz",
+ "integrity": "sha512-RJ8J5O6UvrclfZpcPSPuKusrdRfoY7uXXoYOOdeswZNtSkQaewT3919yz6RyloDBR+iwcUyz5zGOUjhgvfuv3g=="
},
"recursive-readdir": {
"version": "2.2.2",
@@ -14682,34 +14726,13 @@
"dev": true
},
"regexp.prototype.flags": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz",
- "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz",
+ "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==",
"dev": true,
"requires": {
- "define-properties": "^1.1.3",
- "es-abstract": "^1.17.0-next.1"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.17.7",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
- "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
- "dev": true,
- "requires": {
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1",
- "is-callable": "^1.2.2",
- "is-regex": "^1.1.1",
- "object-inspect": "^1.8.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.1",
- "string.prototype.trimend": "^1.0.1",
- "string.prototype.trimstart": "^1.0.1"
- }
- }
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
}
},
"regexpp": {
@@ -14739,9 +14762,9 @@
"dev": true
},
"regjsparser": {
- "version": "0.6.4",
- "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz",
- "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==",
+ "version": "0.6.7",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.7.tgz",
+ "integrity": "sha512-ib77G0uxsA2ovgiYbCVGx4Pv3PSttAx2vIwidqQzbL2U5S4Q+j00HdSAneSBuyVcMvEnTXMjiGgB+DlXozVhpQ==",
"dev": true,
"requires": {
"jsesc": "~0.5.0"
@@ -14869,14 +14892,14 @@
"dev": true
},
"renderkid": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.4.tgz",
- "integrity": "sha512-K2eXrSOJdq+HuKzlcjOlGoOarUu5SDguDEhE7+Ah4zuOWL40j8A/oHvLlLob9PSTNvVnBd+/q0Er1QfpEuem5g==",
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz",
+ "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==",
"dev": true,
"requires": {
- "css-select": "^1.1.0",
+ "css-select": "^2.0.2",
"dom-converter": "^0.2",
- "htmlparser2": "^3.3.0",
+ "htmlparser2": "^3.10.1",
"lodash": "^4.17.20",
"strip-ansi": "^3.0.0"
},
@@ -14887,34 +14910,6 @@
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
},
- "css-select": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
- "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
- "dev": true,
- "requires": {
- "boolbase": "~1.0.0",
- "css-what": "2.1",
- "domutils": "1.5.1",
- "nth-check": "~1.0.1"
- }
- },
- "css-what": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
- "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
- "dev": true
- },
- "domutils": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
- "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
- "dev": true,
- "requires": {
- "dom-serializer": "0",
- "domelementtype": "1"
- }
- },
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
@@ -15798,9 +15793,9 @@
"dev": true
},
"semver-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz",
- "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.2.tgz",
+ "integrity": "sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA==",
"dev": true
},
"send": {
@@ -16022,13 +16017,14 @@
"optional": true
},
"side-channel": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.3.tgz",
- "integrity": "sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"dev": true,
"requires": {
- "es-abstract": "^1.18.0-next.0",
- "object-inspect": "^1.8.0"
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
}
},
"signal-exit": {
@@ -16066,20 +16062,38 @@
"dev": true
},
"slice-ansi": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
- "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
"dev": true,
"requires": {
- "ansi-styles": "^3.2.0",
- "astral-regex": "^1.0.0",
- "is-fullwidth-code-point": "^2.0.0"
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
},
"dependencies": {
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
}
}
@@ -16461,9 +16475,9 @@
}
},
"ssri": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.0.tgz",
- "integrity": "sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
+ "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
"dev": true,
"requires": {
"minipass": "^3.1.1"
@@ -16525,9 +16539,9 @@
}
},
"statuses": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.0.tgz",
- "integrity": "sha512-w9jNUUQdpuVoYqXxnyOakhckBbOxRaoYqJscyIBYCS5ixyCnO7nQn7zBZvP9zf5QOPZcz2DLUpE3KsNPbJBOFA=="
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
},
"stealthy-require": {
"version": "1.1.1",
@@ -16638,6 +16652,11 @@
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
"dev": true
},
+ "strict-event-emitter": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.1.0.tgz",
+ "integrity": "sha512-8hSYfU+WKLdNcHVXJ0VxRXiPESalzRe7w1l8dg9+/22Ry+iZQUoQuoJ27R30GMD1TiyYINWsIEGY05WrskhSKw=="
+ },
"strict-uri-encode": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
@@ -16964,54 +16983,34 @@
"dev": true
},
"table": {
- "version": "5.4.6",
- "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
- "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
+ "version": "6.0.7",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz",
+ "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==",
"dev": true,
"requires": {
- "ajv": "^6.10.2",
- "lodash": "^4.17.14",
- "slice-ansi": "^2.1.0",
- "string-width": "^3.0.0"
+ "ajv": "^7.0.2",
+ "lodash": "^4.17.20",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.2.0"
},
"dependencies": {
- "ansi-regex": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
- "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
- "dev": true
- },
- "emoji-regex": {
+ "ajv": {
"version": "7.0.3",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
- "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
- "dev": true
- },
- "string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.0.3.tgz",
+ "integrity": "sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ==",
"dev": true,
"requires": {
- "emoji-regex": "^7.0.1",
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^5.1.0"
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
}
},
- "strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "dev": true,
- "requires": {
- "ansi-regex": "^4.1.0"
- }
+ "json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
}
}
},
@@ -17022,9 +17021,9 @@
"dev": true
},
"tar": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz",
- "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz",
+ "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==",
"dev": true,
"requires": {
"chownr": "^2.0.0",
@@ -17155,6 +17154,15 @@
"yocto-queue": "^0.1.0"
}
},
+ "pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "requires": {
+ "find-up": "^4.0.0"
+ }
+ },
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -17488,14 +17496,14 @@
}
},
"tslib": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
- "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+ "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
},
"tsutils": {
- "version": "3.17.1",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz",
- "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==",
+ "version": "3.20.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.20.0.tgz",
+ "integrity": "sha512-RYbuQuvkhuqVeXweWT3tJLKOEJ/UUw9GjNEZGWdrLLlM+611o1gwLHBpxoFJKKl25fLprp2eVthtKs5JOrNeXg==",
"dev": true,
"requires": {
"tslib": "^1.8.1"
@@ -17581,6 +17589,12 @@
"is-typedarray": "^1.0.0"
}
},
+ "typescript": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
+ "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
+ "dev": true
+ },
"typographic-apostrophes": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/typographic-apostrophes/-/typographic-apostrophes-1.1.1.tgz",
@@ -17809,9 +17823,9 @@
}
},
"universalify": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
- "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
"dev": true
},
"unpipe": {
@@ -17892,9 +17906,9 @@
}
},
"uri-js": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
- "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"requires": {
"punycode": "^2.1.0"
}
@@ -18045,9 +18059,9 @@
"dev": true
},
"v8-to-istanbul": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.0.0.tgz",
- "integrity": "sha512-fLL2rFuQpMtm9r8hrAV2apXX/WqHJ6+IC4/eQVdMDGBUgH/YMV4Gv3duk3kjmyg6uiQWBAA9nJwue4iJUOkHeA==",
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz",
+ "integrity": "sha512-uXUVqNUCLa0AH1vuVxzi+MI4RfxEOKt9pBgKwHbgH7st8Kv2P1m+jvWNnektzBh5QShF3ODgKmUFCf38LnVz1g==",
"dev": true,
"requires": {
"@types/istanbul-lib-coverage": "^2.0.1",
@@ -18789,9 +18803,9 @@
}
},
"webpack-dev-middleware": {
- "version": "3.7.2",
- "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz",
- "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==",
+ "version": "3.7.3",
+ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz",
+ "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==",
"dev": true,
"requires": {
"memory-fs": "^0.4.1",
@@ -18802,9 +18816,9 @@
},
"dependencies": {
"mime": {
- "version": "2.4.6",
- "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
- "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.0.tgz",
+ "integrity": "sha512-ft3WayFSFUVBuJj7BMLKAQcSlItKtfjsKDDsii3rqFDAZ7t11zRe8ASw/GlmivGwVUYtwkQrxiGGpL6gFvB0ag==",
"dev": true
}
}
@@ -19805,9 +19819,9 @@
}
},
"ws": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz",
- "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==",
+ "version": "7.4.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz",
+ "integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==",
"dev": true
},
"x-is-string": {
diff --git a/package.json b/package.json
index 848ad8fb..18441e65 100644
--- a/package.json
+++ b/package.json
@@ -13,11 +13,11 @@
"npm": ">=6"
},
"dependencies": {
- "@kentcdodds/react-workshop-app": "^2.20.0",
- "@testing-library/react": "^11.2.2",
- "@testing-library/user-event": "^12.5.0",
+ "@kentcdodds/react-workshop-app": "^3.0.0",
+ "@testing-library/react": "^11.2.3",
+ "@testing-library/user-event": "^12.6.2",
"chalk": "^4.1.0",
- "codegen.macro": "^4.0.0",
+ "codegen.macro": "^4.1.0",
"mq-polyfill": "^1.1.8",
"react": "^17.0.1",
"react-dom": "^17.0.1",
@@ -26,10 +26,11 @@
"devDependencies": {
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
- "husky": "^4.3.5",
+ "husky": "^4.3.8",
"npm-run-all": "^4.1.5",
"prettier": "^2.2.1",
- "react-scripts": "^4.0.1"
+ "react-scripts": "^4.0.1",
+ "typescript": "^4.1.3"
},
"scripts": {
"start": "react-scripts start",
@@ -53,7 +54,14 @@
]
},
"eslintConfig": {
- "extends": "react-app"
+ "extends": [
+ "react-app",
+ "react-app/jest",
+ "plugin:jsx-a11y/recommended"
+ ],
+ "plugins": [
+ "jsx-a11y"
+ ]
},
"babel": {
"presets": [
diff --git a/public/mockServiceWorker.js b/public/mockServiceWorker.js
index d8703e53..0de6bf7b 100644
--- a/public/mockServiceWorker.js
+++ b/public/mockServiceWorker.js
@@ -7,7 +7,7 @@
/* eslint-disable */
/* tslint:disable */
-const INTEGRITY_CHECKSUM = 'd1e0e502f550d40a34bee90822e4bf98'
+const INTEGRITY_CHECKSUM = '7a54d6f8bbbda3fb393dcd9176d1fd19'
const bypassHeaderName = 'x-msw-bypass'
let clients = {}
@@ -74,11 +74,23 @@ self.addEventListener('message', async function (event) {
}
})
-self.addEventListener('fetch', async function (event) {
+self.addEventListener('fetch', function (event) {
const { clientId, request } = event
+ const requestId = uuidv4()
const requestClone = request.clone()
const getOriginalResponse = () => fetch(requestClone)
+ // Bypass navigation requests.
+ if (request.mode === 'navigate') {
+ return
+ }
+
+ // Bypass mocking if the current client isn't present in the internal clients map
+ // (i.e. has the mocking disabled).
+ if (!clients[clientId]) {
+ return
+ }
+
// Opening the DevTools triggers the "only-if-cached" request
// that cannot be handled by the worker. Bypass such requests.
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
@@ -89,20 +101,15 @@ self.addEventListener('fetch', async function (event) {
new Promise(async (resolve, reject) => {
const client = await event.target.clients.get(clientId)
- if (
- // Bypass mocking when no clients active
- !client ||
- // Bypass mocking if the current client has mocking disabled
- !clients[clientId] ||
- // Bypass mocking for navigation requests
- request.mode === 'navigate'
- ) {
+ // Bypass mocking when the request client is not active.
+ if (!client) {
return resolve(getOriginalResponse())
}
// Bypass requests with the explicit bypass header
if (requestClone.headers.get(bypassHeaderName) === 'true') {
const modifiedHeaders = serializeHeaders(requestClone.headers)
+
// Remove the bypass header to comply with the CORS preflight check
delete modifiedHeaders[bypassHeaderName]
@@ -119,6 +126,7 @@ self.addEventListener('fetch', async function (event) {
const rawClientMessage = await sendToClient(client, {
type: 'REQUEST',
payload: {
+ id: requestId,
url: request.url,
method: request.method,
headers: reqHeaders,
@@ -180,14 +188,34 @@ If you wish to mock an error response, please refer to this guide: https://mswjs
return resolve(createResponse(clientMessage))
}
}
- }).catch((error) => {
- console.error(
- '[MSW] Failed to mock a "%s" request to "%s": %s',
- request.method,
- request.url,
- error,
- )
- }),
+ })
+ .then(async (response) => {
+ const client = await event.target.clients.get(clientId)
+ const clonedResponse = response.clone()
+
+ sendToClient(client, {
+ type: 'RESPONSE',
+ payload: {
+ requestId,
+ ok: clonedResponse.ok,
+ status: clonedResponse.status,
+ statusText: clonedResponse.statusText,
+ body: await clonedResponse.text(),
+ headers: serializeHeaders(clonedResponse.headers),
+ redirected: clonedResponse.redirected,
+ },
+ })
+
+ return response
+ })
+ .catch((error) => {
+ console.error(
+ '[MSW] Failed to mock a "%s" request to "%s": %s',
+ request.method,
+ request.url,
+ error,
+ )
+ }),
)
})
@@ -233,3 +261,11 @@ function ensureKeys(keys, obj) {
return acc
}, {})
}
+
+function uuidv4() {
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+ const r = (Math.random() * 16) | 0
+ const v = c == 'x' ? r : (r & 0x3) | 0x8
+ return v.toString(16)
+ })
+}
diff --git a/src/__tests__/01.js b/src/__tests__/01.tsx
similarity index 85%
rename from src/__tests__/01.js
rename to src/__tests__/01.tsx
index 623fa83d..dfca97b9 100644
--- a/src/__tests__/01.js
+++ b/src/__tests__/01.tsx
@@ -2,7 +2,8 @@ import * as React from 'react'
import {alfredTip} from '@kentcdodds/react-workshop-app/test-utils'
import {render} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
-import App from '../final/01'
+import App from '../final/01.js'
+// import App from '../final-ts/01'
// import App from '../exercise/01'
test('clicking the button increments the count with useReducer', () => {
@@ -10,6 +11,9 @@ test('clicking the button increments the count with useReducer', () => {
const {container} = render( )
const button = container.querySelector('button')
+ if (!button) {
+ throw new Error('button node is null')
+ }
userEvent.click(button)
expect(button).toHaveTextContent('1')
userEvent.click(button)
diff --git a/src/__tests__/02.extra-3.js b/src/__tests__/02.extra-3.tsx
similarity index 83%
rename from src/__tests__/02.extra-3.js
rename to src/__tests__/02.extra-3.tsx
index ef89295b..4f564915 100644
--- a/src/__tests__/02.extra-3.js
+++ b/src/__tests__/02.extra-3.tsx
@@ -3,16 +3,20 @@ import {alfredTip} from '@kentcdodds/react-workshop-app/test-utils'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../final/02.extra-3'
+// import App from '../final-ts/02.extra-3'
// import App from '../exercise/02'
+let fetchSpy: jest.SpyInstance
+let consoleErrorSpy: jest.SpyInstance
+
beforeEach(() => {
- jest.spyOn(window, 'fetch')
- jest.spyOn(console, 'error')
+ fetchSpy = jest.spyOn(window, 'fetch')
+ consoleErrorSpy = jest.spyOn(console, 'error')
})
afterEach(() => {
- window.fetch.mockRestore()
- console.error.mockRestore()
+ fetchSpy.mockRestore()
+ consoleErrorSpy.mockRestore()
})
test('displays the pokemon', async () => {
@@ -34,7 +38,7 @@ test('displays the pokemon', async () => {
await screen.findByRole('heading', {name: /ditto/i})
// verify that when props remain the same a request is not made
- window.fetch.mockClear()
+ fetchSpy.mockClear()
userEvent.click(submit)
@@ -46,7 +50,7 @@ test('displays the pokemon', async () => {
)
// verify error handling
- console.error.mockImplementation(() => {})
+ consoleErrorSpy.mockImplementation(() => {})
userEvent.clear(input)
userEvent.type(input, 'george')
@@ -56,7 +60,7 @@ test('displays the pokemon', async () => {
)
expect(console.error).toHaveBeenCalledTimes(2)
- console.error.mockReset()
+ consoleErrorSpy.mockReset()
userEvent.type(input, 'mew')
userEvent.click(submit)
diff --git a/src/__tests__/02.js b/src/__tests__/02.tsx
similarity index 78%
rename from src/__tests__/02.js
rename to src/__tests__/02.tsx
index 9c1b290e..4b88b9ad 100644
--- a/src/__tests__/02.js
+++ b/src/__tests__/02.tsx
@@ -2,17 +2,21 @@ import * as React from 'react'
import {alfredTip} from '@kentcdodds/react-workshop-app/test-utils'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
-import App from '../final/02'
+// import App from '../final/02'
+import App from '../final-ts/02'
// import App from '../exercise/02'
+let spyFetch: jest.SpyInstance
+let spyConsoleError: jest.SpyInstance
+
beforeEach(() => {
- jest.spyOn(window, 'fetch')
- jest.spyOn(console, 'error')
+ spyFetch = jest.spyOn(window, 'fetch')
+ spyConsoleError = jest.spyOn(console, 'error')
})
afterEach(() => {
- window.fetch.mockRestore()
- console.error.mockRestore()
+ spyFetch.mockRestore()
+ spyConsoleError.mockRestore()
})
test('displays the pokemon', async () => {
@@ -34,7 +38,7 @@ test('displays the pokemon', async () => {
await screen.findByRole('heading', {name: /ditto/i})
// verify that when props remain the same a request is not made
- window.fetch.mockClear()
+ spyFetch.mockClear()
userEvent.click(submit)
@@ -46,7 +50,7 @@ test('displays the pokemon', async () => {
)
// verify error handling
- console.error.mockImplementation(() => {})
+ spyConsoleError.mockImplementation(() => {})
userEvent.clear(input)
userEvent.type(input, 'george')
@@ -56,5 +60,5 @@ test('displays the pokemon', async () => {
)
expect(console.error).toHaveBeenCalledTimes(2)
- console.error.mockReset()
+ spyConsoleError.mockReset()
})
diff --git a/src/__tests__/03.extra-2.js b/src/__tests__/03.extra-2.tsx
similarity index 81%
rename from src/__tests__/03.extra-2.js
rename to src/__tests__/03.extra-2.tsx
index 45281b4c..7d35aef9 100644
--- a/src/__tests__/03.extra-2.js
+++ b/src/__tests__/03.extra-2.tsx
@@ -3,16 +3,20 @@ import {alfredTip} from '@kentcdodds/react-workshop-app/test-utils'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../final/03.extra-2'
+// import App from '../final-ts/03.extra-2'
// import App from '../exercise/03.extra-2'
+let fetchSpy: jest.SpyInstance
+let consoleErrorSpy: jest.SpyInstance
+
beforeEach(() => {
- jest.spyOn(window, 'fetch')
- jest.spyOn(console, 'error')
+ fetchSpy = jest.spyOn(window, 'fetch')
+ consoleErrorSpy = jest.spyOn(console, 'error')
})
afterEach(() => {
- window.fetch.mockRestore()
- console.error.mockRestore()
+ fetchSpy.mockRestore()
+ consoleErrorSpy.mockRestore()
})
test('displays the pokemon', async () => {
@@ -34,7 +38,7 @@ test('displays the pokemon', async () => {
await screen.findByRole('heading', {name: /ditto/i})
// verify that when props remain the same a request is not made
- window.fetch.mockClear()
+ fetchSpy.mockClear()
userEvent.click(submit)
@@ -46,7 +50,7 @@ test('displays the pokemon', async () => {
)
// verify error handling
- console.error.mockImplementation(() => {})
+ consoleErrorSpy.mockImplementation(() => {})
userEvent.clear(input)
userEvent.type(input, 'george')
@@ -56,8 +60,8 @@ test('displays the pokemon', async () => {
)
expect(console.error).toHaveBeenCalledTimes(2)
- console.error.mockReset()
- window.fetch.mockClear()
+ consoleErrorSpy.mockReset()
+ fetchSpy.mockClear()
// use the cached value
userEvent.click(screen.getByRole('button', {name: /ditto/i}))
diff --git a/src/__tests__/03.js b/src/__tests__/03.tsx
similarity index 94%
rename from src/__tests__/03.js
rename to src/__tests__/03.tsx
index d79c9f1e..c44dc591 100644
--- a/src/__tests__/03.js
+++ b/src/__tests__/03.tsx
@@ -2,6 +2,7 @@ import * as React from 'react'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../final/03'
+// import App from '../final-ts/03'
// import App from '../exercise/03'
test('clicking the button increments the count', () => {
diff --git a/src/__tests__/04.js b/src/__tests__/04.tsx
similarity index 94%
rename from src/__tests__/04.js
rename to src/__tests__/04.tsx
index e97fc4ec..d1add309 100644
--- a/src/__tests__/04.js
+++ b/src/__tests__/04.tsx
@@ -2,6 +2,7 @@ import * as React from 'react'
import {render} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../final/04'
+// import App from '../final-ts/04'
// import App from '../exercise/04'
test('adds and removes children from the log', () => {
@@ -24,12 +25,12 @@ test('scrolls to the bottom', () => {
const scrollTopSetter = jest.fn()
Object.defineProperties(log, {
scrollHeight: {
- get() {
+ get(): number {
return 100
},
},
scrollTop: {
- get() {
+ get(): number {
return 0
},
set: scrollTopSetter,
diff --git a/src/__tests__/05.js b/src/__tests__/05.tsx
similarity index 97%
rename from src/__tests__/05.js
rename to src/__tests__/05.tsx
index 02bd4326..85e9aaeb 100644
--- a/src/__tests__/05.js
+++ b/src/__tests__/05.tsx
@@ -2,6 +2,7 @@ import * as React from 'react'
import {render} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import App from '../final/05'
+// import App from '../final-ts/05'
// import App from '../exercise/05'
test('adds and removes children from the log', () => {
diff --git a/src/__tests__/06.js b/src/__tests__/06.tsx
similarity index 98%
rename from src/__tests__/06.js
rename to src/__tests__/06.tsx
index 8ccdf5bd..6d68b9ae 100644
--- a/src/__tests__/06.js
+++ b/src/__tests__/06.tsx
@@ -3,6 +3,7 @@ import * as React from 'react'
import {alfredTip} from '@kentcdodds/react-workshop-app/test-utils'
import {render, act} from '@testing-library/react'
import App from '../final/06'
+// import App from '../final-ts/06'
// import App from '../exercise/06'
beforeAll(() => {
diff --git a/src/exercise/03.extra-2.js b/src/exercise/03.extra-2.js
index 29d9cd56..9d491a4d 100644
--- a/src/exercise/03.extra-2.js
+++ b/src/exercise/03.extra-2.js
@@ -40,8 +40,8 @@ function PokemonInfo({pokemonName}) {
const [cache, dispatch] = React.useReducer(pokemonCacheReducer, {})
// 🐨 get the cache and dispatch from useContext with PokemonCacheContext
- const {data: pokemon, status, error, run, setData} = useAsync()
-
+ const {state, run, setData} = useAsync()
+ const {data: pokemon, status, error} = state
React.useEffect(() => {
if (!pokemonName) {
return
diff --git a/src/final-ts/01.extra-1.tsx b/src/final-ts/01.extra-1.tsx
new file mode 100644
index 00000000..81b71c33
--- /dev/null
+++ b/src/final-ts/01.extra-1.tsx
@@ -0,0 +1,35 @@
+// useReducer: simple Counter
+// 💯 accept the step as the action
+// http://localhost:3000/isolated/final-ts/01.extra-1.tsx
+
+import * as React from 'react'
+
+type State = number
+
+
+type Reducer = (state: State, action: Action) => State
+
+// React also export the same type definition at `React.Reducer` and it has the
+// exact same api
+const countReducer: Reducer = (count, change) => count + change
+
+//#region Counter
+interface CounterProps {
+ initialCount?: number
+ step?: number
+}
+const Counter: React.VFC = ({initialCount = 0, step = 1}) => {
+ const [count, changeCount] = React.useReducer(countReducer, initialCount)
+ const increment: React.MouseEventHandler = () =>
+ changeCount(step)
+ return {count}
+}
+//#endregion Counter
+
+//#region Usage
+const Usage: React.VFC = () => {
+ return
+}
+//#endregion Usage
+
+export default Usage
diff --git a/src/final-ts/01.extra-2.tsx b/src/final-ts/01.extra-2.tsx
new file mode 100644
index 00000000..d99abd7a
--- /dev/null
+++ b/src/final-ts/01.extra-2.tsx
@@ -0,0 +1,39 @@
+// useReducer: simple Counter
+// 💯 simulate setState with an object
+// http://localhost:3000/isolated/final-ts/01.extra-2.tsx
+
+import * as React from 'react'
+
+//#region reducer
+interface State {
+ count: number
+}
+
+const countReducer: React.Reducer = (state, action) => ({
+ ...state,
+ ...action,
+})
+//#endregion reducer
+
+//#region Counter
+interface CounterProps {
+ initialCount?: number
+ step?: number
+}
+const Counter: React.VFC = ({initialCount = 0, step = 1}) => {
+ const initialState: State = {count: initialCount}
+ const [state, setState] = React.useReducer(countReducer, initialState)
+ const {count} = state
+ const increment: React.MouseEventHandler = () =>
+ setState({count: count + step})
+ return {count}
+}
+//#endregion Counter
+
+//#region App
+const App: React.VFC = () => {
+ return
+}
+//#endregion App
+
+export default App
diff --git a/src/final-ts/01.extra-3.tsx b/src/final-ts/01.extra-3.tsx
new file mode 100644
index 00000000..ea4fab5a
--- /dev/null
+++ b/src/final-ts/01.extra-3.tsx
@@ -0,0 +1,40 @@
+// useReducer: simple Counter
+// 💯 simulate setState with an object OR function
+// http://localhost:3000/isolated/final-ts/01.extra-3.tsx
+
+import * as React from 'react'
+
+//#region reducer
+interface State {
+ count: number
+}
+type Action = State | ((prevState: State) => State)
+
+const countReducer: React.Reducer = (state, action) => ({
+ ...state,
+ ...(typeof action === 'function' ? action(state) : action),
+})
+//#endregion reducer
+
+//#region Counter
+interface CounterProps {
+ initialCount?: number
+ step?: number
+}
+const Counter: React.VFC = ({initialCount = 0, step = 1}) => {
+ const initialState: State = {count: initialCount}
+ const [state, setState] = React.useReducer(countReducer, initialState)
+ const {count} = state
+ const increment: React.MouseEventHandler = () =>
+ setState(currentState => ({count: currentState.count + step}))
+ return {count}
+}
+//#endregion Counter
+
+//#region App
+const App: React.VFC = () => {
+ return
+}
+//#endregion App
+
+export default App
diff --git a/src/final-ts/01.extra-4.tsx b/src/final-ts/01.extra-4.tsx
new file mode 100644
index 00000000..81792561
--- /dev/null
+++ b/src/final-ts/01.extra-4.tsx
@@ -0,0 +1,73 @@
+// useReducer: simple Counter
+// 💯 traditional dispatch object with a type and switch statement
+// http://localhost:3000/isolated/final-ts/01.extra-4.tsx
+
+import * as React from 'react'
+
+//#region reducer
+
+interface State {
+ count: number
+}
+
+/**
+ * an utility type for building Action types.
+ * Definitely overkill for this small example, but quite common in the real world
+ */
+interface ActionType {
+ type: Type
+}
+
+interface IncrementAction extends ActionType<'increment'> {
+ step: number
+}
+
+interface DecrementAction extends ActionType<'decrement'> {
+ step: number
+}
+
+/**
+ * Action type is defined as the discriminated union type of all the custom
+ * action that you have defined.
+ * This ensure that you can't dispatch a misshaped Action by accident.
+ */
+type Action = IncrementAction | DecrementAction
+
+const countReducer: React.Reducer = (state, action) => {
+ const {type, step} = action
+ switch (type) {
+ case 'increment': {
+ return {
+ ...state,
+ count: state.count + step,
+ }
+ }
+ default: {
+ throw new Error(`Unsupported action type: ${action.type}`)
+ }
+ }
+}
+//#endregion reducer
+
+//#region Counter
+interface CounterProps {
+ initialCount?: number
+ step?: number
+}
+const Counter: React.VFC = ({initialCount = 0, step = 1}) => {
+ const initialState: State = {count: initialCount}
+ const [state, dispatch] = React.useReducer(countReducer, initialState)
+ const {count} = state
+ const increment: React.MouseEventHandler = () =>
+ dispatch({type: 'increment', step})
+ return {count}
+}
+//#endregion Counter
+
+//#region App
+const App: React.VFC = () => {
+ return
+}
+//#endregion App
+
+export default App
diff --git a/src/final-ts/01.tsx b/src/final-ts/01.tsx
new file mode 100644
index 00000000..d0e28950
--- /dev/null
+++ b/src/final-ts/01.tsx
@@ -0,0 +1,31 @@
+// useReducer: simple Counter
+// http://localhost:3000/isolated/final-ts/01.tsx
+
+import * as React from 'react'
+
+type State = number
+
+const countReducer = (state: State, newState: State): State => newState
+
+//#region Counter
+interface CounterProps {
+ initialCount?: number
+ step?: number
+}
+const Counter: React.VFC = ({initialCount = 0, step = 1}) => {
+ const [count, setCount] = React.useReducer(countReducer, initialCount)
+
+ const increment: React.MouseEventHandler = () =>
+ setCount(count + step)
+
+ return {count}
+}
+//#endregion Counter
+
+//#region App
+const App: React.VFC = () => {
+ return
+}
+//#endregion App
+
+export default App
diff --git a/src/final-ts/02.extra-1.tsx b/src/final-ts/02.extra-1.tsx
new file mode 100644
index 00000000..52484626
--- /dev/null
+++ b/src/final-ts/02.extra-1.tsx
@@ -0,0 +1,202 @@
+// useCallback: custom hooks
+// 💯 use useCallback to empower the user to customize memoization
+// http://localhost:3000/isolated/final-ts/02.extra-1.tsx
+
+import * as React from 'react'
+import {
+ fetchPokemon,
+ PokemonForm,
+ PokemonDataView,
+ PokemonInfoFallback,
+ PokemonErrorBoundary,
+} from '../pokemon'
+
+//#region useAsync: a generic custom hook that would live in a separate module
+export enum Status {
+ IDLE = 'idle',
+ PENDING = 'pending',
+ RESOLVED = 'resolved',
+ REJECTED = 'rejected',
+}
+interface FiniteState<
+ Status extends 'idle' | 'pending' | 'resolved' | 'rejected',
+ Data extends unknown = null,
+ Err extends null | Error = null
+> {
+ status: Status
+ data: Data
+ error: Err
+}
+
+type State =
+ | FiniteState<'idle'>
+ | FiniteState<'pending'>
+ | FiniteState<'resolved', Data>
+ | FiniteState<'rejected', null, Error>
+
+interface ActionType<
+ Type extends 'idle' | 'pending' | 'resolved' | 'rejected'
+> {
+ type: Type
+}
+
+interface ActionIdle extends ActionType {}
+interface ActionPending extends ActionType {}
+
+interface ActionResolved extends ActionType {
+ data: Data
+}
+
+interface ActionRejected extends ActionType {
+ error: Error
+}
+
+type Action =
+ | ActionIdle
+ | ActionPending
+ | ActionResolved
+ | ActionRejected
+
+type AsyncReducer = React.Reducer, Action>
+function asyncReducer(
+ state: State,
+ action: Action,
+): State {
+ switch (action.type) {
+ case Status.IDLE:
+ return {
+ status: Status.IDLE,
+ data: null,
+ error: null,
+ }
+
+ case Status.PENDING:
+ return {
+ status: Status.PENDING,
+ data: null,
+ error: null,
+ }
+
+ case Status.RESOLVED:
+ return {
+ status: Status.RESOLVED,
+ data: action.data,
+ error: null,
+ }
+
+ case Status.REJECTED:
+ return {
+ status: Status.REJECTED,
+ data: null,
+ error: action.error,
+ }
+
+ default: {
+ // @ts-ignore: exhaustive fallthrough checks: Property 'type' does not exist on type 'never'.
+ throw new Error(`Unhandled action type: ${action.type}`)
+ }
+ }
+}
+
+export function useAsync(
+ asyncCallback: () => void | Promise,
+ initialState: State,
+): State {
+ const [state, dispatch] = React.useReducer>(asyncReducer, {
+ // @ts-expect-error: 'status' is specified more than once, so this usage will be overwritten.
+ status: Status.IDLE,
+ data: null,
+ error: null,
+ ...initialState,
+ })
+
+ React.useEffect(() => {
+ const promise = asyncCallback()
+ if (!promise) return
+ dispatch({type: Status.PENDING})
+ promise.then(
+ data => dispatch({type: Status.RESOLVED, data}),
+ error => dispatch({type: Status.REJECTED, error}),
+ )
+ }, [asyncCallback])
+
+ return state
+}
+//#endregion useAsync
+
+//#region PokemonInfo
+const PokemonInfo: React.VFC<{pokemonName?: string}> = ({pokemonName}) => {
+ const asyncCallback = React.useCallback(() => {
+ if (!pokemonName) return
+ return fetchPokemon(pokemonName)
+ }, [pokemonName])
+
+ const state = useAsync(asyncCallback, {
+ status: pokemonName ? 'pending' : 'idle',
+ error: null,
+ data: null,
+ })
+
+ switch (state.status) {
+ case 'idle':
+ return <>Submit a pokemon>
+
+ case 'pending':
+ return
+
+ case 'rejected':
+ throw state.error
+
+ case 'resolved':
+ return
+
+ default:
+ throw new Error('This should be impossible')
+ }
+}
+
+//#endregion PokemonInfo
+
+function App(): JSX.Element {
+ const [pokemonName, setPokemonName] = React.useState('')
+
+ function handleSubmit(newPokemonName: string): void {
+ setPokemonName(newPokemonName)
+ }
+
+ function handleReset(): void {
+ setPokemonName('')
+ }
+
+ return (
+
+ )
+}
+
+function AppWithUnmountCheckbox(): JSX.Element {
+ const [mountApp, setMountApp] = React.useState(true)
+ return (
+
+
+ setMountApp(e.target.checked)}
+ />{' '}
+ Mount Component
+
+
+ {mountApp ?
: null}
+
+ )
+}
+
+export default AppWithUnmountCheckbox
diff --git a/src/final-ts/02.extra-2.tsx b/src/final-ts/02.extra-2.tsx
new file mode 100644
index 00000000..dfa35cb2
--- /dev/null
+++ b/src/final-ts/02.extra-2.tsx
@@ -0,0 +1,200 @@
+// useCallback: custom hooks
+// 💯 return a memoized `run` function from useAsync
+// http://localhost:3000/isolated/final-ts/02.extra-2.tsx
+
+import * as React from 'react'
+import {
+ fetchPokemon,
+ PokemonForm,
+ PokemonDataView,
+ PokemonInfoFallback,
+ PokemonErrorBoundary,
+ IPokemon,
+} from '../pokemon'
+
+//#region useAsync: a generic custom hook that would live in a separate module
+export enum Status {
+ IDLE = 'idle',
+ PENDING = 'pending',
+ RESOLVED = 'resolved',
+ REJECTED = 'rejected',
+}
+interface FiniteState<
+ Status extends 'idle' | 'pending' | 'resolved' | 'rejected',
+ Data extends unknown = null,
+ Err extends null | Error = null
+> {
+ status: Status
+ data: Data
+ error: Err
+}
+
+type State =
+ | FiniteState<'idle'>
+ | FiniteState<'pending'>
+ | FiniteState<'resolved', Data>
+ | FiniteState<'rejected', null, Error>
+
+interface ActionType<
+ Type extends 'idle' | 'pending' | 'resolved' | 'rejected'
+> {
+ type: Type
+}
+
+interface ActionIdle extends ActionType {}
+interface ActionPending extends ActionType {}
+
+interface ActionResolved extends ActionType {
+ data: Data
+}
+
+interface ActionRejected extends ActionType {
+ error: Error
+}
+
+type Action =
+ | ActionIdle
+ | ActionPending
+ | ActionResolved
+ | ActionRejected
+
+type AsyncReducer = React.Reducer, Action>
+function asyncReducer(
+ state: State,
+ action: Action,
+): State {
+ switch (action.type) {
+ case Status.IDLE:
+ return {
+ status: Status.IDLE,
+ data: null,
+ error: null,
+ }
+
+ case Status.PENDING:
+ return {
+ status: Status.PENDING,
+ data: null,
+ error: null,
+ }
+
+ case Status.RESOLVED:
+ return {
+ status: Status.RESOLVED,
+ data: action.data,
+ error: null,
+ }
+
+ case Status.REJECTED:
+ return {
+ status: Status.REJECTED,
+ data: null,
+ error: action.error,
+ }
+
+ default: {
+ // @ts-ignore: exhaustive fallthrough checks: Property 'type' does not exist on type 'never'.
+ throw new Error(`Unhandled action type: ${action.type}`)
+ }
+ }
+}
+
+export function useAsync(
+ initialState: State,
+): {state: State; run: (promise: Promise) => void} {
+ const [state, dispatch] = React.useReducer>(asyncReducer, {
+ // @ts-expect-error: 'status' is specified more than once, so this usage will be overwritten.
+ status: Status.IDLE,
+ data: null,
+ error: null,
+ ...initialState,
+ })
+
+ const run = React.useCallback((promise: Promise) => {
+ dispatch({type: Status.PENDING})
+ promise.then(
+ data => dispatch({type: Status.RESOLVED, data}),
+ error => dispatch({type: Status.REJECTED, error}),
+ )
+ }, [])
+
+ return {state, run}
+}
+//#endregion useAsync
+
+//#region PokemonInfo
+const PokemonInfo: React.VFC<{pokemonName?: string}> = ({pokemonName}) => {
+ const {state, run} = useAsync({
+ status: pokemonName ? 'pending' : 'idle',
+ error: null,
+ data: null,
+ })
+
+ React.useEffect(() => {
+ if (!pokemonName) return
+ run(fetchPokemon(pokemonName))
+ }, [pokemonName, run])
+
+ switch (state.status) {
+ case 'idle':
+ return <>Submit a pokemon>
+
+ case 'pending':
+ return
+
+ case 'rejected':
+ throw state.error
+
+ case 'resolved':
+ return
+
+ default:
+ throw new Error('This should be impossible')
+ }
+}
+
+//#endregion PokemonInfo
+
+function App(): JSX.Element {
+ const [pokemonName, setPokemonName] = React.useState('')
+
+ function handleSubmit(newPokemonName: string): void {
+ setPokemonName(newPokemonName)
+ }
+
+ function handleReset(): void {
+ setPokemonName('')
+ }
+
+ return (
+
+ )
+}
+
+function AppWithUnmountCheckbox(): JSX.Element {
+ const [mountApp, setMountApp] = React.useState(true)
+ return (
+
+
+ setMountApp(e.target.checked)}
+ />{' '}
+ Mount Component
+
+
+ {mountApp ?
: null}
+
+ )
+}
+
+export default AppWithUnmountCheckbox
diff --git a/src/final-ts/02.extra-3.tsx b/src/final-ts/02.extra-3.tsx
new file mode 100644
index 00000000..f146bda4
--- /dev/null
+++ b/src/final-ts/02.extra-3.tsx
@@ -0,0 +1,248 @@
+// useCallback: custom hooks
+// 💯 make safeDispatch with useCallback, useRef, and useEffect
+// http://localhost:3000/isolated/final-ts/02.extra-3.tsx
+
+import * as React from 'react'
+import {
+ fetchPokemon,
+ PokemonForm,
+ PokemonDataView,
+ PokemonInfoFallback,
+ PokemonErrorBoundary,
+ IPokemon,
+} from '../pokemon'
+
+//#region useAsync: a generic custom hook that would live in a separate module
+export enum Status {
+ IDLE = 'idle',
+ PENDING = 'pending',
+ RESOLVED = 'resolved',
+ REJECTED = 'rejected',
+}
+interface FiniteState<
+ Status extends 'idle' | 'pending' | 'resolved' | 'rejected',
+ Data extends unknown = null,
+ Err extends null | Error = null
+> {
+ status: Status
+ data: Data
+ error: Err
+}
+
+type State =
+ | FiniteState<'idle'>
+ | FiniteState<'pending'>
+ | FiniteState<'resolved', Data>
+ | FiniteState<'rejected', null, Error>
+
+interface ActionType<
+ Type extends 'idle' | 'pending' | 'resolved' | 'rejected'
+> {
+ type: Type
+}
+
+interface ActionIdle extends ActionType {}
+interface ActionPending extends ActionType {}
+
+interface ActionResolved extends ActionType {
+ data: Data
+}
+
+interface ActionRejected extends ActionType {
+ error: Error
+}
+
+type Action =
+ | ActionIdle
+ | ActionPending
+ | ActionResolved
+ | ActionRejected
+
+function useSafeDispatch void>(
+ dispatch: Dispatch,
+): Dispatch {
+ const mountedRef = React.useRef(false)
+
+ // to make this even more generic you should use the useLayoutEffect hook to
+ // make sure that you are correctly setting the mountedRef.current immediately
+ // after React updates the DOM. Even though this effect does not interact
+ // with the dom another side effect inside a useLayoutEffect which does
+ // interact with the dom may depend on the value being set
+ React.useEffect(() => {
+ mountedRef.current = true
+ return () => {
+ mountedRef.current = false
+ }
+ }, [])
+
+ // eslint react-hooks/exhaustive-deps rule unfortunately is not abel to parse
+ // through this typescript type casting syntax here, and therefore is raising
+ // a warning. Do not worry, everything is still fine and dandy!
+ // eslint-disable-next-line
+ return React.useCallback(
+ ((...args) => {
+ if (mountedRef.current) {
+ dispatch(...args)
+ }
+ }) as Dispatch,
+ [dispatch],
+ )
+}
+
+type AsyncReducer = React.Reducer, Action>
+function asyncReducer(
+ state: State,
+ action: Action,
+): State {
+ switch (action.type) {
+ case Status.IDLE:
+ return {
+ status: Status.IDLE,
+ data: null,
+ error: null,
+ }
+
+ case Status.PENDING:
+ return {
+ status: Status.PENDING,
+ data: null,
+ error: null,
+ }
+
+ case Status.RESOLVED:
+ return {
+ status: Status.RESOLVED,
+ data: action.data,
+ error: null,
+ }
+
+ case Status.REJECTED:
+ return {
+ status: Status.REJECTED,
+ data: null,
+ error: action.error,
+ }
+
+ default: {
+ // @ts-ignore: exhaustive fallthrough checks: Property 'type' does not exist on type 'never'.
+ throw new Error(`Unhandled action type: ${action.type}`)
+ }
+ }
+}
+
+function useAsync(
+ initialState: State,
+): {
+ state: State
+ run: (promise: Promise) => void
+} {
+ const [state, unsafeDispatch] = React.useReducer>(
+ asyncReducer,
+ {
+ // @ts-expect-error: 'status' is specified more than once, so this usage will be overwritten.
+ status: Status.IDLE,
+ data: null,
+ error: null,
+ ...initialState,
+ },
+ )
+
+ const dispatch = useSafeDispatch(unsafeDispatch)
+
+ const run = React.useCallback(
+ (promise: Promise): void => {
+ dispatch({type: Status.PENDING})
+ promise.then(
+ data => {
+ dispatch({type: Status.RESOLVED, data})
+ },
+ error => {
+ dispatch({type: Status.REJECTED, error})
+ },
+ )
+ },
+ [dispatch],
+ )
+
+ return {state, run}
+}
+
+//#region PokemonInfo
+const PokemonInfo: React.VFC<{pokemonName?: string}> = ({pokemonName}) => {
+ const {state, run} = useAsync({
+ status: pokemonName ? 'pending' : 'idle',
+ data: null,
+ error: null,
+ })
+
+ React.useEffect(() => {
+ if (!pokemonName) {
+ return
+ }
+ run(fetchPokemon(pokemonName))
+ }, [pokemonName, run])
+
+ switch (state.status) {
+ case 'idle':
+ return <>Submit a pokemon>
+
+ case 'pending':
+ return
+
+ case 'rejected':
+ throw state.error
+
+ case 'resolved':
+ return
+
+ default:
+ throw new Error('This should be impossible')
+ }
+}
+//#endregion useAsync
+
+//#endregion PokemonInfo
+
+function App(): JSX.Element {
+ const [pokemonName, setPokemonName] = React.useState('')
+
+ function handleSubmit(newPokemonName: string): void {
+ setPokemonName(newPokemonName)
+ }
+
+ function handleReset(): void {
+ setPokemonName('')
+ }
+
+ return (
+
+ )
+}
+
+function AppWithUnmountCheckbox(): JSX.Element {
+ const [mountApp, setMountApp] = React.useState(true)
+ return (
+
+
+ setMountApp(e.target.checked)}
+ />{' '}
+ Mount Component
+
+
+ {mountApp ?
: null}
+
+ )
+}
+
+export default AppWithUnmountCheckbox
diff --git a/src/final-ts/02.tsx b/src/final-ts/02.tsx
new file mode 100644
index 00000000..d2b98331
--- /dev/null
+++ b/src/final-ts/02.tsx
@@ -0,0 +1,203 @@
+// useCallback: custom hooks
+// http://localhost:3000/isolated/final-ts/02.tsx
+
+import * as React from 'react'
+import {
+ fetchPokemon,
+ PokemonForm,
+ PokemonDataView,
+ PokemonInfoFallback,
+ PokemonErrorBoundary,
+} from '../pokemon'
+
+
+//#region useAsync: a generic custom hook that would live in a separate module
+export enum Status {
+ IDLE = 'idle',
+ PENDING = 'pending',
+ RESOLVED = 'resolved',
+ REJECTED = 'rejected',
+}
+interface FiniteState<
+ Status extends 'idle' | 'pending' | 'resolved' | 'rejected',
+ Data extends unknown = null,
+ Err extends null | Error = null
+> {
+ status: Status
+ data: Data
+ error: Err
+}
+
+type State =
+ | FiniteState<'idle'>
+ | FiniteState<'pending'>
+ | FiniteState<'resolved', Data>
+ | FiniteState<'rejected', null, Error>
+
+interface ActionType<
+ Type extends 'idle' | 'pending' | 'resolved' | 'rejected'
+> {
+ type: Type
+}
+
+interface ActionIdle extends ActionType {}
+interface ActionPending extends ActionType {}
+
+interface ActionResolved extends ActionType {
+ data: Data
+}
+
+interface ActionRejected extends ActionType {
+ error: Error
+}
+
+type Action =
+ | ActionIdle
+ | ActionPending
+ | ActionResolved
+ | ActionRejected
+
+type AsyncReducer = React.Reducer, Action>
+function asyncReducer(
+ state: State,
+ action: Action,
+): State {
+ switch (action.type) {
+ case Status.IDLE:
+ return {
+ status: Status.IDLE,
+ data: null,
+ error: null,
+ }
+
+ case Status.PENDING:
+ return {
+ status: Status.PENDING,
+ data: null,
+ error: null,
+ }
+
+ case Status.RESOLVED:
+ return {
+ status: Status.RESOLVED,
+ data: action.data,
+ error: null,
+ }
+
+ case Status.REJECTED:
+ return {
+ status: Status.REJECTED,
+ data: null,
+ error: action.error,
+ }
+
+ default: {
+ // @ts-ignore: exhaustive fallthrough checks: Property 'type' does not exist on type 'never'.
+ throw new Error(`Unhandled action type: ${action.type}`)
+ }
+ }
+}
+
+export function useAsync(
+ asyncCallback: () => void | Promise,
+ initialState: State,
+ dependencies: ReadonlyArray,
+): State {
+ const [state, dispatch] = React.useReducer>(asyncReducer, {
+ // @ts-expect-error: 'status' is specified more than once, so this usage will be overwritten.
+ status: Status.IDLE,
+ data: null,
+ error: null,
+ ...initialState,
+ })
+
+ React.useEffect(() => {
+ const promise = asyncCallback()
+ if (!promise) return
+ dispatch({type: Status.PENDING})
+ promise.then(
+ data => dispatch({type: Status.RESOLVED, data}),
+ error => dispatch({type: Status.REJECTED, error}),
+ )
+ // too bad the eslint plugin can't statically analyze this :-(
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, dependencies)
+
+ return state
+}
+//#endregion useAsync
+
+//#region PokemonInfo
+const PokemonInfo: React.VFC<{pokemonName?: string}> = ({pokemonName}) => {
+ const state = useAsync(
+ () => {
+ if (!pokemonName) return
+ return fetchPokemon(pokemonName)
+ },
+ {status: pokemonName ? 'pending' : 'idle', error: null, data: null},
+ [pokemonName],
+ )
+
+ switch (state.status) {
+ case 'idle':
+ return <>Submit a pokemon>
+
+ case 'pending':
+ return
+
+ case 'rejected':
+ throw state.error
+
+ case 'resolved':
+ return
+
+ default:
+ throw new Error('This should be impossible')
+ }
+}
+
+//#endregion PokemonInfo
+
+function App(): JSX.Element {
+ const [pokemonName, setPokemonName] = React.useState('')
+
+ function handleSubmit(newPokemonName: string): void {
+ setPokemonName(newPokemonName)
+ }
+
+ function handleReset(): void {
+ setPokemonName('')
+ }
+
+ return (
+
+ )
+}
+
+function AppWithUnmountCheckbox(): JSX.Element {
+ const [mountApp, setMountApp] = React.useState(true)
+ return (
+
+
+ setMountApp(e.target.checked)}
+ />{' '}
+ Mount Component
+
+
+ {mountApp ?
: null}
+
+ )
+}
+
+export default AppWithUnmountCheckbox
diff --git a/src/final-ts/03.extra-1.tsx b/src/final-ts/03.extra-1.tsx
new file mode 100644
index 00000000..85a9c621
--- /dev/null
+++ b/src/final-ts/03.extra-1.tsx
@@ -0,0 +1,56 @@
+// useContext: simple Counter
+// 💯 create a consumer hook
+// http://localhost:3000/isolated/final-ts/03.extra-1.tsx
+
+import * as React from 'react'
+
+type CounterContextInterface = readonly [
+ number,
+ React.Dispatch>,
+]
+
+// in JS calling React.createContext() with no argument doesn't raise any issue,
+// in Typescript land thought, the compiler will yell at you!
+// In fact, said function is defined as such:
+// ``` function createContext(defaultValue: T ): Context ```
+// where the defaultValue argument is required. if you want to read morea about it
+// this is the issue discussion: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24509#issuecomment-382213106
+// The possible options are listed in theses examples: https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/context#extended-example
+const CountContext = React.createContext(undefined!)
+
+const CountProvider: React.FC = props => {
+ const value = React.useState(0)
+ return
+}
+
+function useCount(): CounterContextInterface {
+ const context = React.useContext(CountContext)
+ if (!context) {
+ throw new Error('useCount must be used within a CountProvider')
+ }
+ return context
+}
+
+function CountDisplay(): JSX.Element {
+ const [count] = useCount()
+ return {`The current count is ${count}`}
+}
+
+function Counter(): JSX.Element {
+ const [, setCount] = useCount()
+ const increment = () => setCount(c => c + 1)
+ return Increment count
+}
+
+function App(): JSX.Element {
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default App
diff --git a/src/final-ts/03.extra-2.tsx b/src/final-ts/03.extra-2.tsx
new file mode 100644
index 00000000..ca158a47
--- /dev/null
+++ b/src/final-ts/03.extra-2.tsx
@@ -0,0 +1,181 @@
+// useContext: Caching response data in context
+// 💯 caching in a context provider (final)
+// http://localhost:3000/isolated/final-ts/03.extra-2.tsx
+
+// you can edit this here and look at the isolated page or you can copy/paste
+// this in the regular exercise file.
+
+import * as React from 'react'
+import {useAsync} from '../utils'
+import {
+ fetchPokemon,
+ PokemonForm,
+ PokemonDataView,
+ PokemonInfoFallback,
+ PokemonErrorBoundary,
+ IPokemon,
+} from '../pokemon'
+
+type PokemonCacheContextInterface = readonly [
+ cache: Record,
+ dispatch: React.Dispatch,
+]
+const PokemonCacheContext = React.createContext(
+ undefined!,
+)
+
+type PokemonName = string
+type State = Record
+type Action = {
+ type: 'ADD_POKEMON'
+ pokemonData: IPokemon
+ pokemonName: PokemonName
+}
+const pokemonCacheReducer: React.Reducer = (state, action) => {
+ switch (action.type) {
+ case 'ADD_POKEMON': {
+ return {...state, [action.pokemonName]: action.pokemonData}
+ }
+ default: {
+ throw new Error(`Unhandled action type: ${action.type}`)
+ }
+ }
+}
+
+function PokemonCacheProvider(props: {
+ children?: React.ReactNode
+}): JSX.Element {
+ const [cache, dispatch] = React.useReducer(pokemonCacheReducer, {})
+ return (
+
+ )
+}
+
+function usePokemonCache(): PokemonCacheContextInterface {
+ const context = React.useContext(PokemonCacheContext)
+ if (!context) {
+ throw new Error(
+ 'usePokemonCache must be used within a PokemonCacheProvider',
+ )
+ }
+ return context
+}
+
+interface PokemonInfoProps {
+ pokemonName: string
+}
+function PokemonInfo({pokemonName}: PokemonInfoProps): JSX.Element {
+ const [cache, dispatch] = usePokemonCache()
+
+ const {state, run, setData} = useAsync({
+ status: pokemonName ? 'pending' : 'idle',
+ error: null,
+ data: null,
+ })
+
+ React.useEffect(() => {
+ if (!pokemonName) {
+ return
+ } else if (cache[pokemonName]) {
+ setData(cache[pokemonName])
+ } else {
+ run(
+ fetchPokemon(pokemonName).then(pokemonData => {
+ dispatch({type: 'ADD_POKEMON', pokemonName, pokemonData})
+ return pokemonData
+ }),
+ )
+ }
+ }, [cache, dispatch, pokemonName, run, setData])
+
+ switch (state.status) {
+ case 'idle':
+ return <>Submit a pokemon>
+
+ case 'pending':
+ return
+
+ case 'rejected':
+ throw state.error
+
+ case 'resolved':
+ return
+
+ default:
+ throw new Error('This should be impossible')
+ }
+}
+
+interface PreviousPokemonProps {
+ onSelect: (pokemonName: string) => void
+}
+function PreviousPokemon({onSelect}: PreviousPokemonProps): JSX.Element {
+ const [cache] = usePokemonCache()
+ return (
+
+ Previous Pokemon
+
+ {Object.keys(cache).map(pokemonName => (
+
+ onSelect(pokemonName)}
+ >
+ {pokemonName}
+
+
+ ))}
+
+
+ )
+}
+
+interface PokemonSectionProps {
+ onSelect: (pokemonName: string) => void
+ pokemonName: string
+}
+function PokemonSection({
+ onSelect,
+ pokemonName,
+}: PokemonSectionProps): JSX.Element {
+ return (
+
+
+
+
+
onSelect('')}
+ resetKeys={[pokemonName]}
+ >
+
+
+
+
+
+ )
+}
+
+function App(): JSX.Element {
+ const [pokemonName, setPokemonName] = React.useState('')
+
+ function handleSubmit(newPokemonName: string): void {
+ setPokemonName(newPokemonName)
+ }
+
+ function handleSelect(newPokemonName: string): void {
+ setPokemonName(newPokemonName)
+ }
+
+ return (
+
+ )
+}
+
+export default App
diff --git a/src/final-ts/03.tsx b/src/final-ts/03.tsx
new file mode 100644
index 00000000..98802fdc
--- /dev/null
+++ b/src/final-ts/03.tsx
@@ -0,0 +1,52 @@
+// useContext: simple Counter
+// http://localhost:3000/isolated/final-ts/03.tsx
+
+import * as React from 'react'
+
+type CounterContextInterface = readonly [
+ number,
+ React.Dispatch>,
+]
+
+// in JS calling React.createContext() with no argument doesn't raise any issue,
+// in Typescript land thought, the compiler will yell at you!
+// In fact, said function is defined as such:
+// ``` function createContext(defaultValue: T ): Context ```
+// where the defaultValue argument is required. if you want to read morea about it
+// this is the issue discussion: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24509#issuecomment-382213106
+// The possible options are listed in theses examples: https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/context#extended-example
+const CountContext = React.createContext(
+ ([] as unknown) as CounterContextInterface,
+)
+
+const CountProvider: React.FC = props => {
+ const [count, setCount] = React.useState(0)
+ const value = [count, setCount] as const
+ // could also do it like this:
+ // const value = React.useState(0)
+ return
+}
+
+function CountDisplay(): JSX.Element {
+ const [count] = React.useContext(CountContext)
+ return {`The current count is ${count}`}
+}
+
+function Counter(): JSX.Element {
+ const [, setCount] = React.useContext(CountContext)
+ const increment = () => setCount(c => c + 1)
+ return Increment count
+}
+
+function App(): JSX.Element {
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default App
diff --git a/src/final-ts/04.tsx b/src/final-ts/04.tsx
new file mode 100644
index 00000000..c3823cb7
--- /dev/null
+++ b/src/final-ts/04.tsx
@@ -0,0 +1,108 @@
+// useLayoutEffect: auto-scrolling textarea
+// http://localhost:3000/isolated/final/04.js
+
+import * as React from 'react'
+interface Message {
+ id: number
+ author: string
+ content: string
+}
+
+interface MessagesDisplayProps {
+ messages: Message[]
+}
+function MessagesDisplay({messages}: MessagesDisplayProps): JSX.Element {
+ const containerRef = React.useRef(null!)
+ React.useLayoutEffect(() => {
+ containerRef.current.scrollTop = containerRef.current.scrollHeight
+ })
+
+ return (
+
+ {messages.map((message, index, array) => (
+
+ {message.author} : {message.content}
+ {array.length - 1 === index ? null :
}
+
+ ))}
+
+ )
+}
+
+// this is to simulate major computation/big rendering tree/etc.
+function sleep(time: number = 0): void {
+ const wakeUpTime = Date.now() + time
+ while (Date.now() < wakeUpTime) {}
+}
+
+function SlooooowSibling(): React.ReactElement | null {
+ // try this with useLayoutEffect as well to see
+ // how it impacts interactivity of the page before updates.
+ React.useEffect(() => {
+ // increase this number to see a more stark difference
+ sleep(300)
+ })
+ return null
+}
+
+function App(): JSX.Element {
+ const [messages, setMessages] = React.useState(
+ allMessages.slice(0, 8),
+ )
+ const addMessage = (): void =>
+ messages.length < allMessages.length
+ ? setMessages(allMessages.slice(0, messages.length + 1))
+ : undefined
+ const removeMessage = (): void =>
+ messages.length > 0
+ ? setMessages(allMessages.slice(0, messages.length - 1))
+ : undefined
+
+ return (
+
+
+ add message
+ remove message
+
+
+
+
+
+ )
+}
+
+export default App
+
+const allMessages: Message[] = [
+ `Leia: Aren't you a little short to be a stormtrooper?`,
+ `Luke: What? Oh... the uniform. I'm Luke Skywalker. I'm here to rescue you.`,
+ `Leia: You're who?`,
+ `Luke: I'm here to rescue you. I've got your R2 unit. I'm here with Ben Kenobi.`,
+ `Leia: Ben Kenobi is here! Where is he?`,
+ `Luke: Come on!`,
+ `Luke: Will you forget it? I already tried it. It's magnetically sealed!`,
+ `Leia: Put that thing away! You're going to get us all killed.`,
+ `Han: Absolutely, Your Worship. Look, I had everything under control until you led us down here. You know, it's not going to take them long to figure out what happened to us.`,
+ `Leia: It could be worse...`,
+ `Han: It's worse.`,
+ `Luke: There's something alive in here!`,
+ `Han: That's your imagination.`,
+ `Luke: Something just moves past my leg! Look! Did you see that?`,
+ `Han: What?`,
+ `Luke: Help!`,
+ `Han: Luke! Luke! Luke!`,
+ `Leia: Luke!`,
+ `Leia: Luke, Luke, grab a hold of this.`,
+ `Luke: Blast it, will you! My gun's jammed.`,
+ `Han: Where?`,
+ `Luke: Anywhere! Oh!!`,
+ `Han: Luke! Luke!`,
+ `Leia: Grab him!`,
+ `Leia: What happened?`,
+ `Luke: I don't know, it just let go of me and disappeared...`,
+ `Han: I've got a very bad feeling about this.`,
+ `Luke: The walls are moving!`,
+ `Leia: Don't just stand there. Try to brace it with something.`,
+ `Luke: Wait a minute!`,
+ `Luke: Threepio! Come in Threepio! Threepio! Where could he be?`,
+].map((m, i) => ({id: i, author: m.split(': ')[0], content: m.split(': ')[1]}))
diff --git a/src/final-ts/05.tsx b/src/final-ts/05.tsx
new file mode 100644
index 00000000..15c93d75
--- /dev/null
+++ b/src/final-ts/05.tsx
@@ -0,0 +1,117 @@
+// useImperativeHandle: scroll to top/bottom
+// http://localhost:3000/isolated/final-ts/05.tsx
+
+import * as React from 'react'
+
+interface Message {
+ id: number
+ author: string
+ content: string
+}
+
+interface MessagesDisplayProps {
+ messages: Message[]
+}
+interface MessagesDisplayRef {
+ scrollToTop: () => void
+ scrollToBottom: () => void
+}
+const MessagesDisplay = React.forwardRef<
+ MessagesDisplayRef,
+ MessagesDisplayProps
+>(function MessagesDisplay({messages}, ref) {
+ const containerRef = React.useRef(null!)
+ React.useLayoutEffect(() => {
+ scrollToBottom()
+ })
+ function scrollToTop() {
+ containerRef.current.scrollTop = 0
+ }
+ function scrollToBottom() {
+ containerRef.current.scrollTop = containerRef.current.scrollHeight
+ }
+ React.useImperativeHandle(ref, () => ({
+ scrollToTop,
+ scrollToBottom,
+ }))
+
+ return (
+
+ {messages.map((message, index, array) => (
+
+ {message.author} : {message.content}
+ {array.length - 1 === index ? null :
}
+
+ ))}
+
+ )
+})
+
+function App(): JSX.Element {
+ const messageDisplayRef = React.useRef(null)
+ const [messages, setMessages] = React.useState(allMessages.slice(0, 8))
+ const addMessage = (): void =>
+ messages.length < allMessages.length
+ ? setMessages(allMessages.slice(0, messages.length + 1))
+ : undefined
+ const removeMessage = (): void =>
+ messages.length > 0
+ ? setMessages(allMessages.slice(0, messages.length - 1))
+ : undefined
+
+ const scrollToTop = (): void => messageDisplayRef.current?.scrollToTop()
+ const scrollToBottom = (): void => messageDisplayRef.current?.scrollToBottom()
+
+ return (
+
+
+ add message
+ remove message
+
+
+
+ scroll to top
+
+
+
+ scroll to bottom
+
+
+ )
+}
+
+export default App
+
+const allMessages: Message[] = [
+ `Leia: Aren't you a little short to be a stormtrooper?`,
+ `Luke: What? Oh... the uniform. I'm Luke Skywalker. I'm here to rescue you.`,
+ `Leia: You're who?`,
+ `Luke: I'm here to rescue you. I've got your R2 unit. I'm here with Ben Kenobi.`,
+ `Leia: Ben Kenobi is here! Where is he?`,
+ `Luke: Come on!`,
+ `Luke: Will you forget it? I already tried it. It's magnetically sealed!`,
+ `Leia: Put that thing away! You're going to get us all killed.`,
+ `Han: Absolutely, Your Worship. Look, I had everything under control until you led us down here. You know, it's not going to take them long to figure out what happened to us.`,
+ `Leia: It could be worse...`,
+ `Han: It's worse.`,
+ `Luke: There's something alive in here!`,
+ `Han: That's your imagination.`,
+ `Luke: Something just moves past my leg! Look! Did you see that?`,
+ `Han: What?`,
+ `Luke: Help!`,
+ `Han: Luke! Luke! Luke!`,
+ `Leia: Luke!`,
+ `Leia: Luke, Luke, grab a hold of this.`,
+ `Luke: Blast it, will you! My gun's jammed.`,
+ `Han: Where?`,
+ `Luke: Anywhere! Oh!!`,
+ `Han: Luke! Luke!`,
+ `Leia: Grab him!`,
+ `Leia: What happened?`,
+ `Luke: I don't know, it just let go of me and disappeared...`,
+ `Han: I've got a very bad feeling about this.`,
+ `Luke: The walls are moving!`,
+ `Leia: Don't just stand there. Try to brace it with something.`,
+ `Luke: Wait a minute!`,
+ `Luke: Threepio! Come in Threepio! Threepio! Where could he be?`,
+].map((m, i) => ({id: i, author: m.split(': ')[0], content: m.split(': ')[1]}))
diff --git a/src/final-ts/06.extra-1.tsx b/src/final-ts/06.extra-1.tsx
new file mode 100644
index 00000000..d705dd59
--- /dev/null
+++ b/src/final-ts/06.extra-1.tsx
@@ -0,0 +1,60 @@
+// useDebugValue: useMedia
+// 💯 use the format function
+// http://localhost:3000/isolated/final-ts/06.extra-1.tsx
+
+import * as React from 'react'
+
+const formatDebugValue = ({
+ query,
+ state,
+}: {
+ query: string
+ state: boolean
+}): string => `\`${query}\` => ${state}`
+
+function useMedia(query: string, initialState: boolean = false): boolean {
+ const [state, setState] = React.useState(initialState)
+ React.useDebugValue({query, state}, formatDebugValue)
+
+ React.useEffect(() => {
+ let mounted = true
+ const mql = window.matchMedia(query)
+ function onChange() {
+ if (!mounted) {
+ return
+ }
+ setState(Boolean(mql.matches))
+ }
+
+ mql.addListener(onChange)
+ setState(mql.matches)
+
+ return () => {
+ mounted = false
+ mql.removeListener(onChange)
+ }
+ }, [query])
+
+ return state
+}
+
+function Box(): JSX.Element {
+ const isBig = useMedia('(min-width: 1000px)')
+ const isMedium = useMedia('(max-width: 999px) and (min-width: 700px)')
+ const isSmall = useMedia('(max-width: 699px)')
+ const color = isBig
+ ? 'green'
+ : isMedium
+ ? 'yellow'
+ : isSmall
+ ? 'red'
+ : 'inherit'
+
+ return
+}
+
+function App(): JSX.Element {
+ return
+}
+
+export default App
diff --git a/src/final-ts/06.tsx b/src/final-ts/06.tsx
new file mode 100644
index 00000000..88f4d146
--- /dev/null
+++ b/src/final-ts/06.tsx
@@ -0,0 +1,51 @@
+// useDebugValue: useMedia
+// http://localhost:3000/isolated/final-ts/06.tsx
+
+import * as React from 'react'
+
+function useMedia(query: string, initialState: boolean = false): boolean {
+ const [state, setState] = React.useState(initialState)
+ React.useDebugValue(`\`${query}\` => ${state}`)
+
+ React.useEffect(() => {
+ let mounted = true
+ const mql: MediaQueryList = window.matchMedia(query)
+ function onChange(): void {
+ if (!mounted) {
+ return
+ }
+ setState(Boolean(mql.matches))
+ }
+
+ mql.addListener(onChange)
+ setState(mql.matches)
+
+ return () => {
+ mounted = false
+ mql.removeListener(onChange)
+ }
+ }, [query])
+
+ return state
+}
+
+function Box(): JSX.Element {
+ const isBig = useMedia('(min-width: 1000px)')
+ const isMedium = useMedia('(max-width: 999px) and (min-width: 700px)')
+ const isSmall = useMedia('(max-width: 699px)')
+ const color = isBig
+ ? 'green'
+ : isMedium
+ ? 'yellow'
+ : isSmall
+ ? 'red'
+ : 'inherit'
+
+ return
+}
+
+function App(): JSX.Element {
+ return
+}
+
+export default App
diff --git a/src/final/03.extra-2.js b/src/final/03.extra-2.js
index af9e84a0..e06cbaf3 100644
--- a/src/final/03.extra-2.js
+++ b/src/final/03.extra-2.js
@@ -46,10 +46,12 @@ function usePokemonCache() {
function PokemonInfo({pokemonName}) {
const [cache, dispatch] = usePokemonCache()
- const {data: pokemon, status, error, run, setData} = useAsync({
+ const {state, run, setData} = useAsync({
status: pokemonName ? 'pending' : 'idle',
})
+ const {data: pokemon, status, error} = state
+
React.useEffect(() => {
if (!pokemonName) {
return
diff --git a/src/pokemon.js b/src/pokemon.tsx
similarity index 65%
rename from src/pokemon.js
rename to src/pokemon.tsx
index b37f6ee0..74d595a6 100644
--- a/src/pokemon.js
+++ b/src/pokemon.tsx
@@ -1,13 +1,52 @@
import * as React from 'react'
-import {ErrorBoundary} from 'react-error-boundary'
+import {ErrorBoundary, FallbackProps} from 'react-error-boundary'
-const formatDate = date =>
+const formatDate = (date: Date): string =>
`${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')} ${String(
date.getSeconds(),
).padStart(2, '0')}.${String(date.getMilliseconds()).padStart(3, '0')}`
+//#region Pokemon interface
+
+interface FetchedAt {
+ fetchedAt: string
+}
+
+/** Represents a Pokémon */
+export interface Pokemon {
+ /** The ID of an object */
+ id: string
+ /** The identifier of this Pokémon */
+ number?: null | string
+ /** The name of this Pokémon */
+ name?: null | string
+ image?: null | string
+
+ attacks: null | PokemonAttack
+}
+
+/** Represents a Pokémon's attack types */
+interface PokemonAttack {
+ /** The fast attacks of this Pokémon */
+ fast?: null | Array
+ /** The special attacks of this Pokémon */
+ special?: null | Array
+}
+
+/** Represents a Pokémon's attack type */
+interface Attack {
+ /** The name of this Pokémon attack */
+ name?: null | string
+ /** The type of this Pokémon attack */
+ type?: null | string
+ /** The damage of this Pokémon attack */
+ damage?: null | number
+}
+export type IPokemon = Pokemon & FetchedAt
+//#endregion
+
// the delay argument is for faking things out a bit
-function fetchPokemon(name, delay = 1500) {
+function fetchPokemon(name: string, delay: number = 1500): Promise {
const pokemonQuery = `
query PokemonInfo($name: String) {
pokemon(name: $name) {
@@ -32,7 +71,7 @@ function fetchPokemon(name, delay = 1500) {
method: 'POST',
headers: {
'content-type': 'application/json;charset=UTF-8',
- delay: delay,
+ delay: String(delay),
},
body: JSON.stringify({
query: pokemonQuery,
@@ -51,24 +90,25 @@ function fetchPokemon(name, delay = 1500) {
}
} else {
// handle the graphql errors
- const error = {
- message: data?.errors?.map(e => e.message).join('\n'),
+ const error: Partial = {
+ message: data?.errors?.map((e: Error) => e.message).join('\n'),
}
return Promise.reject(error)
}
})
}
-function PokemonInfoFallback({name}) {
+function PokemonInfoFallback({name}: {name: string}): JSX.Element {
const initialName = React.useRef(name).current
- const fallbackPokemonData = {
+ const fallbackPokemonData: IPokemon = {
+ id: '',
name: initialName,
number: 'XXX',
image: '/img/pokemon/fallback-pokemon.jpg',
attacks: {
special: [
- {name: 'Loading Attack 1', type: 'Type', damage: 'XX'},
- {name: 'Loading Attack 2', type: 'Type', damage: 'XX'},
+ {name: 'Loading Attack 1', type: 'Type', damage: null},
+ {name: 'Loading Attack 2', type: 'Type', damage: null},
],
},
fetchedAt: 'loading...',
@@ -76,11 +116,11 @@ function PokemonInfoFallback({name}) {
return
}
-function PokemonDataView({pokemon}) {
+function PokemonDataView({pokemon}: {pokemon: IPokemon}): JSX.Element {
return (
-
+
@@ -90,11 +130,11 @@ function PokemonDataView({pokemon}) {
- {pokemon.attacks.special.map(attack => (
-
- {attack.name} :{' '}
+ {pokemon.attacks?.special?.map((attack, idx) => (
+
+ {attack?.name} :{' '}
- {attack.damage} ({attack.type})
+ {attack?.damage} ({attack?.type})
))}
@@ -105,11 +145,16 @@ function PokemonDataView({pokemon}) {
)
}
+interface PokemonFormProps {
+ pokemonName: string
+ initialPokemonName?: string
+ onSubmit: (pokemonName: string) => void
+}
function PokemonForm({
pokemonName: externalPokemonName,
initialPokemonName = externalPokemonName || '',
onSubmit,
-}) {
+}: PokemonFormProps): JSX.Element {
const [pokemonName, setPokemonName] = React.useState(initialPokemonName)
// this is generally not a great idea. We're synchronizing state when it is
@@ -124,16 +169,16 @@ function PokemonForm({
}
}, [externalPokemonName])
- function handleChange(e) {
+ function handleChange(e: React.ChangeEvent): void {
setPokemonName(e.target.value)
}
- function handleSubmit(e) {
+ function handleSubmit(e: React.FormEvent): void {
e.preventDefault()
onSubmit(pokemonName)
}
- function handleSelect(newPokemonName) {
+ function handleSelect(newPokemonName: string): void {
setPokemonName(newPokemonName)
onSubmit(newPokemonName)
}
@@ -184,7 +229,10 @@ function PokemonForm({
)
}
-function ErrorFallback({error, resetErrorBoundary}) {
+function ErrorFallback({
+ error,
+ resetErrorBoundary,
+}: FallbackProps): JSX.Element {
return (
There was an error:{' '}
@@ -194,7 +242,9 @@ function ErrorFallback({error, resetErrorBoundary}) {
)
}
-function PokemonErrorBoundary(props) {
+function PokemonErrorBoundary(
+ props: Omit
, 'FallbackComponent'>,
+): JSX.Element {
return
}
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
new file mode 100644
index 00000000..6431bc5f
--- /dev/null
+++ b/src/react-app-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/src/setupTests.js b/src/setupTests.js
deleted file mode 100644
index d9dd7e1a..00000000
--- a/src/setupTests.js
+++ /dev/null
@@ -1 +0,0 @@
-import '@kentcdodds/react-workshop-app/setup-tests'
diff --git a/src/setupTests.ts b/src/setupTests.ts
new file mode 100644
index 00000000..9ccf8935
--- /dev/null
+++ b/src/setupTests.ts
@@ -0,0 +1,8 @@
+// jest.config.ts
+import type {Config} from '@jest/types'
+
+import '@kentcdodds/react-workshop-app/setup-tests'
+
+// Sync object
+const config: Config.InitialOptions = {}
+export default config
diff --git a/src/types.d.ts b/src/types.d.ts
new file mode 100644
index 00000000..3f69993a
--- /dev/null
+++ b/src/types.d.ts
@@ -0,0 +1,14 @@
+declare module '@kentcdodds/react-workshop-app/test-utils' {
+ declare function alfredTip(
+ shouldThrow: unknown | ((...args: unknown[]) => unknown),
+ tip: string,
+ ): void
+
+ export {alfredTip}
+}
+
+declare module 'mq-polyfill' {
+ declare function matchMediaPolyfill(window: Window): void
+
+ export default matchMediaPolyfill
+}
diff --git a/src/utils.js b/src/utils.js
deleted file mode 100644
index 2ff73970..00000000
--- a/src/utils.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import * as React from 'react'
-
-function useSafeDispatch(dispatch) {
- const mounted = React.useRef(false)
-
- React.useLayoutEffect(() => {
- mounted.current = true
- return () => (mounted.current = false)
- }, [])
-
- return React.useCallback(
- (...args) => (mounted.current ? dispatch(...args) : void 0),
- [dispatch],
- )
-}
-
-function asyncReducer(state, action) {
- switch (action.type) {
- case 'pending': {
- return {status: 'pending', data: null, error: null}
- }
- case 'resolved': {
- return {status: 'resolved', data: action.data, error: null}
- }
- case 'rejected': {
- return {status: 'rejected', data: null, error: action.error}
- }
- default: {
- throw new Error(`Unhandled action type: ${action.type}`)
- }
- }
-}
-
-function useAsync(initialState) {
- const [state, unsafeDispatch] = React.useReducer(asyncReducer, {
- status: 'idle',
- data: null,
- error: null,
- ...initialState,
- })
-
- const dispatch = useSafeDispatch(unsafeDispatch)
-
- const {data, error, status} = state
-
- const run = React.useCallback(
- promise => {
- dispatch({type: 'pending'})
- promise.then(
- data => {
- dispatch({type: 'resolved', data})
- },
- error => {
- dispatch({type: 'rejected', error})
- },
- )
- },
- [dispatch],
- )
-
- const setData = React.useCallback(
- data => dispatch({type: 'resolved', data}),
- [dispatch],
- )
- const setError = React.useCallback(
- error => dispatch({type: 'rejected', error}),
- [dispatch],
- )
-
- return {
- setData,
- setError,
- error,
- status,
- data,
- run,
- }
-}
-
-export {useAsync}
diff --git a/src/utils.tsx b/src/utils.tsx
new file mode 100644
index 00000000..75f353cd
--- /dev/null
+++ b/src/utils.tsx
@@ -0,0 +1,166 @@
+import * as React from 'react'
+
+export enum Status {
+ IDLE = 'idle',
+ PENDING = 'pending',
+ RESOLVED = 'resolved',
+ REJECTED = 'rejected',
+}
+
+interface FiniteState<
+ Status extends 'idle' | 'pending' | 'resolved' | 'rejected',
+ Data extends unknown = null,
+ Err extends null | Error = null
+> {
+ status: Status
+ data: Data
+ error: Err
+}
+
+interface ActionType<
+ Type extends 'idle' | 'pending' | 'resolved' | 'rejected'
+> {
+ type: Type
+}
+
+interface ActionIdle extends ActionType {}
+interface ActionPending extends ActionType {}
+
+interface ActionResolved extends ActionType {
+ data: Data
+}
+
+interface ActionRejected extends ActionType {
+ error: Error
+}
+
+type State =
+ | FiniteState<'idle'>
+ | FiniteState<'pending'>
+ | FiniteState<'resolved', Data>
+ | FiniteState<'rejected', null, Error>
+
+type Action =
+ | ActionIdle
+ | ActionPending
+ | ActionResolved
+ | ActionRejected
+
+function useSafeDispatch void>(
+ dispatch: Dispatch,
+): Dispatch {
+ const mounted = React.useRef(false)
+
+ React.useLayoutEffect(() => {
+ mounted.current = true
+ return () => {
+ mounted.current = false
+ }
+ }, [])
+
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ return React.useCallback(
+ ((...args) => {
+ if (mounted.current) {
+ dispatch(...args)
+ }
+ }) as Dispatch,
+ [dispatch],
+ )
+}
+
+type AsyncReducer = React.Reducer, Action>
+function asyncReducer(
+ state: State,
+ action: Action,
+): State {
+ switch (action.type) {
+ case Status.IDLE:
+ return {
+ status: Status.IDLE,
+ data: null,
+ error: null,
+ }
+
+ case Status.PENDING:
+ return {
+ status: Status.PENDING,
+ data: null,
+ error: null,
+ }
+
+ case Status.RESOLVED:
+ return {
+ status: Status.RESOLVED,
+ data: action.data,
+ error: null,
+ }
+
+ case Status.REJECTED:
+ return {
+ status: Status.REJECTED,
+ data: null,
+ error: action.error,
+ }
+
+ default: {
+ // @ts-ignore: exhaustive fallthrough checks: Property 'type' does not exist on type 'never'.
+ throw new Error(`Unhandled action type: ${action.type}`)
+ }
+ }
+}
+
+function useAsync(
+ initialState?: State,
+): Readonly<{
+ setData: (data: Data) => void
+ setError: (error: Error) => void
+ state: State
+ run: (promise: Promise) => void
+}> {
+ const [state, unsafeDispatch] = React.useReducer>(
+ asyncReducer,
+ {
+ status: Status.IDLE,
+ data: null,
+ error: null,
+ ...initialState,
+ },
+ )
+
+ const dispatch = useSafeDispatch(unsafeDispatch)
+
+ const run = React.useCallback(
+ (promise: Promise) => {
+ dispatch({type: Status.PENDING})
+ promise.then(
+ data => {
+ dispatch({type: Status.RESOLVED, data})
+ },
+ error => {
+ dispatch({type: Status.REJECTED, error})
+ },
+ )
+ },
+ [dispatch],
+ )
+
+ const setData = React.useCallback(
+ (data: Data) => dispatch({type: Status.RESOLVED, data}),
+ [dispatch],
+ )
+
+ const setError = React.useCallback(
+ (error: Error) => dispatch({type: Status.REJECTED, error}),
+ [dispatch],
+ )
+
+ return {
+ setData,
+ setError,
+ state,
+ run,
+ } as const
+}
+
+export {useAsync}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 00000000..10ee6a4c
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx"
+ },
+ "include": ["src", "./src/types.d.ts"]
+}