From 9004e358f9740ff7b312c509945b066cd39d85af Mon Sep 17 00:00:00 2001 From: shmck Date: Tue, 13 Aug 2019 22:23:31 -0700 Subject: [PATCH 001/117] setup server api --- .env | 1 + package-lock.json | 38 +++++++++++++++++++++++-- package.json | 3 ++ src/services/api/api.ts | 13 +++++++++ src/services/api/gql/query/tutorial.gql | 16 +++++++++++ src/services/api/index.ts | 2 +- 6 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 .env create mode 100644 src/services/api/api.ts create mode 100644 src/services/api/gql/query/tutorial.gql diff --git a/.env b/.env new file mode 100644 index 00000000..b4851fcc --- /dev/null +++ b/.env @@ -0,0 +1 @@ +API_URL=http://localhost:3000/graphql \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 27c37cfb..02fc807b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,14 @@ "js-tokens": "^4.0.0" } }, + "@types/dotenv": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz", + "integrity": "sha512-ftQl3DtBvqHl9L16tpqqzA4YzCSXZfi7g8cQceTz5rOlYtk/IZbFjAv3mLOQlNIgOaylCQWQoBdDQHPgEBJPHg==", + "requires": { + "@types/node": "*" + } + }, "@types/mocha": { "version": "5.2.7", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", @@ -33,8 +41,7 @@ "@types/node": { "version": "12.7.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz", - "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==", - "dev": true + "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==" }, "agent-base": { "version": "4.3.0", @@ -107,6 +114,15 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, + "axios": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", + "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -307,6 +323,11 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, + "dotenv": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.0.0.tgz", + "integrity": "sha512-30xVGqjLjiUOArT4+M5q9sYdvuR4riM6yK9wMcas9Vbp6zZa+ocC9dp6QoftuhTPhFAiLK/0C5Ni2nou/Bk8lg==" + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -408,6 +429,14 @@ "locate-path": "^3.0.0" } }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -556,6 +585,11 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" + }, "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", diff --git a/package.json b/package.json index df6dbb07..dc74208e 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "test": "npm run build && node ./node_modules/vscode/bin/test" }, "devDependencies": { + "@types/dotenv": "^6.1.1", "@types/mocha": "^5.2.7", "@types/node": "^12.7.1", "concurrently": "^4.1.1", @@ -61,6 +62,8 @@ "typescript": "^3.5.3" }, "dependencies": { + "axios": "^0.19.0", + "dotenv": "^8.0.0", "vscode": "^1.1.36", "xstate": "^4.6.7" }, diff --git a/src/services/api/api.ts b/src/services/api/api.ts new file mode 100644 index 00000000..c51faa37 --- /dev/null +++ b/src/services/api/api.ts @@ -0,0 +1,13 @@ +import axios from 'axios' + +require('dotenv').config() + +const api = axios.create({ + baseURL: process.env.API_URL, + method: 'POST', + headers: { + 'Content-Type': 'application/graphql', + } +}) + +export default api \ No newline at end of file diff --git a/src/services/api/gql/query/tutorial.gql b/src/services/api/gql/query/tutorial.gql new file mode 100644 index 00000000..9397a9c6 --- /dev/null +++ b/src/services/api/gql/query/tutorial.gql @@ -0,0 +1,16 @@ +query getTutorial($tutorialId: ID!) { + tutorial(id: $tutorialId) { + id + testRunner + codingLanguage + repo { + uri + branch + } + latestVersion { + version + coderoadVersion + data + } + } +} diff --git a/src/services/api/index.ts b/src/services/api/index.ts index 8429ba4f..dbcac727 100644 --- a/src/services/api/index.ts +++ b/src/services/api/index.ts @@ -12,7 +12,7 @@ const tutorialsData: { [key: string]: CR.Tutorial } = { [basicTutorial.id]: basicTutorial, } -// TODO: replace with fetch resource +// TODO: replace with fetch resource in ./api.ts export default async function fetch(options: Options): Promise { switch (options.resource) { case 'getTutorialsSummary': From 4bd3fad30add813f356fd3ef22d093907e80b7d6 Mon Sep 17 00:00:00 2001 From: shmck Date: Tue, 13 Aug 2019 22:31:55 -0700 Subject: [PATCH 002/117] setup apollo on web --- web-app/.env | 1 - web-app/package-lock.json | 211 ++++++++++++++++++- web-app/package.json | 3 + web-app/src/App.tsx | 16 +- web-app/src/containers/Continue/tutorial.gql | 24 +++ web-app/src/containers/New/tutorials.gql | 17 ++ web-app/src/services/api/index.tsx | 2 +- web-app/src/services/apollo/index.ts | 7 + 8 files changed, 271 insertions(+), 10 deletions(-) delete mode 100644 web-app/.env create mode 100644 web-app/src/containers/Continue/tutorial.gql create mode 100644 web-app/src/containers/New/tutorials.gql create mode 100644 web-app/src/services/apollo/index.ts diff --git a/web-app/.env b/web-app/.env deleted file mode 100644 index ed7b099e..00000000 --- a/web-app/.env +++ /dev/null @@ -1 +0,0 @@ -PUBLIC_URL=./ \ No newline at end of file diff --git a/web-app/package-lock.json b/web-app/package-lock.json index 4dac4fd7..33fe4d0a 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -25,6 +25,40 @@ } } }, + "@apollo/react-common": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@apollo/react-common/-/react-common-3.0.0.tgz", + "integrity": "sha512-EqHASkcmxipy2hU8rja+lD1S1HoTdodKKyJZZ3dgewnAHXnzXnnC3rw1+lkrgXPFsI2n2d2N2LYisD79OCdPmw==", + "requires": { + "ts-invariant": "^0.4.4", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, + "@apollo/react-hooks": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@apollo/react-hooks/-/react-hooks-3.0.0.tgz", + "integrity": "sha512-7kaV6rkx2WZjDYcBmp52oyhTxbNn5Jc4AUmsXZVEnDu9uuvNYURA8bLlJNF8yu4zS7ed8D+ZebC0y0bhrz8wIg==", + "requires": { + "@apollo/react-common": "^3.0.0", + "@wry/equality": "^0.1.9", + "ts-invariant": "^0.4.4", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", @@ -2806,6 +2840,11 @@ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.12.tgz", "integrity": "sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw==" }, + "@types/zen-observable": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.0.tgz", + "integrity": "sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg==" + }, "@typescript-eslint/eslint-plugin": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.6.0.tgz", @@ -3001,6 +3040,23 @@ "@xtuc/long": "4.2.2" } }, + "@wry/context": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.4.4.tgz", + "integrity": "sha512-LrKVLove/zw6h2Md/KZyWxIkFM6AoyKp71OqpH9Hiip1csjPVoD3tPxlbQUNxEnHENks3UGgNpSBCAfq9KWuag==", + "requires": { + "@types/node": ">=6", + "tslib": "^1.9.3" + } + }, + "@wry/equality": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.1.9.tgz", + "integrity": "sha512-mB6ceGjpMGz1ZTza8HYnrPGos2mC6So4NhS1PtZ8s4Qt0K7fBiIGhpSxUbQmhwcSWE3no+bYxmI2OL6KuXYmoQ==", + "requires": { + "tslib": "^1.9.3" + } + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -3196,6 +3252,110 @@ "normalize-path": "^2.1.1" } }, + "apollo-boost": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/apollo-boost/-/apollo-boost-0.4.4.tgz", + "integrity": "sha512-ASngBvazmp9xNxXfJ2InAzfDwz65o4lswlEPrWoN35scXmCz8Nz4k3CboUXbrcN/G0IExkRf/W7o9Rg0cjEBqg==", + "requires": { + "apollo-cache": "^1.3.2", + "apollo-cache-inmemory": "^1.6.3", + "apollo-client": "^2.6.4", + "apollo-link": "^1.0.6", + "apollo-link-error": "^1.0.3", + "apollo-link-http": "^1.3.1", + "graphql-tag": "^2.4.2", + "ts-invariant": "^0.4.0", + "tslib": "^1.9.3" + } + }, + "apollo-cache": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.3.2.tgz", + "integrity": "sha512-+KA685AV5ETEJfjZuviRTEImGA11uNBp/MJGnaCvkgr+BYRrGLruVKBv6WvyFod27WEB2sp7SsG8cNBKANhGLg==", + "requires": { + "apollo-utilities": "^1.3.2", + "tslib": "^1.9.3" + } + }, + "apollo-cache-inmemory": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.6.3.tgz", + "integrity": "sha512-S4B/zQNSuYc0M/1Wq8dJDTIO9yRgU0ZwDGnmlqxGGmFombOZb9mLjylewSfQKmjNpciZ7iUIBbJ0mHlPJTzdXg==", + "requires": { + "apollo-cache": "^1.3.2", + "apollo-utilities": "^1.3.2", + "optimism": "^0.10.0", + "ts-invariant": "^0.4.0", + "tslib": "^1.9.3" + } + }, + "apollo-client": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/apollo-client/-/apollo-client-2.6.4.tgz", + "integrity": "sha512-oWOwEOxQ9neHHVZrQhHDbI6bIibp9SHgxaLRVPoGvOFy7OH5XUykZE7hBQAVxq99tQjBzgytaZffQkeWo1B4VQ==", + "requires": { + "@types/zen-observable": "^0.8.0", + "apollo-cache": "1.3.2", + "apollo-link": "^1.0.0", + "apollo-utilities": "1.3.2", + "symbol-observable": "^1.0.2", + "ts-invariant": "^0.4.0", + "tslib": "^1.9.3", + "zen-observable": "^0.8.0" + } + }, + "apollo-link": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.12.tgz", + "integrity": "sha512-fsgIAXPKThyMVEMWQsUN22AoQI+J/pVXcjRGAShtk97h7D8O+SPskFinCGEkxPeQpE83uKaqafB2IyWdjN+J3Q==", + "requires": { + "apollo-utilities": "^1.3.0", + "ts-invariant": "^0.4.0", + "tslib": "^1.9.3", + "zen-observable-ts": "^0.8.19" + } + }, + "apollo-link-error": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.11.tgz", + "integrity": "sha512-442DNqn3CNRikDaenMMkoDmCRmkoUx/XyUMlRTZBEFdTw3FYPQLsmDO3hzzC4doY5/BHcn9/jdYh9EeLx4HPsA==", + "requires": { + "apollo-link": "^1.2.12", + "apollo-link-http-common": "^0.2.14", + "tslib": "^1.9.3" + } + }, + "apollo-link-http": { + "version": "1.5.15", + "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.15.tgz", + "integrity": "sha512-epZFhCKDjD7+oNTVK3P39pqWGn4LEhShAoA1Q9e2tDrBjItNfviiE33RmcLcCURDYyW5JA6SMgdODNI4Is8tvQ==", + "requires": { + "apollo-link": "^1.2.12", + "apollo-link-http-common": "^0.2.14", + "tslib": "^1.9.3" + } + }, + "apollo-link-http-common": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.14.tgz", + "integrity": "sha512-v6mRU1oN6XuX8beVIRB6OpF4q1ULhSnmy7ScnHnuo1qV6GaFmDcbdvXqxIkAV1Q8SQCo2lsv4HeqJOWhFfApOg==", + "requires": { + "apollo-link": "^1.2.12", + "ts-invariant": "^0.4.0", + "tslib": "^1.9.3" + } + }, + "apollo-utilities": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.2.tgz", + "integrity": "sha512-JWNHj8XChz7S4OZghV6yc9FNnzEXj285QYp/nLNh943iObycI5GTDO3NGR9Dth12LRrSFMeDOConPfPln+WGfg==", + "requires": { + "@wry/equality": "^0.1.2", + "fast-json-stable-stringify": "^2.0.0", + "ts-invariant": "^0.4.0", + "tslib": "^1.9.3" + } + }, "app-root-dir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz", @@ -8190,6 +8350,19 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, + "graphql": { + "version": "14.4.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.4.2.tgz", + "integrity": "sha512-6uQadiRgnpnSS56hdZUSvFrVcQ6OF9y6wkxJfKquFtHlnl7+KSuWwSJsdwiK1vybm1HgcdbpGkCpvhvsVQ0UZQ==", + "requires": { + "iterall": "^1.2.2" + } + }, + "graphql-tag": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", + "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==" + }, "growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", @@ -9181,6 +9354,11 @@ "handlebars": "^4.1.2" } }, + "iterall": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", + "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" + }, "jest": { "version": "24.7.1", "resolved": "https://registry.npmjs.org/jest/-/jest-24.7.1.tgz", @@ -11789,6 +11967,14 @@ "is-wsl": "^1.1.0" } }, + "optimism": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.10.2.tgz", + "integrity": "sha512-zPfBIxFFWMmQboM9+Z4MSJqc1PXp82v1PFq/GfQaufI69mHKlup7ykGNnfuGIGssXJQkmhSodQ/k9EWwjd8O8A==", + "requires": { + "@wry/context": "^0.4.0" + } + }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -15783,8 +15969,7 @@ "symbol-observable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" }, "symbol-tree": { "version": "3.2.2", @@ -16143,6 +16328,14 @@ "glob": "^7.1.2" } }, + "ts-invariant": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz", + "integrity": "sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA==", + "requires": { + "tslib": "^1.9.3" + } + }, "ts-pnp": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.2.tgz", @@ -17297,6 +17490,20 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "zen-observable": { + "version": "0.8.14", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.14.tgz", + "integrity": "sha512-kQz39uonEjEESwh+qCi83kcC3rZJGh4mrZW7xjkSQYXkq//JZHTtKo+6yuVloTgMtzsIWOJrjIrKvk/dqm0L5g==" + }, + "zen-observable-ts": { + "version": "0.8.19", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.19.tgz", + "integrity": "sha512-u1a2rpE13G+jSzrg3aiCqXU5tN2kw41b+cBZGmnc+30YimdkKiDj9bTowcB41eL77/17RF/h+393AuVgShyheQ==", + "requires": { + "tslib": "^1.9.3", + "zen-observable": "^0.8.0" + } } } } diff --git a/web-app/package.json b/web-app/package.json index 19948df2..a0225a09 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -4,6 +4,9 @@ "private": true, "dependencies": { "@alifd/next": "^1.16.6", + "@apollo/react-hooks": "^3.0.0", + "apollo-boost": "^0.4.4", + "graphql": "^14.4.2", "markdown-it": "^9.1.0", "markdown-it-emoji": "^1.4.0", "markdown-it-prism": "^2.0.2", diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index 8008c8b2..e48c7cfe 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -1,6 +1,8 @@ import * as React from 'react' +import { ApolloProvider } from '@apollo/react-hooks' import * as CR from 'typings' +import client from './services/apollo' import Debugger from './components/Debugger' import Routes from './Routes' import DataContext, { initialData, initialState } from './utils/DataContext' @@ -49,12 +51,14 @@ const App = () => { // TODO: refactor cond to user and accept first route as if/else if return ( - -
- {process.env.REACT_APP_DEBUG && } - -
-
+ + +
+ {process.env.REACT_APP_DEBUG && } + +
+
+
) } diff --git a/web-app/src/containers/Continue/tutorial.gql b/web-app/src/containers/Continue/tutorial.gql new file mode 100644 index 00000000..cbd8b82f --- /dev/null +++ b/web-app/src/containers/Continue/tutorial.gql @@ -0,0 +1,24 @@ +query getTutorial($tutorialId: ID!) { + tutorial(id: $tutorialId) { + id + title + text + createdBy { + id + name + } + createdAt + codingLanguage + repo { + uri + branch + owner + name + } + latestVersion { + version + coderoadVersion + data + } + } +} diff --git a/web-app/src/containers/New/tutorials.gql b/web-app/src/containers/New/tutorials.gql new file mode 100644 index 00000000..9247c267 --- /dev/null +++ b/web-app/src/containers/New/tutorials.gql @@ -0,0 +1,17 @@ +query getTutorials { + tutorials { + id + title + text + createdBy { + id + name + } + createdAt + codingLanguage + latestVersion { + version + coderoadVersion + } + } +} diff --git a/web-app/src/services/api/index.tsx b/web-app/src/services/api/index.tsx index aa05ea0d..2bfdb83c 100644 --- a/web-app/src/services/api/index.tsx +++ b/web-app/src/services/api/index.tsx @@ -18,7 +18,7 @@ export default async function fetch(options: Options): Promise { switch (options.resource) { case 'getTutorialsSummary': // list of ids with summaries - let data: { [id: string]: CR.TutorialSummary } = {} + const data: { [id: string]: CR.TutorialSummary } = {} for (const tutorial of Object.values(tutorialsData)) { data[tutorial.id] = tutorial.data.summary } diff --git a/web-app/src/services/apollo/index.ts b/web-app/src/services/apollo/index.ts new file mode 100644 index 00000000..a3f3c502 --- /dev/null +++ b/web-app/src/services/apollo/index.ts @@ -0,0 +1,7 @@ +import ApolloClient from 'apollo-boost' + +const client = new ApolloClient({ + uri: process.env.REACT_APP_GQL_URI, +}) + +export default client \ No newline at end of file From 44562617d2f3e7d695fc3e6bc58fb95ef6264031 Mon Sep 17 00:00:00 2001 From: shmck Date: Tue, 13 Aug 2019 23:08:37 -0700 Subject: [PATCH 003/117] setup new page query --- web-app/src/containers/New/index.tsx | 61 +++++++++++++++--------- web-app/src/containers/New/query.ts | 16 +++++++ web-app/src/containers/New/tutorials.gql | 17 ------- 3 files changed, 54 insertions(+), 40 deletions(-) create mode 100644 web-app/src/containers/New/query.ts delete mode 100644 web-app/src/containers/New/tutorials.gql diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index a48edbb4..fc4be722 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -4,35 +4,50 @@ import { Button } from '@alifd/next' import Cond from '../../components/Cond' import DataContext from '../../utils/DataContext' import { send } from '../../utils/vscode' +import { useQuery } from '@apollo/react-hooks' +import query from './query' + import LoadingPage from '../../containers/LoadingPage' interface Props { + state: any + tutorialList: any[] onNew(tutorialId: string): void } -export const NewPage = (props: Props) => { +export const NewPage = (props: Props) => ( +
+ +
+

Start a new Project

+ {props.tutorialList.map(tutorial => ( +
+

{tutorial.title}

+

{tutorial.description}

+ +
+ ))} +
+
+ + + +
+) + +export default () => { + console.log('load new') const { state } = React.useContext(DataContext) + const { data, loading, error } = useQuery(query) const [tutorialList] = React.useState([{ id: '1', title: 'Demo', description: 'A basic demo' }]) - // context - return ( -
- -
-

Start a new Project

- {tutorialList.map(tutorial => ( -
-

{tutorial.title}

-

{tutorial.description}

- -
- ))} -
-
- - - -
- ) -} + console.log('data', data) + if (loading) { + return null + } -export default () => send('TUTORIAL_START')} /> + if (error) { + return
'Error'
+ } + + return send('TUTORIAL_START')} state={state} tutorialList={tutorialList} /> +} diff --git a/web-app/src/containers/New/query.ts b/web-app/src/containers/New/query.ts new file mode 100644 index 00000000..49d2a643 --- /dev/null +++ b/web-app/src/containers/New/query.ts @@ -0,0 +1,16 @@ +import { gql } from 'apollo-boost' + +export default gql` + query getTutorials { + tutorials { + id + title + text + codingLanguage + latestVersion { + version + coderoadVersion + } + } + } +` diff --git a/web-app/src/containers/New/tutorials.gql b/web-app/src/containers/New/tutorials.gql deleted file mode 100644 index 9247c267..00000000 --- a/web-app/src/containers/New/tutorials.gql +++ /dev/null @@ -1,17 +0,0 @@ -query getTutorials { - tutorials { - id - title - text - createdBy { - id - name - } - createdAt - codingLanguage - latestVersion { - version - coderoadVersion - } - } -} From d0f984bcdc18603213d610546053a5db7f4bb536 Mon Sep 17 00:00:00 2001 From: shmck Date: Fri, 16 Aug 2019 07:02:04 -0700 Subject: [PATCH 004/117] npm updates --- web-app/package-lock.json | 398 ++++++++++++++++++++------------------ web-app/package.json | 19 +- 2 files changed, 215 insertions(+), 202 deletions(-) diff --git a/web-app/package-lock.json b/web-app/package-lock.json index 33fe4d0a..f15e6859 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@alifd/next": { - "version": "1.16.6", - "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.16.6.tgz", - "integrity": "sha512-hGK0qlVp46hgRWZJeIvWF/Lkc8mAAHswbBdDxEyMjMaXtLBH6uZsO6/RvORP4VHM+1bE3qIUU58PeSuhVAkGVA==", + "version": "1.16.7", + "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.16.7.tgz", + "integrity": "sha512-TSmRNooTozOA2HDolqmCWEgaEjtat+ZObZTHJ0Qdyk9QPD2Dr3qu1nUqGRPyC0PA7hipa6S7FjibPH901ZwCxg==", "requires": { "babel-runtime": "^6.26.0", "classnames": "^2.2.3", @@ -26,9 +26,9 @@ } }, "@apollo/react-common": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@apollo/react-common/-/react-common-3.0.0.tgz", - "integrity": "sha512-EqHASkcmxipy2hU8rja+lD1S1HoTdodKKyJZZ3dgewnAHXnzXnnC3rw1+lkrgXPFsI2n2d2N2LYisD79OCdPmw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@apollo/react-common/-/react-common-3.0.1.tgz", + "integrity": "sha512-7SC4qqPFo/41AhaQKCRovIshKkm4JLEGXyRHi+NPsaNJyk2J/HrWREnlHVqoPzYeIyq33f1L6j/NAkKn1NOnnQ==", "requires": { "ts-invariant": "^0.4.4", "tslib": "^1.10.0" @@ -42,11 +42,11 @@ } }, "@apollo/react-hooks": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@apollo/react-hooks/-/react-hooks-3.0.0.tgz", - "integrity": "sha512-7kaV6rkx2WZjDYcBmp52oyhTxbNn5Jc4AUmsXZVEnDu9uuvNYURA8bLlJNF8yu4zS7ed8D+ZebC0y0bhrz8wIg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@apollo/react-hooks/-/react-hooks-3.0.1.tgz", + "integrity": "sha512-Boai/T+2z3m23Gy82m1pB+FOlrhkBJ//EIYa3pqX9sUsvgRWMKC+3NxpeHEUYqsf0qzFiM1dO4Pn9OxCFstM8g==", "requires": { - "@apollo/react-common": "^3.0.0", + "@apollo/react-common": "^3.0.1", "@wry/equality": "^0.1.9", "ts-invariant": "^0.4.4", "tslib": "^1.10.0" @@ -1100,9 +1100,9 @@ } }, "@emotion/core": { - "version": "10.0.15", - "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.0.15.tgz", - "integrity": "sha512-VHwwl3k/ddMfQOHYgOJryXOs2rGJ5AfKLQGm5AVolNonnr6tkmDI4nzIMNaPpveoXVs7sP0OrF24UunIPxveQw==", + "version": "10.0.16", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.0.16.tgz", + "integrity": "sha512-whbiiA7FfPreBY4BqWky2qRfAZvq+4dKQ1WNJuiYQwPCNmb0pEYDgNheSbZoNKtGTtfPaM28hBbZAKWD5EZXmQ==", "dev": true, "requires": { "@babel/runtime": "^7.4.3", @@ -1481,16 +1481,16 @@ } }, "@storybook/addon-actions": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-5.1.10.tgz", - "integrity": "sha512-njl2AHBGi27NvisOB8LFnWH/3RcyJT/CW7tl1cvV2j5FH2oBjq5MsjxKyJIcKwC677k1Wr8G8fw/zSEHrPpmgA==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-5.1.11.tgz", + "integrity": "sha512-Fp4b8cBYrl9zudvamVYTxE1XK2tzg91hgBDoVxIbDvSMZ2aQXSq8B5OFS4eSdvg+ldEOBbvIgUNS1NIw+FGntQ==", "dev": true, "requires": { - "@storybook/addons": "5.1.10", - "@storybook/api": "5.1.10", - "@storybook/components": "5.1.10", - "@storybook/core-events": "5.1.10", - "@storybook/theming": "5.1.10", + "@storybook/addons": "5.1.11", + "@storybook/api": "5.1.11", + "@storybook/components": "5.1.11", + "@storybook/core-events": "5.1.11", + "@storybook/theming": "5.1.11", "core-js": "^3.0.1", "fast-deep-equal": "^2.0.1", "global": "^4.3.2", @@ -1503,16 +1503,16 @@ } }, "@storybook/addon-knobs": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/addon-knobs/-/addon-knobs-5.1.10.tgz", - "integrity": "sha512-j5wXBIPGQxK+guFDAi8xNBdUnyQglhDplVoC9SswkSMarqtWq02TT+OLN2VSBgpvzHmhLUW3autjJGfmwP4ltQ==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/addon-knobs/-/addon-knobs-5.1.11.tgz", + "integrity": "sha512-16GY8IPxVBcmq5TqPtP6254Qw5FvdefDZjIQd+ByJJliQjXZMQKxEl6JhRq98iUfSxEB+6JCPnpKPa666jmCMA==", "dev": true, "requires": { - "@storybook/addons": "5.1.10", - "@storybook/client-api": "5.1.10", - "@storybook/components": "5.1.10", - "@storybook/core-events": "5.1.10", - "@storybook/theming": "5.1.10", + "@storybook/addons": "5.1.11", + "@storybook/client-api": "5.1.11", + "@storybook/components": "5.1.11", + "@storybook/core-events": "5.1.11", + "@storybook/theming": "5.1.11", "copy-to-clipboard": "^3.0.8", "core-js": "^3.0.1", "escape-html": "^1.0.3", @@ -1535,14 +1535,14 @@ } }, "@storybook/addon-links": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-5.1.10.tgz", - "integrity": "sha512-LDDcIU4ae76063baWuoi7dWI8YeSCq595siUlxM+aNydxHsIdQhi7vH1GRJL1oqCvvYLykdopcjKofO5EiTVdw==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-5.1.11.tgz", + "integrity": "sha512-NV4gRduMNm0dchKCWAZ4YQSYOdj5acoztGIz3w+xs9e+MAXOHXs7iL8sBbqAFlfz4elPGHWW+8NGn9UYxQFK+Q==", "dev": true, "requires": { - "@storybook/addons": "5.1.10", - "@storybook/core-events": "5.1.10", - "@storybook/router": "5.1.10", + "@storybook/addons": "5.1.11", + "@storybook/core-events": "5.1.11", + "@storybook/router": "5.1.11", "common-tags": "^1.8.0", "core-js": "^3.0.1", "global": "^4.3.2", @@ -1559,30 +1559,30 @@ } }, "@storybook/addons": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-5.1.10.tgz", - "integrity": "sha512-M9b2PCp9RZxDC6wL7vVt2SCKCGXrrEAOsdpMvU569yB1zoUPEiiqElVDwb91O2eAGPnmd2yjImp90kOpKUW0EA==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-5.1.11.tgz", + "integrity": "sha512-714Xg6pX4rjDY1urL94w4oOxIiK6jCFSp4oKvqLj7dli5CG7d34Yt9joyTgOb2pkbrgmbMWAZJq0L0iOjHzpzw==", "dev": true, "requires": { - "@storybook/api": "5.1.10", - "@storybook/channels": "5.1.10", - "@storybook/client-logger": "5.1.10", + "@storybook/api": "5.1.11", + "@storybook/channels": "5.1.11", + "@storybook/client-logger": "5.1.11", "core-js": "^3.0.1", "global": "^4.3.2", "util-deprecate": "^1.0.2" } }, "@storybook/api": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/api/-/api-5.1.10.tgz", - "integrity": "sha512-YeZe/71zLMmgT95IMAEZOc9AwL6Y23mWvkZMwFbkokxS9+bU/qmVlQ0B9c3JBzO3OSs7sXaRqyP1o3QkQgVsiw==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-5.1.11.tgz", + "integrity": "sha512-zzPZM6W67D4YKCbUN4RhC/w+/CtnH/hFbSh/QUBdwXFB1aLh2qA1UTyB8i6m6OA6JgVHBqEkl10KhmeILLv/eA==", "dev": true, "requires": { - "@storybook/channels": "5.1.10", - "@storybook/client-logger": "5.1.10", - "@storybook/core-events": "5.1.10", - "@storybook/router": "5.1.10", - "@storybook/theming": "5.1.10", + "@storybook/channels": "5.1.11", + "@storybook/client-logger": "5.1.11", + "@storybook/core-events": "5.1.11", + "@storybook/router": "5.1.11", + "@storybook/theming": "5.1.11", "core-js": "^3.0.1", "fast-deep-equal": "^2.0.1", "global": "^4.3.2", @@ -1598,37 +1598,37 @@ } }, "@storybook/channel-postmessage": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-5.1.10.tgz", - "integrity": "sha512-kQZIwltN2cWDXluhCfdModFDK1LHV9ZhNQ1b/uD9vn1c65rQ9u7r4lRajCfS0X1dmAWqz48cBcEurAubNgmswg==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-5.1.11.tgz", + "integrity": "sha512-S7Uq7+c9kOJ9BB4H9Uro2+dVhqoMchYCipQzAkD4jIIwK99RNzGdAaRipDC1k0k/C+v2SOa+D5xBbb3XVYPSrg==", "dev": true, "requires": { - "@storybook/channels": "5.1.10", - "@storybook/client-logger": "5.1.10", + "@storybook/channels": "5.1.11", + "@storybook/client-logger": "5.1.11", "core-js": "^3.0.1", "global": "^4.3.2", "telejson": "^2.2.1" } }, "@storybook/channels": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-5.1.10.tgz", - "integrity": "sha512-w7n/bV1BLu51KI1eLc75lN9H1ssBc3PZMXk88GkMiKyBVRzPlJA5ixnzH86qwYGReE0dhRpsgHXZ5XmoKaVmPA==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-5.1.11.tgz", + "integrity": "sha512-MlrjVGNvYOnDvv2JDRhr4wikbnZ8HCFCpVsFqKPFxj7I3OYBR417RvFkydX3Rtx4kwB9rmZEgLhfAfsSytkALg==", "dev": true, "requires": { "core-js": "^3.0.1" } }, "@storybook/client-api": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-5.1.10.tgz", - "integrity": "sha512-v2PqiNUhwDlVDLYL94f6LFjdYMToTpuwWh9aeqzt/4PAJUnIcA+2P8+qXiYdJTqQy/u7P72HFMlc9Ru4tl3QFg==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-5.1.11.tgz", + "integrity": "sha512-znzSxZ1ZCqtEKrFoW7xT8iBbdiAXaQ8RNxQFKHuYPqWX+RLol6S3duEOxu491X2SzUg0StUmrX5qL9Rnth8dRQ==", "dev": true, "requires": { - "@storybook/addons": "5.1.10", - "@storybook/client-logger": "5.1.10", - "@storybook/core-events": "5.1.10", - "@storybook/router": "5.1.10", + "@storybook/addons": "5.1.11", + "@storybook/client-logger": "5.1.11", + "@storybook/core-events": "5.1.11", + "@storybook/router": "5.1.11", "common-tags": "^1.8.0", "core-js": "^3.0.1", "eventemitter3": "^3.1.0", @@ -1663,22 +1663,22 @@ } }, "@storybook/client-logger": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-5.1.10.tgz", - "integrity": "sha512-vB1NoFWRTgcERwodhbgoDwI00eqU8++nXI7GhMS1CY8haZaSp3gyKfHRWyfH+M+YjQuGBRUcvIk4gK6OtSrDOw==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-5.1.11.tgz", + "integrity": "sha512-je4To+9zD3SEJsKe9R4u15N4bdXFBR7pdBToaRIur+XSvvShLFehZGseQi+4uPAj8vyG34quGTCeUC/BKY0LwQ==", "dev": true, "requires": { "core-js": "^3.0.1" } }, "@storybook/components": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/components/-/components-5.1.10.tgz", - "integrity": "sha512-QUQeeQp1xNWiL4VlxFAea0kqn2zvBfmfPlUddOFO9lBhT6pVy0xYPjXjbTVWjVcYzZpyUNWw5GplqrR5jhlaCA==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-5.1.11.tgz", + "integrity": "sha512-EQgD7HL2CWnnY968KrwUSU2dtKFGTGRJVc4vwphYEeZwAI0lX6qbTMuwEP22hDZ2OSRBxcvcXT8cvduDlZlFng==", "dev": true, "requires": { - "@storybook/client-logger": "5.1.10", - "@storybook/theming": "5.1.10", + "@storybook/client-logger": "5.1.11", + "@storybook/theming": "5.1.11", "core-js": "^3.0.1", "global": "^4.3.2", "markdown-to-jsx": "^6.9.1", @@ -1698,9 +1698,9 @@ } }, "@storybook/core": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/core/-/core-5.1.10.tgz", - "integrity": "sha512-zkNjufOFrLpFpmr73F/gaJh0W0vWqXIo5zrKvQt1LqmMeCU/v8MstHi4XidlK43UpeogfaXl5tjNCQDO/bd0Dw==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-5.1.11.tgz", + "integrity": "sha512-LkSoAJlLEtrzFcoINX3dz4oT6xUPEHEp2/WAXLqUFeCnzJHAxIsRvbVxB49Kh/2TrgDFZpL9Or8XXMzZtE6KYw==", "dev": true, "requires": { "@babel/plugin-proposal-class-properties": "^7.3.3", @@ -1708,15 +1708,15 @@ "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-transform-react-constant-elements": "^7.2.0", "@babel/preset-env": "^7.4.5", - "@storybook/addons": "5.1.10", - "@storybook/channel-postmessage": "5.1.10", - "@storybook/client-api": "5.1.10", - "@storybook/client-logger": "5.1.10", - "@storybook/core-events": "5.1.10", - "@storybook/node-logger": "5.1.10", - "@storybook/router": "5.1.10", - "@storybook/theming": "5.1.10", - "@storybook/ui": "5.1.10", + "@storybook/addons": "5.1.11", + "@storybook/channel-postmessage": "5.1.11", + "@storybook/client-api": "5.1.11", + "@storybook/client-logger": "5.1.11", + "@storybook/core-events": "5.1.11", + "@storybook/node-logger": "5.1.11", + "@storybook/router": "5.1.11", + "@storybook/theming": "5.1.11", + "@storybook/ui": "5.1.11", "airbnb-js-shims": "^1 || ^2", "autoprefixer": "^9.4.9", "babel-plugin-add-react-displayname": "^0.0.5", @@ -1764,6 +1764,7 @@ "shelljs": "^0.8.3", "style-loader": "^0.23.1", "terser-webpack-plugin": "^1.2.4", + "unfetch": "^4.1.0", "url-loader": "^1.1.2", "util-deprecate": "^1.0.2", "webpack": "^4.33.0", @@ -1772,9 +1773,9 @@ }, "dependencies": { "acorn": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz", - "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", "dev": true }, "ajv": { @@ -1870,9 +1871,9 @@ } }, "graceful-fs": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz", - "integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", "dev": true }, "locate-path": { @@ -2113,9 +2114,9 @@ } }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -2127,9 +2128,9 @@ "dev": true }, "webpack": { - "version": "4.39.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.1.tgz", - "integrity": "sha512-/LAb2TJ2z+eVwisldp3dqTEoNhzp/TLCZlmZm3GGGAlnfIWDgOEE758j/9atklNLfRyhKbZTCOIoPqLJXeBLbQ==", + "version": "4.39.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.2.tgz", + "integrity": "sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", @@ -2170,18 +2171,18 @@ } }, "@storybook/core-events": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-5.1.10.tgz", - "integrity": "sha512-Lvu/rNcgS+XCkQKSGdNpUSWjpFF9AOSHPXsvkwHbRwJYdMDn3FznlXfDUiubOWtsziXHB6vl3wkKDlH+ckb32Q==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-5.1.11.tgz", + "integrity": "sha512-m+yIFRdB47+IPBFBGS2OUXrSLkoz5iAXvb3c0lGAePf5wSR+o/Ni/9VD5l6xBf+InxHLSc9gcDEJehrT0fJAaQ==", "dev": true, "requires": { "core-js": "^3.0.1" } }, "@storybook/node-logger": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-5.1.10.tgz", - "integrity": "sha512-Z4UKh7QBOboQhUF5S/dKOx3OWWCNZGwYu8HZa/O+P68+XnQDhuZCYwqWG49xFhZd0Jb0W9gdUL2mWJw5POG9PA==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-5.1.11.tgz", + "integrity": "sha512-LG0KM4lzb9LEffcO3Ps9FcHHsVgQUc/oG+kz3p0u9fljFoL3cJHF1Mb4o+HrSydtdWZs/spwZ/BLEo5n/AByDw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -2200,16 +2201,16 @@ } }, "@storybook/react": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-5.1.10.tgz", - "integrity": "sha512-wWy9l83KgbP8P2A8AbkwExEAdA0iznb4jEnCGzP1hAv8Q5LmL3MLPb1dIZqhWrg+E2m3tZei+7A7qu2Q8/cLLw==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-5.1.11.tgz", + "integrity": "sha512-y8/L2OWvev3fGREhAmToLVDPf8YEZMs5+vzSdzXlVlPkqHyAmWPtLY4sRB6K+TsEF0gwaC5F2BvMnKxbNYwd/Q==", "dev": true, "requires": { "@babel/plugin-transform-react-constant-elements": "^7.2.0", "@babel/preset-flow": "^7.0.0", "@babel/preset-react": "^7.0.0", - "@storybook/core": "5.1.10", - "@storybook/node-logger": "5.1.10", + "@storybook/core": "5.1.11", + "@storybook/node-logger": "5.1.11", "@svgr/webpack": "^4.0.3", "babel-plugin-add-react-displayname": "^0.0.5", "babel-plugin-named-asset-import": "^0.3.1", @@ -2228,9 +2229,9 @@ }, "dependencies": { "acorn": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz", - "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", "dev": true }, "ajv": { @@ -2400,9 +2401,9 @@ "dev": true }, "webpack": { - "version": "4.39.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.1.tgz", - "integrity": "sha512-/LAb2TJ2z+eVwisldp3dqTEoNhzp/TLCZlmZm3GGGAlnfIWDgOEE758j/9atklNLfRyhKbZTCOIoPqLJXeBLbQ==", + "version": "4.39.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.2.tgz", + "integrity": "sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", @@ -2445,9 +2446,9 @@ } }, "@storybook/router": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/router/-/router-5.1.10.tgz", - "integrity": "sha512-BdG6/essPZFHCP2ewCG0gYFQfmuuTSHXAB5fd/rwxLSYj1IzNznC5OxkvnSaTr4rgoxxaW/z1hbN1NuA0ivlFA==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-5.1.11.tgz", + "integrity": "sha512-Xt7R1IOWLlIxis6VKV9G8F+e/G4G8ng1zXCqoDq+/RlWzlQJ5ccO4bUm2/XGS1rEgY4agMzmzjum18HoATpLGA==", "dev": true, "requires": { "@reach/router": "^1.2.1", @@ -2466,14 +2467,14 @@ } }, "@storybook/theming": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-5.1.10.tgz", - "integrity": "sha512-5cN1lmdVUwAR8U3T49Lfb8JW5RBvxBSPGZpUmbLGz1zi0tWBJgYXoGtw4RbTBjV9kCQOXkHGH12AsdDxHh931w==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-5.1.11.tgz", + "integrity": "sha512-PtRPfiAWx5pQbTm45yyPB+CuW/vyDmcmNOt+xnDzK52omeWaSD7XK2RfadN3u4QXCgha7zs35Ppx1htJio2NRA==", "dev": true, "requires": { "@emotion/core": "^10.0.9", "@emotion/styled": "^10.0.7", - "@storybook/client-logger": "5.1.10", + "@storybook/client-logger": "5.1.11", "common-tags": "^1.8.0", "core-js": "^3.0.1", "deep-object-diff": "^1.1.0", @@ -2494,19 +2495,19 @@ } }, "@storybook/ui": { - "version": "5.1.10", - "resolved": "https://registry.npmjs.org/@storybook/ui/-/ui-5.1.10.tgz", - "integrity": "sha512-ezkoVtzoKh93z2wzkqVIqyrIzTkj8tizgAkoPa7mUAbLCxu6LErHITODQoyEiJWI4Epy3yU9GYXFWwT71hdwsA==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@storybook/ui/-/ui-5.1.11.tgz", + "integrity": "sha512-mopuFSwtodvH4HRdaSBlgYxzYca1qyvzZ0BxOPocXhiFfFR+V9NyNJqKKRA3vinWuuZWpYcnPTu3h8skmjMirg==", "dev": true, "requires": { - "@storybook/addons": "5.1.10", - "@storybook/api": "5.1.10", - "@storybook/channels": "5.1.10", - "@storybook/client-logger": "5.1.10", - "@storybook/components": "5.1.10", - "@storybook/core-events": "5.1.10", - "@storybook/router": "5.1.10", - "@storybook/theming": "5.1.10", + "@storybook/addons": "5.1.11", + "@storybook/api": "5.1.11", + "@storybook/channels": "5.1.11", + "@storybook/client-logger": "5.1.11", + "@storybook/components": "5.1.11", + "@storybook/core-events": "5.1.11", + "@storybook/router": "5.1.11", + "@storybook/theming": "5.1.11", "copy-to-clipboard": "^3.0.8", "core-js": "^3.0.1", "core-js-pure": "^3.0.1", @@ -2756,9 +2757,9 @@ } }, "@types/node": { - "version": "12.7.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz", - "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==" + "version": "12.7.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz", + "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==" }, "@types/prop-types": { "version": "15.7.1", @@ -2772,9 +2773,9 @@ "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==" }, "@types/react": { - "version": "16.9.1", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.1.tgz", - "integrity": "sha512-jGM2x8F7m7/r+81N/BOaUKVwbC5Cdw6ExlWEUpr77XPwVeNvAppnPEnMMLMfxRDYL8FPEX8MHjwtD2NQMJ0yyQ==", + "version": "16.9.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.2.tgz", + "integrity": "sha512-jYP2LWwlh+FTqGd9v7ynUKZzjj98T8x7Yclz479QdRhHfuW9yQ+0jjnD31eXSXutmBpppj5PYNLYLRfnZJvcfg==", "dev": true, "requires": { "@types/prop-types": "*", @@ -3345,6 +3346,21 @@ "tslib": "^1.9.3" } }, + "apollo-storybook-core": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/apollo-storybook-core/-/apollo-storybook-core-0.5.2.tgz", + "integrity": "sha512-8CbKUbRMIxGnz5Ci1jx7dOSDmCcktykfID96wji+E/vFVzE+dvGunuvEJexiVjCOebXJinXe6dqWJZuETot+Sw==", + "dev": true + }, + "apollo-storybook-react": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/apollo-storybook-react/-/apollo-storybook-react-0.2.1.tgz", + "integrity": "sha512-xERyr0EQbiUOBLE3pLRuM27T4Fsh2dVIV8yRy0VZ3eIAsXQrcuxTuM4d5kV+UiYqBNgH9M14+C6OuF9DNMilRw==", + "dev": true, + "requires": { + "apollo-storybook-core": "^0.5.2" + } + }, "apollo-utilities": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.2.tgz", @@ -3797,9 +3813,9 @@ } }, "babel-plugin-emotion": { - "version": "10.0.15", - "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.0.15.tgz", - "integrity": "sha512-E3W68Zk8EcKpRUDW2tsFKi4gsavapMRjfr2/KKgG3l7l2zZpiKk0BxB59Ul9C0w0ekv6my/ylGOk2WroaqKXPw==", + "version": "10.0.16", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.0.16.tgz", + "integrity": "sha512-a01Xrourr/VRpw4KicX9drDwfVGHmw8HmlQk++N4fv0j73EfHKWC1Ah4Vu8s1cTGVvTiwum+UhVpJenV8j03FQ==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", @@ -3868,15 +3884,15 @@ } }, "babel-plugin-minify-dead-code-elimination": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.0.tgz", - "integrity": "sha512-XQteBGXlgEoAKc/BhO6oafUdT4LBa7ARi55mxoyhLHNuA+RlzRmeMAfc31pb/UqU01wBzRc36YqHQzopnkd/6Q==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz", + "integrity": "sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==", "dev": true, "requires": { "babel-helper-evaluate-path": "^0.5.0", "babel-helper-mark-eval-scopes": "^0.4.3", "babel-helper-remove-or-void": "^0.4.3", - "lodash.some": "^4.6.0" + "lodash": "^4.17.11" } }, "babel-plugin-minify-flip-comparisons": { @@ -3889,11 +3905,12 @@ } }, "babel-plugin-minify-guarded-expressions": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.3.tgz", - "integrity": "sha1-zHCbRFP9IbHzAod0RMifiEJ845c=", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz", + "integrity": "sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==", "dev": true, "requires": { + "babel-helper-evaluate-path": "^0.5.0", "babel-helper-flip-expressions": "^0.4.3" } }, @@ -3925,11 +3942,12 @@ "dev": true }, "babel-plugin-minify-simplify": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.0.tgz", - "integrity": "sha512-TM01J/YcKZ8XIQd1Z3nF2AdWHoDsarjtZ5fWPDksYZNsoOjQ2UO2EWm824Ym6sp127m44gPlLFiO5KFxU8pA5Q==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz", + "integrity": "sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==", "dev": true, "requires": { + "babel-helper-evaluate-path": "^0.5.0", "babel-helper-flip-expressions": "^0.4.3", "babel-helper-is-nodes-equiv": "^0.0.1", "babel-helper-to-multiple-sequence-expressions": "^0.5.0" @@ -4067,21 +4085,21 @@ } }, "babel-preset-minify": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.0.tgz", - "integrity": "sha512-xj1s9Mon+RFubH569vrGCayA9Fm2GMsCgDRm1Jb8SgctOB7KFcrVc2o8K3YHUyMz+SWP8aea75BoS8YfsXXuiA==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz", + "integrity": "sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==", "dev": true, "requires": { "babel-plugin-minify-builtins": "^0.5.0", "babel-plugin-minify-constant-folding": "^0.5.0", - "babel-plugin-minify-dead-code-elimination": "^0.5.0", + "babel-plugin-minify-dead-code-elimination": "^0.5.1", "babel-plugin-minify-flip-comparisons": "^0.4.3", - "babel-plugin-minify-guarded-expressions": "^0.4.3", + "babel-plugin-minify-guarded-expressions": "^0.4.4", "babel-plugin-minify-infinity": "^0.4.3", "babel-plugin-minify-mangle-names": "^0.5.0", "babel-plugin-minify-numeric-literals": "^0.4.3", "babel-plugin-minify-replace": "^0.5.0", - "babel-plugin-minify-simplify": "^0.5.0", + "babel-plugin-minify-simplify": "^0.5.1", "babel-plugin-minify-type-constructors": "^0.4.3", "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", "babel-plugin-transform-member-expression-literals": "^6.9.4", @@ -4094,7 +4112,7 @@ "babel-plugin-transform-remove-undefined": "^0.5.0", "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", "babel-plugin-transform-undefined-to-void": "^6.9.4", - "lodash.isplainobject": "^4.0.6" + "lodash": "^4.17.11" } }, "babel-preset-react-app": { @@ -5763,9 +5781,9 @@ }, "dependencies": { "acorn": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz", - "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", "dev": true }, "ajv": { @@ -5899,9 +5917,9 @@ "dev": true }, "webpack": { - "version": "4.39.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.1.tgz", - "integrity": "sha512-/LAb2TJ2z+eVwisldp3dqTEoNhzp/TLCZlmZm3GGGAlnfIWDgOEE758j/9atklNLfRyhKbZTCOIoPqLJXeBLbQ==", + "version": "4.39.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.2.tgz", + "integrity": "sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", @@ -6309,9 +6327,9 @@ } }, "csstype": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.5.tgz", - "integrity": "sha512-JsTaiksRsel5n7XwqPAfB0l3TFKdpjW/kgAELf9vrb5adGA7UCPLajKK5s3nFrcFm3Rkyp/Qkgl73ENc1UY3cA==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.6.tgz", + "integrity": "sha512-RpFbQGUE74iyPgvr46U9t1xoQBM8T4BL8SxrN66Le2xYAPSaDJJKeztV3awugusb3g3G9iL8StmkBBXhcbbXhg==", "dev": true }, "currently-unhandled": { @@ -10622,9 +10640,9 @@ } }, "core-js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.0.tgz", - "integrity": "sha512-gybgLzmr7SQRSF6UzGYXducx4eE10ONQlyEnQoqiGPbmbn7zLkb73tPfc4YbZN0lvcTQwoLNPjq4RuCaCumGyQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", + "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", "dev": true }, "dotenv": { @@ -10789,23 +10807,11 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true - }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" }, - "lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", - "dev": true - }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -13758,9 +13764,9 @@ } }, "react-draggable": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-3.3.0.tgz", - "integrity": "sha512-U7/jD0tAW4T0S7DCPK0kkKLyL0z61sC/eqU+NUfDjnq+JtBKaYKDHpsK2wazctiA4alEzCXUnzkREoxppOySVw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-3.3.1.tgz", + "integrity": "sha512-JeKyuO5f1jnVwMHdNkFpmaQoYn/6CyIiCDGSKbTgRisEtekjeUCeKmlNaNTLlpKOEu0SaKcBA1HlypSqWN/8Tw==", "dev": true, "requires": { "classnames": "^2.2.5", @@ -13860,13 +13866,13 @@ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "react-popper": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.3.tgz", - "integrity": "sha512-ynMZBPkXONPc5K4P5yFWgZx5JGAUIP3pGGLNs58cfAPgK67olx7fmLp+AdpZ0+GoQ+ieFDa/z4cdV6u7sioH6w==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.4.tgz", + "integrity": "sha512-9AcQB29V+WrBKk6X7p0eojd1f25/oJajVdMZkywIoAV6Ag7hzE1Mhyeup2Q1QnvFRtGQFQvtqfhlEoDAPfKAVA==", "dev": true, "requires": { "@babel/runtime": "^7.1.2", - "create-react-context": "<=0.2.2", + "create-react-context": "^0.3.0", "popper.js": "^1.14.4", "prop-types": "^15.6.1", "typed-styles": "^0.0.7", @@ -13874,13 +13880,13 @@ }, "dependencies": { "create-react-context": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.2.tgz", - "integrity": "sha512-KkpaLARMhsTsgp0d2NA/R94F/eDLbhXERdIq3LvX2biCAXcDvHYoOqHfWCHf1+OLj+HKBotLG3KqaOOf+C1C+A==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz", + "integrity": "sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==", "dev": true, "requires": { - "fbjs": "^0.8.0", - "gud": "^1.0.0" + "gud": "^1.0.0", + "warning": "^4.0.3" } }, "warning": { @@ -16472,6 +16478,12 @@ } } }, + "unfetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.1.0.tgz", + "integrity": "sha512-crP/n3eAPUJxZXM9T80/yv0YhkTEx2K1D3h7D1AJM6fzsWZrxdyRuLN0JH/dkZh1LNH8LxCnBzoPFCPbb2iGpg==", + "dev": true + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", diff --git a/web-app/package.json b/web-app/package.json index a0225a09..9b26c66f 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -3,8 +3,8 @@ "version": "0.1.0", "private": true, "dependencies": { - "@alifd/next": "^1.16.6", - "@apollo/react-hooks": "^3.0.0", + "@alifd/next": "^1.16.7", + "@apollo/react-hooks": "^3.0.1", "apollo-boost": "^0.4.4", "graphql": "^14.4.2", "markdown-it": "^9.1.0", @@ -41,18 +41,19 @@ }, "devDependencies": { "@babel/core": "^7.5.4", - "@storybook/addon-actions": "^5.1.10", - "@storybook/addon-knobs": "^5.1.10", - "@storybook/addon-links": "^5.1.10", - "@storybook/addons": "^5.1.10", - "@storybook/react": "^5.1.10", + "@storybook/addon-actions": "^5.1.11", + "@storybook/addon-knobs": "^5.1.11", + "@storybook/addon-links": "^5.1.11", + "@storybook/addons": "^5.1.11", + "@storybook/react": "^5.1.11", "@types/highlight.js": "^9.12.3", "@types/jest": "^24.0.17", "@types/markdown-it": "0.0.8", - "@types/node": "^12.7.1", - "@types/react": "^16.9.1", + "@types/node": "^12.7.2", + "@types/react": "^16.9.2", "@types/react-dom": "^16.8.5", "@types/storybook__react": "^4.0.2", + "apollo-storybook-react": "^0.2.1", "babel-loader": "^8.0.5", "babel-plugin-import": "^1.12.0", "node-sass": "^4.12.0", From a591a2d4d7815abbad1a35d7a661fef0e59e4bba Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 17 Aug 2019 17:00:10 -0700 Subject: [PATCH 005/117] sort-package-json --- package-lock.json | 17 ++++++- package.json | 77 ++++++++++++++++---------------- web-app/package-lock.json | 93 +++++++++++++++++++++++++++++++++++++++ web-app/package.json | 41 +++++++++-------- 4 files changed, 168 insertions(+), 60 deletions(-) diff --git a/package-lock.json b/package-lock.json index 02fc807b..81ee6636 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz", "integrity": "sha512-ftQl3DtBvqHl9L16tpqqzA4YzCSXZfi7g8cQceTz5rOlYtk/IZbFjAv3mLOQlNIgOaylCQWQoBdDQHPgEBJPHg==", + "dev": true, "requires": { "@types/node": "*" } @@ -41,7 +42,8 @@ "@types/node": { "version": "12.7.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz", - "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==" + "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==", + "dev": true }, "agent-base": { "version": "4.3.0", @@ -493,6 +495,14 @@ "path-is-absolute": "^1.0.0" } }, + "graphql": { + "version": "14.4.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.4.2.tgz", + "integrity": "sha512-6uQadiRgnpnSS56hdZUSvFrVcQ6OF9y6wkxJfKquFtHlnl7+KSuWwSJsdwiK1vybm1HgcdbpGkCpvhvsVQ0UZQ==", + "requires": { + "iterall": "^1.2.2" + } + }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -618,6 +628,11 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, + "iterall": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", + "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/package.json b/package.json index dc74208e..f574e4ee 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,8 @@ { "name": "coderoad-vscode", - "displayName": "CodeRoad", - "description": "Interactive tutorials in your editor", "version": "0.0.1", - "engines": { - "vscode": "^1.34.0" - }, - "categories": [ - "Other" - ], - "publisher": "Shawn McKay", - "author": { - "name": "Shawn McKay " - }, + "description": "Interactive tutorials in your editor", + "homepage": "https://github.com/shmck/coderoad-vscode/README.md", "bugs": { "url": "https://github.com/shmck/coderoad-vscode/issues", "email": "shawn.j.mckay@gmail.com" @@ -21,35 +11,29 @@ "type": "git", "url": "https://github.com/shmck/coderoad-vscode.git" }, - "homepage": "https://github.com/shmck/coderoad-vscode/README.md", - "galleryBanner": { - "color": "#C80000", - "theme": "dark" + "license": "SEE LICENSE IN LICENSE.md", + "author": { + "name": "Shawn McKay " }, - "activationEvents": [ - "onCommand:coderoad.start" - ], "main": "./build/extension.js", - "contributes": { - "commands": [ - { - "command": "coderoad.start", - "title": "Start", - "category": "CodeRoad" - } - ] - }, "scripts": { - "vscode:prepublish": "npm run build", - "machine": "node ./out/state/index.js", "build": "rm -rf build && concurrently \"npm run build:ext\" \"npm run build:web\"", "build:ext": "npm run compile", "build:web": "cd web-app && npm run build", "compile": "tsc -p ./", - "watch": "tsc -watch -p ./", "postinstall": "node ./node_modules/vscode/bin/install", + "machine": "node ./out/state/index.js", "storybook": "cd web-app && npm run storybook", - "test": "npm run build && node ./node_modules/vscode/bin/test" + "test": "npm run build && node ./node_modules/vscode/bin/test", + "vscode:prepublish": "npm run build", + "watch": "tsc -watch -p ./" + }, + "dependencies": { + "axios": "^0.19.0", + "dotenv": "^8.0.0", + "graphql": "^14.4.2", + "vscode": "^1.1.36", + "xstate": "^4.6.7" }, "devDependencies": { "@types/dotenv": "^6.1.1", @@ -61,11 +45,28 @@ "tslint-config-prettier": "^1.18.0", "typescript": "^3.5.3" }, - "dependencies": { - "axios": "^0.19.0", - "dotenv": "^8.0.0", - "vscode": "^1.1.36", - "xstate": "^4.6.7" + "engines": { + "vscode": "^1.34.0" + }, + "activationEvents": [ + "onCommand:coderoad.start" + ], + "categories": [ + "Other" + ], + "contributes": { + "commands": [ + { + "command": "coderoad.start", + "title": "Start", + "category": "CodeRoad" + } + ] + }, + "displayName": "CodeRoad", + "galleryBanner": { + "color": "#C80000", + "theme": "dark" }, - "license": "SEE LICENSE IN LICENSE.md" + "publisher": "Shawn McKay" } diff --git a/web-app/package-lock.json b/web-app/package-lock.json index f15e6859..f65e1a8b 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -41,6 +41,48 @@ } } }, + "@apollo/react-components": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@apollo/react-components/-/react-components-3.0.1.tgz", + "integrity": "sha512-IQwcwv+ItW/QHUeO2zQH+CJGnqepPwwShD9H6+v1ptLvixggodr7S4KalNKXgRUVJsoPBFiVgpTMoJe3h4+Eyg==", + "dev": true, + "requires": { + "@apollo/react-common": "^3.0.1", + "@apollo/react-hooks": "^3.0.1", + "prop-types": "^15.7.2", + "ts-invariant": "^0.4.4", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + } + } + }, + "@apollo/react-hoc": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@apollo/react-hoc/-/react-hoc-3.0.1.tgz", + "integrity": "sha512-sKt0/xjr6jknJztJRWA0zX9wUY/xBq6lwyqPxrRM72hCatz/BSi1tgVv9LMHTA0aJPBK79pWXFq/EeiXW2LkVw==", + "dev": true, + "requires": { + "@apollo/react-common": "^3.0.1", + "@apollo/react-components": "^3.0.1", + "hoist-non-react-statics": "^3.3.0", + "ts-invariant": "^0.4.4", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + } + } + }, "@apollo/react-hooks": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@apollo/react-hooks/-/react-hooks-3.0.1.tgz", @@ -59,6 +101,25 @@ } } }, + "@apollo/react-ssr": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@apollo/react-ssr/-/react-ssr-3.0.1.tgz", + "integrity": "sha512-eeAaajIH1zbMk+zigNAlEeyVH80ELrsjvRCcQxH80+THgnJx/hgkKfmhG2p1q2Djefyv6VfImAwd4xqX6/LRSA==", + "dev": true, + "requires": { + "@apollo/react-common": "^3.0.1", + "@apollo/react-hooks": "^3.0.1", + "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + } + } + }, "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", @@ -6535,6 +6596,12 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, + "deprecated-decorator": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz", + "integrity": "sha1-AJZjF7ehL+kvPMgx91g68ym4bDc=", + "dev": true + }, "des.js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", @@ -8381,6 +8448,19 @@ "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==" }, + "graphql-tools": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-4.0.5.tgz", + "integrity": "sha512-kQCh3IZsMqquDx7zfIGWBau42xe46gmqabwYkpPlCLIjcEY1XK+auP7iGRD9/205BPyoQdY8hT96MPpgERdC9Q==", + "dev": true, + "requires": { + "apollo-link": "^1.2.3", + "apollo-utilities": "^1.0.1", + "deprecated-decorator": "^0.1.6", + "iterall": "^1.1.3", + "uuid": "^3.1.0" + } + }, "growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", @@ -13589,6 +13669,19 @@ "prop-types": "^15.6.2" } }, + "react-apollo": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/react-apollo/-/react-apollo-3.0.1.tgz", + "integrity": "sha512-2hsSYBfxPqPquS8CupWq+U+6XuDfr/Rr1ssXwfOTYe5gCyTthdUqafIm+pyStur9X2W4ZNQMFyjVicsPNq2tnA==", + "dev": true, + "requires": { + "@apollo/react-common": "^3.0.1", + "@apollo/react-components": "^3.0.1", + "@apollo/react-hoc": "^3.0.1", + "@apollo/react-hooks": "^3.0.1", + "@apollo/react-ssr": "^3.0.1" + } + }, "react-app-polyfill": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.1.tgz", diff --git a/web-app/package.json b/web-app/package.json index 9b26c66f..f78f431c 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -2,30 +2,13 @@ "name": "coderoad-app", "version": "0.1.0", "private": true, - "dependencies": { - "@alifd/next": "^1.16.7", - "@apollo/react-hooks": "^3.0.1", - "apollo-boost": "^0.4.4", - "graphql": "^14.4.2", - "markdown-it": "^9.1.0", - "markdown-it-emoji": "^1.4.0", - "markdown-it-prism": "^2.0.2", - "moment": "^2.24.0", - "react": "^16.9.0", - "react-dom": "^16.9.0", - "react-scripts": "3.0.1", - "typescript": "^3.5.3" - }, "scripts": { - "start": "react-scripts start", "build": "react-scripts build", "postbuild": "cp -R ./build/ ../build/ && cp public/webpackBuild.js ../build/webpackBuild.js", - "test": "react-scripts test", + "build-storybook": "build-storybook", + "start": "react-scripts start", "storybook": "start-storybook -p 6006", - "build-storybook": "build-storybook" - }, - "eslintConfig": { - "extends": "react-app" + "test": "react-scripts test" }, "browserslist": { "production": [ @@ -39,6 +22,23 @@ "last 1 safari version" ] }, + "eslintConfig": { + "extends": "react-app" + }, + "dependencies": { + "@alifd/next": "^1.16.7", + "@apollo/react-hooks": "^3.0.1", + "apollo-boost": "^0.4.4", + "graphql": "^14.4.2", + "markdown-it": "^9.1.0", + "markdown-it-emoji": "^1.4.0", + "markdown-it-prism": "^2.0.2", + "moment": "^2.24.0", + "react": "^16.9.0", + "react-dom": "^16.9.0", + "react-scripts": "3.0.1", + "typescript": "^3.5.3" + }, "devDependencies": { "@babel/core": "^7.5.4", "@storybook/addon-actions": "^5.1.11", @@ -53,7 +53,6 @@ "@types/react": "^16.9.2", "@types/react-dom": "^16.8.5", "@types/storybook__react": "^4.0.2", - "apollo-storybook-react": "^0.2.1", "babel-loader": "^8.0.5", "babel-plugin-import": "^1.12.0", "node-sass": "^4.12.0", From 5a060fdd6c5f739480b33addcfc169a9d5adcf8b Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 17 Aug 2019 17:00:35 -0700 Subject: [PATCH 006/117] migrate codegen graphql typings --- typings/graphql.d.ts | 202 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 typings/graphql.d.ts diff --git a/typings/graphql.d.ts b/typings/graphql.d.ts new file mode 100644 index 00000000..ac8d5d9b --- /dev/null +++ b/typings/graphql.d.ts @@ -0,0 +1,202 @@ +import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; +export type Maybe = T | null; +export type RequireFields = { [X in Exclude]?: T[X] } & { [P in K]-?: NonNullable }; +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: string, + String: string, + Boolean: boolean, + Int: number, + Float: number, + /** + * A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the + * `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO + * 8601 standard for representation of dates and times using the Gregorian calendar. + **/ + DateTime: any, + /** Git commit hash */ + Commit: any, + /** The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */ + JSON: any, + /** The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */ + JSONObject: any, + /** The `Upload` scalar type represents a file upload. */ + Upload: any, +}; + + + +export type AuthenticateUserPayload = { + __typename?: 'AuthenticateUserPayload', + user: User, + token: Scalars['String'], +}; + +export enum CacheControlScope { + Public = 'PUBLIC', + Private = 'PRIVATE' +} + + + +export enum EnumCodingLanguage { + Javascript = 'JAVASCRIPT' +} + +export enum EnumTestRunner { + Jest = 'JEST' +} + +export type GithubUser = { + __typename?: 'GithubUser', + id: Scalars['ID'], + name?: Maybe, + email?: Maybe, + location?: Maybe, + avatarUrl?: Maybe, +}; + + + +export type Level = { + __typename?: 'Level', + id: Scalars['ID'], + title?: Maybe, + text?: Maybe, + stages?: Maybe>>, + setup?: Maybe, +}; + +export type Mutation = { + __typename?: 'Mutation', + authenticate?: Maybe, +}; + + +export type MutationAuthenticateArgs = { + accessToken: Scalars['String'] +}; + +export type Query = { + __typename?: 'Query', + tutorial?: Maybe, + tutorials?: Maybe>>, + user?: Maybe, + level?: Maybe, + stage?: Maybe, + step?: Maybe, + stepActions?: Maybe, +}; + + +export type QueryTutorialArgs = { + id: Scalars['ID'] +}; + + +export type QueryLevelArgs = { + id: Scalars['ID'] +}; + + +export type QueryStageArgs = { + id: Scalars['ID'] +}; + + +export type QueryStepArgs = { + id: Scalars['ID'] +}; + + +export type QueryStepActionsArgs = { + id: Scalars['ID'] +}; + +export enum Role { + Admin = 'ADMIN', + User = 'USER' +} + +export type Stage = { + __typename?: 'Stage', + id: Scalars['ID'], + title?: Maybe, + text?: Maybe, + steps?: Maybe>>, + setup?: Maybe, +}; + +export type Step = { + __typename?: 'Step', + id: Scalars['ID'], + title?: Maybe, + text?: Maybe, + setup?: Maybe, + solution?: Maybe, +}; + +export type StepActions = { + __typename?: 'StepActions', + id: Scalars['ID'], + commits?: Maybe>>, + files?: Maybe>>, + commands?: Maybe>>, +}; + +export type Tutorial = { + __typename?: 'Tutorial', + id: Scalars['ID'], + repo?: Maybe, + createdBy?: Maybe, + createdAt?: Maybe, + updatedBy?: Maybe, + updatedAt?: Maybe, + codingLanguage?: Maybe, + testRunner?: Maybe, + title?: Maybe, + text?: Maybe, + releasedAt?: Maybe, + releasedBy?: Maybe, + latestVersion?: Maybe, + versions?: Maybe>>, +}; + +export type TutorialRepo = { + __typename?: 'TutorialRepo', + tutorialId: Scalars['ID'], + uri?: Maybe, + branch?: Maybe, + name?: Maybe, + owner?: Maybe, +}; + +export type TutorialVersion = { + __typename?: 'TutorialVersion', + tutorialId: Scalars['ID'], + version: Scalars['String'], + coderoadVersion?: Maybe, + createdAt?: Maybe, + createdBy?: Maybe, + publishedAt?: Maybe, + publishedBy?: Maybe, + levels?: Maybe>>, +}; + + +export type User = { + __typename?: 'User', + id: Scalars['ID'], + name?: Maybe, + email?: Maybe, + location?: Maybe, + avatarUrl?: Maybe, + createdAt?: Maybe, + updatedAt?: Maybe, + githubUser?: Maybe, +}; +export type TutorialSummaryFragment = ( + { __typename?: 'Tutorial' } + & Pick +); + From f3f9765dbfc129d1c48ec134cc8388c3fc5bb8de Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 17 Aug 2019 17:00:48 -0700 Subject: [PATCH 007/117] cleanup routes --- web-app/src/Routes.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 7238d629..fdded7cb 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -45,7 +45,10 @@ const Routes = ({ state }: Props) => { - + + + + From 2d84fa8e4bb96fc9d56dfb82b3a81762c04d1eee Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 17 Aug 2019 19:35:24 -0700 Subject: [PATCH 008/117] setup apollo decorator --- web-app/stories/utils/ApolloDecorator.tsx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 web-app/stories/utils/ApolloDecorator.tsx diff --git a/web-app/stories/utils/ApolloDecorator.tsx b/web-app/stories/utils/ApolloDecorator.tsx new file mode 100644 index 00000000..3d70710b --- /dev/null +++ b/web-app/stories/utils/ApolloDecorator.tsx @@ -0,0 +1,22 @@ +import React, { Fragment } from 'react' +import ApolloClient from 'apollo-boost' +import { ApolloProvider } from '@apollo/react-hooks' + +const graphqlClient = new ApolloClient({ + uri: 'http://localhost:4000/graphql', + headers: { + Authorization: process.env.GQL_AUTH_TOKEN, + }, +}) + +function StorybookProvider({ children }) { + return ( + + {children} + + ) +} + +export default story => { + return {story()} +} From 1114d13641d97e0abb4724b6c099f5f6c4f738c7 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 17 Aug 2019 19:35:52 -0700 Subject: [PATCH 009/117] new queryTutorials loaded --- .../components/TutorialList/TutorialItem.tsx | 18 ++++++++ web-app/src/components/TutorialList/index.tsx | 24 ++++++++++ web-app/src/containers/New/index.tsx | 44 ++++++------------- .../New/{query.ts => queryTutorials.ts} | 0 web-app/stories/New.stories.tsx | 36 +++++++++++++-- 5 files changed, 88 insertions(+), 34 deletions(-) create mode 100644 web-app/src/components/TutorialList/TutorialItem.tsx create mode 100644 web-app/src/components/TutorialList/index.tsx rename web-app/src/containers/New/{query.ts => queryTutorials.ts} (100%) diff --git a/web-app/src/components/TutorialList/TutorialItem.tsx b/web-app/src/components/TutorialList/TutorialItem.tsx new file mode 100644 index 00000000..71a3e0bb --- /dev/null +++ b/web-app/src/components/TutorialList/TutorialItem.tsx @@ -0,0 +1,18 @@ +import * as React from 'react' +import { Button } from '@alifd/next' + +interface Props { + title?: string + text?: string + onNew(): void +} + +const TutorialItem = (props: Props) => ( +
+

{props.title || 'Title'}

+

{props.text || 'Description'}

+ +
+) + +export default TutorialItem diff --git a/web-app/src/components/TutorialList/index.tsx b/web-app/src/components/TutorialList/index.tsx new file mode 100644 index 00000000..abd775e7 --- /dev/null +++ b/web-app/src/components/TutorialList/index.tsx @@ -0,0 +1,24 @@ +import * as React from 'react' + +import * as T from '../../../../typings/graphql' +import TutorialItem from './TutorialItem' + +interface Props { + tutorialList: T.Tutorial[] + onNew(id: string): void +} + +const TutorialList = (props: Props) => ( +
+ {props.tutorialList.map((tutorial: T.Tutorial) => ( + props.onNew(tutorial.id)} + title={tutorial.title} + text={tutorial.text} + /> + ))} +
+) + +export default TutorialList diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index fc4be722..3e11afc0 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -1,53 +1,35 @@ import * as React from 'react' -import { Button } from '@alifd/next' - -import Cond from '../../components/Cond' -import DataContext from '../../utils/DataContext' -import { send } from '../../utils/vscode' import { useQuery } from '@apollo/react-hooks' -import query from './query' +import * as T from '../../../../typings/graphql' -import LoadingPage from '../../containers/LoadingPage' +import queryTutorials from './queryTutorials' +import { send } from '../../utils/vscode' +import TutorialList from '../../components/TutorialList' interface Props { - state: any - tutorialList: any[] + tutorialList: T.Tutorial[] onNew(tutorialId: string): void } export const NewPage = (props: Props) => (
- -
-

Start a new Project

- {props.tutorialList.map(tutorial => ( -
-

{tutorial.title}

-

{tutorial.description}

- -
- ))} -
-
- - - +

Start a new Project

+
) -export default () => { - console.log('load new') - const { state } = React.useContext(DataContext) - const { data, loading, error } = useQuery(query) - const [tutorialList] = React.useState([{ id: '1', title: 'Demo', description: 'A basic demo' }]) +const NewPageContainer = () => { + const { data, loading, error } = useQuery(queryTutorials) console.log('data', data) if (loading) { return null } if (error) { - return
'Error'
+ return
{JSON.stringify(error, null, 2)}
} - return send('TUTORIAL_START')} state={state} tutorialList={tutorialList} /> + return send('TUTORIAL_START')} tutorialList={data.tutorials} /> } + +export default NewPageContainer diff --git a/web-app/src/containers/New/query.ts b/web-app/src/containers/New/queryTutorials.ts similarity index 100% rename from web-app/src/containers/New/query.ts rename to web-app/src/containers/New/queryTutorials.ts diff --git a/web-app/stories/New.stories.tsx b/web-app/stories/New.stories.tsx index f82ef46e..dfa2fd34 100644 --- a/web-app/stories/New.stories.tsx +++ b/web-app/stories/New.stories.tsx @@ -1,8 +1,38 @@ import React from 'react' - import { storiesOf } from '@storybook/react' import { action } from '@storybook/addon-actions' +import * as T from '../../typings/graphql' +import apolloProvider from './utils/ApolloDecorator' -import { NewPage } from '../src/containers/New' +import TutorialList from '../src/components/TutorialList' +import TutorialItem from '../src/components/TutorialList/TutorialItem' +import NewContainer from '../src/containers/New' -storiesOf('New', module).add('Page', () => ) +storiesOf('New', module) + .add('Tutorial', () => { + const tutorial: T.Tutorial = { + id: '1', + title: 'Tutorial 1', + text: 'The first one', + } + return + }) + .add('TutorialList', () => { + const tutorialList: T.Tutorial[] = [ + { + id: '1', + title: 'Tutorial 1', + text: 'The first one', + }, + { + id: '2', + title: 'Tutorial 2', + text: 'The second one', + }, + ] + return + }) + .addDecorator(apolloProvider) + .add('Container', () => { + return + }) From 4b1d714e7cc66c36fcc2ac8e5fe4fa821d9e21aa Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 17 Aug 2019 20:42:33 -0700 Subject: [PATCH 010/117] migrate latestVersion to version --- src/services/api/gql/query/tutorial.gql | 2 +- typings/graphql.d.ts | 2 +- web-app/src/containers/Continue/tutorial.gql | 2 +- web-app/src/containers/New/queryTutorials.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/api/gql/query/tutorial.gql b/src/services/api/gql/query/tutorial.gql index 9397a9c6..1f998568 100644 --- a/src/services/api/gql/query/tutorial.gql +++ b/src/services/api/gql/query/tutorial.gql @@ -7,7 +7,7 @@ query getTutorial($tutorialId: ID!) { uri branch } - latestVersion { + version { version coderoadVersion data diff --git a/typings/graphql.d.ts b/typings/graphql.d.ts index ac8d5d9b..0d764a0e 100644 --- a/typings/graphql.d.ts +++ b/typings/graphql.d.ts @@ -158,7 +158,7 @@ export type Tutorial = { text?: Maybe, releasedAt?: Maybe, releasedBy?: Maybe, - latestVersion?: Maybe, + version?: Maybe, versions?: Maybe>>, }; diff --git a/web-app/src/containers/Continue/tutorial.gql b/web-app/src/containers/Continue/tutorial.gql index cbd8b82f..3160c520 100644 --- a/web-app/src/containers/Continue/tutorial.gql +++ b/web-app/src/containers/Continue/tutorial.gql @@ -15,7 +15,7 @@ query getTutorial($tutorialId: ID!) { owner name } - latestVersion { + version { version coderoadVersion data diff --git a/web-app/src/containers/New/queryTutorials.ts b/web-app/src/containers/New/queryTutorials.ts index 49d2a643..e7ed5001 100644 --- a/web-app/src/containers/New/queryTutorials.ts +++ b/web-app/src/containers/New/queryTutorials.ts @@ -7,7 +7,7 @@ export default gql` title text codingLanguage - latestVersion { + version { version coderoadVersion } From 5d38263991fc6538a64a1efe9d5231d5a3624cb4 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 17 Aug 2019 20:56:15 -0700 Subject: [PATCH 011/117] remove data from version, schema change --- src/services/api/gql/query/tutorial.gql | 1 - web-app/src/containers/Continue/tutorial.gql | 1 - 2 files changed, 2 deletions(-) diff --git a/src/services/api/gql/query/tutorial.gql b/src/services/api/gql/query/tutorial.gql index 1f998568..444f4a8b 100644 --- a/src/services/api/gql/query/tutorial.gql +++ b/src/services/api/gql/query/tutorial.gql @@ -10,7 +10,6 @@ query getTutorial($tutorialId: ID!) { version { version coderoadVersion - data } } } diff --git a/web-app/src/containers/Continue/tutorial.gql b/web-app/src/containers/Continue/tutorial.gql index 3160c520..0d3a9d80 100644 --- a/web-app/src/containers/Continue/tutorial.gql +++ b/web-app/src/containers/Continue/tutorial.gql @@ -18,7 +18,6 @@ query getTutorial($tutorialId: ID!) { version { version coderoadVersion - data } } } From 8d4d43fb2f3e4d449a898aaa492089610df9551d Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 17 Aug 2019 20:56:27 -0700 Subject: [PATCH 012/117] ckean up new container loading --- web-app/src/containers/New/index.tsx | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 3e11afc0..ace121e0 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -4,6 +4,7 @@ import * as T from '../../../../typings/graphql' import queryTutorials from './queryTutorials' import { send } from '../../utils/vscode' +import LoadingPage from '../LoadingPage' import TutorialList from '../../components/TutorialList' interface Props { @@ -18,18 +19,28 @@ export const NewPage = (props: Props) => ( ) +const Loading = () => + const NewPageContainer = () => { const { data, loading, error } = useQuery(queryTutorials) - console.log('data', data) if (loading) { - return null + return Loading } if (error) { - return
{JSON.stringify(error, null, 2)}
+ return ( +
+
{error.message}
+

{JSON.stringify(error, null, 2)}

+
+ ) } - return send('TUTORIAL_START')} tutorialList={data.tutorials} /> + return ( + + send('TUTORIAL_START')} tutorialList={data.tutorials} /> + + ) } export default NewPageContainer From 64837c085eb72399c67577cb129baa4f1094b088 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 17 Aug 2019 21:18:48 -0700 Subject: [PATCH 013/117] load continue container --- web-app/src/containers/Continue/index.tsx | 73 +++++++++++++------ .../{tutorial.gql => queryTutorial.ts} | 9 ++- web-app/stories/Continue.stories.tsx | 16 +++- web-app/stories/New.stories.tsx | 4 +- 4 files changed, 72 insertions(+), 30 deletions(-) rename web-app/src/containers/Continue/{tutorial.gql => queryTutorial.ts} (61%) diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index c40ff78b..a31dd9b5 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -1,33 +1,62 @@ import * as React from 'react' -import { send } from '../../utils/vscode' -import DataContext from '../../utils/DataContext' +import { useQuery } from '@apollo/react-hooks' import { Button, Card } from '@alifd/next' +import { send } from '../../utils/vscode' +import LoadingPage from '../LoadingPage' +import queryTutorial from './queryTutorial' +import * as T from '../../../../typings/graphql' + interface Props { + tutorial: T.Tutorial onContinue(): void } -export const ContinuePage = (props: Props) => { - // context - const { data } = React.useContext(DataContext) +export const ContinuePage = (props: Props) => ( +
+

Continue

+ +
+

{props.tutorial.title}

+

{props.tutorial.text}

+ +
+
+
+) + +const Loading = () => + +const ContinuePageContainer = () => { + // TODO: load specific tutorialId + const { data, loading, error } = useQuery(queryTutorial, { + variables: { + tutorialId: 1, + version: '0.1.0', + }, + }) + + if (loading) { + return Loading + } + + if (error) { + return ( +
+
{error.message}
+

{JSON.stringify(error, null, 2)}

+
+ ) + } + return ( -
-

Continue

- -
-

{data.summary.title}

-

{data.summary.description}

- -
-
-
+ { + send('TUTORIAL_START') + }} + /> ) } -export default () => ( - { - send('TUTORIAL_START') - }} - /> -) +export default ContinuePageContainer diff --git a/web-app/src/containers/Continue/tutorial.gql b/web-app/src/containers/Continue/queryTutorial.ts similarity index 61% rename from web-app/src/containers/Continue/tutorial.gql rename to web-app/src/containers/Continue/queryTutorial.ts index 0d3a9d80..43739ed9 100644 --- a/web-app/src/containers/Continue/tutorial.gql +++ b/web-app/src/containers/Continue/queryTutorial.ts @@ -1,4 +1,7 @@ -query getTutorial($tutorialId: ID!) { +import { gql } from 'apollo-boost' + +export default gql` + query getTutorial($tutorialId: ID!, $version: String) { tutorial(id: $tutorialId) { id title @@ -15,9 +18,11 @@ query getTutorial($tutorialId: ID!) { owner name } - version { + version(version: $version) { version coderoadVersion } } } + +` diff --git a/web-app/stories/Continue.stories.tsx b/web-app/stories/Continue.stories.tsx index 92d413ee..2aaf9bf4 100644 --- a/web-app/stories/Continue.stories.tsx +++ b/web-app/stories/Continue.stories.tsx @@ -3,7 +3,17 @@ import React from 'react' import { storiesOf } from '@storybook/react' import { action } from '@storybook/addon-actions' -import { ContinuePage } from '../src/containers/Continue' -import demo from './data/basic' +import apolloProvider from './utils/ApolloDecorator' +import ContinuePageContainer, { ContinuePage } from '../src/containers/Continue' -storiesOf('Continue', module).add('Page', () => ) +storiesOf('Continue', module) + .add('Page', () => { + const tutorial = { + id: '1', + title: 'Example Tutorial', + text: 'Some summary', + } + return + }) + .addDecorator(apolloProvider) + .add('Container', () => ) diff --git a/web-app/stories/New.stories.tsx b/web-app/stories/New.stories.tsx index dfa2fd34..e652ceab 100644 --- a/web-app/stories/New.stories.tsx +++ b/web-app/stories/New.stories.tsx @@ -33,6 +33,4 @@ storiesOf('New', module) return }) .addDecorator(apolloProvider) - .add('Container', () => { - return - }) + .add('Container', () => ) From b2fcd7a9e1519860056da07e55a8e0b1efe58bb1 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 10:34:27 -0700 Subject: [PATCH 014/117] add error component --- package-lock.json | 6 ++++ package.json | 1 + web-app/src/components/Error/index.tsx | 45 ++++++++++++++++++++++++++ web-app/src/containers/New/index.tsx | 8 ++--- 4 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 web-app/src/components/Error/index.tsx diff --git a/package-lock.json b/package-lock.json index 81ee6636..cc42bfaa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,12 @@ "@types/node": "*" } }, + "@types/graphql": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-14.2.3.tgz", + "integrity": "sha512-UoCovaxbJIxagCvVfalfK7YaNhmxj3BQFRQ2RHQKLiu+9wNXhJnlbspsLHt/YQM99IaLUUFJNzCwzc6W0ypMeQ==", + "dev": true + }, "@types/mocha": { "version": "5.2.7", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", diff --git a/package.json b/package.json index f574e4ee..50d9de6c 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ }, "devDependencies": { "@types/dotenv": "^6.1.1", + "@types/graphql": "^14.2.3", "@types/mocha": "^5.2.7", "@types/node": "^12.7.1", "concurrently": "^4.1.1", diff --git a/web-app/src/components/Error/index.tsx b/web-app/src/components/Error/index.tsx new file mode 100644 index 00000000..124c4934 --- /dev/null +++ b/web-app/src/components/Error/index.tsx @@ -0,0 +1,45 @@ +import * as React from 'react' +import { ApolloError } from 'apollo-boost' +import { GraphQLError } from 'graphql' + +const styles = { + container: { + color: '#D8000C', + backgroundColor: '#FFBABA', + padding: '1rem', + }, +} + +interface Props { + error: ApolloError +} + +const ErrorView = ({ error }: Props) => { + console.log('ERROR:', error) + return ( +
+

Error

+ {error.graphQLErrors && ( +
+ {error.graphQLErrors.map(({ message, locations, path }: GraphQLError) => ( +
+ [GraphQL error]: Message: {message}, Location: {locations}, Path: {path} +
+ ))} +
+ )} + {error.networkError && ( +
+ [Network error]: {error.networkError.message} +
+ )} + {error.extraInfo && ( +

+ [Extra info]: {JSON.stringify(error.extraInfo)} +

+ )} +
+ ) +} + +export default ErrorView diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index ace121e0..346015b4 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -5,6 +5,7 @@ import * as T from '../../../../typings/graphql' import queryTutorials from './queryTutorials' import { send } from '../../utils/vscode' import LoadingPage from '../LoadingPage' +import ErrorView from '../../components/Error' import TutorialList from '../../components/TutorialList' interface Props { @@ -28,12 +29,7 @@ const NewPageContainer = () => { } if (error) { - return ( -
-
{error.message}
-

{JSON.stringify(error, null, 2)}

-
- ) + return } return ( From 0c9b0b9331292465596dcfec58fc861a1c933898 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 12:39:22 -0700 Subject: [PATCH 015/117] clenaup level summary progress --- web-app/src/containers/Continue/index.tsx | 8 +-- web-app/src/containers/Tutorial/LevelPage.tsx | 34 ---------- .../Tutorial/LevelSummaryPage/index.tsx | 66 +++++++++++++++++++ .../Tutorial/LevelSummaryPage/queryLevels.ts | 25 +++++++ web-app/src/containers/Tutorial/index.tsx | 4 +- web-app/stories/Level.stories.tsx | 10 +++ 6 files changed, 105 insertions(+), 42 deletions(-) delete mode 100644 web-app/src/containers/Tutorial/LevelPage.tsx create mode 100644 web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx create mode 100644 web-app/src/containers/Tutorial/LevelSummaryPage/queryLevels.ts diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index a31dd9b5..3ee5d1ca 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -5,6 +5,7 @@ import { Button, Card } from '@alifd/next' import { send } from '../../utils/vscode' import LoadingPage from '../LoadingPage' import queryTutorial from './queryTutorial' +import ErrorView from '../../components/Error' import * as T from '../../../../typings/graphql' interface Props { @@ -41,12 +42,7 @@ const ContinuePageContainer = () => { } if (error) { - return ( -
-
{error.message}
-

{JSON.stringify(error, null, 2)}

-
- ) + return } return ( diff --git a/web-app/src/containers/Tutorial/LevelPage.tsx b/web-app/src/containers/Tutorial/LevelPage.tsx deleted file mode 100644 index d95966b3..00000000 --- a/web-app/src/containers/Tutorial/LevelPage.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import * as React from 'react' -import DataContext from '../../utils/DataContext' -import Level from '../../components/Level' - -interface LevelProps { - send(action: string): void -} - -const LevelPage = (props: LevelProps) => { - const { position, data, progress } = React.useContext(DataContext) - const { levelId } = position - const level = data.levels[levelId] - const onNext = (): void => { - props.send('NEXT') - } - const onBack = (): void => { - props.send('BACK') - } - - const stages: { [stageId: string]: any } = {} - for (const stageId of level.stageList) { - stages[stageId] = { - ...data.stages[stageId], - status: { - complete: progress.stages[stageId] || false, - active: position.stageId === stageId, - }, - } - } - - return -} - -export default LevelPage diff --git a/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx b/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx new file mode 100644 index 00000000..acfb344f --- /dev/null +++ b/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx @@ -0,0 +1,66 @@ +import * as React from 'react' +import { useQuery } from '@apollo/react-hooks' + +import ErrorView from '../../../components/Error' +// import Level from '../../../components/Level' +import * as T from '../../../../../typings/graphql' +import queryLevels from './queryLevels' + +interface LevelProps { + levels: T.Level[] + send(action: string): void +} + +export const LevelSummaryPage = (props: LevelProps) => { + // const { levelId } = position + // const level = data.levels[levelId] + // const onNext = (): void => { + // props.send('NEXT') + // } + // const onBack = (): void => { + // props.send('BACK') + // } + + // const stages: { [stageId: string]: any } = {} + // for (const stageId of level.stageList) { + // stages[stageId] = { + // ...data.stages[stageId], + // status: { + // complete: progress.stages[stageId] || false, + // active: position.stageId === stageId, + // }, + // } + // } + + return
LevelSummaryPage
+ + // return +} + +interface ContainerProps { + send(action: string): void +} + +const LevelSummaryPageContainer = (props: ContainerProps) => { + const { loading, error, data } = useQuery(queryLevels, { + variables: { + tutorialId: '1', + version: '0.1.0', + levelId: '1', + }, + }) + + if (loading) { + return
Loading Levels...
+ } + + if (error) { + return + } + + const { levels } = data.tutorial.version + + return +} + +export default LevelSummaryPageContainer diff --git a/web-app/src/containers/Tutorial/LevelSummaryPage/queryLevels.ts b/web-app/src/containers/Tutorial/LevelSummaryPage/queryLevels.ts new file mode 100644 index 00000000..64977c47 --- /dev/null +++ b/web-app/src/containers/Tutorial/LevelSummaryPage/queryLevels.ts @@ -0,0 +1,25 @@ +import { gql } from 'apollo-boost' + +export default gql` + query getLevel($tutorialId: ID!, $version: String, $levelId: ID!) { + tutorial(id: $tutorialId) { + id + version(version: $version) { + version + coderoadVersion + level(levelId: $levelId) { + id + title + text + + stages { + id + title + text + + } + } + } + } +} +` diff --git a/web-app/src/containers/Tutorial/index.tsx b/web-app/src/containers/Tutorial/index.tsx index a0180919..c9658225 100644 --- a/web-app/src/containers/Tutorial/index.tsx +++ b/web-app/src/containers/Tutorial/index.tsx @@ -4,7 +4,7 @@ import { send } from '../../utils/vscode' import Router from '../../components/Router' import LoadingPage from '../LoadingPage' import SummaryPage from './SummaryPage' -import LevelPage from './LevelPage' +import LevelSummaryPage from './LevelSummaryPage' import StagePage from './StagePage' import CompletedPage from './CompletedPage' @@ -24,7 +24,7 @@ const Tutorial = (props: Props) => {
- + diff --git a/web-app/stories/Level.stories.tsx b/web-app/stories/Level.stories.tsx index 6e87383f..229bc9e4 100644 --- a/web-app/stories/Level.stories.tsx +++ b/web-app/stories/Level.stories.tsx @@ -1,11 +1,14 @@ import React from 'react' import { object, withKnobs } from '@storybook/addon-knobs' +import { action } from '@storybook/addon-actions' import { linkTo } from '@storybook/addon-links' import { storiesOf } from '@storybook/react' import SideBarDecorator from './utils/SideBarDecorator' +import apolloProvider from './utils/ApolloDecorator' import Level from '../src/components/Level' +import LevelSummaryPageContainer, { LevelSummaryPage } from '../src/containers/Tutorial/LevelSummaryPage' storiesOf('Tutorial SideBar', module) .addDecorator(SideBarDecorator) @@ -58,3 +61,10 @@ storiesOf('Tutorial SideBar', module) onBack={linkTo('TUtorial SideBar', 'Summary')} /> )) + .add('Level Summary', () => { + return + }) + .addDecorator(apolloProvider) + .add('Level Summary Container', () => { + return + }) From f57b3679e278d5262e0e398962bf891db6d3fab1 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 12:39:29 -0700 Subject: [PATCH 016/117] apollo decorator with local cache --- web-app/src/services/apollo/index.ts | 42 ++++++++++++++++++++++- web-app/stories/utils/ApolloDecorator.tsx | 11 ++---- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/web-app/src/services/apollo/index.ts b/web-app/src/services/apollo/index.ts index a3f3c502..78487437 100644 --- a/web-app/src/services/apollo/index.ts +++ b/web-app/src/services/apollo/index.ts @@ -1,7 +1,47 @@ -import ApolloClient from 'apollo-boost' +import ApolloClient, { InMemoryCache } from 'apollo-boost' const client = new ApolloClient({ uri: process.env.REACT_APP_GQL_URI, + headers: { + Authorization: process.env.GQL_AUTH_TOKEN, + }, + cache: new InMemoryCache(), + resolvers: { + Mutation: { + setStatus: (_root, variables, { cache, getCacheKey }) => { + // TODO: optimize status setting to act on diffs + + // set local cache + function set(typename: string, id: string, status: 'ACTIVE' | 'COMPLETE') { + const writeId = getCacheKey({ __typename: typename, id }) + const data = { status } + cache.writeData({ id: writeId, data }) + } + + const { progress, position } = variables + + // set level progress & active + for (const levelId of Object.keys(progress.levels)) { + set('Level', levelId, 'COMPLETE') + } + set('Level', position.levelId, 'ACTIVE') + + // set stage progress & active + for (const stageId of Object.keys(progress.stages)) { + set('Stage', stageId, 'COMPLETE') + } + set('Stage', position.stageId, 'ACTIVE') + + // set step progress & active + for (const stepId of Object.keys(progress.steps)) { + set('Step', stepId, 'COMPLETE') + } + set('Step', position.stepId, 'ACTIVE') + + return null + }, + }, + }, }) export default client \ No newline at end of file diff --git a/web-app/stories/utils/ApolloDecorator.tsx b/web-app/stories/utils/ApolloDecorator.tsx index 3d70710b..d49def86 100644 --- a/web-app/stories/utils/ApolloDecorator.tsx +++ b/web-app/stories/utils/ApolloDecorator.tsx @@ -1,17 +1,10 @@ import React, { Fragment } from 'react' -import ApolloClient from 'apollo-boost' +import client from '../../src/services/apollo' import { ApolloProvider } from '@apollo/react-hooks' -const graphqlClient = new ApolloClient({ - uri: 'http://localhost:4000/graphql', - headers: { - Authorization: process.env.GQL_AUTH_TOKEN, - }, -}) - function StorybookProvider({ children }) { return ( - + {children} ) From 2b16a0b9d9cc3c10e1ad58005bf33eae2063a8ec Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 14:57:29 -0700 Subject: [PATCH 017/117] working LevelStage container --- typings/graphql.d.ts | 3 ++ .../components/Level/LevelStageSummary.tsx | 8 ++-- web-app/src/components/Level/index.tsx | 44 +++++++++---------- .../Tutorial/LevelSummaryPage/index.tsx | 43 ++++++------------ .../{queryLevels.ts => queryLevel.ts} | 4 +- web-app/src/services/apollo/index.ts | 15 +++++++ 6 files changed, 60 insertions(+), 57 deletions(-) rename web-app/src/containers/Tutorial/LevelSummaryPage/{queryLevels.ts => queryLevel.ts} (88%) diff --git a/typings/graphql.d.ts b/typings/graphql.d.ts index 0d764a0e..f502902f 100644 --- a/typings/graphql.d.ts +++ b/typings/graphql.d.ts @@ -65,6 +65,7 @@ export type Level = { text?: Maybe, stages?: Maybe>>, setup?: Maybe, + status?: 'INCOMPLETE' | 'COMPLETE' | 'ACTIVE', }; export type Mutation = { @@ -125,6 +126,7 @@ export type Stage = { text?: Maybe, steps?: Maybe>>, setup?: Maybe, + status?: 'INCOMPLETE' | 'COMPLETE' | 'ACTIVE', }; export type Step = { @@ -134,6 +136,7 @@ export type Step = { text?: Maybe, setup?: Maybe, solution?: Maybe, + status?: 'INCOMPLETE' | 'COMPLETE' | 'ACTIVE' }; export type StepActions = { diff --git a/web-app/src/components/Level/LevelStageSummary.tsx b/web-app/src/components/Level/LevelStageSummary.tsx index 50837f69..e4892d75 100644 --- a/web-app/src/components/Level/LevelStageSummary.tsx +++ b/web-app/src/components/Level/LevelStageSummary.tsx @@ -1,6 +1,6 @@ import { Icon } from '@alifd/next' import * as React from 'react' -import CC from '../../../../typings/context' +import * as T from '../../../../typings/graphql' import Markdown from '../Markdown' @@ -24,17 +24,17 @@ const styles = { } interface Props { - stage: CC.StageWithStatus + stage: T.Stage onNext(): void } const LevelStageSummary = (props: Props) => { const { stage, onNext } = props - const { active } = stage.status + const active = stage.status === 'ACTIVE' return (
- {stage.content.text} + {stage.text || ''}
{active && }
diff --git a/web-app/src/components/Level/index.tsx b/web-app/src/components/Level/index.tsx index e457bec5..0dbfbdc4 100644 --- a/web-app/src/components/Level/index.tsx +++ b/web-app/src/components/Level/index.tsx @@ -1,7 +1,6 @@ import { Button, Step } from '@alifd/next' import * as React from 'react' -import CR from 'typings' -import CC from '../../../../typings/context' +import * as T from '../../../../typings/graphql' import Markdown from '../Markdown' import LevelStageSummary from './LevelStageSummary' @@ -25,45 +24,46 @@ const styles = { } interface Props { - level: CR.TutorialLevel - stages: { - [stageId: string]: any // CC.StageWithStatus - } + level: T.Level onNext(): void onBack(): void } -const Level = ({ level, stages, onNext, onBack }: Props) => { - const { content, stageList } = level - const { title, text } = content - const activeIndex = stageList.findIndex((stageId: string) => { - return stages[stageId].status.active - }) - +const Level = ({ level, onNext, onBack }: Props) => { + if (!level || !level.stages) { + throw new Error('No level stages found') + } + const activeIndex = level.stages.findIndex((stage: T.Stage | null) => stage && stage.status === 'ACTIVE') || 0 return (
-

{title}

- {text} +

{level.title}

+ {level.text || ''}
- {stageList.map((stageId: string, index: number) => { - const stage: CC.StageWithStatus = stages[stageId] - const { active } = stage.status - const clickHandler = active ? onNext : () => {} + {level.stages.map((stage: T.Stage | null, index: number) => { + if (!stage) { + return null + } + const active = stage.status === 'ACTIVE' + const clickHandler = active + ? onNext + : () => { + /* empty */ + } // note - must add click handler to title, content & step.item // as all are separted components return ( - {stage.content.title || `Stage ${index + 1}`} + {stage.title || `Stage ${index + 1}`} } - content={} + content={} onClick={clickHandler} /> ) diff --git a/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx b/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx index acfb344f..b577f92a 100644 --- a/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx @@ -2,39 +2,24 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' import ErrorView from '../../../components/Error' -// import Level from '../../../components/Level' +import Level from '../../../components/Level' import * as T from '../../../../../typings/graphql' -import queryLevels from './queryLevels' +import queryLevel from './queryLevel' interface LevelProps { - levels: T.Level[] + level: T.Level send(action: string): void } export const LevelSummaryPage = (props: LevelProps) => { - // const { levelId } = position - // const level = data.levels[levelId] - // const onNext = (): void => { - // props.send('NEXT') - // } - // const onBack = (): void => { - // props.send('BACK') - // } - - // const stages: { [stageId: string]: any } = {} - // for (const stageId of level.stageList) { - // stages[stageId] = { - // ...data.stages[stageId], - // status: { - // complete: progress.stages[stageId] || false, - // active: position.stageId === stageId, - // }, - // } - // } - - return
LevelSummaryPage
- - // return + const onNext = (): void => { + props.send('NEXT') + } + const onBack = (): void => { + props.send('BACK') + } + console.log('props', props) + return } interface ContainerProps { @@ -42,7 +27,7 @@ interface ContainerProps { } const LevelSummaryPageContainer = (props: ContainerProps) => { - const { loading, error, data } = useQuery(queryLevels, { + const { loading, error, data } = useQuery(queryLevel, { variables: { tutorialId: '1', version: '0.1.0', @@ -58,9 +43,9 @@ const LevelSummaryPageContainer = (props: ContainerProps) => { return } - const { levels } = data.tutorial.version + const { level } = data.tutorial.version - return + return } export default LevelSummaryPageContainer diff --git a/web-app/src/containers/Tutorial/LevelSummaryPage/queryLevels.ts b/web-app/src/containers/Tutorial/LevelSummaryPage/queryLevel.ts similarity index 88% rename from web-app/src/containers/Tutorial/LevelSummaryPage/queryLevels.ts rename to web-app/src/containers/Tutorial/LevelSummaryPage/queryLevel.ts index 64977c47..70ce134a 100644 --- a/web-app/src/containers/Tutorial/LevelSummaryPage/queryLevels.ts +++ b/web-app/src/containers/Tutorial/LevelSummaryPage/queryLevel.ts @@ -11,12 +11,12 @@ export default gql` id title text - + status @client stages { id title text - + status @client } } } diff --git a/web-app/src/services/apollo/index.ts b/web-app/src/services/apollo/index.ts index 78487437..4fa5c194 100644 --- a/web-app/src/services/apollo/index.ts +++ b/web-app/src/services/apollo/index.ts @@ -41,6 +41,21 @@ const client = new ApolloClient({ return null }, }, + Level: { + status() { + return 'INCOMPLETE' + } + }, + Stage: { + status() { + return 'INCOMPLETE' + } + }, + Step: { + status() { + return 'INCOMPLETE' + } + } }, }) From 204840f89409ed162acfb917355e31a4c3bad990 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 15:03:07 -0700 Subject: [PATCH 018/117] update level stories & structure --- .../Tutorial/LevelSummaryPage/index.tsx | 1 - web-app/stories/Level.stories.tsx | 82 +++++++++++-------- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx b/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx index b577f92a..7d13b1a5 100644 --- a/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx @@ -18,7 +18,6 @@ export const LevelSummaryPage = (props: LevelProps) => { const onBack = (): void => { props.send('BACK') } - console.log('props', props) return } diff --git a/web-app/stories/Level.stories.tsx b/web-app/stories/Level.stories.tsx index 229bc9e4..0311ae01 100644 --- a/web-app/stories/Level.stories.tsx +++ b/web-app/stories/Level.stories.tsx @@ -16,53 +16,65 @@ storiesOf('Tutorial SideBar', module) .add('Level', () => ( )) .add('Level Summary', () => { - return + return ( + + ) }) .addDecorator(apolloProvider) .add('Level Summary Container', () => { From 2bc96a1ba498218d2948cdd669c9d5395384e12a Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 15:53:57 -0700 Subject: [PATCH 019/117] cleanup gql paths --- web-app/src/components/Level/index.tsx | 2 +- web-app/src/components/Stage/index.tsx | 37 ++++++++++--------- web-app/src/components/TutorialList/index.tsx | 2 +- web-app/src/containers/Continue/index.tsx | 2 +- web-app/src/containers/New/index.tsx | 2 +- .../Tutorial/LevelSummaryPage/index.tsx | 2 +- web-app/tsconfig.paths.json | 3 +- 7 files changed, 27 insertions(+), 23 deletions(-) diff --git a/web-app/src/components/Level/index.tsx b/web-app/src/components/Level/index.tsx index 0dbfbdc4..027e92b9 100644 --- a/web-app/src/components/Level/index.tsx +++ b/web-app/src/components/Level/index.tsx @@ -1,6 +1,6 @@ import { Button, Step } from '@alifd/next' import * as React from 'react' -import * as T from '../../../../typings/graphql' +import * as T from 'typings/graphql' import Markdown from '../Markdown' import LevelStageSummary from './LevelStageSummary' diff --git a/web-app/src/components/Stage/index.tsx b/web-app/src/components/Stage/index.tsx index df8ce9e1..5b3e065e 100644 --- a/web-app/src/components/Stage/index.tsx +++ b/web-app/src/components/Stage/index.tsx @@ -1,6 +1,6 @@ import { Button, Step } from '@alifd/next' import * as React from 'react' -import CR from 'typings' +import * as T from 'typings/graphql' import Markdown from '../Markdown' import StepDescription from './StepDescription' @@ -23,36 +23,39 @@ const styles = { } interface Props { - stage: CR.TutorialStage - steps: { - [stepId: string]: any // CC.Step - } + stage: T.Stage complete: boolean onContinue(): void } -const Stage = ({ stage, steps, onContinue, complete }: Props) => { - const { stepList, content } = stage - const { title, text } = content +const Stage = ({ stage, onContinue, complete }: Props) => { + if (!stage.steps) { + throw new Error('No Stage steps found') + } + // grab the active step - const activeIndex = stepList.findIndex((stepId: string) => { - return steps[stepId].status.active + const activeIndex: number = stage.steps.findIndex((step: T.Step | null) => { + return step && step.status === 'ACTIVE' }) + return (
-

{title}

- {text} +

{stage.title}

+ {stage.text || ''}
- {stepList.map((stepId: string, index: number) => { - const step = steps[stepId] + {stage.steps.map((step: T.Step | null, index: number) => { + if (!step) { + return null + } + const hide = status === 'INCOMPLETE' return ( } + key={step.id} + title={step.title || `Step ${index + 1}`} + content={} /> ) })} diff --git a/web-app/src/components/TutorialList/index.tsx b/web-app/src/components/TutorialList/index.tsx index abd775e7..b88fedc3 100644 --- a/web-app/src/components/TutorialList/index.tsx +++ b/web-app/src/components/TutorialList/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' -import * as T from '../../../../typings/graphql' +import * as T from 'typings/graphql' import TutorialItem from './TutorialItem' interface Props { diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index 3ee5d1ca..aefa695f 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -1,12 +1,12 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' import { Button, Card } from '@alifd/next' +import * as T from 'typings/graphql' import { send } from '../../utils/vscode' import LoadingPage from '../LoadingPage' import queryTutorial from './queryTutorial' import ErrorView from '../../components/Error' -import * as T from '../../../../typings/graphql' interface Props { tutorial: T.Tutorial diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 346015b4..2595ff65 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' -import * as T from '../../../../typings/graphql' +import * as T from 'typings/graphql' import queryTutorials from './queryTutorials' import { send } from '../../utils/vscode' diff --git a/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx b/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx index 7d13b1a5..b756d1fb 100644 --- a/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx @@ -1,9 +1,9 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' +import * as T from 'typings/graphql' import ErrorView from '../../../components/Error' import Level from '../../../components/Level' -import * as T from '../../../../../typings/graphql' import queryLevel from './queryLevel' interface LevelProps { diff --git a/web-app/tsconfig.paths.json b/web-app/tsconfig.paths.json index 1ae54a31..8b9fea6b 100644 --- a/web-app/tsconfig.paths.json +++ b/web-app/tsconfig.paths.json @@ -3,7 +3,8 @@ "baseUrl": "src", "rootDirs": ["src", "stories"], "paths": { - "typings": ["../../typings/index.d.ts"] + "typings": ["../../typings/index.d.ts"], + "typings/graphql": ["../../typings/graphql.d.ts"] }, "allowSyntheticDefaultImports": true }, From 372658d3f2bc4cb3de380529d1545afc732097f3 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 15:54:07 -0700 Subject: [PATCH 020/117] add level/stage/step to gql --- typings/graphql.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/typings/graphql.d.ts b/typings/graphql.d.ts index f502902f..f58bb942 100644 --- a/typings/graphql.d.ts +++ b/typings/graphql.d.ts @@ -184,6 +184,9 @@ export type TutorialVersion = { publishedAt?: Maybe, publishedBy?: Maybe, levels?: Maybe>>, + level?: Maybe, + stage?: Maybe, + step?: Maybe, }; From 44613b6f7a8909af9961f54ce6797786763eacbc Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 15:54:20 -0700 Subject: [PATCH 021/117] migrate stage page --- .../components/Level/LevelStageSummary.tsx | 2 +- .../Stage/StepDescription/index.tsx | 12 ++--- web-app/src/containers/Tutorial/StagePage.tsx | 41 --------------- .../Tutorial/StageSummaryPage/index.tsx | 50 +++++++++++++++++++ .../Tutorial/StageSummaryPage/queryStage.ts | 19 +++++++ 5 files changed, 75 insertions(+), 49 deletions(-) delete mode 100644 web-app/src/containers/Tutorial/StagePage.tsx create mode 100644 web-app/src/containers/Tutorial/StageSummaryPage/index.tsx create mode 100644 web-app/src/containers/Tutorial/StageSummaryPage/queryStage.ts diff --git a/web-app/src/components/Level/LevelStageSummary.tsx b/web-app/src/components/Level/LevelStageSummary.tsx index e4892d75..64f366c3 100644 --- a/web-app/src/components/Level/LevelStageSummary.tsx +++ b/web-app/src/components/Level/LevelStageSummary.tsx @@ -1,6 +1,6 @@ import { Icon } from '@alifd/next' import * as React from 'react' -import * as T from '../../../../typings/graphql' +import * as T from 'typings/graphql' import Markdown from '../Markdown' diff --git a/web-app/src/components/Stage/StepDescription/index.tsx b/web-app/src/components/Stage/StepDescription/index.tsx index 24688dce..dcbe179f 100644 --- a/web-app/src/components/Stage/StepDescription/index.tsx +++ b/web-app/src/components/Stage/StepDescription/index.tsx @@ -1,5 +1,4 @@ import * as React from 'react' -import CR from 'typings' import Markdown from '../../Markdown' const styles = { @@ -12,18 +11,17 @@ const styles = { } interface Props { - content: CR.TutorialStepContent - status: any // CC.StageStepStatus + text?: string | null + hide: boolean } -const StepDescription = ({ content, status }: Props) => { - const hidden = !status.active && !status.complete - if (hidden) { +const StepDescription = ({ text, hide }: Props) => { + if (hide) { return null } return (
- {content.text} + {text || ''}
) } diff --git a/web-app/src/containers/Tutorial/StagePage.tsx b/web-app/src/containers/Tutorial/StagePage.tsx deleted file mode 100644 index 10416207..00000000 --- a/web-app/src/containers/Tutorial/StagePage.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import * as React from 'react' -import DataContext from '../../utils/DataContext' -import Stage from '../../components/Stage' - -interface PageProps { - send(action: string): void -} - -const StagePage = (props: PageProps) => { - const { position, data, progress } = React.useContext(DataContext) - const { stageId } = position - const stage = data.stages[stageId] - - if (!stage) { - // may throw if no stage is supplied on restart - return
No Stage!
- } - - const stageComplete = progress.stages[stageId] || false - - const onContinue = (): void => { - props.send('STAGE_NEXT') - } - - // create step subset - const steps: { [stepId: string]: any } = {} - for (const stepId of stage.stepList) { - steps[stepId] = { - ...data.steps[stepId], - status: { - // flag progressed steps as complete - complete: progress.steps[stepId] || false, - // set active step to active - active: position.stepId === stepId, - }, - } - } - return -} - -export default StagePage diff --git a/web-app/src/containers/Tutorial/StageSummaryPage/index.tsx b/web-app/src/containers/Tutorial/StageSummaryPage/index.tsx new file mode 100644 index 00000000..b7ca8469 --- /dev/null +++ b/web-app/src/containers/Tutorial/StageSummaryPage/index.tsx @@ -0,0 +1,50 @@ +import * as React from 'react' +import { useQuery } from '@apollo/react-hooks' +import * as T from 'typings/graphql' + +import Stage from '../../../components/Stage' +import ErrorView from '../../../components/Error' +import queryStage from './queryStage' + +interface PageProps { + stage: T.Stage + send(action: string): void +} + +export const StageSummaryPage = ({ stage, send }: PageProps) => { + if (!stage) { + // may throw if no stage is supplied on restart + throw new Error('No stage provided') + } + + const stageComplete = stage.status === 'COMPLETE' + + const onContinue = (): void => { + send('STAGE_NEXT') + } + + return +} + +const StageSummaryPageContainer = props => { + const { loading, error, data } = useQuery(queryStage, { + variables: { + tutorialId: '1', + version: '1.0.0', + stageId: '1', + }, + }) + if (loading) { + return
Loading Levels...
+ } + + if (error) { + return + } + + const { stage } = data.tutorial.version + + return +} + +export default StageSummaryPageContainer diff --git a/web-app/src/containers/Tutorial/StageSummaryPage/queryStage.ts b/web-app/src/containers/Tutorial/StageSummaryPage/queryStage.ts new file mode 100644 index 00000000..de2d4df0 --- /dev/null +++ b/web-app/src/containers/Tutorial/StageSummaryPage/queryStage.ts @@ -0,0 +1,19 @@ +import { gql } from 'apollo-boost' + +export default gql` + query getStage($tutorialId: ID!, $version: String, $stageId: ID!) { + tutorial(id: $tutorialId) { + id + version(version: $version) { + version + coderoadVersion + stage(stageId: $stageId) { + id + title + text + status @client + } + } + } +} +` From df11100e699612df30f18013feebf8add8dc424f Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 16:20:23 -0700 Subject: [PATCH 022/117] fix typing paths for storybook --- tslint.json | 5 +++-- web-app/.storybook/webpack.config.js | 3 +++ web-app/src/components/Stage/StepDescription/index.tsx | 2 +- web-app/src/containers/Continue/index.tsx | 4 ++-- web-app/src/containers/New/index.tsx | 6 +++--- .../src/containers/Tutorial/LevelSummaryPage/index.tsx | 4 ++-- .../src/containers/Tutorial/StageSummaryPage/index.tsx | 4 ++-- web-app/src/containers/Tutorial/SummaryPage.tsx | 4 ++-- web-app/src/containers/Tutorial/index.tsx | 8 ++++---- web-app/tsconfig.paths.json | 7 ++++++- 10 files changed, 28 insertions(+), 19 deletions(-) diff --git a/tslint.json b/tslint.json index 702ed407..a4ffba90 100644 --- a/tslint.json +++ b/tslint.json @@ -13,10 +13,11 @@ "semicolon": [true, "never"], "triple-equals": true, "forin": false, - "no-console": false + "no-console": false, + "no-submodule-imports": false }, "defaultSeverity": "warning", - "no-submodule-imports": false, + "linterOptions": { "exclude": ["node_modules/**"] } diff --git a/web-app/.storybook/webpack.config.js b/web-app/.storybook/webpack.config.js index c1b26045..b81e78c1 100644 --- a/web-app/.storybook/webpack.config.js +++ b/web-app/.storybook/webpack.config.js @@ -16,5 +16,8 @@ module.exports = ({ config }) => { }, }) config.resolve.extensions.push('.ts', '.tsx') + + config.resolve.modules = ['node_modules', path.resolve(__dirname, '../src')] + return config } diff --git a/web-app/src/components/Stage/StepDescription/index.tsx b/web-app/src/components/Stage/StepDescription/index.tsx index dcbe179f..fc696f9d 100644 --- a/web-app/src/components/Stage/StepDescription/index.tsx +++ b/web-app/src/components/Stage/StepDescription/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import Markdown from '../../Markdown' +import Markdown from 'components/Markdown' const styles = { // active: { diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index aefa695f..a1eaa39b 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -3,10 +3,10 @@ import { useQuery } from '@apollo/react-hooks' import { Button, Card } from '@alifd/next' import * as T from 'typings/graphql' -import { send } from '../../utils/vscode' +import { send } from 'utils/vscode' import LoadingPage from '../LoadingPage' import queryTutorial from './queryTutorial' -import ErrorView from '../../components/Error' +import ErrorView from 'components/Error' interface Props { tutorial: T.Tutorial diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 2595ff65..10ad4a4a 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -3,10 +3,10 @@ import { useQuery } from '@apollo/react-hooks' import * as T from 'typings/graphql' import queryTutorials from './queryTutorials' -import { send } from '../../utils/vscode' +import { send } from 'utils/vscode' import LoadingPage from '../LoadingPage' -import ErrorView from '../../components/Error' -import TutorialList from '../../components/TutorialList' +import ErrorView from 'components/Error' +import TutorialList from 'components/TutorialList' interface Props { tutorialList: T.Tutorial[] diff --git a/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx b/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx index b756d1fb..4725e832 100644 --- a/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx @@ -2,8 +2,8 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' import * as T from 'typings/graphql' -import ErrorView from '../../../components/Error' -import Level from '../../../components/Level' +import ErrorView from 'components/Error' +import Level from 'components/Level' import queryLevel from './queryLevel' interface LevelProps { diff --git a/web-app/src/containers/Tutorial/StageSummaryPage/index.tsx b/web-app/src/containers/Tutorial/StageSummaryPage/index.tsx index b7ca8469..91ee700d 100644 --- a/web-app/src/containers/Tutorial/StageSummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/StageSummaryPage/index.tsx @@ -2,8 +2,8 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' import * as T from 'typings/graphql' -import Stage from '../../../components/Stage' -import ErrorView from '../../../components/Error' +import Stage from 'components/Stage' +import ErrorView from 'components/Error' import queryStage from './queryStage' interface PageProps { diff --git a/web-app/src/containers/Tutorial/SummaryPage.tsx b/web-app/src/containers/Tutorial/SummaryPage.tsx index e1eacc70..f9eb34f5 100644 --- a/web-app/src/containers/Tutorial/SummaryPage.tsx +++ b/web-app/src/containers/Tutorial/SummaryPage.tsx @@ -1,6 +1,6 @@ import * as React from 'react' -import DataContext from '../../utils/DataContext' -import Summary from '../../components/Summary' +import DataContext from 'utils/DataContext' +import Summary from 'components/Summary' interface PageProps { send(action: string): void diff --git a/web-app/src/containers/Tutorial/index.tsx b/web-app/src/containers/Tutorial/index.tsx index c9658225..35dd831a 100644 --- a/web-app/src/containers/Tutorial/index.tsx +++ b/web-app/src/containers/Tutorial/index.tsx @@ -1,11 +1,11 @@ import * as React from 'react' -import { send } from '../../utils/vscode' +import { send } from 'utils/vscode' -import Router from '../../components/Router' +import Router from 'components/Router' import LoadingPage from '../LoadingPage' import SummaryPage from './SummaryPage' import LevelSummaryPage from './LevelSummaryPage' -import StagePage from './StagePage' +import StageSummaryPage from './StageSummaryPage' import CompletedPage from './CompletedPage' const { Route } = Router @@ -27,7 +27,7 @@ const Tutorial = (props: Props) => { - + diff --git a/web-app/tsconfig.paths.json b/web-app/tsconfig.paths.json index 8b9fea6b..b09fea6a 100644 --- a/web-app/tsconfig.paths.json +++ b/web-app/tsconfig.paths.json @@ -3,8 +3,13 @@ "baseUrl": "src", "rootDirs": ["src", "stories"], "paths": { + "components/*": ["./components/*"], + "containers/*": ["./containers/*"], + "services/*": ["./services/*"], + "styles/*": ["./styles/*"], "typings": ["../../typings/index.d.ts"], - "typings/graphql": ["../../typings/graphql.d.ts"] + "typings/graphql": ["../../typings/graphql.d.ts"], + "utils/*": ["./utils/*"] }, "allowSyntheticDefaultImports": true }, From 7bab14b0625642545165e610dd62771db2407bca Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 16:20:32 -0700 Subject: [PATCH 023/117] cleanup Stage story --- web-app/src/components/Stage/index.tsx | 7 ++-- web-app/stories/Stage.stories.tsx | 53 +++++++++++--------------- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/web-app/src/components/Stage/index.tsx b/web-app/src/components/Stage/index.tsx index 5b3e065e..3145bc23 100644 --- a/web-app/src/components/Stage/index.tsx +++ b/web-app/src/components/Stage/index.tsx @@ -24,11 +24,10 @@ const styles = { interface Props { stage: T.Stage - complete: boolean onContinue(): void } -const Stage = ({ stage, onContinue, complete }: Props) => { +const Stage = ({ stage, onContinue }: Props) => { if (!stage.steps) { throw new Error('No Stage steps found') } @@ -50,7 +49,7 @@ const Stage = ({ stage, onContinue, complete }: Props) => { if (!step) { return null } - const hide = status === 'INCOMPLETE' + const hide = step.status === 'INCOMPLETE' return ( {
- {complete && ( + {stage.status === 'COMPLETE' && (
diff --git a/web-app/stories/Stage.stories.tsx b/web-app/stories/Stage.stories.tsx index 7b22dda1..b75636cb 100644 --- a/web-app/stories/Stage.stories.tsx +++ b/web-app/stories/Stage.stories.tsx @@ -1,9 +1,8 @@ import React from 'react' import { action } from '@storybook/addon-actions' -import { boolean, object, withKnobs } from '@storybook/addon-knobs' +import { object, withKnobs } from '@storybook/addon-knobs' import { storiesOf } from '@storybook/react' -import demo from './data/basic' import SideBarDecorator from './utils/SideBarDecorator' import Stage from '../src/components/Stage' @@ -13,44 +12,38 @@ storiesOf('Tutorial SideBar', module) .addDecorator(withKnobs) .add('Stage', () => ( )) From c69b8680dc69b23152d3c219ea0f865efbf159bf Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 16:30:53 -0700 Subject: [PATCH 024/117] working stage container --- .../{LevelSummaryPage => LevelPage}/index.tsx | 0 .../queryLevel.ts | 0 .../{StageSummaryPage => StagePage}/index.tsx | 29 ++++++------------- .../queryStage.ts | 6 ++++ web-app/src/containers/Tutorial/index.tsx | 4 +-- web-app/stories/Level.stories.tsx | 2 +- web-app/stories/Stage.stories.tsx | 4 +++ 7 files changed, 22 insertions(+), 23 deletions(-) rename web-app/src/containers/Tutorial/{LevelSummaryPage => LevelPage}/index.tsx (100%) rename web-app/src/containers/Tutorial/{LevelSummaryPage => LevelPage}/queryLevel.ts (100%) rename web-app/src/containers/Tutorial/{StageSummaryPage => StagePage}/index.tsx (54%) rename web-app/src/containers/Tutorial/{StageSummaryPage => StagePage}/queryStage.ts (76%) diff --git a/web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx similarity index 100% rename from web-app/src/containers/Tutorial/LevelSummaryPage/index.tsx rename to web-app/src/containers/Tutorial/LevelPage/index.tsx diff --git a/web-app/src/containers/Tutorial/LevelSummaryPage/queryLevel.ts b/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts similarity index 100% rename from web-app/src/containers/Tutorial/LevelSummaryPage/queryLevel.ts rename to web-app/src/containers/Tutorial/LevelPage/queryLevel.ts diff --git a/web-app/src/containers/Tutorial/StageSummaryPage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx similarity index 54% rename from web-app/src/containers/Tutorial/StageSummaryPage/index.tsx rename to web-app/src/containers/Tutorial/StagePage/index.tsx index 91ee700d..52778c64 100644 --- a/web-app/src/containers/Tutorial/StageSummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -1,36 +1,19 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' -import * as T from 'typings/graphql' import Stage from 'components/Stage' import ErrorView from 'components/Error' import queryStage from './queryStage' interface PageProps { - stage: T.Stage send(action: string): void } -export const StageSummaryPage = ({ stage, send }: PageProps) => { - if (!stage) { - // may throw if no stage is supplied on restart - throw new Error('No stage provided') - } - - const stageComplete = stage.status === 'COMPLETE' - - const onContinue = (): void => { - send('STAGE_NEXT') - } - - return -} - -const StageSummaryPageContainer = props => { +const StageSummaryPageContainer = (props: PageProps) => { const { loading, error, data } = useQuery(queryStage, { variables: { tutorialId: '1', - version: '1.0.0', + version: '0.1.0', stageId: '1', }, }) @@ -42,9 +25,15 @@ const StageSummaryPageContainer = props => { return } + console.log('data', data) + const { stage } = data.tutorial.version - return + const onContinue = (): void => { + props.send('STAGE_NEXT') + } + + return } export default StageSummaryPageContainer diff --git a/web-app/src/containers/Tutorial/StageSummaryPage/queryStage.ts b/web-app/src/containers/Tutorial/StagePage/queryStage.ts similarity index 76% rename from web-app/src/containers/Tutorial/StageSummaryPage/queryStage.ts rename to web-app/src/containers/Tutorial/StagePage/queryStage.ts index de2d4df0..5b261720 100644 --- a/web-app/src/containers/Tutorial/StageSummaryPage/queryStage.ts +++ b/web-app/src/containers/Tutorial/StagePage/queryStage.ts @@ -12,6 +12,12 @@ export default gql` title text status @client + steps { + id + title + text + status @client + } } } } diff --git a/web-app/src/containers/Tutorial/index.tsx b/web-app/src/containers/Tutorial/index.tsx index 35dd831a..db660874 100644 --- a/web-app/src/containers/Tutorial/index.tsx +++ b/web-app/src/containers/Tutorial/index.tsx @@ -4,8 +4,8 @@ import { send } from 'utils/vscode' import Router from 'components/Router' import LoadingPage from '../LoadingPage' import SummaryPage from './SummaryPage' -import LevelSummaryPage from './LevelSummaryPage' -import StageSummaryPage from './StageSummaryPage' +import LevelSummaryPage from './LevelPage' +import StageSummaryPage from './StagePage' import CompletedPage from './CompletedPage' const { Route } = Router diff --git a/web-app/stories/Level.stories.tsx b/web-app/stories/Level.stories.tsx index 0311ae01..a18ecb12 100644 --- a/web-app/stories/Level.stories.tsx +++ b/web-app/stories/Level.stories.tsx @@ -8,7 +8,7 @@ import SideBarDecorator from './utils/SideBarDecorator' import apolloProvider from './utils/ApolloDecorator' import Level from '../src/components/Level' -import LevelSummaryPageContainer, { LevelSummaryPage } from '../src/containers/Tutorial/LevelSummaryPage' +import LevelSummaryPageContainer, { LevelSummaryPage } from '../src/containers/Tutorial/LevelPage' storiesOf('Tutorial SideBar', module) .addDecorator(SideBarDecorator) diff --git a/web-app/stories/Stage.stories.tsx b/web-app/stories/Stage.stories.tsx index b75636cb..5390d26d 100644 --- a/web-app/stories/Stage.stories.tsx +++ b/web-app/stories/Stage.stories.tsx @@ -6,6 +6,8 @@ import { storiesOf } from '@storybook/react' import SideBarDecorator from './utils/SideBarDecorator' import Stage from '../src/components/Stage' +import StageContainer from '../src/containers/Tutorial/StagePage' +import ApolloDecorator from './utils/ApolloDecorator' storiesOf('Tutorial SideBar', module) .addDecorator(SideBarDecorator) @@ -47,3 +49,5 @@ storiesOf('Tutorial SideBar', module) onContinue={action('onContinue')} /> )) + .addDecorator(ApolloDecorator) + .add('Stage Summary Container', () => ) From 00b3550a7cf4a86809949e0b8c64e6f0b75a7f1b Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 16:40:34 -0700 Subject: [PATCH 025/117] cleanup storybook summary --- web-app/src/components/Summary/index.tsx | 27 +++++++-------- .../containers/Tutorial/StagePage/index.tsx | 2 +- .../src/containers/Tutorial/SummaryPage.tsx | 14 -------- .../containers/Tutorial/SummaryPage/index.tsx | 33 +++++++++++++++++++ .../Tutorial/SummaryPage/querySummary.ts | 15 +++++++++ web-app/stories/Summary.stories.tsx | 11 +------ 6 files changed, 62 insertions(+), 40 deletions(-) delete mode 100644 web-app/src/containers/Tutorial/SummaryPage.tsx create mode 100644 web-app/src/containers/Tutorial/SummaryPage/index.tsx create mode 100644 web-app/src/containers/Tutorial/SummaryPage/querySummary.ts diff --git a/web-app/src/components/Summary/index.tsx b/web-app/src/components/Summary/index.tsx index ee8d56a8..2daf7a38 100644 --- a/web-app/src/components/Summary/index.tsx +++ b/web-app/src/components/Summary/index.tsx @@ -1,6 +1,5 @@ import { Button } from '@alifd/next' import * as React from 'react' -import CR from 'typings' const styles = { card: { @@ -16,23 +15,21 @@ const styles = { } interface Props { - data: CR.TutorialData + title: string + text: string onNext(): void } -const Summary = ({ data, onNext }: Props) => { - const { summary } = data - return ( -
-
-

{summary.title}

-

{summary.description}

-
-
- -
+const Summary = ({ title, text, onNext }: Props) => ( +
+
+

{title}

+

{text}

- ) -} +
+ +
+
+) export default Summary diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index 52778c64..13b026d1 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -18,7 +18,7 @@ const StageSummaryPageContainer = (props: PageProps) => { }, }) if (loading) { - return
Loading Levels...
+ return
Loading Stage...
} if (error) { diff --git a/web-app/src/containers/Tutorial/SummaryPage.tsx b/web-app/src/containers/Tutorial/SummaryPage.tsx deleted file mode 100644 index f9eb34f5..00000000 --- a/web-app/src/containers/Tutorial/SummaryPage.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from 'react' -import DataContext from 'utils/DataContext' -import Summary from 'components/Summary' - -interface PageProps { - send(action: string): void -} - -const SummaryPage = (props: PageProps) => { - const { data } = React.useContext(DataContext) - return props.send('NEXT')} /> -} - -export default SummaryPage diff --git a/web-app/src/containers/Tutorial/SummaryPage/index.tsx b/web-app/src/containers/Tutorial/SummaryPage/index.tsx new file mode 100644 index 00000000..75932113 --- /dev/null +++ b/web-app/src/containers/Tutorial/SummaryPage/index.tsx @@ -0,0 +1,33 @@ +import * as React from 'react' +import { useQuery } from '@apollo/react-hooks' + +import querySummary from './querySummary' +import Summary from 'components/Summary' +import ErrorView from 'components/Error' + +interface PageProps { + send(action: string): void +} + +const SummaryPage = (props: PageProps) => { + const { loading, error, data } = useQuery(querySummary, { + variables: { + tutorialId: '1', + }, + }) + + if (loading) { + return
Loading Summary...
+ } + + if (error) { + return + } + + const { title, text } = data.tutorial + const onNext = () => props.send('NEXT') + + return +} + +export default SummaryPage diff --git a/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts b/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts new file mode 100644 index 00000000..78dcf89a --- /dev/null +++ b/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts @@ -0,0 +1,15 @@ +import { gql } from 'apollo-boost' + +export default gql` + query getSummary($tutorialId: ID!, $version: String) { + tutorial(id: $tutorialId) { + id + title + text + version(version: $version) { + version + coderoadVersion + } + } +} +` diff --git a/web-app/stories/Summary.stories.tsx b/web-app/stories/Summary.stories.tsx index 3b5d61ce..3798bda1 100644 --- a/web-app/stories/Summary.stories.tsx +++ b/web-app/stories/Summary.stories.tsx @@ -1,22 +1,13 @@ import React from 'react' -import { object, withKnobs } from '@storybook/addon-knobs' import { linkTo } from '@storybook/addon-links' import { storiesOf } from '@storybook/react' import SideBarDecorator from './utils/SideBarDecorator' import Summary from '../src/components/Summary' -import demo from './data/basic' storiesOf('Tutorial SideBar', module) .addDecorator(SideBarDecorator) - .addDecorator(withKnobs) .add('Summary', () => ( - + )) From 223019ede305966e57b9635913a0e0600c1275d1 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 16:47:04 -0700 Subject: [PATCH 026/117] cleanup step stories --- web-app/stories/Step.stories.tsx | 64 ++++++++++++-------------------- 1 file changed, 23 insertions(+), 41 deletions(-) diff --git a/web-app/stories/Step.stories.tsx b/web-app/stories/Step.stories.tsx index 982ad4b9..96027531 100644 --- a/web-app/stories/Step.stories.tsx +++ b/web-app/stories/Step.stories.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { object, withKnobs } from '@storybook/addon-knobs' +import { boolean, text, withKnobs } from '@storybook/addon-knobs' import { storiesOf } from '@storybook/react' import SideBarDecorator from './utils/SideBarDecorator' @@ -9,46 +9,28 @@ import Step from '../src/components/Stage/StepDescription' const stepText = 'This is a long paragraph of step text intended to wrap around the side after a short period of writing to demonstrate text wrap among other things' +const paragraphText = `Markdown included \`code\`, *bold*, & _italics_. + \`\`\`javascript + var a = 12 + + function example(a) { + return a + 1 + } + \`\`\` + + Headers can be added: + + # h1 + ## h2 + ### h3 + #### h4 + ##### h5 + + Emojis: :) :| :( + ` + storiesOf('Tutorial SideBar', module) .addDecorator(SideBarDecorator) .addDecorator(withKnobs) - .add('Step', () => ( - - )) - .add('Step Markdown', () => ( - - )) + .add('Step', () => ) + .add('Step Markdown', () => ) From d0d2f07b5db837adcab74b9c7bea3b67810dc7ee Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 16:55:08 -0700 Subject: [PATCH 027/117] restructure single use components into containers --- .../New}/TutorialList/TutorialItem.tsx | 0 .../src/{components => containers/New}/TutorialList/index.tsx | 0 web-app/src/containers/New/index.tsx | 2 +- .../Tutorial/LevelPage}/Level/LevelStageSummary.tsx | 2 +- .../Tutorial/LevelPage}/Level/index.tsx | 2 +- web-app/src/containers/Tutorial/LevelPage/index.tsx | 2 +- .../Tutorial/StagePage}/Stage/StepDescription/index.tsx | 0 .../Tutorial/StagePage}/Stage/index.tsx | 2 +- web-app/src/containers/Tutorial/StagePage/index.tsx | 2 +- .../Tutorial/SummaryPage}/Summary/index.tsx | 0 web-app/src/containers/Tutorial/SummaryPage/index.tsx | 2 +- web-app/stories/Level.stories.tsx | 2 +- web-app/stories/New.stories.tsx | 4 ++-- web-app/stories/Stage.stories.tsx | 2 +- web-app/stories/Step.stories.tsx | 2 +- web-app/stories/Summary.stories.tsx | 2 +- 16 files changed, 13 insertions(+), 13 deletions(-) rename web-app/src/{components => containers/New}/TutorialList/TutorialItem.tsx (100%) rename web-app/src/{components => containers/New}/TutorialList/index.tsx (100%) rename web-app/src/{components => containers/Tutorial/LevelPage}/Level/LevelStageSummary.tsx (95%) rename web-app/src/{components => containers/Tutorial/LevelPage}/Level/index.tsx (98%) rename web-app/src/{components => containers/Tutorial/StagePage}/Stage/StepDescription/index.tsx (100%) rename web-app/src/{components => containers/Tutorial/StagePage}/Stage/index.tsx (97%) rename web-app/src/{components => containers/Tutorial/SummaryPage}/Summary/index.tsx (100%) diff --git a/web-app/src/components/TutorialList/TutorialItem.tsx b/web-app/src/containers/New/TutorialList/TutorialItem.tsx similarity index 100% rename from web-app/src/components/TutorialList/TutorialItem.tsx rename to web-app/src/containers/New/TutorialList/TutorialItem.tsx diff --git a/web-app/src/components/TutorialList/index.tsx b/web-app/src/containers/New/TutorialList/index.tsx similarity index 100% rename from web-app/src/components/TutorialList/index.tsx rename to web-app/src/containers/New/TutorialList/index.tsx diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 10ad4a4a..21efde9c 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -6,7 +6,7 @@ import queryTutorials from './queryTutorials' import { send } from 'utils/vscode' import LoadingPage from '../LoadingPage' import ErrorView from 'components/Error' -import TutorialList from 'components/TutorialList' +import TutorialList from './TutorialList' interface Props { tutorialList: T.Tutorial[] diff --git a/web-app/src/components/Level/LevelStageSummary.tsx b/web-app/src/containers/Tutorial/LevelPage/Level/LevelStageSummary.tsx similarity index 95% rename from web-app/src/components/Level/LevelStageSummary.tsx rename to web-app/src/containers/Tutorial/LevelPage/Level/LevelStageSummary.tsx index 64f366c3..ec3cd81b 100644 --- a/web-app/src/components/Level/LevelStageSummary.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/Level/LevelStageSummary.tsx @@ -2,7 +2,7 @@ import { Icon } from '@alifd/next' import * as React from 'react' import * as T from 'typings/graphql' -import Markdown from '../Markdown' +import Markdown from 'components/Markdown' const styles = { card: { diff --git a/web-app/src/components/Level/index.tsx b/web-app/src/containers/Tutorial/LevelPage/Level/index.tsx similarity index 98% rename from web-app/src/components/Level/index.tsx rename to web-app/src/containers/Tutorial/LevelPage/Level/index.tsx index 027e92b9..9d043c4b 100644 --- a/web-app/src/components/Level/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/Level/index.tsx @@ -2,7 +2,7 @@ import { Button, Step } from '@alifd/next' import * as React from 'react' import * as T from 'typings/graphql' -import Markdown from '../Markdown' +import Markdown from 'components/Markdown' import LevelStageSummary from './LevelStageSummary' const styles = { diff --git a/web-app/src/containers/Tutorial/LevelPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx index 4725e832..780eb9df 100644 --- a/web-app/src/containers/Tutorial/LevelPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/index.tsx @@ -3,7 +3,7 @@ import { useQuery } from '@apollo/react-hooks' import * as T from 'typings/graphql' import ErrorView from 'components/Error' -import Level from 'components/Level' +import Level from './Level' import queryLevel from './queryLevel' interface LevelProps { diff --git a/web-app/src/components/Stage/StepDescription/index.tsx b/web-app/src/containers/Tutorial/StagePage/Stage/StepDescription/index.tsx similarity index 100% rename from web-app/src/components/Stage/StepDescription/index.tsx rename to web-app/src/containers/Tutorial/StagePage/Stage/StepDescription/index.tsx diff --git a/web-app/src/components/Stage/index.tsx b/web-app/src/containers/Tutorial/StagePage/Stage/index.tsx similarity index 97% rename from web-app/src/components/Stage/index.tsx rename to web-app/src/containers/Tutorial/StagePage/Stage/index.tsx index 3145bc23..572c129c 100644 --- a/web-app/src/components/Stage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/Stage/index.tsx @@ -2,7 +2,7 @@ import { Button, Step } from '@alifd/next' import * as React from 'react' import * as T from 'typings/graphql' -import Markdown from '../Markdown' +import Markdown from 'components/Markdown' import StepDescription from './StepDescription' const styles = { diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index 13b026d1..ef78f5b4 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -1,8 +1,8 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' -import Stage from 'components/Stage' import ErrorView from 'components/Error' +import Stage from './Stage' import queryStage from './queryStage' interface PageProps { diff --git a/web-app/src/components/Summary/index.tsx b/web-app/src/containers/Tutorial/SummaryPage/Summary/index.tsx similarity index 100% rename from web-app/src/components/Summary/index.tsx rename to web-app/src/containers/Tutorial/SummaryPage/Summary/index.tsx diff --git a/web-app/src/containers/Tutorial/SummaryPage/index.tsx b/web-app/src/containers/Tutorial/SummaryPage/index.tsx index 75932113..d0d2a2b0 100644 --- a/web-app/src/containers/Tutorial/SummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/SummaryPage/index.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' import querySummary from './querySummary' -import Summary from 'components/Summary' +import Summary from './Summary' import ErrorView from 'components/Error' interface PageProps { diff --git a/web-app/stories/Level.stories.tsx b/web-app/stories/Level.stories.tsx index a18ecb12..46b8f7c1 100644 --- a/web-app/stories/Level.stories.tsx +++ b/web-app/stories/Level.stories.tsx @@ -7,7 +7,7 @@ import { storiesOf } from '@storybook/react' import SideBarDecorator from './utils/SideBarDecorator' import apolloProvider from './utils/ApolloDecorator' -import Level from '../src/components/Level' +import Level from '../src/containers/Tutorial/LevelPage/Level' import LevelSummaryPageContainer, { LevelSummaryPage } from '../src/containers/Tutorial/LevelPage' storiesOf('Tutorial SideBar', module) diff --git a/web-app/stories/New.stories.tsx b/web-app/stories/New.stories.tsx index e652ceab..4952ea37 100644 --- a/web-app/stories/New.stories.tsx +++ b/web-app/stories/New.stories.tsx @@ -4,8 +4,8 @@ import { action } from '@storybook/addon-actions' import * as T from '../../typings/graphql' import apolloProvider from './utils/ApolloDecorator' -import TutorialList from '../src/components/TutorialList' -import TutorialItem from '../src/components/TutorialList/TutorialItem' +import TutorialList from '../src/containers/New/TutorialList' +import TutorialItem from '../src/containers/New/TutorialList/TutorialItem' import NewContainer from '../src/containers/New' storiesOf('New', module) diff --git a/web-app/stories/Stage.stories.tsx b/web-app/stories/Stage.stories.tsx index 5390d26d..b4013fb2 100644 --- a/web-app/stories/Stage.stories.tsx +++ b/web-app/stories/Stage.stories.tsx @@ -5,7 +5,7 @@ import { object, withKnobs } from '@storybook/addon-knobs' import { storiesOf } from '@storybook/react' import SideBarDecorator from './utils/SideBarDecorator' -import Stage from '../src/components/Stage' +import Stage from '../src/containers/Tutorial/StagePage/Stage' import StageContainer from '../src/containers/Tutorial/StagePage' import ApolloDecorator from './utils/ApolloDecorator' diff --git a/web-app/stories/Step.stories.tsx b/web-app/stories/Step.stories.tsx index 96027531..dfede1c9 100644 --- a/web-app/stories/Step.stories.tsx +++ b/web-app/stories/Step.stories.tsx @@ -4,7 +4,7 @@ import { boolean, text, withKnobs } from '@storybook/addon-knobs' import { storiesOf } from '@storybook/react' import SideBarDecorator from './utils/SideBarDecorator' -import Step from '../src/components/Stage/StepDescription' +import Step from '../src/containers/Tutorial/StagePage/Stage/StepDescription' const stepText = 'This is a long paragraph of step text intended to wrap around the side after a short period of writing to demonstrate text wrap among other things' diff --git a/web-app/stories/Summary.stories.tsx b/web-app/stories/Summary.stories.tsx index 3798bda1..df547406 100644 --- a/web-app/stories/Summary.stories.tsx +++ b/web-app/stories/Summary.stories.tsx @@ -4,7 +4,7 @@ import { linkTo } from '@storybook/addon-links' import { storiesOf } from '@storybook/react' import SideBarDecorator from './utils/SideBarDecorator' -import Summary from '../src/components/Summary' +import Summary from '../src/containers/Tutorial/SummaryPage/Summary' storiesOf('Tutorial SideBar', module) .addDecorator(SideBarDecorator) From b022179d219df7d44187bddcf12cd55415f8dc7d Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 18 Aug 2019 23:33:28 -0700 Subject: [PATCH 028/117] remove old web api --- web-app/src/services/api/index.tsx | 32 ------------------------------ 1 file changed, 32 deletions(-) delete mode 100644 web-app/src/services/api/index.tsx diff --git a/web-app/src/services/api/index.tsx b/web-app/src/services/api/index.tsx deleted file mode 100644 index 2bfdb83c..00000000 --- a/web-app/src/services/api/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import * as CR from 'typings' - -// temporary tutorials -import basicTutorial from '../../tutorials/basic' - -interface Options { - resource: string - params?: any -} - -const tutorialsData: { [key: string]: CR.Tutorial } = { - tutorialId: basicTutorial, -} - -// TODO: replace with fetch resource -export default async function fetch(options: Options): Promise { - console.log('options', options) - switch (options.resource) { - case 'getTutorialsSummary': - // list of ids with summaries - const data: { [id: string]: CR.TutorialSummary } = {} - for (const tutorial of Object.values(tutorialsData)) { - data[tutorial.id] = tutorial.data.summary - } - return data - case 'getTutorial': - // specific tutorial by id - return tutorialsData[options.params.id] - default: - throw new Error('Resource not found') - } -} From 24eb6a68e219716223bcf7eed24a9518a197f6ad Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 19 Aug 2019 00:21:10 -0700 Subject: [PATCH 029/117] absolute paths not allowed --- web-app/package-lock.json | 3180 ++++++++++++----- web-app/package.json | 4 +- web-app/src/containers/Continue/index.tsx | 4 +- web-app/src/containers/New/index.tsx | 4 +- .../LevelPage/Level/LevelStageSummary.tsx | 2 +- .../Tutorial/LevelPage/Level/index.tsx | 2 +- .../containers/Tutorial/LevelPage/index.tsx | 2 +- .../StagePage/Stage/StepDescription/index.tsx | 2 +- .../Tutorial/StagePage/Stage/index.tsx | 2 +- .../containers/Tutorial/StagePage/index.tsx | 2 +- .../containers/Tutorial/SummaryPage/index.tsx | 2 +- web-app/src/containers/Tutorial/index.tsx | 4 +- web-app/tsconfig.paths.json | 7 +- 13 files changed, 2228 insertions(+), 989 deletions(-) diff --git a/web-app/package-lock.json b/web-app/package-lock.json index f65e1a8b..12227d51 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -41,48 +41,6 @@ } } }, - "@apollo/react-components": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@apollo/react-components/-/react-components-3.0.1.tgz", - "integrity": "sha512-IQwcwv+ItW/QHUeO2zQH+CJGnqepPwwShD9H6+v1ptLvixggodr7S4KalNKXgRUVJsoPBFiVgpTMoJe3h4+Eyg==", - "dev": true, - "requires": { - "@apollo/react-common": "^3.0.1", - "@apollo/react-hooks": "^3.0.1", - "prop-types": "^15.7.2", - "ts-invariant": "^0.4.4", - "tslib": "^1.10.0" - }, - "dependencies": { - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - } - } - }, - "@apollo/react-hoc": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@apollo/react-hoc/-/react-hoc-3.0.1.tgz", - "integrity": "sha512-sKt0/xjr6jknJztJRWA0zX9wUY/xBq6lwyqPxrRM72hCatz/BSi1tgVv9LMHTA0aJPBK79pWXFq/EeiXW2LkVw==", - "dev": true, - "requires": { - "@apollo/react-common": "^3.0.1", - "@apollo/react-components": "^3.0.1", - "hoist-non-react-statics": "^3.3.0", - "ts-invariant": "^0.4.4", - "tslib": "^1.10.0" - }, - "dependencies": { - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - } - } - }, "@apollo/react-hooks": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@apollo/react-hooks/-/react-hooks-3.0.1.tgz", @@ -101,25 +59,6 @@ } } }, - "@apollo/react-ssr": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@apollo/react-ssr/-/react-ssr-3.0.1.tgz", - "integrity": "sha512-eeAaajIH1zbMk+zigNAlEeyVH80ELrsjvRCcQxH80+THgnJx/hgkKfmhG2p1q2Djefyv6VfImAwd4xqX6/LRSA==", - "dev": true, - "requires": { - "@apollo/react-common": "^3.0.1", - "@apollo/react-hooks": "^3.0.1", - "tslib": "^1.10.0" - }, - "dependencies": { - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - } - } - }, "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", @@ -261,6 +200,7 @@ "version": "7.4.4", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.4.4.tgz", "integrity": "sha512-UbBHIa2qeAGgyiNR9RszVF7bUHEdgS4JAUNT8SiqrAN6YJVxlOxeLr5pBzb5kan302dejJ9nla4RyKcR1XT6XA==", + "dev": true, "requires": { "@babel/helper-function-name": "^7.1.0", "@babel/helper-member-expression-to-functions": "^7.0.0", @@ -420,6 +360,7 @@ "version": "7.4.4", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz", "integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==", + "dev": true, "requires": { "@babel/template": "^7.4.4", "@babel/traverse": "^7.4.4", @@ -455,6 +396,7 @@ "version": "7.4.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.4.0.tgz", "integrity": "sha512-t2ECPNOXsIeK1JxJNKmgbzQtoG27KIlVE61vTqX0DKR9E9sZlVVxWUtEW9D5FlZ8b8j7SBNCHY47GgPKCKlpPg==", + "dev": true, "requires": { "@babel/helper-create-class-features-plugin": "^7.4.0", "@babel/helper-plugin-utils": "^7.0.0" @@ -464,12 +406,22 @@ "version": "7.4.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.4.0.tgz", "integrity": "sha512-d08TLmXeK/XbgCo7ZeZ+JaeZDtDai/2ctapTRsWWkkmy7G/cqz8DQN/HlWG7RR4YmfXxmExsbU3SuCjlM7AtUg==", + "dev": true, "requires": { "@babel/helper-create-class-features-plugin": "^7.4.0", "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-decorators": "^7.2.0" } }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz", + "integrity": "sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0" + } + }, "@babel/plugin-proposal-json-strings": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", @@ -676,6 +628,7 @@ "version": "7.4.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.4.0.tgz", "integrity": "sha512-C4ZVNejHnfB22vI2TYN4RUp2oCmq6cSEAg4RygSvYZUECRqUu9O4PMEMNJ4wsemaRGg27BbgYctG4BZh+AgIHw==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-flow": "^7.2.0" @@ -859,6 +812,7 @@ "version": "7.4.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.4.3.tgz", "integrity": "sha512-7Q61bU+uEI7bCUFReT1NKn7/X6sDQsZ7wL1sJ9IYMAO7cI+eg6x9re1cEw2fCRMbbTVyoeUKWSV1M6azEfKCfg==", + "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0", @@ -869,7 +823,8 @@ "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true } } }, @@ -1276,27 +1231,33 @@ "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.0.0.tgz", "integrity": "sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw==" }, + "@hapi/bourne": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", + "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==" + }, "@hapi/hoek": { - "version": "6.2.4", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-6.2.4.tgz", - "integrity": "sha512-HOJ20Kc93DkDVvjwHyHawPwPkX44sIrbXazAUDiUXaY2R9JwQGo2PhFfnQtdrsIe4igjG2fPgMra7NYw7qhy0A==" + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.2.1.tgz", + "integrity": "sha512-JPiBy+oSmsq3St7XlipfN5pNA6bDJ1kpa73PrK/zR29CVClDVqy04AanM/M/qx5bSF+I61DdCfAvRrujau+zRg==" }, "@hapi/joi": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.0.3.tgz", - "integrity": "sha512-z6CesJ2YBwgVCi+ci8SI8zixoj8bGFn/vZb9MBPbSyoxsS2PnWYjHcyTM17VLK6tx64YVK38SDIh10hJypB+ig==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", + "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", "requires": { "@hapi/address": "2.x.x", - "@hapi/hoek": "6.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "8.x.x", "@hapi/topo": "3.x.x" } }, "@hapi/topo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.0.tgz", - "integrity": "sha512-gZDI/eXOIk8kP2PkUKjWu9RW8GGVd2Hkgjxyr/S7Z+JF+0mr7bAlbw+DkTRxnD580o8Kqxlnba9wvqp5aOHBww==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.3.tgz", + "integrity": "sha512-JmS9/vQK6dcUYn7wc2YZTqzIKubAQcJKu2KCKAru6es482U5RT5fP1EXCPtlXpiK7PR0On/kpQKI4fRKkzpZBQ==", "requires": { - "@hapi/hoek": "6.x.x" + "@hapi/hoek": "8.x.x" } }, "@icons/material": { @@ -1306,46 +1267,47 @@ "dev": true }, "@jest/console": { - "version": "24.7.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.7.1.tgz", - "integrity": "sha512-iNhtIy2M8bXlAOULWVTUxmnelTLFneTNEkHCgPmgd+zNwy9zVddJ6oS5rZ9iwoscNdT5mMwUd0C51v/fSlzItg==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", "requires": { - "@jest/source-map": "^24.3.0", + "@jest/source-map": "^24.9.0", "chalk": "^2.0.1", "slash": "^2.0.0" } }, "@jest/core": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.8.0.tgz", - "integrity": "sha512-R9rhAJwCBQzaRnrRgAdVfnglUuATXdwTRsYqs6NMdVcAl5euG8LtWDe+fVkN27YfKVBW61IojVsXKaOmSnqd/A==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", + "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", "requires": { "@jest/console": "^24.7.1", - "@jest/reporters": "^24.8.0", - "@jest/test-result": "^24.8.0", - "@jest/transform": "^24.8.0", - "@jest/types": "^24.8.0", + "@jest/reporters": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", "ansi-escapes": "^3.0.0", "chalk": "^2.0.1", "exit": "^0.1.2", "graceful-fs": "^4.1.15", - "jest-changed-files": "^24.8.0", - "jest-config": "^24.8.0", - "jest-haste-map": "^24.8.0", - "jest-message-util": "^24.8.0", + "jest-changed-files": "^24.9.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", "jest-regex-util": "^24.3.0", - "jest-resolve-dependencies": "^24.8.0", - "jest-runner": "^24.8.0", - "jest-runtime": "^24.8.0", - "jest-snapshot": "^24.8.0", - "jest-util": "^24.8.0", - "jest-validate": "^24.8.0", - "jest-watcher": "^24.8.0", + "jest-resolve": "^24.9.0", + "jest-resolve-dependencies": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "jest-watcher": "^24.9.0", "micromatch": "^3.1.10", "p-each-series": "^1.0.0", - "pirates": "^4.0.1", "realpath-native": "^1.1.0", "rimraf": "^2.5.4", + "slash": "^2.0.0", "strip-ansi": "^5.0.0" }, "dependencies": { @@ -1354,6 +1316,18 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, + "jest-resolve": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "requires": { + "@jest/types": "^24.9.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -1365,35 +1339,35 @@ } }, "@jest/environment": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.8.0.tgz", - "integrity": "sha512-vlGt2HLg7qM+vtBrSkjDxk9K0YtRBi7HfRFaDxoRtyi+DyVChzhF20duvpdAnKVBV6W5tym8jm0U9EfXbDk1tw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", + "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", "requires": { - "@jest/fake-timers": "^24.8.0", - "@jest/transform": "^24.8.0", - "@jest/types": "^24.8.0", - "jest-mock": "^24.8.0" + "@jest/fake-timers": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0" } }, "@jest/fake-timers": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.8.0.tgz", - "integrity": "sha512-2M4d5MufVXwi6VzZhJ9f5S/wU4ud2ck0kxPof1Iz3zWx6Y+V2eJrES9jEktB6O3o/oEyk+il/uNu9PvASjWXQw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", "requires": { - "@jest/types": "^24.8.0", - "jest-message-util": "^24.8.0", - "jest-mock": "^24.8.0" + "@jest/types": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0" } }, "@jest/reporters": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.8.0.tgz", - "integrity": "sha512-eZ9TyUYpyIIXfYCrw0UHUWUvE35vx5I92HGMgS93Pv7du+GHIzl+/vh8Qj9MCWFK/4TqyttVBPakWMOfZRIfxw==", - "requires": { - "@jest/environment": "^24.8.0", - "@jest/test-result": "^24.8.0", - "@jest/transform": "^24.8.0", - "@jest/types": "^24.8.0", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "requires": { + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", "chalk": "^2.0.1", "exit": "^0.1.2", "glob": "^7.1.2", @@ -1401,24 +1375,24 @@ "istanbul-lib-instrument": "^3.0.1", "istanbul-lib-report": "^2.0.4", "istanbul-lib-source-maps": "^3.0.1", - "istanbul-reports": "^2.1.1", - "jest-haste-map": "^24.8.0", - "jest-resolve": "^24.8.0", - "jest-runtime": "^24.8.0", - "jest-util": "^24.8.0", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", "jest-worker": "^24.6.0", - "node-notifier": "^5.2.1", + "node-notifier": "^5.4.2", "slash": "^2.0.0", "source-map": "^0.6.0", "string-length": "^2.0.0" }, "dependencies": { "jest-resolve": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.8.0.tgz", - "integrity": "sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", "requires": { - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "browser-resolve": "^1.11.3", "chalk": "^2.0.1", "jest-pnp-resolver": "^1.2.1", @@ -1433,9 +1407,9 @@ } }, "@jest/source-map": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.3.0.tgz", - "integrity": "sha512-zALZt1t2ou8le/crCeeiRYzvdnTzaIlpOWaet45lNSqNJUnXbppUUFR4ZUAlzgDmKee4Q5P/tKXypI1RiHwgag==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", "requires": { "callsites": "^3.0.0", "graceful-fs": "^4.1.15", @@ -1455,42 +1429,43 @@ } }, "@jest/test-result": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.8.0.tgz", - "integrity": "sha512-+YdLlxwizlfqkFDh7Mc7ONPQAhA4YylU1s529vVM1rsf67vGZH/2GGm5uO8QzPeVyaVMobCQ7FTxl38QrKRlng==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", "requires": { - "@jest/console": "^24.7.1", - "@jest/types": "^24.8.0", + "@jest/console": "^24.9.0", + "@jest/types": "^24.9.0", "@types/istanbul-lib-coverage": "^2.0.0" } }, "@jest/test-sequencer": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.8.0.tgz", - "integrity": "sha512-OzL/2yHyPdCHXEzhoBuq37CE99nkme15eHkAzXRVqthreWZamEMA0WoetwstsQBCXABhczpK03JNbc4L01vvLg==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", "requires": { - "@jest/test-result": "^24.8.0", - "jest-haste-map": "^24.8.0", - "jest-runner": "^24.8.0", - "jest-runtime": "^24.8.0" + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" } }, "@jest/transform": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.8.0.tgz", - "integrity": "sha512-xBMfFUP7TortCs0O+Xtez2W7Zu1PLH9bvJgtraN1CDST6LBM/eTOZ9SfwS/lvV8yOfcDpFmwf9bq5cYbXvqsvA==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", + "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", "requires": { "@babel/core": "^7.1.0", - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "babel-plugin-istanbul": "^5.1.0", "chalk": "^2.0.1", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.1.15", - "jest-haste-map": "^24.8.0", - "jest-regex-util": "^24.3.0", - "jest-util": "^24.8.0", + "jest-haste-map": "^24.9.0", + "jest-regex-util": "^24.9.0", + "jest-util": "^24.9.0", "micromatch": "^3.1.10", + "pirates": "^4.0.1", "realpath-native": "^1.1.0", "slash": "^2.0.0", "source-map": "^0.6.1", @@ -1505,13 +1480,13 @@ } }, "@jest/types": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.8.0.tgz", - "integrity": "sha512-g17UxVr2YfBtaMUxn9u/4+siG1ptg9IGYAYwvpwn61nBg779RXnjE/m7CxYcIzEt0AbHZZAHSEZNhkE2WxURVg==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^12.0.9" + "@types/yargs": "^13.0.0" } }, "@mrmlnc/readdir-enhanced": { @@ -2634,7 +2609,8 @@ "@svgr/babel-plugin-svg-dynamic-title": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.0.tgz", - "integrity": "sha512-3eI17Pb3jlg3oqV4Tie069n1SelYKBUpI90txDcnBWk4EGFW+YQGyQjy6iuJAReH0RnpUJ9jUExrt/xniGvhqw==" + "integrity": "sha512-3eI17Pb3jlg3oqV4Tie069n1SelYKBUpI90txDcnBWk4EGFW+YQGyQjy6iuJAReH0RnpUJ9jUExrt/xniGvhqw==", + "dev": true }, "@svgr/babel-plugin-svg-em-dimensions": { "version": "4.2.0", @@ -2655,6 +2631,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-4.3.0.tgz", "integrity": "sha512-Lgy1RJiZumGtv6yJroOxzFuL64kG/eIcivJQ7y9ljVWL+0QXvFz4ix1xMrmjMD+rpJWwj50ayCIcFelevG/XXg==", + "dev": true, "requires": { "@svgr/babel-plugin-add-jsx-attribute": "^4.2.0", "@svgr/babel-plugin-remove-jsx-attribute": "^4.2.0", @@ -2670,6 +2647,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/@svgr/core/-/core-4.3.0.tgz", "integrity": "sha512-Ycu1qrF5opBgKXI0eQg3ROzupalCZnSDETKCK/3MKN4/9IEmt3jPX/bbBjftklnRW+qqsCEpO0y/X9BTRw2WBg==", + "dev": true, "requires": { "@svgr/plugin-jsx": "^4.3.0", "camelcase": "^5.3.1", @@ -2680,6 +2658,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.2.0.tgz", "integrity": "sha512-IvAeb7gqrGB5TH9EGyBsPrMRH/QCzIuAkLySKvH2TLfLb2uqk98qtJamordRQTpHH3e6TORfBXoTo7L7Opo/Ow==", + "dev": true, "requires": { "@babel/types": "^7.4.0" } @@ -2688,6 +2667,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-4.3.0.tgz", "integrity": "sha512-0ab8zJdSOTqPfjZtl89cjq2IOmXXUYV3Fs7grLT9ur1Al3+x3DSp2+/obrYKUGbQUnLq96RMjSZ7Icd+13vwlQ==", + "dev": true, "requires": { "@babel/core": "^7.4.3", "@svgr/babel-preset": "^4.3.0", @@ -2701,6 +2681,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-4.2.0.tgz", "integrity": "sha512-zUEKgkT172YzHh3mb2B2q92xCnOAMVjRx+o0waZ1U50XqKLrVQ/8dDqTAtnmapdLsGurv8PSwenjLCUpj6hcvw==", + "dev": true, "requires": { "cosmiconfig": "^5.2.0", "merge-deep": "^3.0.2", @@ -2711,6 +2692,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-4.1.0.tgz", "integrity": "sha512-d09ehQWqLMywP/PT/5JvXwPskPK9QCXUjiSkAHehreB381qExXf5JFCBWhfEyNonRbkIneCeYM99w+Ud48YIQQ==", + "dev": true, "requires": { "@babel/core": "^7.1.6", "@babel/plugin-transform-react-constant-elements": "^7.0.0", @@ -2752,13 +2734,18 @@ } }, "@types/babel__traverse": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.6.tgz", - "integrity": "sha512-XYVgHF2sQ0YblLRMLNPB3CkFMewzFmlDsH/TneZFHUXDlABQgh88uOxuez7ZcXxayLFrqLwtDH1t+FmlFwNZxw==", + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", + "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", "requires": { "@babel/types": "^7.3.0" } }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==" + }, "@types/highlight.js": { "version": "9.12.3", "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz", @@ -2802,6 +2789,11 @@ "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", "dev": true }, + "@types/json-schema": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", + "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==" + }, "@types/linkify-it": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-2.1.0.tgz", @@ -2870,12 +2862,14 @@ "@types/unist": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", - "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==" + "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==", + "dev": true }, "@types/vfile": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/vfile/-/vfile-3.0.2.tgz", "integrity": "sha512-b3nLFGaGkJ9rzOcuXRfHkZMdjsawuDD0ENL9fzTophtBg8FJHSGbH7daXkEpcwy3v7Xol3pAvsmlYyFhR4pqJw==", + "dev": true, "requires": { "@types/node": "*", "@types/unist": "*", @@ -2886,6 +2880,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/vfile-message/-/vfile-message-1.0.1.tgz", "integrity": "sha512-mlGER3Aqmq7bqR1tTTIVHq8KSAFFRyGbrxuM8C/H82g6k7r2fS+IMEkIu3D7JHzG10NvPdR8DNx0jr0pwpp4dA==", + "dev": true, "requires": { "@types/node": "*", "@types/unist": "*" @@ -2898,9 +2893,17 @@ "dev": true }, "@types/yargs": { - "version": "12.0.12", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.12.tgz", - "integrity": "sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw==" + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.2.tgz", + "integrity": "sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ==", + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.0.0.tgz", + "integrity": "sha512-wBlsw+8n21e6eTd4yVv8YD/E3xq0O6nNnJIquutAsFGE7EyMKz7W6RNT6BRu1SmdgmlCZ9tb0X+j+D6HGr8pZw==" }, "@types/zen-observable": { "version": "0.8.0", @@ -2908,30 +2911,42 @@ "integrity": "sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg==" }, "@typescript-eslint/eslint-plugin": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.6.0.tgz", - "integrity": "sha512-U224c29E2lo861TQZs6GSmyC0OYeRNg6bE9UVIiFBxN2MlA0nq2dCrgIVyyRbC05UOcrgf2Wk/CF2gGOPQKUSQ==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.13.0.tgz", + "integrity": "sha512-WQHCozMnuNADiqMtsNzp96FNox5sOVpU8Xt4meaT4em8lOG1SrOv92/mUbEHQVh90sldKSfcOc/I0FOb/14G1g==", "requires": { - "@typescript-eslint/parser": "1.6.0", - "@typescript-eslint/typescript-estree": "1.6.0", - "requireindex": "^1.2.0", + "@typescript-eslint/experimental-utils": "1.13.0", + "eslint-utils": "^1.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^2.0.1", "tsutils": "^3.7.0" } }, + "@typescript-eslint/experimental-utils": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz", + "integrity": "sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg==", + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "1.13.0", + "eslint-scope": "^4.0.0" + } + }, "@typescript-eslint/parser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.6.0.tgz", - "integrity": "sha512-VB9xmSbfafI+/kI4gUK3PfrkGmrJQfh0N4EScT1gZXSZyUxpsBirPL99EWZg9MmPG0pzq/gMtgkk7/rAHj4aQw==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.13.0.tgz", + "integrity": "sha512-ITMBs52PCPgLb2nGPoeT4iU3HdQZHcPaZVw+7CsFagRJHUhyeTgorEwHXhFf3e7Evzi8oujKNpHc8TONth8AdQ==", "requires": { - "@typescript-eslint/typescript-estree": "1.6.0", - "eslint-scope": "^4.0.0", + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "1.13.0", + "@typescript-eslint/typescript-estree": "1.13.0", "eslint-visitor-keys": "^1.0.0" } }, "@typescript-eslint/typescript-estree": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.6.0.tgz", - "integrity": "sha512-A4CanUwfaG4oXobD5y7EXbsOHjCwn8tj1RDd820etpPAjH+Icjc2K9e/DQM1Hac5zH2BSy+u6bjvvF2wwREvYA==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz", + "integrity": "sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==", "requires": { "lodash.unescape": "4.0.1", "semver": "5.5.0" @@ -3150,22 +3165,24 @@ } }, "acorn": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", - "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==" - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz", + "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==" }, "acorn-globals": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz", - "integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.3.tgz", + "integrity": "sha512-vkR40VwS2SYO98AIeFvzWWh+xyc2qi9s7OoXSFEGIP/rOJKzjnhykaZJNnHdoq4BL2gGxI5EZOU16z896EYnOQ==", "requires": { "acorn": "^6.0.1", "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==" + } } }, "acorn-jsx": { @@ -3174,15 +3191,55 @@ "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==" }, "acorn-walk": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", - "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==" + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==" }, "address": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz", "integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg==" }, + "adjust-sourcemap-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-2.0.0.tgz", + "integrity": "sha512-4hFsTsn58+YjrU9qKzML2JSSDqKvN8mUGQ0nNIrfPi8hmIONT4L3uUaT6MKdMsZ9AjsU6D2xDkZxCkbQPxChrA==", + "requires": { + "assert": "1.4.1", + "camelcase": "5.0.0", + "loader-utils": "1.2.3", + "object-path": "0.11.4", + "regex-parser": "2.2.10" + }, + "dependencies": { + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "requires": { + "util": "0.10.3" + } + }, + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==" + }, + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } + }, "airbnb-js-shims": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/airbnb-js-shims/-/airbnb-js-shims-2.2.0.tgz", @@ -3407,21 +3464,6 @@ "tslib": "^1.9.3" } }, - "apollo-storybook-core": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/apollo-storybook-core/-/apollo-storybook-core-0.5.2.tgz", - "integrity": "sha512-8CbKUbRMIxGnz5Ci1jx7dOSDmCcktykfID96wji+E/vFVzE+dvGunuvEJexiVjCOebXJinXe6dqWJZuETot+Sw==", - "dev": true - }, - "apollo-storybook-react": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/apollo-storybook-react/-/apollo-storybook-react-0.2.1.tgz", - "integrity": "sha512-xERyr0EQbiUOBLE3pLRuM27T4Fsh2dVIV8yRy0VZ3eIAsXQrcuxTuM4d5kV+UiYqBNgH9M14+C6OuF9DNMilRw==", - "dev": true, - "requires": { - "apollo-storybook-core": "^0.5.2" - } - }, "apollo-utilities": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.2.tgz", @@ -3471,6 +3513,11 @@ "commander": "^2.11.0" } }, + "arity-n": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz", + "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U=" + }, "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", @@ -3661,9 +3708,9 @@ "dev": true }, "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, "asynckit": { "version": "0.4.0", @@ -3679,6 +3726,7 @@ "version": "9.6.0", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.0.tgz", "integrity": "sha512-kuip9YilBqhirhHEGHaBTZKXL//xxGnzvsD0FtBQa6z+A69qZD6s/BAX9VzDF1i9VKDquTJDQaPLSEhOnL6FvQ==", + "dev": true, "requires": { "browserslist": "^4.6.1", "caniuse-lite": "^1.0.30000971", @@ -3760,9 +3808,9 @@ } }, "babel-eslint": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz", - "integrity": "sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.2.tgz", + "integrity": "sha512-UdsurWPtgiPgpJ06ryUnuaSXC2s0WoSZnQmEpbAH65XZSdwowgN5MvyP7e88nW07FYXv72erVtpBkxyDVKhH1Q==", "requires": { "@babel/code-frame": "^7.0.0", "@babel/parser": "^7.0.0", @@ -3834,29 +3882,37 @@ "dev": true }, "babel-jest": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.8.0.tgz", - "integrity": "sha512-+5/kaZt4I9efoXzPlZASyK/lN9qdRKmmUav9smVc0ruPQD7IsfucQ87gpOE8mn2jbDuS6M/YOW6n3v9ZoIfgnw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", + "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", "requires": { - "@jest/transform": "^24.8.0", - "@jest/types": "^24.8.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", "@types/babel__core": "^7.1.0", "babel-plugin-istanbul": "^5.1.0", - "babel-preset-jest": "^24.6.0", + "babel-preset-jest": "^24.9.0", "chalk": "^2.4.2", "slash": "^2.0.0" } }, "babel-loader": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.5.tgz", - "integrity": "sha512-NTnHnVRd2JnRqPC0vW+iOQWU5pchDbYXsG2E6DMXEpMfUcQKclF9gmf3G3ZMhzG7IG9ji4coL0cm+FxeWxDpnw==", + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", + "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", "dev": true, "requires": { "find-cache-dir": "^2.0.0", "loader-utils": "^1.0.2", "mkdirp": "^0.5.1", - "util.promisify": "^1.0.0" + "pify": "^4.0.1" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } } }, "babel-plugin-add-react-displayname": { @@ -3869,6 +3925,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.2.0.tgz", "integrity": "sha512-fP899ELUnTaBcIzmrW7nniyqqdYWrWuJUyPWHxFa/c7r7hS6KC8FscNfLlBNIoPSc55kYMGEEKjPjJGCLbE1qA==", + "dev": true, "requires": { "object.assign": "^4.1.0" } @@ -3902,19 +3959,20 @@ } }, "babel-plugin-istanbul": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.4.tgz", - "integrity": "sha512-dySz4VJMH+dpndj0wjJ8JPs/7i1TdSPb1nRrn56/92pKOF9VKC1FMFJmMXjzlGGusnCAqujP6PBCiKq0sVA+YQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", "requires": { + "@babel/helper-plugin-utils": "^7.0.0", "find-up": "^3.0.0", "istanbul-lib-instrument": "^3.3.0", "test-exclude": "^5.2.3" } }, "babel-plugin-jest-hoist": { - "version": "24.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.6.0.tgz", - "integrity": "sha512-3pKNH6hMt9SbOv0F3WVmy5CWQ4uogS3k0GY5XLyQHJ9EGpAT9XWkFd2ZiXXtkwFHdAHa5j7w7kfxSP5lAIwu7w==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", + "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", "requires": { "@types/babel__traverse": "^7.0.6" } @@ -3923,6 +3981,7 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.5.1.tgz", "integrity": "sha512-xN3KhAxPzsJ6OQTktCanNpIFnnMsCV+t8OloKxIL72D6+SUZYFn9qfklPgef5HyyDtzYZqqb+fs1S12+gQY82Q==", + "dev": true, "requires": { "@babel/runtime": "^7.4.2", "cosmiconfig": "^5.2.0", @@ -4026,7 +4085,8 @@ "babel-plugin-named-asset-import": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.2.tgz", - "integrity": "sha512-CxwvxrZ9OirpXQ201Ec57OmGhmI8/ui/GwTDy0hSp6CmRvgRC0pSair6Z04Ck+JStA0sMPZzSJ3uE4n17EXpPQ==" + "integrity": "sha512-CxwvxrZ9OirpXQ201Ec57OmGhmI8/ui/GwTDy0hSp6CmRvgRC0pSair6Z04Ck+JStA0sMPZzSJ3uE4n17EXpPQ==", + "dev": true }, "babel-plugin-react-docgen": { "version": "3.1.0", @@ -4137,12 +4197,12 @@ "dev": true }, "babel-preset-jest": { - "version": "24.6.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.6.0.tgz", - "integrity": "sha512-pdZqLEdmy1ZK5kyRUfvBb2IfTPb2BUvIJczlPspS8fWmBQslNNDBqVfh7BW5leOVJMDZKzjD8XEyABTk6gQ5yw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", + "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", "requires": { "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.6.0" + "babel-plugin-jest-hoist": "^24.9.0" } }, "babel-preset-minify": { @@ -4180,6 +4240,7 @@ "version": "9.0.0", "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-9.0.0.tgz", "integrity": "sha512-YVsDA8HpAKklhFLJtl9+AgaxrDaor8gGvDFlsg1ByOS0IPGUovumdv4/gJiAnLcDmZmKlH6+9sVOz4NVW7emAg==", + "dev": true, "requires": { "@babel/core": "7.4.3", "@babel/plugin-proposal-class-properties": "7.4.0", @@ -4205,6 +4266,7 @@ "version": "7.4.3", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.3.tgz", "integrity": "sha512-oDpASqKFlbspQfzAE7yaeTmdljSH2ADIvBlb0RwbStltTuWa0+7CCI1fYVINNv9saHPa1W7oaKeuNuKj+RQCvA==", + "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "@babel/generator": "^7.4.0", @@ -4226,6 +4288,7 @@ "version": "7.4.3", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.3.tgz", "integrity": "sha512-xC//6DNSSHVjq8O2ge0dyYlhshsH4T7XdCVoxbi5HzLYWfsC5ooFlJjrXk8RcAT+hjHAK9UjBXdylzSoDK3t4g==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-object-rest-spread": "^7.2.0" @@ -4235,6 +4298,7 @@ "version": "7.4.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.3.tgz", "integrity": "sha512-PUaIKyFUDtG6jF5DUJOfkBdwAS/kFFV3XFk7Nn0a6vR7ZT8jYw5cGtIlat77wcnd0C6ViGqo/wyNf4ZHytF/nQ==", + "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.0.0", "@babel/helper-define-map": "^7.4.0", @@ -4250,6 +4314,7 @@ "version": "7.4.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.3.tgz", "integrity": "sha512-rVTLLZpydDFDyN4qnXdzwoVpk1oaXHIvPEOkOLyr88o7oHxVc/LyrnDx+amuBWGOwUb7D1s/uLsKBNTx08htZg==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0" } @@ -4258,6 +4323,7 @@ "version": "7.4.3", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.3.tgz", "integrity": "sha512-FYbZdV12yHdJU5Z70cEg0f6lvtpZ8jFSDakTm7WXeJbLXh4R0ztGEu/SW7G1nJ2ZvKwDhz8YrbA84eYyprmGqw==", + "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/helper-plugin-utils": "^7.0.0", @@ -4312,7 +4378,8 @@ "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true } } }, @@ -4345,7 +4412,8 @@ "bail": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.4.tgz", - "integrity": "sha512-S8vuDB4w6YpRhICUDET3guPlQpaJl7od94tpZ0Fvnyp+MKW/HyDTcRDck+29C9g+d/qQHnddRH3+94kZdrW0Ww==" + "integrity": "sha512-S8vuDB4w6YpRhICUDET3guPlQpaJl7od94tpZ0Fvnyp+MKW/HyDTcRDck+29C9g+d/qQHnddRH3+94kZdrW0Ww==", + "dev": true }, "balanced-match": { "version": "1.0.0", @@ -4695,9 +4763,9 @@ } }, "bser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", - "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz", + "integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==", "requires": { "node-int64": "^0.4.0" } @@ -4738,21 +4806,22 @@ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, "cacache": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", - "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.2.tgz", + "integrity": "sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg==", "requires": { - "bluebird": "^3.5.3", + "bluebird": "^3.5.5", "chownr": "^1.1.1", "figgy-pudding": "^3.5.1", - "glob": "^7.1.3", + "glob": "^7.1.4", "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", + "rimraf": "^2.6.3", "ssri": "^6.0.1", "unique-filename": "^1.1.1", "y18n": "^4.0.0" @@ -4875,7 +4944,8 @@ "ccount": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.4.tgz", - "integrity": "sha512-fpZ81yYfzentuieinmGnphk0pLkOTMm6MZdVqwd77ROvhko6iujLNGrHH5E7utq3ygWklwfmwuG+A7P+NpqT6w==" + "integrity": "sha512-fpZ81yYfzentuieinmGnphk0pLkOTMm6MZdVqwd77ROvhko6iujLNGrHH5E7utq3ygWklwfmwuG+A7P+NpqT6w==", + "dev": true }, "chalk": { "version": "2.4.2", @@ -5533,13 +5603,48 @@ } }, "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "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==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + } } }, "clone-deep": { @@ -5632,7 +5737,8 @@ "comma-separated-tokens": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.7.tgz", - "integrity": "sha512-Jrx3xsP4pPv4AwJUDWY9wOXGtwPXARej6Xd99h4TUGotmf8APuquKMpK+dnD3UgyxK7OEWaisjZz+3b5jtL6xQ==" + "integrity": "sha512-Jrx3xsP4pPv4AwJUDWY9wOXGtwPXARej6Xd99h4TUGotmf8APuquKMpK+dnD3UgyxK7OEWaisjZz+3b5jtL6xQ==", + "dev": true }, "commander": { "version": "2.20.0", @@ -5654,6 +5760,14 @@ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, + "compose-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz", + "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=", + "requires": { + "arity-n": "^1.0.4" + } + }, "compressible": { "version": "2.0.17", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz", @@ -5708,9 +5822,9 @@ } }, "confusing-browser-globals": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.7.tgz", - "integrity": "sha512-cgHI1azax5ATrZ8rJ+ODDML9Fvu67PimB6aNxBrc/QwSaDaM9eTfIEUHx3bBLJJ82ioSb+/5zfsMCCEJax3ByQ==" + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.8.tgz", + "integrity": "sha512-lI7asCibVJ6Qd3FGU7mu4sfG4try4LX3+GVS+Gv8UlrEf2AeW57piecapnog2UHZSbcX/P/1UDWVaTsblowlZg==" }, "connect-history-api-fallback": { "version": "1.6.0", @@ -5802,7 +5916,8 @@ "core-js": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.1.tgz", - "integrity": "sha512-sco40rF+2KlE0ROMvydjkrVMMG1vYilP2ALoRXcYR4obqbYIuV3Bg+51GEDW+HF8n7NRA+iaA4qD0nD9lo9mew==" + "integrity": "sha512-sco40rF+2KlE0ROMvydjkrVMMG1vYilP2ALoRXcYR4obqbYIuV3Bg+51GEDW+HF8n7NRA+iaA4qD0nD9lo9mew==", + "dev": true }, "core-js-compat": { "version": "3.1.3", @@ -6153,19 +6268,37 @@ "randomfill": "^1.0.3" } }, - "css-blank-pseudo": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", - "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", "requires": { - "postcss": "^7.0.5" - } - }, - "css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=" - }, + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "css-blank-pseudo": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", + "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", + "requires": { + "postcss": "^7.0.5" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=" + }, "css-declaration-sorter": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", @@ -6375,14 +6508,14 @@ } }, "cssom": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", - "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==" + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" }, "cssstyle": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.2.tgz", - "integrity": "sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", "requires": { "cssom": "0.3.x" } @@ -6407,6 +6540,15 @@ "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, "damerau-levenshtein": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz", @@ -6596,12 +6738,6 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, - "deprecated-decorator": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz", - "integrity": "sha1-AJZjF7ehL+kvPMgx91g68ym4bDc=", - "dev": true - }, "des.js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", @@ -6651,9 +6787,9 @@ } }, "diff-sequences": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.3.0.tgz", - "integrity": "sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==" + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==" }, "diffie-hellman": { "version": "5.0.3", @@ -7008,18 +7144,47 @@ "is-symbol": "^1.0.2" } }, + "es5-ext": { + "version": "0.10.50", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz", + "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==", + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "^1.0.0" + } + }, "es5-shim": { "version": "4.5.13", "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.5.13.tgz", "integrity": "sha512-xi6hh6gsvDE0MaW4Vp1lgNEBpVcCXRWfPXj5egDvtgLz4L9MEvNwYEMdJH+JJinWkwa8c3c3o5HduV7dB/e1Hw==", "dev": true }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, "es6-shim": { "version": "0.35.5", "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.5.tgz", "integrity": "sha512-E9kK/bjtCQRpN1K28Xh4BlmP8egvZBGJJ+9GtnzOwt7mdqtrjHFuVGr7QJfdjBIKqrlU5duPf3pCBoDrkjVYFg==", "dev": true }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -7031,9 +7196,9 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", - "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", + "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", "requires": { "esprima": "^3.1.3", "estraverse": "^4.2.0", @@ -7056,75 +7221,212 @@ } }, "eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.2.0.tgz", + "integrity": "sha512-sS0SZwm5UAoI83F+cgdomz0cBNPs+AnRvEboNYeWvrZ8UcDHCu/5muocwoDL2TkHq9skkP0GvZjmwI8HG7S3sw==", "requires": { "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", + "ajv": "^6.10.0", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", "debug": "^4.0.1", "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.0", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.0", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", + "glob-parent": "^5.0.0", "globals": "^11.7.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", + "inquirer": "^6.4.1", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", - "lodash": "^4.17.11", + "lodash": "^4.17.14", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", "progress": "^2.0.0", "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", "table": "^5.2.3", - "text-table": "^0.2.0" + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "dependencies": { - "import-fresh": { + "ansi-escapes": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", + "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "requires": { + "type-fest": "^0.5.2" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==" + }, + "figures": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", - "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.0.0.tgz", + "integrity": "sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "glob-parent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, + "inquirer": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.1.tgz", + "integrity": "sha512-uxNHBeQhRXIoHWTSNYUFhQVrHYFThIt6IVo2fFmSe8aBwdR3/w6b58hJpiL/fMukFkvGzjg+hSxFtwvVmKZmXw==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "string-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", + "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^5.2.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "type-fest": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", + "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==" } } }, "eslint-config-react-app": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-4.0.1.tgz", - "integrity": "sha512-ZsaoXUIGsK8FCi/x4lT2bZR5mMkL/Kgj+Lnw690rbvvUr/uiwgFiD8FcfAhkCycm7Xte6O5lYz4EqMx2vX7jgw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.0.1.tgz", + "integrity": "sha512-GYXP3F/0PSHlYfGHhahqnJze8rYKxzXgrzXVqRRd4rDO40ga4NA3aHM7/HKbwceDN0/C1Ij3BoAWFawJgRbXEw==", "requires": { - "confusing-browser-globals": "^1.0.7" + "confusing-browser-globals": "^1.0.8" } }, "eslint-import-resolver-node": { @@ -7152,9 +7454,9 @@ } }, "eslint-loader": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.1.2.tgz", - "integrity": "sha512-rA9XiXEOilLYPOIInvVH5S/hYfyTPyxag6DZhoQOduM+3TkghAEQ3VcFO8VnX4J4qg/UIBzp72aOf/xvYmpmsg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.2.1.tgz", + "integrity": "sha512-RLgV9hoCVsMLvOxCuNjdqOrUqIj9oJg8hF44vzJaYqsAHuY9G2YAeN3joQ9nxP0p5Th9iFSIpKo+SD8KISxXRg==", "requires": { "loader-fs-cache": "^1.0.0", "loader-utils": "^1.0.2", @@ -7164,9 +7466,9 @@ } }, "eslint-module-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz", - "integrity": "sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", + "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", "requires": { "debug": "^2.6.8", "pkg-dir": "^2.0.0" @@ -7234,28 +7536,36 @@ } }, "eslint-plugin-flowtype": { - "version": "2.50.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.50.1.tgz", - "integrity": "sha512-9kRxF9hfM/O6WGZcZPszOVPd2W0TLHBtceulLTsGfwMPtiCCLnCW0ssRiOOiXyqrCA20pm1iXdXm7gQeN306zQ==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-3.13.0.tgz", + "integrity": "sha512-bhewp36P+t7cEV0b6OdmoRWJCBYRiHFlqPZAG1oS3SF+Y0LQkeDvFSM4oxoxvczD1OdONCXMlJfQFiWLcV9urw==", "requires": { - "lodash": "^4.17.10" + "lodash": "^4.17.15" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + } } }, "eslint-plugin-import": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.16.0.tgz", - "integrity": "sha512-z6oqWlf1x5GkHIFgrSvtmudnqM6Q60KM4KvpWi5ubonMjycLjndvd5+8VAZIsTlHC03djdgJuyKG6XO577px6A==", + "version": "2.18.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", + "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", "requires": { + "array-includes": "^3.0.3", "contains-path": "^0.1.0", "debug": "^2.6.9", "doctrine": "1.5.0", "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.3.0", + "eslint-module-utils": "^2.4.0", "has": "^1.0.3", - "lodash": "^4.17.11", "minimatch": "^3.0.4", + "object.values": "^1.1.0", "read-pkg-up": "^2.0.0", - "resolve": "^1.9.0" + "resolve": "^1.11.0" }, "dependencies": { "debug": { @@ -7368,14 +7678,23 @@ "find-up": "^2.0.0", "read-pkg": "^2.0.0" } + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "requires": { + "path-parse": "^1.0.6" + } } } }, "eslint-plugin-jsx-a11y": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz", - "integrity": "sha512-cjN2ObWrRz0TTw7vEcGQrx+YltMvZoOEx4hWU8eEERDnBIU00OTq7Vr+jA7DFKxiwLNv4tTh5Pq2GUNEa8b6+w==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz", + "integrity": "sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg==", "requires": { + "@babel/runtime": "^7.4.5", "aria-query": "^3.0.0", "array-includes": "^3.0.3", "ast-types-flow": "^0.0.7", @@ -7383,21 +7702,33 @@ "damerau-levenshtein": "^1.0.4", "emoji-regex": "^7.0.2", "has": "^1.0.3", - "jsx-ast-utils": "^2.0.1" + "jsx-ast-utils": "^2.2.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz", + "integrity": "sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + } } }, "eslint-plugin-react": { - "version": "7.12.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz", - "integrity": "sha512-1puHJkXJY+oS1t467MjbqjvX53uQ05HXwjqDgdbGBqf5j9eeydI54G3KwiJmWciQ0HTBacIKw2jgwSBSH3yfgQ==", + "version": "7.14.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz", + "integrity": "sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA==", "requires": { "array-includes": "^3.0.3", "doctrine": "^2.1.0", "has": "^1.0.3", - "jsx-ast-utils": "^2.0.1", + "jsx-ast-utils": "^2.1.0", + "object.entries": "^1.1.0", "object.fromentries": "^2.0.0", - "prop-types": "^15.6.2", - "resolve": "^1.9.0" + "object.values": "^1.1.0", + "prop-types": "^15.7.2", + "resolve": "^1.10.1" }, "dependencies": { "doctrine": { @@ -7407,13 +7738,21 @@ "requires": { "esutils": "^2.0.2" } + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "requires": { + "path-parse": "^1.0.6" + } } } }, "eslint-plugin-react-hooks": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.6.0.tgz", - "integrity": "sha512-lHBVRIaz5ibnIgNG07JNiAuBUeKhEf8l4etNx5vfAEwqQ5tcuK3jV9yjmopPgQDagQb7HwIuQVsE3IVcGrRnag==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz", + "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==" }, "eslint-scope": { "version": "4.0.3", @@ -7425,9 +7764,12 @@ } }, "eslint-utils": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", - "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz", + "integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==", + "requires": { + "eslint-visitor-keys": "^1.0.0" + } }, "eslint-visitor-keys": { "version": "1.0.0", @@ -7435,13 +7777,20 @@ "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==" }, "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.0.tgz", + "integrity": "sha512-boA7CHRLlVWUSg3iL5Kmlt/xT3Q+sXnKoRYYzj1YeM10A76TEJBbotV5pKbnK42hEUIr121zTv+QLRM5LsCPXQ==", "requires": { - "acorn": "^6.0.7", + "acorn": "^7.0.0", "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==" + } } }, "esprima": { @@ -7577,16 +7926,16 @@ } }, "expect": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.8.0.tgz", - "integrity": "sha512-/zYvP8iMDrzaaxHVa724eJBCKqSHmO0FA7EDkBiRHxg6OipmMn1fN+C8T9L9K8yr7UONkOifu6+LLH+z76CnaA==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", "requires": { - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "ansi-styles": "^3.2.0", - "jest-get-type": "^24.8.0", - "jest-matcher-utils": "^24.8.0", - "jest-message-util": "^24.8.0", - "jest-regex-util": "^24.3.0" + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" } }, "express": { @@ -7994,9 +8343,9 @@ } }, "flatted": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", - "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==" }, "flatten": { "version": "1.0.2", @@ -8058,6 +8407,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-1.1.1.tgz", "integrity": "sha512-gqWAEMLlae/oeVnN6RWCAhesOJMswAN1MaKNqhhjXHV5O0/rTUjWI4UbgQHdlrVbCnb+xLotXmJbBlC66QmpFw==", + "dev": true, "requires": { "babel-code-frame": "^6.22.0", "chalk": "^2.4.1", @@ -8072,7 +8422,8 @@ "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true } } }, @@ -8146,9 +8497,9 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.6.tgz", - "integrity": "sha512-vfmKZp3XPM36DNF0qhW+Cdxk7xm7gTEHY1clv1Xq1arwRQuKZgAhw+NZNWbJBtuaNxzNXwhfdPYRrvIbjfS33A==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz", + "integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==", "optional": true }, "fstream": { @@ -8448,19 +8799,6 @@ "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==" }, - "graphql-tools": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-4.0.5.tgz", - "integrity": "sha512-kQCh3IZsMqquDx7zfIGWBau42xe46gmqabwYkpPlCLIjcEY1XK+auP7iGRD9/205BPyoQdY8hT96MPpgERdC9Q==", - "dev": true, - "requires": { - "apollo-link": "^1.2.3", - "apollo-utilities": "^1.0.1", - "deprecated-decorator": "^0.1.6", - "iterall": "^1.1.3", - "uuid": "^3.1.0" - } - }, "growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", @@ -8476,6 +8814,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz", "integrity": "sha512-5iI7omclyqrnWw4XbXAmGhPsABkSIDQonv2K0h61lybgofWa6iZyvrI3r2zsJH4P8Nb64fFVzlvfhs0g7BBxAA==", + "dev": true, "requires": { "duplexer": "^0.1.1", "pify": "^3.0.0" @@ -8618,6 +8957,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-5.0.1.tgz", "integrity": "sha512-UfPzdl6fbxGAxqGYNThRUhRlDYY7sXu6XU9nQeX4fFZtV+IHbyEJtd+DUuwOqNV4z3K05E/1rIkoVr/JHmeWWA==", + "dev": true, "requires": { "ccount": "^1.0.3", "hastscript": "^5.0.0", @@ -8629,12 +8969,14 @@ "hast-util-parse-selector": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.2.tgz", - "integrity": "sha512-jIMtnzrLTjzqgVEQqPEmwEZV+ea4zHRFTP8Z2Utw0I5HuBOXHzUPPQWr6ouJdJqDKLbFU/OEiYwZ79LalZkmmw==" + "integrity": "sha512-jIMtnzrLTjzqgVEQqPEmwEZV+ea4zHRFTP8Z2Utw0I5HuBOXHzUPPQWr6ouJdJqDKLbFU/OEiYwZ79LalZkmmw==", + "dev": true }, "hastscript": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-5.1.0.tgz", "integrity": "sha512-7mOQX5VfVs/gmrOGlN8/EDfp1GqV6P3gTNVt+KnX4gbYhpASTM8bklFdFQCbFRAadURXAmw0R1QQdBdqp7jswQ==", + "dev": true, "requires": { "comma-separated-tokens": "^1.0.0", "hast-util-parse-selector": "^2.2.0", @@ -8946,16 +9288,10 @@ "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" - }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" }, "inflight": { "version": "1.0.6", @@ -8980,6 +9316,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==", + "dev": true, "requires": { "ansi-escapes": "^3.2.0", "chalk": "^2.4.2", @@ -8999,12 +9336,14 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, "requires": { "ansi-regex": "^4.1.0" } @@ -9099,7 +9438,8 @@ "is-buffer": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "dev": true }, "is-callable": { "version": "1.1.4", @@ -9270,7 +9610,8 @@ "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true }, "is-plain-object": { "version": "2.0.4", @@ -9306,7 +9647,8 @@ "is-root": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.0.0.tgz", - "integrity": "sha512-F/pJIk8QD6OX5DNhRB7hWamLsUilmkDGho48KbgZ6xg/lmAZXHxzXQ91jzB3yRSw5kdQGGGc4yz8HYhTYIMWPg==" + "integrity": "sha512-F/pJIk8QD6OX5DNhRB7hWamLsUilmkDGho48KbgZ6xg/lmAZXHxzXQ91jzB3yRSw5kdQGGGc4yz8HYhTYIMWPg==", + "dev": true }, "is-stream": { "version": "1.1.0", @@ -9458,76 +9800,76 @@ "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" }, "jest": { - "version": "24.7.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-24.7.1.tgz", - "integrity": "sha512-AbvRar5r++izmqo5gdbAjTeA6uNRGoNRuj5vHB0OnDXo2DXWZJVuaObiGgtlvhKb+cWy2oYbQSfxv7Q7GjnAtA==", + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.8.0.tgz", + "integrity": "sha512-o0HM90RKFRNWmAWvlyV8i5jGZ97pFwkeVoGvPW1EtLTgJc2+jcuqcbbqcSZLE/3f2S5pt0y2ZBETuhpWNl1Reg==", "requires": { "import-local": "^2.0.0", - "jest-cli": "^24.7.1" + "jest-cli": "^24.8.0" }, "dependencies": { "jest-cli": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.8.0.tgz", - "integrity": "sha512-+p6J00jSMPQ116ZLlHJJvdf8wbjNbZdeSX9ptfHX06/MSNaXmKihQzx5vQcw0q2G6JsdVkUIdWbOWtSnaYs3yA==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", + "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", "requires": { - "@jest/core": "^24.8.0", - "@jest/test-result": "^24.8.0", - "@jest/types": "^24.8.0", + "@jest/core": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", "chalk": "^2.0.1", "exit": "^0.1.2", "import-local": "^2.0.0", "is-ci": "^2.0.0", - "jest-config": "^24.8.0", - "jest-util": "^24.8.0", - "jest-validate": "^24.8.0", + "jest-config": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", "prompts": "^2.0.1", "realpath-native": "^1.1.0", - "yargs": "^12.0.2" + "yargs": "^13.3.0" } } } }, "jest-changed-files": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.8.0.tgz", - "integrity": "sha512-qgANC1Yrivsq+UrLXsvJefBKVoCsKB0Hv+mBb6NMjjZ90wwxCDmU3hsCXBya30cH+LnPYjwgcU65i6yJ5Nfuug==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", "requires": { - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "execa": "^1.0.0", "throat": "^4.0.0" } }, "jest-config": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.8.0.tgz", - "integrity": "sha512-Czl3Nn2uEzVGsOeaewGWoDPD8GStxCpAe0zOYs2x2l0fZAgPbCr3uwUkgNKV3LwE13VXythM946cd5rdGkkBZw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", "requires": { "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^24.8.0", - "@jest/types": "^24.8.0", - "babel-jest": "^24.8.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", "chalk": "^2.0.1", "glob": "^7.1.1", - "jest-environment-jsdom": "^24.8.0", - "jest-environment-node": "^24.8.0", - "jest-get-type": "^24.8.0", - "jest-jasmine2": "^24.8.0", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.8.0", - "jest-util": "^24.8.0", - "jest-validate": "^24.8.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", "micromatch": "^3.1.10", - "pretty-format": "^24.8.0", + "pretty-format": "^24.9.0", "realpath-native": "^1.1.0" }, "dependencies": { "jest-resolve": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.8.0.tgz", - "integrity": "sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", "requires": { - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "browser-resolve": "^1.11.3", "chalk": "^2.0.1", "jest-pnp-resolver": "^1.2.1", @@ -9537,46 +9879,46 @@ } }, "jest-diff": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.8.0.tgz", - "integrity": "sha512-wxetCEl49zUpJ/bvUmIFjd/o52J+yWcoc5ZyPq4/W1LUKGEhRYDIbP1KcF6t+PvqNrGAFk4/JhtxDq/Nnzs66g==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", "requires": { "chalk": "^2.0.1", - "diff-sequences": "^24.3.0", - "jest-get-type": "^24.8.0", - "pretty-format": "^24.8.0" + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" } }, "jest-docblock": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.3.0.tgz", - "integrity": "sha512-nlANmF9Yq1dufhFlKG9rasfQlrY7wINJbo3q01tu56Jv5eBU5jirylhF2O5ZBnLxzOVBGRDz/9NAwNyBtG4Nyg==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", "requires": { "detect-newline": "^2.1.0" } }, "jest-each": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.8.0.tgz", - "integrity": "sha512-NrwK9gaL5+XgrgoCsd9svsoWdVkK4gnvyhcpzd6m487tXHqIdYeykgq3MKI1u4I+5Zf0tofr70at9dWJDeb+BA==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", "requires": { - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "chalk": "^2.0.1", - "jest-get-type": "^24.8.0", - "jest-util": "^24.8.0", - "pretty-format": "^24.8.0" + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" } }, "jest-environment-jsdom": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.8.0.tgz", - "integrity": "sha512-qbvgLmR7PpwjoFjM/sbuqHJt/NCkviuq9vus9NBn/76hhSidO+Z6Bn9tU8friecegbJL8gzZQEMZBQlFWDCwAQ==", - "requires": { - "@jest/environment": "^24.8.0", - "@jest/fake-timers": "^24.8.0", - "@jest/types": "^24.8.0", - "jest-mock": "^24.8.0", - "jest-util": "^24.8.0", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", + "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0", "jsdom": "^11.5.1" } }, @@ -9590,6 +9932,11 @@ "jsdom": "^14.0.0" }, "dependencies": { + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==" + }, "jsdom": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-14.1.0.tgz", @@ -9644,36 +9991,36 @@ } }, "jest-environment-node": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.8.0.tgz", - "integrity": "sha512-vIGUEScd1cdDgR6sqn2M08sJTRLQp6Dk/eIkCeO4PFHxZMOgy+uYLPMC4ix3PEfM5Au/x3uQ/5Tl0DpXXZsJ/Q==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", + "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", "requires": { - "@jest/environment": "^24.8.0", - "@jest/fake-timers": "^24.8.0", - "@jest/types": "^24.8.0", - "jest-mock": "^24.8.0", - "jest-util": "^24.8.0" + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0" } }, "jest-get-type": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.8.0.tgz", - "integrity": "sha512-RR4fo8jEmMD9zSz2nLbs2j0zvPpk/KCEz3a62jJWbd2ayNo0cb+KFRxPHVhE4ZmgGJEQp0fosmNz84IfqM8cMQ==" + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==" }, "jest-haste-map": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.8.0.tgz", - "integrity": "sha512-ZBPRGHdPt1rHajWelXdqygIDpJx8u3xOoLyUBWRW28r3tagrgoepPrzAozW7kW9HrQfhvmiv1tncsxqHJO1onQ==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", "requires": { - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "anymatch": "^2.0.0", "fb-watchman": "^2.0.0", "fsevents": "^1.2.7", "graceful-fs": "^4.1.15", "invariant": "^2.2.4", - "jest-serializer": "^24.4.0", - "jest-util": "^24.8.0", - "jest-worker": "^24.6.0", + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", "micromatch": "^3.1.10", "sane": "^4.0.3", "walker": "^1.0.7" @@ -10163,55 +10510,56 @@ } }, "jest-jasmine2": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.8.0.tgz", - "integrity": "sha512-cEky88npEE5LKd5jPpTdDCLvKkdyklnaRycBXL6GNmpxe41F0WN44+i7lpQKa/hcbXaQ+rc9RMaM4dsebrYong==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", + "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", "requires": { "@babel/traverse": "^7.1.0", - "@jest/environment": "^24.8.0", - "@jest/test-result": "^24.8.0", - "@jest/types": "^24.8.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", "chalk": "^2.0.1", "co": "^4.6.0", - "expect": "^24.8.0", + "expect": "^24.9.0", "is-generator-fn": "^2.0.0", - "jest-each": "^24.8.0", - "jest-matcher-utils": "^24.8.0", - "jest-message-util": "^24.8.0", - "jest-runtime": "^24.8.0", - "jest-snapshot": "^24.8.0", - "jest-util": "^24.8.0", - "pretty-format": "^24.8.0", + "jest-each": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0", "throat": "^4.0.0" } }, "jest-leak-detector": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.8.0.tgz", - "integrity": "sha512-cG0yRSK8A831LN8lIHxI3AblB40uhv0z+SsQdW3GoMMVcK+sJwrIIyax5tu3eHHNJ8Fu6IMDpnLda2jhn2pD/g==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", + "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", "requires": { - "pretty-format": "^24.8.0" + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" } }, "jest-matcher-utils": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.8.0.tgz", - "integrity": "sha512-lex1yASY51FvUuHgm0GOVj7DCYEouWSlIYmCW7APSqB9v8mXmKSn5+sWVF0MhuASG0bnYY106/49JU1FZNl5hw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", "requires": { "chalk": "^2.0.1", - "jest-diff": "^24.8.0", - "jest-get-type": "^24.8.0", - "pretty-format": "^24.8.0" + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" } }, "jest-message-util": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.8.0.tgz", - "integrity": "sha512-p2k71rf/b6ns8btdB0uVdljWo9h0ovpnEe05ZKWceQGfXYr4KkzgKo3PBi8wdnd9OtNh46VpNIJynUn/3MKm1g==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", "requires": { "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.8.0", - "@jest/types": "^24.8.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", "@types/stack-utils": "^1.0.1", "chalk": "^2.0.1", "micromatch": "^3.1.10", @@ -10220,11 +10568,11 @@ } }, "jest-mock": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.8.0.tgz", - "integrity": "sha512-6kWugwjGjJw+ZkK4mDa0Df3sDlUTsV47MSrT0nGQ0RBWJbpODDQ8MHDVtGtUYBne3IwZUhtB7elxHspU79WH3A==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", "requires": { - "@jest/types": "^24.8.0" + "@jest/types": "^24.9.0" } }, "jest-pnp-resolver": { @@ -10233,16 +10581,16 @@ "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==" }, "jest-regex-util": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.3.0.tgz", - "integrity": "sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg==" + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==" }, "jest-resolve": { - "version": "24.7.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.7.1.tgz", - "integrity": "sha512-Bgrc+/UUZpGJ4323sQyj85hV9d+ANyPNu6XfRDUcyFNX1QrZpSoM0kE4Mb2vZMAYTJZsBFzYe8X1UaOkOELSbw==", + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.8.0.tgz", + "integrity": "sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==", "requires": { - "@jest/types": "^24.7.0", + "@jest/types": "^24.8.0", "browser-resolve": "^1.11.3", "chalk": "^2.0.1", "jest-pnp-resolver": "^1.2.1", @@ -10250,47 +10598,47 @@ } }, "jest-resolve-dependencies": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.8.0.tgz", - "integrity": "sha512-hyK1qfIf/krV+fSNyhyJeq3elVMhK9Eijlwy+j5jqmZ9QsxwKBiP6qukQxaHtK8k6zql/KYWwCTQ+fDGTIJauw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", + "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", "requires": { - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "jest-regex-util": "^24.3.0", - "jest-snapshot": "^24.8.0" + "jest-snapshot": "^24.9.0" } }, "jest-runner": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.8.0.tgz", - "integrity": "sha512-utFqC5BaA3JmznbissSs95X1ZF+d+4WuOWwpM9+Ak356YtMhHE/GXUondZdcyAAOTBEsRGAgH/0TwLzfI9h7ow==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", + "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", "requires": { "@jest/console": "^24.7.1", - "@jest/environment": "^24.8.0", - "@jest/test-result": "^24.8.0", - "@jest/types": "^24.8.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", "chalk": "^2.4.2", "exit": "^0.1.2", "graceful-fs": "^4.1.15", - "jest-config": "^24.8.0", + "jest-config": "^24.9.0", "jest-docblock": "^24.3.0", - "jest-haste-map": "^24.8.0", - "jest-jasmine2": "^24.8.0", - "jest-leak-detector": "^24.8.0", - "jest-message-util": "^24.8.0", - "jest-resolve": "^24.8.0", - "jest-runtime": "^24.8.0", - "jest-util": "^24.8.0", + "jest-haste-map": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-leak-detector": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", "jest-worker": "^24.6.0", "source-map-support": "^0.5.6", "throat": "^4.0.0" }, "dependencies": { "jest-resolve": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.8.0.tgz", - "integrity": "sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", "requires": { - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "browser-resolve": "^1.11.3", "chalk": "^2.0.1", "jest-pnp-resolver": "^1.2.1", @@ -10300,41 +10648,41 @@ } }, "jest-runtime": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.8.0.tgz", - "integrity": "sha512-Mq0aIXhvO/3bX44ccT+czU1/57IgOMyy80oM0XR/nyD5zgBcesF84BPabZi39pJVA6UXw+fY2Q1N+4BiVUBWOA==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", + "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", "requires": { "@jest/console": "^24.7.1", - "@jest/environment": "^24.8.0", + "@jest/environment": "^24.9.0", "@jest/source-map": "^24.3.0", - "@jest/transform": "^24.8.0", - "@jest/types": "^24.8.0", - "@types/yargs": "^12.0.2", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", "chalk": "^2.0.1", "exit": "^0.1.2", "glob": "^7.1.3", "graceful-fs": "^4.1.15", - "jest-config": "^24.8.0", - "jest-haste-map": "^24.8.0", - "jest-message-util": "^24.8.0", - "jest-mock": "^24.8.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0", "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.8.0", - "jest-snapshot": "^24.8.0", - "jest-util": "^24.8.0", - "jest-validate": "^24.8.0", + "jest-resolve": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", "realpath-native": "^1.1.0", "slash": "^2.0.0", "strip-bom": "^3.0.0", - "yargs": "^12.0.2" + "yargs": "^13.3.0" }, "dependencies": { "jest-resolve": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.8.0.tgz", - "integrity": "sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", "requires": { - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "browser-resolve": "^1.11.3", "chalk": "^2.0.1", "jest-pnp-resolver": "^1.2.1", @@ -10344,35 +10692,36 @@ } }, "jest-serializer": { - "version": "24.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.4.0.tgz", - "integrity": "sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q==" + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" }, "jest-snapshot": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.8.0.tgz", - "integrity": "sha512-5ehtWoc8oU9/cAPe6fez6QofVJLBKyqkY2+TlKTOf0VllBB/mqUNdARdcjlZrs9F1Cv+/HKoCS/BknT0+tmfPg==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", + "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", "requires": { "@babel/types": "^7.0.0", - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "chalk": "^2.0.1", - "expect": "^24.8.0", - "jest-diff": "^24.8.0", - "jest-matcher-utils": "^24.8.0", - "jest-message-util": "^24.8.0", - "jest-resolve": "^24.8.0", + "expect": "^24.9.0", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "pretty-format": "^24.8.0", - "semver": "^5.5.0" + "pretty-format": "^24.9.0", + "semver": "^6.2.0" }, "dependencies": { "jest-resolve": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.8.0.tgz", - "integrity": "sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", "requires": { - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "browser-resolve": "^1.11.3", "chalk": "^2.0.1", "jest-pnp-resolver": "^1.2.1", @@ -10380,22 +10729,22 @@ } }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, "jest-util": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.8.0.tgz", - "integrity": "sha512-DYZeE+XyAnbNt0BG1OQqKy/4GVLPtzwGx5tsnDrFcax36rVE3lTA5fbvgmbVPUZf9w77AJ8otqR4VBbfFJkUZA==", - "requires": { - "@jest/console": "^24.7.1", - "@jest/fake-timers": "^24.8.0", - "@jest/source-map": "^24.3.0", - "@jest/test-result": "^24.8.0", - "@jest/types": "^24.8.0", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "requires": { + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", "callsites": "^3.0.0", "chalk": "^2.0.1", "graceful-fs": "^4.1.15", @@ -10418,22 +10767,22 @@ } }, "jest-validate": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.8.0.tgz", - "integrity": "sha512-+/N7VOEMW1Vzsrk3UWBDYTExTPwf68tavEPKDnJzrC6UlHtUDU/fuEdXqFoHzv9XnQ+zW6X3qMZhJ3YexfeLDA==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", "requires": { - "@jest/types": "^24.8.0", - "camelcase": "^5.0.0", + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", "chalk": "^2.0.1", - "jest-get-type": "^24.8.0", - "leven": "^2.1.0", - "pretty-format": "^24.8.0" + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" } }, "jest-watch-typeahead": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-0.3.0.tgz", - "integrity": "sha512-+uOtlppt9ysST6k6ZTqsPI0WNz2HLa8bowiZylZoQCQaAVn7XsVmHhZREkz73FhKelrFrpne4hQQjdq42nFEmA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-0.3.1.tgz", + "integrity": "sha512-cDIko96c4Yqg/7mfye1eEYZ6Pvugo9mnOOhGQod3Es7/KptNv1b+9gFVaotzdqNqTlwbkA80BnWHtzV4dc+trA==", "requires": { "ansi-escapes": "^3.0.0", "chalk": "^2.4.1", @@ -10459,25 +10808,25 @@ } }, "jest-watcher": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.8.0.tgz", - "integrity": "sha512-SBjwHt5NedQoVu54M5GEx7cl7IGEFFznvd/HNT8ier7cCAx/Qgu9ZMlaTQkvK22G1YOpcWBLQPFSImmxdn3DAw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", + "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", "requires": { - "@jest/test-result": "^24.8.0", - "@jest/types": "^24.8.0", - "@types/yargs": "^12.0.9", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", "ansi-escapes": "^3.0.0", "chalk": "^2.0.1", - "jest-util": "^24.8.0", + "jest-util": "^24.9.0", "string-length": "^2.0.0" } }, "jest-worker": { - "version": "24.6.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.6.0.tgz", - "integrity": "sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", "requires": { - "merge-stream": "^1.0.1", + "merge-stream": "^2.0.0", "supports-color": "^6.1.0" }, "dependencies": { @@ -10642,11 +10991,12 @@ } }, "jsx-ast-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.1.0.tgz", - "integrity": "sha512-yDGDG2DS4JcqhA6blsuYbtsT09xL8AoLuUR2Gb5exrw7UEM19sBcOTq+YBBhrNbl0PUC4R4LnFu+dHg2HKeVvA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.1.tgz", + "integrity": "sha512-v3FxCcAf20DayI+uxnCuw795+oOIkVu6EnJ1+kSzhqqTZHNkTZ7B66ZgLp4oLJ/gbA64cI0B7WRoHZMSRdyVRQ==", "requires": { - "array-includes": "^3.0.3" + "array-includes": "^3.0.3", + "object.assign": "^4.1.0" } }, "killable": { @@ -10753,9 +11103,9 @@ "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" }, "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" }, "levn": { "version": "0.3.0", @@ -10897,26 +11247,21 @@ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" }, - "lodash.tail": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", - "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=" - }, "lodash.template": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", - "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", "requires": { - "lodash._reinterpolate": "~3.0.0", + "lodash._reinterpolate": "^3.0.0", "lodash.templatesettings": "^4.0.0" } }, "lodash.templatesettings": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz", - "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", "requires": { - "lodash._reinterpolate": "~3.0.0" + "lodash._reinterpolate": "^3.0.0" } }, "lodash.throttle": { @@ -10936,9 +11281,9 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "loglevel": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.2.tgz", - "integrity": "sha512-Jt2MHrCNdtIe1W6co3tF5KXGRkzF+TYffiQstfXa04mrss9IKXzAAXYWak8LbZseAQY03sH2GzMCMU0ZOUc9bg==" + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.3.tgz", + "integrity": "sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==" }, "loose-envify": { "version": "1.4.0", @@ -11279,12 +11624,9 @@ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, "merge-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", - "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", - "requires": { - "readable-stream": "^2.0.1" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "merge2": { "version": "1.2.3", @@ -11556,6 +11898,11 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -11636,9 +11983,9 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" }, "node-libs-browser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", - "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", "requires": { "assert": "^1.1.1", "browserify-zlib": "^0.2.0", @@ -11650,7 +11997,7 @@ "events": "^3.0.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", - "path-browserify": "0.0.0", + "path-browserify": "0.0.1", "process": "^0.11.10", "punycode": "^1.2.4", "querystring-es3": "^0.2.0", @@ -11662,7 +12009,7 @@ "tty-browserify": "0.0.0", "url": "^0.11.0", "util": "^0.11.0", - "vm-browserify": "0.0.4" + "vm-browserify": "^1.0.1" }, "dependencies": { "punycode": { @@ -11678,21 +12025,26 @@ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=" }, "node-notifier": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz", - "integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.2.tgz", + "integrity": "sha512-85nkTziazE2dR4pyoLxMwz0b9MmxFQPVXYs/WlWI7CPtBkARJOV+89khdNjpbclXIJDECQYnTvh1xuZV3WHkCA==", "requires": { "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", + "is-wsl": "^2.1.0", + "semver": "^6.3.0", "shellwords": "^0.1.1", - "which": "^1.3.0" + "which": "^1.3.1" }, "dependencies": { + "is-wsl": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.0.tgz", + "integrity": "sha512-pFTjpv/x5HRj8kbZ/Msxi9VrvtOMRBqaDi3OIcbwPI3OuH+r3lLxVWukLITBaOGJIbA/w2+M1eVmVa4XNQlAmQ==" + }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -11932,6 +12284,11 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, + "object-path": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz", + "integrity": "sha1-NwrnUvvzfePqcKhhwju6iRVpGUk=" + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -11955,7 +12312,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", - "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.12.0", @@ -12040,7 +12396,6 @@ "version": "6.4.0", "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", - "dev": true, "requires": { "is-wsl": "^1.1.0" } @@ -12083,11 +12438,11 @@ } }, "optimize-css-assets-webpack-plugin": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.1.tgz", - "integrity": "sha512-Rqm6sSjWtx9FchdP0uzTQDc7GXDKnwVEGoSxjezPkzMewx7gEWE9IMUYKmigTRC4U3RaNSwYVnUDLuIdtTpm0A==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz", + "integrity": "sha512-q9fbvCRS6EYtUKKSwI87qm2IxlyJK5b4dygW1rKUBT6mMDhdG5e5bZT63v6tnJR9F9FB/H5a0HTmtw+laUBxKA==", "requires": { - "cssnano": "^4.1.0", + "cssnano": "^4.1.10", "last-call-webpack-plugin": "^3.0.0" } }, @@ -12292,9 +12647,9 @@ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" }, "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=" + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" }, "path-dirname": { "version": "1.0.2", @@ -12444,11 +12799,11 @@ "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" }, "pnp-webpack-plugin": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.2.1.tgz", - "integrity": "sha512-W6GctK7K2qQiVR+gYSv/Gyt6jwwIH4vwdviFqx+Y2jAtVf5eZyYIDf5Ac2NCDMBiX5yWscBLZElPTsyA1UtVVA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.5.0.tgz", + "integrity": "sha512-jd9olUr9D7do+RN8Wspzhpxhgp1n6Vd0NtQ4SFkmIACZoEL1nkyAdW9Ygrinjec0vgDcWjscFQQ1gDW8rsfKTg==", "requires": { - "ts-pnp": "^1.0.0" + "ts-pnp": "^1.1.2" } }, "polished": { @@ -12478,9 +12833,9 @@ "dev": true }, "portfinder": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz", - "integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==", + "version": "1.0.22", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.22.tgz", + "integrity": "sha512-aZuwaz9ujJsyE8C5kurXAD8UmRxsJr+RtZWyQRvRk19Z2ri5uuHw5YS4tDBZrJlOS9Zw96uAbBuPb6W4wgvV5A==", "requires": { "async": "^1.5.2", "debug": "^2.2.0", @@ -12671,12 +13026,37 @@ } }, "postcss-custom-properties": { - "version": "8.0.10", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.10.tgz", - "integrity": "sha512-GDL0dyd7++goDR4SSasYdRNNvp4Gqy1XMzcCnTijiph7VB27XXpJ8bW/AI0i2VSBZ55TpdGhMr37kMSpRfYD0Q==", + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", + "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", "requires": { - "postcss": "^7.0.14", + "postcss": "^7.0.17", "postcss-values-parser": "^2.0.1" + }, + "dependencies": { + "postcss": { + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", + "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, "postcss-custom-selectors": { @@ -12831,11 +13211,11 @@ } }, "postcss-initial": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.0.tgz", - "integrity": "sha512-WzrqZ5nG9R9fUtrA+we92R4jhVvEB32IIRTzfIG/PLL8UV4CvbF1ugTEHEFX6vWxl41Xt5RTCJPEZkuWzrOM+Q==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.1.tgz", + "integrity": "sha512-I2Sz83ZSHybMNh02xQDK609lZ1/QOyYeuizCjzEhlMgeV/HcDJapQiH4yTqLjZss0X6/6VvKFXUeObaHpJoINw==", "requires": { - "lodash.template": "^4.2.4", + "lodash.template": "^4.5.0", "postcss": "^7.0.2" } }, @@ -13027,9 +13407,9 @@ } }, "postcss-nesting": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.0.tgz", - "integrity": "sha512-WSsbVd5Ampi3Y0nk/SKr5+K34n52PqMqEfswu6RtU4r7wA8vSD+gM8/D9qq4aJkHImwn1+9iEFTbjoWsQeqtaQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz", + "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==", "requires": { "postcss": "^7.0.2" } @@ -13171,26 +13551,26 @@ } }, "postcss-preset-env": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.6.0.tgz", - "integrity": "sha512-I3zAiycfqXpPIFD6HXhLfWXIewAWO8emOKz+QSsxaUZb9Dp8HbF5kUf+4Wy/AxR33o+LRoO8blEWCHth0ZsCLA==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz", + "integrity": "sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg==", "requires": { - "autoprefixer": "^9.4.9", - "browserslist": "^4.4.2", - "caniuse-lite": "^1.0.30000939", + "autoprefixer": "^9.6.1", + "browserslist": "^4.6.4", + "caniuse-lite": "^1.0.30000981", "css-blank-pseudo": "^0.1.4", "css-has-pseudo": "^0.10.0", "css-prefers-color-scheme": "^3.1.1", - "cssdb": "^4.3.0", - "postcss": "^7.0.14", + "cssdb": "^4.4.0", + "postcss": "^7.0.17", "postcss-attribute-case-insensitive": "^4.0.1", "postcss-color-functional-notation": "^2.0.1", "postcss-color-gray": "^5.0.0", - "postcss-color-hex-alpha": "^5.0.2", + "postcss-color-hex-alpha": "^5.0.3", "postcss-color-mod-function": "^3.0.3", "postcss-color-rebeccapurple": "^4.0.1", - "postcss-custom-media": "^7.0.7", - "postcss-custom-properties": "^8.0.9", + "postcss-custom-media": "^7.0.8", + "postcss-custom-properties": "^8.0.11", "postcss-custom-selectors": "^5.1.2", "postcss-dir-pseudo-class": "^5.0.0", "postcss-double-position-gradients": "^1.0.0", @@ -13212,6 +13592,83 @@ "postcss-replace-overflow-wrap": "^3.0.0", "postcss-selector-matches": "^4.0.0", "postcss-selector-not": "^4.0.0" + }, + "dependencies": { + "autoprefixer": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.1.tgz", + "integrity": "sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==", + "requires": { + "browserslist": "^4.6.3", + "caniuse-lite": "^1.0.30000980", + "chalk": "^2.4.2", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.17", + "postcss-value-parser": "^4.0.0" + } + }, + "browserslist": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.6.tgz", + "integrity": "sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA==", + "requires": { + "caniuse-lite": "^1.0.30000984", + "electron-to-chromium": "^1.3.191", + "node-releases": "^1.1.25" + } + }, + "caniuse-lite": { + "version": "1.0.30000989", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz", + "integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==" + }, + "electron-to-chromium": { + "version": "1.3.235", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.235.tgz", + "integrity": "sha512-xNabEDbMIKPLQd6xgv4nyyeMaWXIKSJr6G51ZhUemHhbz6kjZAYcygA8CvfEcMF+Mt5eLmDWaLmfSOWdQxzBVQ==" + }, + "node-releases": { + "version": "1.1.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.27.tgz", + "integrity": "sha512-9iXUqHKSGo6ph/tdXVbHFbhRVQln4ZDTIBJCzsa90HimnBYc5jw8RWYt4wBYFHehGyC3koIz5O4mb2fHrbPOuA==", + "requires": { + "semver": "^5.3.0" + } + }, + "postcss": { + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", + "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "postcss-value-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", + "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, "postcss-pseudo-class-any-link": { @@ -13354,9 +13811,9 @@ "dev": true }, "pretty-bytes": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.2.0.tgz", - "integrity": "sha512-ujANBhiUsl9AhREUDUEY1GPOharMGm8x8juS7qOHybcLi7XsKfrYQ88hSly1l2i0klXHTDYrlL8ihMCG55Dc3w==" + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.3.0.tgz", + "integrity": "sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg==" }, "pretty-error": { "version": "2.1.1", @@ -13368,11 +13825,11 @@ } }, "pretty-format": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.8.0.tgz", - "integrity": "sha512-P952T7dkrDEplsR+TuY7q3VXDae5Sr7zmQb12JU/NDQa/3CH7/QW0yvqLcGN6jL+zQFKaoJcPc+yJxMTGmosqw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", "requires": { - "@jest/types": "^24.8.0", + "@jest/types": "^24.9.0", "ansi-regex": "^4.0.0", "ansi-styles": "^3.2.0", "react-is": "^16.8.4" @@ -13420,9 +13877,9 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, "promise": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", - "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.3.tgz", + "integrity": "sha512-HeRDUL1RJiLhyA0/grn+PTShlBAcLuh/1BJGtrvjwbvRDCTLLMEz9rOGCV+R3vHY4MixIuoMEd9Yq/XvsTPcjw==", "requires": { "asap": "~2.0.6" } @@ -13455,12 +13912,12 @@ } }, "prompts": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.1.0.tgz", - "integrity": "sha512-+x5TozgqYdOwWsQFZizE/Tra3fKvAoy037kOyU6cgz84n8f6zxngLOV4O32kTwt9FcLCxAqw0P/c8rOr9y+Gfg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", + "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==", "requires": { - "kleur": "^3.0.2", - "sisteransi": "^1.0.0" + "kleur": "^3.0.3", + "sisteransi": "^1.0.3" } }, "prop-types": { @@ -13477,6 +13934,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.1.0.tgz", "integrity": "sha512-tODH6R3+SwTkAQckSp2S9xyYX8dEKYkeXw+4TmJzTxnNzd6mQPu1OD4f9zPrvw/Rm4wpPgI+Zp63mNSGNzUgHg==", + "dev": true, "requires": { "xtend": "^4.0.1" } @@ -13669,30 +14127,29 @@ "prop-types": "^15.6.2" } }, - "react-apollo": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/react-apollo/-/react-apollo-3.0.1.tgz", - "integrity": "sha512-2hsSYBfxPqPquS8CupWq+U+6XuDfr/Rr1ssXwfOTYe5gCyTthdUqafIm+pyStur9X2W4ZNQMFyjVicsPNq2tnA==", - "dev": true, - "requires": { - "@apollo/react-common": "^3.0.1", - "@apollo/react-components": "^3.0.1", - "@apollo/react-hoc": "^3.0.1", - "@apollo/react-hooks": "^3.0.1", - "@apollo/react-ssr": "^3.0.1" - } - }, "react-app-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.1.tgz", - "integrity": "sha512-LbVpT1NdzTdDDs7xEZdebjDrqsvKi5UyVKUQqtTYYNyC1JJYVAwNQWe4ybWvoT2V2WW9PGVO2u5Y6aVj4ER/Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.2.tgz", + "integrity": "sha512-yZcpLnIr0FOIzrOOz9JC37NWAWEuCaQWmYn9EWjEzlCW4cOmA5MkT5L3iP8QuUeFnoqVCTJgjIWYbXEJgNXhGA==", "requires": { - "core-js": "3.0.1", + "core-js": "3.1.4", "object-assign": "4.1.1", - "promise": "8.0.2", + "promise": "8.0.3", "raf": "3.4.1", - "regenerator-runtime": "0.13.2", + "regenerator-runtime": "0.13.3", "whatwg-fetch": "3.0.0" + }, + "dependencies": { + "core-js": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.4.tgz", + "integrity": "sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ==" + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + } } }, "react-clientside-effect": { @@ -13722,6 +14179,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.0.1.tgz", "integrity": "sha512-pnaeMo/Pxel8aZpxk1WwxT3uXxM3tEwYvsjCYn5R7gNxjhN1auowdcLDzFB8kr7rafAj2rxmvfic/fbac5CzwQ==", + "dev": true, "requires": { "@babel/code-frame": "7.0.0", "address": "1.0.3", @@ -13753,12 +14211,14 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true }, "browserslist": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.5.4.tgz", "integrity": "sha512-rAjx494LMjqKnMPhFkuLmLp8JWEX0o8ADTGeAbOqaF+XCvYLreZrG5uVjnPBlAQ8REZK4pzXGvp0bWgrFtKaag==", + "dev": true, "requires": { "caniuse-lite": "^1.0.30000955", "electron-to-chromium": "^1.3.122", @@ -13769,6 +14229,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz", "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==", + "dev": true, "requires": { "ansi-escapes": "^3.2.0", "chalk": "^2.4.2", @@ -13789,6 +14250,7 @@ "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" } @@ -13869,7 +14331,8 @@ "react-error-overlay": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-5.1.6.tgz", - "integrity": "sha512-X1Y+0jR47ImDVr54Ab6V9eGk0Hnu7fVWGeHQSOXHf/C2pF9c6uy3gef8QUeuUiWlNb0i08InPSE5a/KJzNzw1Q==" + "integrity": "sha512-X1Y+0jR47ImDVr54Ab6V9eGk0Hnu7fVWGeHQSOXHf/C2pF9c6uy3gef8QUeuUiWlNb0i08InPSE5a/KJzNzw1Q==", + "dev": true }, "react-fast-compare": { "version": "2.0.4", @@ -14028,190 +14491,774 @@ } }, "react-scripts": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.0.1.tgz", - "integrity": "sha512-LKEjBhVpEB+c312NeJhzF+NATxF7JkHNr5GhtwMeRS1cMeLElMeIu8Ye7WGHtDP7iz7ra4ryy48Zpo6G/cwWUw==", - "requires": { - "@babel/core": "7.4.3", - "@svgr/webpack": "4.1.0", - "@typescript-eslint/eslint-plugin": "1.6.0", - "@typescript-eslint/parser": "1.6.0", - "babel-eslint": "10.0.1", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.1.1.tgz", + "integrity": "sha512-dbjTG9vJC61OI62hIswQYg5xHvwlxDTH6QXz6ICEuA5AqkFQWk1LKl76sk8fVL2WsyumbBc4FErALwKcEV2vNA==", + "requires": { + "@babel/core": "7.5.5", + "@svgr/webpack": "4.3.2", + "@typescript-eslint/eslint-plugin": "1.13.0", + "@typescript-eslint/parser": "1.13.0", + "babel-eslint": "10.0.2", "babel-jest": "^24.8.0", - "babel-loader": "8.0.5", - "babel-plugin-named-asset-import": "^0.3.2", - "babel-preset-react-app": "^9.0.0", + "babel-loader": "8.0.6", + "babel-plugin-named-asset-import": "^0.3.3", + "babel-preset-react-app": "^9.0.1", "camelcase": "^5.2.0", "case-sensitive-paths-webpack-plugin": "2.2.0", "css-loader": "2.1.1", "dotenv": "6.2.0", "dotenv-expand": "4.2.0", - "eslint": "^5.16.0", - "eslint-config-react-app": "^4.0.1", - "eslint-loader": "2.1.2", - "eslint-plugin-flowtype": "2.50.1", - "eslint-plugin-import": "2.16.0", - "eslint-plugin-jsx-a11y": "6.2.1", - "eslint-plugin-react": "7.12.4", - "eslint-plugin-react-hooks": "^1.5.0", + "eslint": "^6.1.0", + "eslint-config-react-app": "^5.0.1", + "eslint-loader": "2.2.1", + "eslint-plugin-flowtype": "3.13.0", + "eslint-plugin-import": "2.18.2", + "eslint-plugin-jsx-a11y": "6.2.3", + "eslint-plugin-react": "7.14.3", + "eslint-plugin-react-hooks": "^1.6.1", "file-loader": "3.0.1", "fs-extra": "7.0.1", - "fsevents": "2.0.6", + "fsevents": "2.0.7", "html-webpack-plugin": "4.0.0-beta.5", "identity-obj-proxy": "3.0.0", "is-wsl": "^1.1.0", - "jest": "24.7.1", + "jest": "24.8.0", "jest-environment-jsdom-fourteen": "0.1.0", - "jest-resolve": "24.7.1", - "jest-watch-typeahead": "0.3.0", + "jest-resolve": "24.8.0", + "jest-watch-typeahead": "0.3.1", "mini-css-extract-plugin": "0.5.0", - "optimize-css-assets-webpack-plugin": "5.0.1", - "pnp-webpack-plugin": "1.2.1", + "optimize-css-assets-webpack-plugin": "5.0.3", + "pnp-webpack-plugin": "1.5.0", "postcss-flexbugs-fixes": "4.1.0", "postcss-loader": "3.0.0", "postcss-normalize": "7.0.1", - "postcss-preset-env": "6.6.0", + "postcss-preset-env": "6.7.0", "postcss-safe-parser": "4.0.1", - "react-app-polyfill": "^1.0.1", - "react-dev-utils": "^9.0.1", - "resolve": "1.10.0", - "sass-loader": "7.1.0", - "semver": "6.0.0", - "style-loader": "0.23.1", - "terser-webpack-plugin": "1.2.3", + "react-app-polyfill": "^1.0.2", + "react-dev-utils": "^9.0.3", + "resolve": "1.12.0", + "resolve-url-loader": "3.1.0", + "sass-loader": "7.2.0", + "semver": "6.3.0", + "style-loader": "1.0.0", + "terser-webpack-plugin": "1.4.1", "ts-pnp": "1.1.2", - "url-loader": "1.1.2", - "webpack": "4.29.6", + "url-loader": "2.1.0", + "webpack": "4.39.1", "webpack-dev-server": "3.2.1", "webpack-manifest-plugin": "2.0.4", - "workbox-webpack-plugin": "4.2.0" + "workbox-webpack-plugin": "4.3.1" }, "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "requires": { + "@babel/highlight": "^7.0.0" + } + }, "@babel/core": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.3.tgz", - "integrity": "sha512-oDpASqKFlbspQfzAE7yaeTmdljSH2ADIvBlb0RwbStltTuWa0+7CCI1fYVINNv9saHPa1W7oaKeuNuKj+RQCvA==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.5.5.tgz", + "integrity": "sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg==", "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.4.0", - "@babel/helpers": "^7.4.3", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.5.5", + "@babel/helpers": "^7.5.5", + "@babel/parser": "^7.5.5", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5", "convert-source-map": "^1.1.0", "debug": "^4.1.0", "json5": "^2.1.0", - "lodash": "^4.17.11", + "lodash": "^4.17.13", "resolve": "^1.3.2", "semver": "^5.4.1", "source-map": "^0.5.0" }, "dependencies": { "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" } } }, - "babel-loader": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.5.tgz", - "integrity": "sha512-NTnHnVRd2JnRqPC0vW+iOQWU5pchDbYXsG2E6DMXEpMfUcQKclF9gmf3G3ZMhzG7IG9ji4coL0cm+FxeWxDpnw==", + "@babel/generator": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.5.tgz", + "integrity": "sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==", "requires": { - "find-cache-dir": "^2.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1", - "util.promisify": "^1.0.0" + "@babel/types": "^7.5.5", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" } }, - "clone-deep": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", - "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "@babel/helper-create-class-features-plugin": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.5.5.tgz", + "integrity": "sha512-ZsxkyYiRA7Bg+ZTRpPvB6AbOFKTFFK4LrvTet8lInm0V468MWCaSYJE+I7v2z2r8KNLtYiV+K5kTCnR7dvyZjg==", "requires": { - "for-own": "^1.0.0", - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.0", - "shallow-clone": "^1.0.0" + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-member-expression-to-functions": "^7.5.5", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.5.5", + "@babel/helper-split-export-declaration": "^7.4.4" } }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "@babel/helper-define-map": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz", + "integrity": "sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg==", "requires": { - "for-in": "^1.0.1" + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.5.5", + "lodash": "^4.17.13" } }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "@babel/helper-member-expression-to-functions": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz", + "integrity": "sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA==", + "requires": { + "@babel/types": "^7.5.5" + } }, - "sass-loader": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", - "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", - "requires": { - "clone-deep": "^2.0.1", - "loader-utils": "^1.0.1", - "lodash.tail": "^4.1.1", - "neo-async": "^2.5.0", - "pify": "^3.0.0", - "semver": "^5.5.0" - }, - "dependencies": { - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" - } + "@babel/helper-replace-supers": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz", + "integrity": "sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg==", + "requires": { + "@babel/helper-member-expression-to-functions": "^7.5.5", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5" } }, - "shallow-clone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", - "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "@babel/helpers": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.5.5.tgz", + "integrity": "sha512-nRq2BUhxZFnfEn/ciJuhklHvFOqjJUD5wpx+1bxUF2axL9C+v4DE/dmp5sT2dKnpOs4orZWzpAZqlCy8QqE/7g==", "requires": { - "is-extendable": "^0.1.1", - "kind-of": "^5.0.0", - "mixin-object": "^2.0.1" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5" } - } - } - }, - "react-select": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-2.4.4.tgz", - "integrity": "sha512-C4QPLgy9h42J/KkdrpVxNmkY6p4lb49fsrbDk/hRcZpX7JvZPNb6mGj+c5SzyEtBv1DmQ9oPH4NmhAFvCrg8Jw==", - "dev": true, - "requires": { - "classnames": "^2.2.5", - "emotion": "^9.1.2", - "memoize-one": "^5.0.0", - "prop-types": "^15.6.0", - "raf": "^3.4.0", - "react-input-autosize": "^2.2.1", - "react-transition-group": "^2.2.1" - } - }, - "react-syntax-highlighter": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-8.1.0.tgz", - "integrity": "sha512-G2bkZxmF3VOa4atEdXIDSfwwCqjw6ZQX5znfTaHcErA1WqHIS0o6DaSCDKFPVaOMXQEB9Hf1UySYQvuJmV8CXg==", - "dev": true, - "requires": { - "babel-runtime": "^6.18.0", - "highlight.js": "~9.12.0", + }, + "@babel/parser": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz", + "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==" + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.5.tgz", + "integrity": "sha512-AF79FsnWFxjlaosgdi421vmYG6/jg79bVD0dpD44QdgobzHKuLZ6S3vl8la9qIeSwGi8i1fS0O1mfuDAAdo1/A==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.5.5", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.4.4.tgz", + "integrity": "sha512-z7MpQz3XC/iQJWXH9y+MaWcLPNSMY9RQSthrLzak8R8hCj0fuyNk+Dzi9kfNe/JxxlWQ2g7wkABbgWjW36MTcw==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-decorators": "^7.2.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz", + "integrity": "sha512-F2DxJJSQ7f64FyTVl5cw/9MWn6naXGdk3Q3UhDbFEEHv+EilCPoeRD3Zh/Utx1CJz4uyKlQ4uH+bJPbEhMV7Zw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz", + "integrity": "sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.5.5.tgz", + "integrity": "sha512-82A3CLRRdYubkG85lKwhZB0WZoHxLGsJdux/cOVaJCJpvYFl1LVzAIFyRsa7CvXqW8rBM4Zf3Bfn8PHt5DP0Sg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.13" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz", + "integrity": "sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.5.5", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.5.5", + "@babel/helper-split-export-declaration": "^7.4.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz", + "integrity": "sha512-YbYgbd3TryYYLGyC7ZR+Tq8H/+bCmwoaxHfJHupom5ECstzbRLTch6gOQbhEY9Z4hiCNHEURgq06ykFv9JZ/QQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz", + "integrity": "sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.4.4.tgz", + "integrity": "sha512-WyVedfeEIILYEaWGAUWzVNyqG4sfsNooMhXWsu/YzOvVGcsnPb5PguysjJqI3t3qiaYj0BR8T2f5njdjTGe44Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.2.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz", + "integrity": "sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==", + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.5.0.tgz", + "integrity": "sha512-xmHq0B+ytyrWJvQTc5OWAC4ii6Dhr0s22STOoydokG51JjWhyYo5mRPXoi+ZmtHQhZZwuXNN+GG5jy5UZZJxIQ==", + "requires": { + "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz", + "integrity": "sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==", + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz", + "integrity": "sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.5.5" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.5.5.tgz", + "integrity": "sha512-6Xmeidsun5rkwnGfMOp6/z9nSzWpHFNVr2Jx7kwoq4mVatQfQx5S56drBgEHF+XQbKOdIaOiMIINvp/kAwMN+w==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "@babel/runtime": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz", + "integrity": "sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "@babel/traverse": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.5.tgz", + "integrity": "sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==", + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.5.5", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.5.5", + "@babel/types": "^7.5.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.1.tgz", + "integrity": "sha512-p6z6JJroP989jHWcuraeWpzdejehTmLUpyC9smhTBWyPN0VVGe2phbYxpPTV7Vh8XzmFrcG55idrnfWn/2oQEw==" + }, + "@svgr/babel-preset": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-4.3.1.tgz", + "integrity": "sha512-rPFKLmyhlh6oeBv3j2vEAj2nd2QbWqpoJLKzBLjwQVt+d9aeXajVaPNEqrES2spjXKR4OxfgSs7U0NtmAEkr0Q==", + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^4.2.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^4.2.0", + "@svgr/babel-plugin-svg-dynamic-title": "^4.3.1", + "@svgr/babel-plugin-svg-em-dimensions": "^4.2.0", + "@svgr/babel-plugin-transform-react-native-svg": "^4.2.0", + "@svgr/babel-plugin-transform-svg-component": "^4.2.0" + } + }, + "@svgr/core": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-4.3.2.tgz", + "integrity": "sha512-N+tP5CLFd1hP9RpO83QJPZY3NL8AtrdqNbuhRgBkjE/49RnMrrRsFm1wY8pueUfAGvzn6tSXUq29o6ah8RuR5w==", + "requires": { + "@svgr/plugin-jsx": "^4.3.2", + "camelcase": "^5.3.1", + "cosmiconfig": "^5.2.1" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.3.2.tgz", + "integrity": "sha512-JioXclZGhFIDL3ddn4Kiq8qEqYM2PyDKV0aYno8+IXTLuYt6TOgHUbUAAFvqtb0Xn37NwP0BTHglejFoYr8RZg==", + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@svgr/plugin-jsx": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-4.3.2.tgz", + "integrity": "sha512-+1GW32RvmNmCsOkMoclA/TppNjHPLMnNZG3/Ecscxawp051XJ2MkO09Hn11VcotdC2EPrDfT8pELGRo+kbZ1Eg==", + "requires": { + "@babel/core": "^7.4.5", + "@svgr/babel-preset": "^4.3.1", + "@svgr/hast-util-to-babel-ast": "^4.3.2", + "svg-parser": "^2.0.0" + } + }, + "@svgr/plugin-svgo": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz", + "integrity": "sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w==", + "requires": { + "cosmiconfig": "^5.2.1", + "merge-deep": "^3.0.2", + "svgo": "^1.2.2" + } + }, + "@svgr/webpack": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-4.3.2.tgz", + "integrity": "sha512-F3VE5OvyOWBEd2bF7BdtFRyI6E9it3mN7teDw0JQTlVtc4HZEYiiLSl+Uf9Uub6IYHVGc+qIrxxDyeedkQru2w==", + "requires": { + "@babel/core": "^7.4.5", + "@babel/plugin-transform-react-constant-elements": "^7.0.0", + "@babel/preset-env": "^7.4.5", + "@babel/preset-react": "^7.0.0", + "@svgr/core": "^4.3.2", + "@svgr/plugin-jsx": "^4.3.2", + "@svgr/plugin-svgo": "^4.3.1", + "loader-utils": "^1.2.3" + } + }, + "address": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.0.tgz", + "integrity": "sha512-4diPfzWbLEIElVG4AnqP+00SULlPzNuyJFNnmMrLgyaxG6tZXJ1sn7mjBu4fHrJE+Yp/jgylOweJn2xsLMFggQ==" + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "babel-loader": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", + "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", + "requires": { + "find-cache-dir": "^2.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "pify": "^4.0.1" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", + "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-macros": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.6.1.tgz", + "integrity": "sha512-6W2nwiXme6j1n2erPOnmRiWfObUhWH7Qw1LMi9XZy8cj+KtESu3T6asZvtk5bMQQjX8te35o7CFueiSdL/2NmQ==", + "requires": { + "@babel/runtime": "^7.4.2", + "cosmiconfig": "^5.2.0", + "resolve": "^1.10.0" + } + }, + "babel-plugin-named-asset-import": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.3.tgz", + "integrity": "sha512-1XDRysF4894BUdMChT+2HHbtJYiO7zx5Be7U6bT8dISy7OdyETMGIAQBMPQCsY1YRf0xcubwnKKaDr5bk15JTA==" + }, + "babel-preset-react-app": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-9.0.1.tgz", + "integrity": "sha512-v7MeY+QxdBhM9oU5uOQCIHLsErYkEbbjctXsb10II+KAnttbe0rvprvP785dRxfa9dI4ZbsGXsRU07Qdi5BtOw==", + "requires": { + "@babel/core": "7.5.5", + "@babel/plugin-proposal-class-properties": "7.5.5", + "@babel/plugin-proposal-decorators": "7.4.4", + "@babel/plugin-proposal-object-rest-spread": "7.5.5", + "@babel/plugin-syntax-dynamic-import": "7.2.0", + "@babel/plugin-transform-destructuring": "7.5.0", + "@babel/plugin-transform-flow-strip-types": "7.4.4", + "@babel/plugin-transform-react-display-name": "7.2.0", + "@babel/plugin-transform-runtime": "7.5.5", + "@babel/preset-env": "7.5.5", + "@babel/preset-react": "7.0.0", + "@babel/preset-typescript": "7.3.3", + "@babel/runtime": "7.5.5", + "babel-plugin-dynamic-import-node": "2.3.0", + "babel-plugin-macros": "2.6.1", + "babel-plugin-transform-react-remove-prop-types": "0.4.24" + }, + "dependencies": { + "@babel/preset-env": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.5.5.tgz", + "integrity": "sha512-GMZQka/+INwsMz1A5UEql8tG015h5j/qjptpKY2gJ7giy8ohzU710YciJB5rcKsWGWHiW3RUnHib0E5/m3Tp3A==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-dynamic-import": "^7.5.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.5.5", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.5.0", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.5.5", + "@babel/plugin-transform-classes": "^7.5.5", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.5.0", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/plugin-transform-duplicate-keys": "^7.5.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.4.4", + "@babel/plugin-transform-function-name": "^7.4.4", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-member-expression-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.5.0", + "@babel/plugin-transform-modules-commonjs": "^7.5.0", + "@babel/plugin-transform-modules-systemjs": "^7.5.0", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.5", + "@babel/plugin-transform-new-target": "^7.4.4", + "@babel/plugin-transform-object-super": "^7.5.5", + "@babel/plugin-transform-parameters": "^7.4.4", + "@babel/plugin-transform-property-literals": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.4.5", + "@babel/plugin-transform-reserved-words": "^7.2.0", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.4.4", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.4.4", + "@babel/types": "^7.5.5", + "browserslist": "^4.6.0", + "core-js-compat": "^3.1.1", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "caniuse-lite": { + "version": "1.0.30000989", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz", + "integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==" + }, + "electron-to-chromium": { + "version": "1.3.235", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.235.tgz", + "integrity": "sha512-xNabEDbMIKPLQd6xgv4nyyeMaWXIKSJr6G51ZhUemHhbz6kjZAYcygA8CvfEcMF+Mt5eLmDWaLmfSOWdQxzBVQ==" + }, + "fork-ts-checker-webpack-plugin": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-1.5.0.tgz", + "integrity": "sha512-zEhg7Hz+KhZlBhILYpXy+Beu96gwvkROWJiTXOCyOOMMrdBIRPvsBpBqgTI4jfJGrJXcqGwJR8zsBGDmzY0jsA==", + "requires": { + "babel-code-frame": "^6.22.0", + "chalk": "^2.4.1", + "chokidar": "^2.0.4", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + } + }, + "inquirer": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz", + "integrity": "sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==", + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + } + }, + "is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" + }, + "node-releases": { + "version": "1.1.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.27.tgz", + "integrity": "sha512-9iXUqHKSGo6ph/tdXVbHFbhRVQln4ZDTIBJCzsa90HimnBYc5jw8RWYt4wBYFHehGyC3koIz5O4mb2fHrbPOuA==", + "requires": { + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "react-dev-utils": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.0.3.tgz", + "integrity": "sha512-OyInhcwsvycQ3Zr2pQN+HV4gtRXrky5mJXIy4HnqrWa+mI624xfYfqGuC9dYbxp4Qq3YZzP8GSGQjv0AgNU15w==", + "requires": { + "@babel/code-frame": "7.5.5", + "address": "1.1.0", + "browserslist": "4.6.6", + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "1.0.5", + "filesize": "3.6.1", + "find-up": "3.0.0", + "fork-ts-checker-webpack-plugin": "1.5.0", + "global-modules": "2.0.0", + "globby": "8.0.2", + "gzip-size": "5.1.1", + "immer": "1.10.0", + "inquirer": "6.5.0", + "is-root": "2.1.0", + "loader-utils": "1.2.3", + "open": "^6.3.0", + "pkg-up": "2.0.0", + "react-error-overlay": "^6.0.1", + "recursive-readdir": "2.2.2", + "shell-quote": "1.6.1", + "sockjs-client": "1.3.0", + "strip-ansi": "5.2.0", + "text-table": "0.2.0" + }, + "dependencies": { + "browserslist": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.6.tgz", + "integrity": "sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA==", + "requires": { + "caniuse-lite": "^1.0.30000984", + "electron-to-chromium": "^1.3.191", + "node-releases": "^1.1.25" + } + } + } + }, + "react-error-overlay": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.1.tgz", + "integrity": "sha512-V9yoTr6MeZXPPd4nV/05eCBvGH9cGzc52FN8fs0O0TVQ3HYYf1n7EgZVtHbldRq5xU9zEzoXIITjYNIfxDDdUw==" + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "schema-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.1.0.tgz", + "integrity": "sha512-g6SViEZAfGNrToD82ZPUjq52KUPDYc+fN5+g6Euo5mLokl/9Yx14z0Cu4RR1m55HtBXejO0sBt+qw79axN+Fiw==", + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "style-loader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.0.0.tgz", + "integrity": "sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw==", + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.0.1" + } + }, + "url-loader": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-2.1.0.tgz", + "integrity": "sha512-kVrp/8VfEm5fUt+fl2E0FQyrpmOYgMEkBsv8+UDP1wFhszECq5JyGF33I7cajlVY90zRZ6MyfgKXngLvHYZX8A==", + "requires": { + "loader-utils": "^1.2.3", + "mime": "^2.4.4", + "schema-utils": "^2.0.0" + } + } + } + }, + "react-select": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-2.4.4.tgz", + "integrity": "sha512-C4QPLgy9h42J/KkdrpVxNmkY6p4lb49fsrbDk/hRcZpX7JvZPNb6mGj+c5SzyEtBv1DmQ9oPH4NmhAFvCrg8Jw==", + "dev": true, + "requires": { + "classnames": "^2.2.5", + "emotion": "^9.1.2", + "memoize-one": "^5.0.0", + "prop-types": "^15.6.0", + "raf": "^3.4.0", + "react-input-autosize": "^2.2.1", + "react-transition-group": "^2.2.1" + } + }, + "react-syntax-highlighter": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-8.1.0.tgz", + "integrity": "sha512-G2bkZxmF3VOa4atEdXIDSfwwCqjw6ZQX5znfTaHcErA1WqHIS0o6DaSCDKFPVaOMXQEB9Hf1UySYQvuJmV8CXg==", + "dev": true, + "requires": { + "babel-runtime": "^6.18.0", + "highlight.js": "~9.12.0", "lowlight": "~1.9.1", "prismjs": "^1.8.4", "refractor": "^2.4.1" @@ -14430,6 +15477,11 @@ "safe-regex": "^1.1.0" } }, + "regex-parser": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.10.tgz", + "integrity": "sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA==" + }, "regexp-tree": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.10.tgz", @@ -14486,6 +15538,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-6.0.0.tgz", "integrity": "sha512-V2OjMD0xcSt39G4uRdMTqDXXm6HwkUbLMDayYKA/d037j8/OtVSQ+tqKwYWOuyBeoCs/3clXRe30VUjeMDTBSA==", + "dev": true, "requires": { "hast-util-from-parse5": "^5.0.0", "parse5": "^5.0.0", @@ -14571,7 +15624,8 @@ "replace-ext": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true }, "request": { "version": "2.88.0", @@ -14649,11 +15703,6 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, - "requireindex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==" - }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -14691,6 +15740,53 @@ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" }, + "resolve-url-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.0.tgz", + "integrity": "sha512-2QcrA+2QgVqsMJ1Hn5NnJXIGCX1clQ1F6QJTqOeiaDw9ACo1G2k+8/shq3mtqne03HOFyskAClqfxKyFBriXZg==", + "requires": { + "adjust-sourcemap-loader": "2.0.0", + "camelcase": "5.0.0", + "compose-function": "3.0.3", + "convert-source-map": "1.6.0", + "es6-iterator": "2.0.3", + "loader-utils": "1.2.3", + "postcss": "7.0.14", + "rework": "1.0.1", + "rework-visit": "1.0.0", + "source-map": "0.6.1" + }, + "dependencies": { + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==" + }, + "postcss": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", + "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -14705,6 +15801,27 @@ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" }, + "rework": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz", + "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=", + "requires": { + "convert-source-map": "^0.3.3", + "css": "^2.0.0" + }, + "dependencies": { + "convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=" + } + } + }, + "rework-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz", + "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=" + }, "rgb-regex": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", @@ -14733,9 +15850,9 @@ } }, "rsvp": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz", - "integrity": "sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA==" + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==" }, "run-async": { "version": "2.3.0", @@ -15025,7 +16142,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.2.0.tgz", "integrity": "sha512-h8yUWaWtsbuIiOCgR9fd9c2lRXZ2uG+h8Dzg/AGNj+Hg/3TO8+BBAW9mEP+mh8ei+qBKqSJ0F1FLlYjNBc61OA==", - "dev": true, "requires": { "clone-deep": "^4.0.1", "loader-utils": "^1.0.1", @@ -15038,7 +16154,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, "requires": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -15048,26 +16163,22 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" }, "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" }, "shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, "requires": { "kind-of": "^6.0.2" } @@ -15080,11 +16191,11 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "saxes": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.9.tgz", - "integrity": "sha512-FZeKhJglhJHk7eWG5YM0z46VHmI3KJpMBAQm3xa9meDvd+wevB5GuBB0wc0exPInZiBBHqi00DbS8AcvCGCFMw==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", + "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", "requires": { - "xmlchars": "^1.3.1" + "xmlchars": "^2.1.1" } }, "scheduler": { @@ -15456,9 +16567,9 @@ } }, "sisteransi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.0.tgz", - "integrity": "sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", + "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==" }, "slash": { "version": "2.0.0", @@ -15677,7 +16788,8 @@ "space-separated-tokens": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.4.tgz", - "integrity": "sha512-UyhMSmeIqZrQn2UdjYpxEkwY9JUrn8pP+7L4f91zRzOQuI8MF1FGLfYU9DKCYeLdo7LXMxwrX5zKFy7eeeVHuA==" + "integrity": "sha512-UyhMSmeIqZrQn2UdjYpxEkwY9JUrn8pP+7L4f91zRzOQuI8MF1FGLfYU9DKCYeLdo7LXMxwrX5zKFy7eeeVHuA==", + "dev": true }, "spdx-correct": { "version": "3.1.0", @@ -15708,9 +16820,9 @@ "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==" }, "spdy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.0.tgz", - "integrity": "sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", + "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", "requires": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -15984,9 +17096,9 @@ } }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==" }, "style-equal": { "version": "1.0.0", @@ -15997,6 +17109,7 @@ "version": "0.23.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "dev": true, "requires": { "loader-utils": "^1.1.0", "schema-utils": "^1.0.0" @@ -16044,6 +17157,11 @@ "has-flag": "^3.0.0" } }, + "svg-parser": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.2.tgz", + "integrity": "sha512-1gtApepKFweigFZj3sGO8KT8LvVZK8io146EzXrpVuWCDAbISz/yMucco3hWTkpZNoPabM+dnMOpy6Swue68Zg==" + }, "svgo": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.2.2.tgz", @@ -16071,9 +17189,9 @@ "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" }, "symbol-tree": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", - "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=" + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "symbol.prototype.description": { "version": "1.0.0", @@ -16085,21 +17203,37 @@ } }, "table": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.0.tgz", - "integrity": "sha512-nHFDrxmbrkU7JAFKqKbDJXfzrX2UBsWmrieXFTGxiI5e4ncg3VqsZeI4EzNmX0ncp4XNGVeoxIWJXfCIXwrsvw==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "requires": { - "ajv": "^6.9.1", - "lodash": "^4.17.11", + "ajv": "^6.10.2", + "lodash": "^4.17.14", "slice-ansi": "^2.1.0", "string-width": "^3.0.0" }, "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -16211,13 +17345,13 @@ } }, "terser": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", - "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.1.4.tgz", + "integrity": "sha512-+ZwXJvdSwbd60jG0Illav0F06GDJF0R4ydZ21Q3wGAFKoBGyJGo34F63vzJHgvYxc1ukOtIjvwEvl9MkjzM6Pg==", "requires": { - "commander": "^2.19.0", + "commander": "^2.20.0", "source-map": "~0.6.1", - "source-map-support": "~0.5.10" + "source-map-support": "~0.5.12" }, "dependencies": { "source-map": { @@ -16228,24 +17362,34 @@ } }, "terser-webpack-plugin": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz", - "integrity": "sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz", + "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==", "requires": { - "cacache": "^11.0.2", - "find-cache-dir": "^2.0.0", + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", "schema-utils": "^1.0.0", - "serialize-javascript": "^1.4.0", + "serialize-javascript": "^1.7.0", "source-map": "^0.6.1", - "terser": "^3.16.1", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" }, "dependencies": { "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } } } }, @@ -16416,7 +17560,8 @@ "trough": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.4.tgz", - "integrity": "sha512-tdzBRDGWcI1OpPVmChbdSKhvSVurznZ8X36AYURAcl+0o2ldlCY2XPzyXNNxwJwwyIU+rIglTCG4kxtNKBQH7Q==" + "integrity": "sha512-tdzBRDGWcI1OpPVmChbdSKhvSVurznZ8X36AYURAcl+0o2ldlCY2XPzyXNNxwJwwyIU+rIglTCG4kxtNKBQH7Q==", + "dev": true }, "true-case-path": { "version": "1.0.3", @@ -16446,9 +17591,9 @@ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" }, "tsutils": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.14.0.tgz", - "integrity": "sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==", + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", "requires": { "tslib": "^1.8.1" } @@ -16471,6 +17616,11 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "type": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/type/-/type-1.0.3.tgz", + "integrity": "sha512-51IMtNfVcee8+9GJvj0spSuFcZHe9vSib6Xtgsny1Km9ugyz2mbS08I3rsUIRYgJohFRFU1160sgRodYz378Hg==" + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -16605,6 +17755,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/unified/-/unified-7.1.0.tgz", "integrity": "sha512-lbk82UOIGuCEsZhPj8rNAkXSDXd6p0QLzIuSsCdxrqnqU56St4eyOB+AlXsVgVeRmetPTYydIuvFfpDIed8mqw==", + "dev": true, "requires": { "@types/unist": "^2.0.0", "@types/vfile": "^3.0.0", @@ -16620,6 +17771,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/vfile/-/vfile-3.0.1.tgz", "integrity": "sha512-y7Y3gH9BsUSdD4KzHsuMaCzRjglXN0W2EcMf0gpvu6+SbsGhMje7xDc8AEoeXy6mIwCKMI6BkjMsRjzQbhMEjQ==", + "dev": true, "requires": { "is-buffer": "^2.0.0", "replace-ext": "1.0.0", @@ -16690,7 +17842,8 @@ "unist-util-stringify-position": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz", - "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==" + "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==", + "dev": true }, "universalify": { "version": "0.1.2", @@ -16786,6 +17939,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", + "dev": true, "requires": { "loader-utils": "^1.1.0", "mime": "^2.0.3", @@ -16843,6 +17997,11 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==" + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -16876,6 +18035,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.0.1.tgz", "integrity": "sha512-lRHFCuC4SQBFr7Uq91oJDJxlnftoTLQ7eKIpMdubhYcVMho4781a8MWXLy3qZrZ0/STD1kRiKc0cQOHm4OkPeA==", + "dev": true, "requires": { "@types/unist": "^2.0.0", "is-buffer": "^2.0.0", @@ -16888,6 +18048,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.1.tgz", "integrity": "sha512-Zqlf6+FRI39Bah8Q6ZnNGrEHUhwJOkHde2MHVk96lLyftfJJckaPslKgzhVcviXj8KcE9UJM9F+a4JEiBUTYgA==", + "dev": true, "requires": { "@types/unist": "^2.0.2" } @@ -16896,6 +18057,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.1.tgz", "integrity": "sha512-KtasSV+uVU7RWhUn4Lw+wW1Zl/nW8JWx7JCPps10Y9JRRIDeDXf8wfBLoOSsJLyo27DqMyAi54C6Jf/d6Kr2Bw==", + "dev": true, "requires": { "@types/unist": "^2.0.2", "unist-util-stringify-position": "^2.0.0" @@ -16907,17 +18069,15 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz", "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==", + "dev": true, "requires": { "unist-util-stringify-position": "^1.1.1" } }, "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "requires": { - "indexof": "0.0.1" - } + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", + "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==" }, "w3c-hr-time": { "version": "1.0.1", @@ -16975,7 +18135,8 @@ "web-namespaces": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.3.tgz", - "integrity": "sha512-r8sAtNmgR0WKOKOxzuSgk09JsHlpKlB+uHi937qypOu3PZ17UxPrierFKDye/uNHjNTTEshu5PId8rojIPj/tA==" + "integrity": "sha512-r8sAtNmgR0WKOKOxzuSgk09JsHlpKlB+uHi937qypOu3PZ17UxPrierFKDye/uNHjNTTEshu5PId8rojIPj/tA==", + "dev": true }, "webidl-conversions": { "version": "4.0.2", @@ -16983,34 +18144,70 @@ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" }, "webpack": { - "version": "4.29.6", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.29.6.tgz", - "integrity": "sha512-MwBwpiE1BQpMDkbnUUaW6K8RFZjljJHArC6tWQJoFm0oQtfoSebtg4Y7/QHnJ/SddtjYLHaKGX64CFjG5rehJw==", + "version": "4.39.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.1.tgz", + "integrity": "sha512-/LAb2TJ2z+eVwisldp3dqTEoNhzp/TLCZlmZm3GGGAlnfIWDgOEE758j/9atklNLfRyhKbZTCOIoPqLJXeBLbQ==", "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-module-context": "1.8.5", "@webassemblyjs/wasm-edit": "1.8.5", "@webassemblyjs/wasm-parser": "1.8.5", - "acorn": "^6.0.5", - "acorn-dynamic-import": "^4.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", + "eslint-scope": "^4.0.3", "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", "schema-utils": "^1.0.0", - "tapable": "^1.1.0", - "terser-webpack-plugin": "^1.1.0", - "watchpack": "^1.5.0", - "webpack-sources": "^1.3.0" + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.1", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==" + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + } } }, "webpack-dev-middleware": { @@ -17071,6 +18268,31 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "decamelize": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", @@ -17085,9 +18307,9 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "strip-ansi": { "version": "3.0.1", @@ -17420,13 +18642,13 @@ "integrity": "sha512-0jXdusCL2uC5gM3yYFT6QMBzKfBr2XTk0g5TPAV4y8IZDyVNDyj1a8uSXy3/XrvkVTmQvLN4O5k3JawGReXr9w==" }, "workbox-webpack-plugin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-4.2.0.tgz", - "integrity": "sha512-YZsiA+y/ns/GdWRaBsfYv8dln1ebWtGnJcTOg1ppO0pO1tScAHX0yGtHIjndxz3L/UUhE8b0NQE9KeLNwJwA5A==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-4.3.1.tgz", + "integrity": "sha512-gJ9jd8Mb8wHLbRz9ZvGN57IAmknOipD3W4XNE/Lk/4lqs5Htw4WOQgakQy/o/4CoXQlMCYldaqUg+EJ35l9MEQ==", "requires": { "@babel/runtime": "^7.0.0", "json-stable-stringify": "^1.0.1", - "workbox-build": "^4.2.0" + "workbox-build": "^4.3.1" } }, "workbox-window": { @@ -17529,7 +18751,8 @@ "x-is-string": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", - "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=" + "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", + "dev": true }, "xml-name-validator": { "version": "3.0.0", @@ -17537,9 +18760,9 @@ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" }, "xmlchars": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-1.3.1.tgz", - "integrity": "sha512-tGkGJkN8XqCod7OT+EvGYK5Z4SfDQGD30zAa58OcnAa0RRWgzUEK72tkXhsX1FZd+rgnhRxFtmO+ihkp8LHSkw==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.1.1.tgz", + "integrity": "sha512-7hew1RPJ1iIuje/Y01bGD/mXokXxegAgVS+e+E0wSi2ILHQkYAH1+JXARwTjZSM4Z4Z+c73aKspEcqj+zPPL/w==" }, "xregexp": { "version": "4.0.0", @@ -17562,35 +18785,56 @@ "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" }, "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", + "cliui": "^5.0.0", "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", + "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", + "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^2.0.0", + "string-width": "^3.0.0", "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" }, "dependencies": { - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "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==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } } } }, "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" diff --git a/web-app/package.json b/web-app/package.json index f78f431c..7b74826a 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -36,7 +36,7 @@ "moment": "^2.24.0", "react": "^16.9.0", "react-dom": "^16.9.0", - "react-scripts": "3.0.1", + "react-scripts": "^3.1.1", "typescript": "^3.5.3" }, "devDependencies": { @@ -53,7 +53,7 @@ "@types/react": "^16.9.2", "@types/react-dom": "^16.8.5", "@types/storybook__react": "^4.0.2", - "babel-loader": "^8.0.5", + "babel-loader": "^8.0.6", "babel-plugin-import": "^1.12.0", "node-sass": "^4.12.0", "sass-loader": "^7.2.0", diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index a1eaa39b..aefa695f 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -3,10 +3,10 @@ import { useQuery } from '@apollo/react-hooks' import { Button, Card } from '@alifd/next' import * as T from 'typings/graphql' -import { send } from 'utils/vscode' +import { send } from '../../utils/vscode' import LoadingPage from '../LoadingPage' import queryTutorial from './queryTutorial' -import ErrorView from 'components/Error' +import ErrorView from '../../components/Error' interface Props { tutorial: T.Tutorial diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 21efde9c..038d4d0f 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -3,9 +3,9 @@ import { useQuery } from '@apollo/react-hooks' import * as T from 'typings/graphql' import queryTutorials from './queryTutorials' -import { send } from 'utils/vscode' +import { send } from '../../utils/vscode' import LoadingPage from '../LoadingPage' -import ErrorView from 'components/Error' +import ErrorView from '../../components/Error' import TutorialList from './TutorialList' interface Props { diff --git a/web-app/src/containers/Tutorial/LevelPage/Level/LevelStageSummary.tsx b/web-app/src/containers/Tutorial/LevelPage/Level/LevelStageSummary.tsx index ec3cd81b..6443ddbf 100644 --- a/web-app/src/containers/Tutorial/LevelPage/Level/LevelStageSummary.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/Level/LevelStageSummary.tsx @@ -2,7 +2,7 @@ import { Icon } from '@alifd/next' import * as React from 'react' import * as T from 'typings/graphql' -import Markdown from 'components/Markdown' +import Markdown from '../../../../components/Markdown' const styles = { card: { diff --git a/web-app/src/containers/Tutorial/LevelPage/Level/index.tsx b/web-app/src/containers/Tutorial/LevelPage/Level/index.tsx index 9d043c4b..cb6eefa5 100644 --- a/web-app/src/containers/Tutorial/LevelPage/Level/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/Level/index.tsx @@ -2,7 +2,7 @@ import { Button, Step } from '@alifd/next' import * as React from 'react' import * as T from 'typings/graphql' -import Markdown from 'components/Markdown' +import Markdown from '../../../../components/Markdown' import LevelStageSummary from './LevelStageSummary' const styles = { diff --git a/web-app/src/containers/Tutorial/LevelPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx index 780eb9df..4eb5c2e8 100644 --- a/web-app/src/containers/Tutorial/LevelPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/index.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' import * as T from 'typings/graphql' -import ErrorView from 'components/Error' +import ErrorView from '../../../components/Error' import Level from './Level' import queryLevel from './queryLevel' diff --git a/web-app/src/containers/Tutorial/StagePage/Stage/StepDescription/index.tsx b/web-app/src/containers/Tutorial/StagePage/Stage/StepDescription/index.tsx index fc696f9d..5ecd71f8 100644 --- a/web-app/src/containers/Tutorial/StagePage/Stage/StepDescription/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/Stage/StepDescription/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import Markdown from 'components/Markdown' +import Markdown from '../../../../../components/Markdown' const styles = { // active: { diff --git a/web-app/src/containers/Tutorial/StagePage/Stage/index.tsx b/web-app/src/containers/Tutorial/StagePage/Stage/index.tsx index 572c129c..dd2a05cc 100644 --- a/web-app/src/containers/Tutorial/StagePage/Stage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/Stage/index.tsx @@ -2,7 +2,7 @@ import { Button, Step } from '@alifd/next' import * as React from 'react' import * as T from 'typings/graphql' -import Markdown from 'components/Markdown' +import Markdown from '../../../../components/Markdown' import StepDescription from './StepDescription' const styles = { diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index ef78f5b4..7c9a2fe7 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' -import ErrorView from 'components/Error' +import ErrorView from '../../../components/Error' import Stage from './Stage' import queryStage from './queryStage' diff --git a/web-app/src/containers/Tutorial/SummaryPage/index.tsx b/web-app/src/containers/Tutorial/SummaryPage/index.tsx index d0d2a2b0..ea229382 100644 --- a/web-app/src/containers/Tutorial/SummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/SummaryPage/index.tsx @@ -3,7 +3,7 @@ import { useQuery } from '@apollo/react-hooks' import querySummary from './querySummary' import Summary from './Summary' -import ErrorView from 'components/Error' +import ErrorView from '../../../components/Error' interface PageProps { send(action: string): void diff --git a/web-app/src/containers/Tutorial/index.tsx b/web-app/src/containers/Tutorial/index.tsx index db660874..0709af3a 100644 --- a/web-app/src/containers/Tutorial/index.tsx +++ b/web-app/src/containers/Tutorial/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' -import { send } from 'utils/vscode' +import { send } from '../../utils/vscode' -import Router from 'components/Router' +import Router from '../../components/Router' import LoadingPage from '../LoadingPage' import SummaryPage from './SummaryPage' import LevelSummaryPage from './LevelPage' diff --git a/web-app/tsconfig.paths.json b/web-app/tsconfig.paths.json index b09fea6a..8b9fea6b 100644 --- a/web-app/tsconfig.paths.json +++ b/web-app/tsconfig.paths.json @@ -3,13 +3,8 @@ "baseUrl": "src", "rootDirs": ["src", "stories"], "paths": { - "components/*": ["./components/*"], - "containers/*": ["./containers/*"], - "services/*": ["./services/*"], - "styles/*": ["./styles/*"], "typings": ["../../typings/index.d.ts"], - "typings/graphql": ["../../typings/graphql.d.ts"], - "utils/*": ["./utils/*"] + "typings/graphql": ["../../typings/graphql.d.ts"] }, "allowSyntheticDefaultImports": true }, From be46fad7221f1306a42940aa4d7a721f593eee34 Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 19 Aug 2019 00:21:31 -0700 Subject: [PATCH 030/117] create setStatus mutation --- web-app/src/App.tsx | 34 ++++++----- .../src/containers/New/TutorialList/index.tsx | 4 +- web-app/src/services/apollo/index.ts | 56 ++----------------- web-app/src/services/apollo/mutations.ts | 7 +++ web-app/src/services/apollo/resolvers.ts | 53 ++++++++++++++++++ web-app/src/services/apollo/typeDefs.ts | 15 +++++ web-app/src/utils/DataContext.tsx | 22 -------- 7 files changed, 102 insertions(+), 89 deletions(-) create mode 100644 web-app/src/services/apollo/mutations.ts create mode 100644 web-app/src/services/apollo/resolvers.ts create mode 100644 web-app/src/services/apollo/typeDefs.ts delete mode 100644 web-app/src/utils/DataContext.tsx diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index e48c7cfe..75e8954d 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -1,11 +1,11 @@ import * as React from 'react' -import { ApolloProvider } from '@apollo/react-hooks' +import { ApolloProvider, useMutation } from '@apollo/react-hooks' import * as CR from 'typings' import client from './services/apollo' +import { SET_STATUS } from './services/apollo/mutations' import Debugger from './components/Debugger' import Routes from './Routes' -import DataContext, { initialData, initialState } from './utils/DataContext' import { send } from './utils/vscode' interface ReceivedEvent { @@ -13,18 +13,29 @@ interface ReceivedEvent { } const App = () => { + const initialState = { SelectTutorial: 'Initial ' } + + // set state machine state const [state, setState] = React.useState(initialState) - const [data, setData]: [CR.MachineContext, (data: CR.MachineContext) => void] = React.useState(initialData) + + // update level/stage/step status based on user progress & position + // TODO: model server more effeciently + const [setStatus] = useMutation(SET_STATUS) // update state based on response from editor const handleEvent = (event: ReceivedEvent): void => { const message = event.data // messages from core + const { progress, position } = message.payload.data + if (message.type === 'SET_STATE') { + // SET_STATE - set state machine state setState(message.payload.state) - setData(message.payload.data) + + setStatus({ variables: { progress, position } }) } else if (message.type === 'SET_DATA') { - setData(message.payload.data) + // SET_DATA - set state machine context + setStatus({ variables: { progress, position } }) } } @@ -44,20 +55,15 @@ const App = () => { const value = { state, - position: data.position, - data: data.data, - progress: data.progress, } // TODO: refactor cond to user and accept first route as if/else if return ( - -
- {process.env.REACT_APP_DEBUG && } - -
-
+
+ {process.env.REACT_APP_DEBUG && } + +
) } diff --git a/web-app/src/containers/New/TutorialList/index.tsx b/web-app/src/containers/New/TutorialList/index.tsx index b88fedc3..c40dbacd 100644 --- a/web-app/src/containers/New/TutorialList/index.tsx +++ b/web-app/src/containers/New/TutorialList/index.tsx @@ -14,8 +14,8 @@ const TutorialList = (props: Props) => ( props.onNew(tutorial.id)} - title={tutorial.title} - text={tutorial.text} + title={tutorial.title || ''} + text={tutorial.text || ''} /> ))}
diff --git a/web-app/src/services/apollo/index.ts b/web-app/src/services/apollo/index.ts index 4fa5c194..c874d569 100644 --- a/web-app/src/services/apollo/index.ts +++ b/web-app/src/services/apollo/index.ts @@ -1,62 +1,16 @@ import ApolloClient, { InMemoryCache } from 'apollo-boost' +import typeDefs from './typeDefs' +import resolvers from './resolvers' + const client = new ApolloClient({ uri: process.env.REACT_APP_GQL_URI, headers: { Authorization: process.env.GQL_AUTH_TOKEN, }, cache: new InMemoryCache(), - resolvers: { - Mutation: { - setStatus: (_root, variables, { cache, getCacheKey }) => { - // TODO: optimize status setting to act on diffs - - // set local cache - function set(typename: string, id: string, status: 'ACTIVE' | 'COMPLETE') { - const writeId = getCacheKey({ __typename: typename, id }) - const data = { status } - cache.writeData({ id: writeId, data }) - } - - const { progress, position } = variables - - // set level progress & active - for (const levelId of Object.keys(progress.levels)) { - set('Level', levelId, 'COMPLETE') - } - set('Level', position.levelId, 'ACTIVE') - - // set stage progress & active - for (const stageId of Object.keys(progress.stages)) { - set('Stage', stageId, 'COMPLETE') - } - set('Stage', position.stageId, 'ACTIVE') - - // set step progress & active - for (const stepId of Object.keys(progress.steps)) { - set('Step', stepId, 'COMPLETE') - } - set('Step', position.stepId, 'ACTIVE') - - return null - }, - }, - Level: { - status() { - return 'INCOMPLETE' - } - }, - Stage: { - status() { - return 'INCOMPLETE' - } - }, - Step: { - status() { - return 'INCOMPLETE' - } - } - }, + typeDefs, + resolvers, }) export default client \ No newline at end of file diff --git a/web-app/src/services/apollo/mutations.ts b/web-app/src/services/apollo/mutations.ts new file mode 100644 index 00000000..f4a0c5ce --- /dev/null +++ b/web-app/src/services/apollo/mutations.ts @@ -0,0 +1,7 @@ +import { gql } from 'apollo-boost' + +export const SET_STATUS = gql` + mutation ToggleTodo($progress: Progress!, $position: Position) { + setStatus(progress: $progress, position: $position) @client + } +` \ No newline at end of file diff --git a/web-app/src/services/apollo/resolvers.ts b/web-app/src/services/apollo/resolvers.ts new file mode 100644 index 00000000..18e987c9 --- /dev/null +++ b/web-app/src/services/apollo/resolvers.ts @@ -0,0 +1,53 @@ +const resolvers = { + Mutation: { + setStatus: (_root, variables, { cache, getCacheKey }) => { + // TODO: optimize status setting to act on diffs + + // set local cache + function set(typename: string, id: string, status: 'ACTIVE' | 'COMPLETE') { + const writeId = getCacheKey({ __typename: typename, id }) + const data = { status } + cache.writeData({ id: writeId, data }) + } + + const { progress, position } = variables + + // set level progress & active + for (const levelId of Object.keys(progress.levels)) { + set('Level', levelId, 'COMPLETE') + } + set('Level', position.levelId, 'ACTIVE') + + // set stage progress & active + for (const stageId of Object.keys(progress.stages)) { + set('Stage', stageId, 'COMPLETE') + } + set('Stage', position.stageId, 'ACTIVE') + + // set step progress & active + for (const stepId of Object.keys(progress.steps)) { + set('Step', stepId, 'COMPLETE') + } + set('Step', position.stepId, 'ACTIVE') + + return null + }, + }, + Level: { + status() { + return 'INCOMPLETE' + } + }, + Stage: { + status() { + return 'INCOMPLETE' + } + }, + Step: { + status() { + return 'INCOMPLETE' + } + } +} + +export default resolvers \ No newline at end of file diff --git a/web-app/src/services/apollo/typeDefs.ts b/web-app/src/services/apollo/typeDefs.ts new file mode 100644 index 00000000..2142f0b7 --- /dev/null +++ b/web-app/src/services/apollo/typeDefs.ts @@ -0,0 +1,15 @@ +import { gql } from 'apollo-boost' + +const typeDefs = gql` + input Progress { + levels: JSONObject + stages: JSONObject + steps: JSONObject + } + input Position { + levelId: String + stageId: String + stepId: String + } +` +export default typeDefs \ No newline at end of file diff --git a/web-app/src/utils/DataContext.tsx b/web-app/src/utils/DataContext.tsx deleted file mode 100644 index ffee2cfc..00000000 --- a/web-app/src/utils/DataContext.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from 'react' -import * as CR from 'typings' - -export const initialState = { SelectTutorial: 'Initial ' } -export const initialData: CR.MachineContext = { - position: { levelId: '', stageId: '', stepId: '' }, - data: { - summary: { - title: '', - description: '', - levelList: [], - }, - levels: {}, - stages: {}, - steps: {}, - }, - progress: { levels: {}, stages: {}, steps: {}, complete: false }, -} - -const DataContext = React.createContext({ state: initialState, ...initialData }) - -export default DataContext From 26ae887ebc69793e9b9bc5bf7e74a201e82f790d Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 19 Aug 2019 00:23:47 -0700 Subject: [PATCH 031/117] resolve build issues --- web-app/src/containers/Continue/index.tsx | 2 +- web-app/src/containers/New/index.tsx | 2 +- web-app/src/services/apollo/resolvers.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index aefa695f..00279ac6 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -38,7 +38,7 @@ const ContinuePageContainer = () => { }) if (loading) { - return Loading + return } if (error) { diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 038d4d0f..560da00b 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -25,7 +25,7 @@ const Loading = () => const NewPageContainer = () => { const { data, loading, error } = useQuery(queryTutorials) if (loading) { - return Loading + return } if (error) { diff --git a/web-app/src/services/apollo/resolvers.ts b/web-app/src/services/apollo/resolvers.ts index 18e987c9..b34b5545 100644 --- a/web-app/src/services/apollo/resolvers.ts +++ b/web-app/src/services/apollo/resolvers.ts @@ -1,6 +1,6 @@ const resolvers = { Mutation: { - setStatus: (_root, variables, { cache, getCacheKey }) => { + setStatus: (_root: any, variables: any, { cache, getCacheKey }: any) => { // TODO: optimize status setting to act on diffs // set local cache From c39666a26a0c7f7facad55106d1914d3aba339e6 Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 19 Aug 2019 19:39:42 -0700 Subject: [PATCH 032/117] update deps --- package-lock.json | 62 +++++++++++++++++------------------------------ package.json | 6 ++--- 2 files changed, 25 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index cc42bfaa..83f09a3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,9 +46,9 @@ "dev": true }, "@types/node": { - "version": "12.7.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz", - "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==", + "version": "12.7.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz", + "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==", "dev": true }, "agent-base": { @@ -242,20 +242,20 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concurrently": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.1.tgz", - "integrity": "sha512-48+FE5RJ0qc8azwKv4keVQWlni1hZeSjcWr8shBelOBtBHcKj1aJFM9lHRiSc1x7lq416pkvsqfBMhSRja+Lhw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.2.tgz", + "integrity": "sha512-Kim9SFrNr2jd8/0yNYqDTFALzUX1tvimmwFWxmp/D4mRI+kbqIIwE2RkBDrxS2ic25O1UgQMI5AtBqdtX3ynYg==", "dev": true, "requires": { - "chalk": "^2.4.1", - "date-fns": "^1.23.0", - "lodash": "^4.17.10", + "chalk": "^2.4.2", + "date-fns": "^1.30.1", + "lodash": "^4.17.15", "read-pkg": "^4.0.1", - "rxjs": "^6.3.3", + "rxjs": "^6.5.2", "spawn-command": "^0.0.2-1", "supports-color": "^4.5.0", - "tree-kill": "^1.1.0", - "yargs": "^12.0.1" + "tree-kill": "^1.2.1", + "yargs": "^12.0.5" }, "dependencies": { "has-flag": { @@ -332,9 +332,9 @@ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, "dotenv": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.0.0.tgz", - "integrity": "sha512-30xVGqjLjiUOArT4+M5q9sYdvuR4riM6yK9wMcas9Vbp6zZa+ocC9dp6QoftuhTPhFAiLK/0C5Ni2nou/Bk8lg==" + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz", + "integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA==" }, "ecc-jsbn": { "version": "0.1.2", @@ -539,13 +539,10 @@ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" }, "hosted-git-info": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.2.tgz", - "integrity": "sha512-CyjlXII6LMsPMyUzxpTt8fzh5QwzGqPmQXgY/Jyf4Zfp27t/FvfhwoE/8laaMUcMy816CkWF20I7NeQhwwY88w==", - "dev": true, - "requires": { - "lru-cache": "^5.1.1" - } + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", + "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", + "dev": true }, "http-proxy-agent": { "version": "2.1.0", @@ -717,15 +714,6 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, "map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", @@ -900,9 +888,9 @@ "dev": true }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -1451,12 +1439,6 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true - }, "yargs": { "version": "12.0.5", "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", diff --git a/package.json b/package.json index 50d9de6c..a52332dd 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ }, "dependencies": { "axios": "^0.19.0", - "dotenv": "^8.0.0", + "dotenv": "^8.1.0", "graphql": "^14.4.2", "vscode": "^1.1.36", "xstate": "^4.6.7" @@ -39,8 +39,8 @@ "@types/dotenv": "^6.1.1", "@types/graphql": "^14.2.3", "@types/mocha": "^5.2.7", - "@types/node": "^12.7.1", - "concurrently": "^4.1.1", + "@types/node": "^12.7.2", + "concurrently": "^4.1.2", "prettier": "^1.18.2", "tslint": "^5.18.0", "tslint-config-prettier": "^1.18.0", From 6c73657bdfd187b4c1d50ee5c360ec259b8e4439 Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 21 Aug 2019 20:28:41 -0700 Subject: [PATCH 033/117] fix react webview script issue --- src/editor/ReactWebView.ts | 338 +++++++++++++++++++------------------ 1 file changed, 176 insertions(+), 162 deletions(-) diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index 446b6a9a..0f42d801 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -2,173 +2,187 @@ import * as path from 'path' import * as CR from 'typings' import * as vscode from 'vscode' +const getNonce = (): string => { + let text = '' + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)) + } + return text +} + + /** * Manages React webview panels */ class ReactWebView { - // @ts-ignore - public loaded: boolean - private panel: vscode.WebviewPanel - private extensionPath: string - private disposables: vscode.Disposable[] = [] - private onReceive: any // TODO: properly type - - public constructor(extensionPath: string) { - this.extensionPath = extensionPath - - // Create and show a new webview panel - this.panel = this.createWebviewPanel(vscode.ViewColumn.Two) - - // Set the webview's initial html content - this.panel.webview.html = this.getHtmlForWebview() - - // Listen for when the panel is disposed - // This happens when the user closes the panel or when the panel is closed programatically - this.panel.onDidDispose(this.dispose, this, this.disposables) - - // Handle messages from the webview - const onReceive = (action: string | CR.Action) => { - // await loading of webview in React before proceeding with loaded state - if (action === 'WEBVIEW_LOADED') { - this.loaded = true - } else { - vscode.commands.executeCommand('coderoad.receive_action', action) - } - } - this.panel.webview.onDidReceiveMessage(onReceive, null, this.disposables) - - // update panel on changes - const updateWindows = () => { - vscode.commands.executeCommand('vscode.setEditorLayout', { - orientation: 0, - groups: [{ groups: [{}], size: 0.6 }, { groups: [{}], size: 0.4 }], - }) - } - - // prevents new panels from going ontop of coderoad panel - vscode.window.onDidChangeActiveTextEditor((textEditor) => { - console.log('onDidChangeActiveTextEditor') - console.log(textEditor) - if (!textEditor || textEditor.viewColumn !== vscode.ViewColumn.Two) { - updateWindows() - } - }) - // // prevents moving coderoad panel on top of left panel - vscode.window.onDidChangeVisibleTextEditors((textEditor) => { - console.log('onDidChangeVisibleTextEditors') - updateWindows() - }) - - // TODO: prevent window from moving to the left when no windows remain on rights - } - - public createOrShow(column: number, callback?: () => void): void { - // If we already have a panel, show it. - // Otherwise, create a new panel. - if (this.panel && this.panel.webview) { - this.panel.reveal(column) - } else { - this.panel = this.createWebviewPanel(column) - } - if (callback) { - // listen for when webview is loaded - // unfortunately there is no easy way of doing this - const webPanelListener = setInterval(() => { - if (this.loaded) { - // callback tells editor the webview has loaded - setTimeout(callback) - clearInterval(webPanelListener) - } - }, 200) - } - } - - public async postMessage(action: CR.Action): Promise { - // Send a message to the webview webview. - // You can send any JSON serializable data. - const success = await this.panel.webview.postMessage(action) - if (!success) { - throw new Error(`Message post failure: ${JSON.stringify(action)}`) - } - } - - private async dispose(): Promise { - // Clean up our resources - this.loaded = false - this.panel.dispose() - Promise.all(this.disposables.map((x) => x.dispose())) - } - - private createWebviewPanel(column: number): vscode.WebviewPanel { - const viewType = 'CodeRoad' - const title = 'CodeRoad' - const config = { - // Enable javascript in the webview - enableScripts: true, - // And restric the webview to only loading content from our extension's `media` directory. - localResourceRoots: [vscode.Uri.file(path.join(this.extensionPath, 'build'))], - // prevents destroying the window when it is in the background - retainContextWhenHidden: true, - } - return vscode.window.createWebviewPanel(viewType, title, column, config) - } - - private getNonce(): string { - let text = '' - const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' - for (let i = 0; i < 32; i++) { - text += possible.charAt(Math.floor(Math.random() * possible.length)) - } - return text - } - - private getHtmlForWebview(): string { - // eslint-disable-next-line - const manifest = require(path.join(this.extensionPath, 'build', 'asset-manifest.json')) - const mainScript = manifest.files['main.js'] - // grab first chunk - const chunk = Object.keys(manifest.files).filter(f => f.match(/^static\/js\/.+\.js$/))[0] - const chunkScript = manifest.files[chunk] - const mainStyle = manifest.files['main.css'] - - const scriptPathOnDisk = vscode.Uri.file(path.join(this.extensionPath, 'build', mainScript)) - const scriptUri = scriptPathOnDisk.with({ scheme: 'vscode-resource' }) - const chunkPathOnDisk = vscode.Uri.file(path.join(this.extensionPath, 'build', chunkScript)) - const chunkUri = chunkPathOnDisk.with({ scheme: 'vscode-resource' }) - const stylePathOnDisk = vscode.Uri.file(path.join(this.extensionPath, 'build', mainStyle)) - const styleUri = stylePathOnDisk.with({ scheme: 'vscode-resource' }) - - // Use a nonce to whitelist which scripts can be run - const [n1, n2, n3] = [1, 2, 3].map(this.getNonce) - - return ` + // @ts-ignore + public loaded: boolean + private panel: vscode.WebviewPanel + private extensionPath: string + private disposables: vscode.Disposable[] = [] + private onReceive: any // TODO: properly type + + public constructor(extensionPath: string) { + this.extensionPath = extensionPath + + // Create and show a new webview panel + this.panel = this.createWebviewPanel(vscode.ViewColumn.Two) + + // Set the webview's initial html content + this.panel.webview.html = this.getHtmlForWebview() + + // Listen for when the panel is disposed + // This happens when the user closes the panel or when the panel is closed programatically + this.panel.onDidDispose(this.dispose, this, this.disposables) + + // Handle messages from the webview + const onReceive = (action: string | CR.Action) => { + // await loading of webview in React before proceeding with loaded state + if (action === 'WEBVIEW_LOADED') { + this.loaded = true + } else { + vscode.commands.executeCommand('coderoad.receive_action', action) + } + } + this.panel.webview.onDidReceiveMessage(onReceive, null, this.disposables) + + // update panel on changes + const updateWindows = () => { + vscode.commands.executeCommand('vscode.setEditorLayout', { + orientation: 0, + groups: [{groups: [{}], size: 0.6}, {groups: [{}], size: 0.4}], + }) + } + + // prevents new panels from going ontop of coderoad panel + vscode.window.onDidChangeActiveTextEditor((textEditor) => { + console.log('onDidChangeActiveTextEditor') + console.log(textEditor) + if (!textEditor || textEditor.viewColumn !== vscode.ViewColumn.Two) { + updateWindows() + } + }) + // // prevents moving coderoad panel on top of left panel + vscode.window.onDidChangeVisibleTextEditors((textEditor) => { + console.log('onDidChangeVisibleTextEditors') + updateWindows() + }) + + // TODO: prevent window from moving to the left when no windows remain on rights + } + + public createOrShow(column: number, callback?: () => void): void { + // If we already have a panel, show it. + // Otherwise, create a new panel. + if (this.panel && this.panel.webview) { + this.panel.reveal(column) + } else { + this.panel = this.createWebviewPanel(column) + } + if (callback) { + // listen for when webview is loaded + // unfortunately there is no easy way of doing this + const webPanelListener = setInterval(() => { + if (this.loaded) { + // callback tells editor the webview has loaded + setTimeout(callback) + clearInterval(webPanelListener) + } + }, 200) + } + } + + public async postMessage(action: CR.Action): Promise { + // Send a message to the webview webview. + // You can send any JSON serializable data. + const success = await this.panel.webview.postMessage(action) + if (!success) { + throw new Error(`Message post failure: ${JSON.stringify(action)}`) + } + } + + private async dispose(): Promise { + // Clean up our resources + this.loaded = false + this.panel.dispose() + Promise.all(this.disposables.map((x) => x.dispose())) + } + + private createWebviewPanel(column: number): vscode.WebviewPanel { + const viewType = 'CodeRoad' + const title = 'CodeRoad' + const config = { + // Enable javascript in the webview + enableScripts: true, + // And restric the webview to only loading content from our extension's `media` directory. + localResourceRoots: [vscode.Uri.file(path.join(this.extensionPath, 'build'))], + // prevents destroying the window when it is in the background + retainContextWhenHidden: true, + } + return vscode.window.createWebviewPanel(viewType, title, column, config) + } + + private getHtmlForWebview(): string { + const buildUri = vscode.Uri.file(path.join(this.extensionPath, 'build')).with({scheme: 'vscode-resource'}) + + const manifest = require(path.join(this.extensionPath, 'build', 'asset-manifest.json')) + + const mainStyle = manifest.files['main.css'] + const stylePathOnDisk = vscode.Uri.file(path.join(this.extensionPath, 'build', mainStyle)) + const styleUri = stylePathOnDisk.with({scheme: 'vscode-resource'}) + + const getSrc = (manifestName: string): any => { + const file = manifest.files[manifestName] + const uriPath = vscode.Uri.file(path.join(this.extensionPath, 'build', file)) + return uriPath.with({scheme: 'vscode-resource'}) + } + + // map over scripts + const scripts = [{ + file: './webpackBuild.js', + }, { + manifest: 'runtime~main.js', + }, { + manifest: 'main.js', + }, { + // grab first file that matches chunk + manifest: Object.keys(manifest.files).filter(f => f.match(/^static\/js\/.+\.js$/))[0], + }].map(script => ({ + nonce: getNonce(), + src: script.manifest ? getSrc(script.manifest) : script.file + })) + + + const indexHtml = ` - - - - - React App - - - - - - - - - - - - -
Loading...
- - - - - ` - } + + + + + React App + + + + + + + + + + + + +
Loading...
+ ${scripts.map(s => ``).join('\n')} + + ` + + console.log(indexHtml) + + return indexHtml + } + } export default ReactWebView From 36af36941e2d9433ed4d5705ff94401b1b40450f Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 21 Aug 2019 20:41:28 -0700 Subject: [PATCH 034/117] create script for styles --- src/editor/ReactWebView.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index 0f42d801..1156c42a 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -128,16 +128,18 @@ class ReactWebView { const manifest = require(path.join(this.extensionPath, 'build', 'asset-manifest.json')) - const mainStyle = manifest.files['main.css'] - const stylePathOnDisk = vscode.Uri.file(path.join(this.extensionPath, 'build', mainStyle)) - const styleUri = stylePathOnDisk.with({scheme: 'vscode-resource'}) - const getSrc = (manifestName: string): any => { const file = manifest.files[manifestName] const uriPath = vscode.Uri.file(path.join(this.extensionPath, 'build', file)) return uriPath.with({scheme: 'vscode-resource'}) } + const styles = [ + 'main.css', + // get style chunk + Object.keys(manifest.files).find(f => f.match(/^static\/css\/.+\.css$/)) || '' + ].map(style => getSrc(style)) + // map over scripts const scripts = [{ file: './webpackBuild.js', @@ -146,8 +148,8 @@ class ReactWebView { }, { manifest: 'main.js', }, { - // grab first file that matches chunk - manifest: Object.keys(manifest.files).filter(f => f.match(/^static\/js\/.+\.js$/))[0], + // get js chunk + manifest: Object.keys(manifest.files).find(f => f.match(/^static\/js\/.+\.js$/)), }].map(script => ({ nonce: getNonce(), src: script.manifest ? getSrc(script.manifest) : script.file @@ -165,7 +167,7 @@ class ReactWebView { - + ${styles.map(styleUri => ``).join('\n')} From a058eff07b8227ec8d9376b4352b875944a92532 Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 21 Aug 2019 20:45:17 -0700 Subject: [PATCH 035/117] update deps --- package-lock.json | 6 +-- package.json | 2 +- web-app/package-lock.json | 84 ++++++++++++++++++++++++++++++--------- web-app/package.json | 8 ++-- 4 files changed, 74 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 83f09a3d..973a215f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1242,9 +1242,9 @@ "dev": true }, "tslint": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz", - "integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.19.0.tgz", + "integrity": "sha512-1LwwtBxfRJZnUvoS9c0uj8XQtAnyhWr9KlNvDIdB+oXyT+VpsOAaEhEgKi1HrZ8rq0ki/AAnbGSv4KM6/AfVZw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", diff --git a/package.json b/package.json index a52332dd..af663e3f 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@types/node": "^12.7.2", "concurrently": "^4.1.2", "prettier": "^1.18.2", - "tslint": "^5.18.0", + "tslint": "^5.19.0", "tslint-config-prettier": "^1.18.0", "typescript": "^3.5.3" }, diff --git a/web-app/package-lock.json b/web-app/package-lock.json index 12227d51..99c5a12c 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@alifd/next": { - "version": "1.16.7", - "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.16.7.tgz", - "integrity": "sha512-TSmRNooTozOA2HDolqmCWEgaEjtat+ZObZTHJ0Qdyk9QPD2Dr3qu1nUqGRPyC0PA7hipa6S7FjibPH901ZwCxg==", + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.17.7.tgz", + "integrity": "sha512-6JEtZ5VzYj5E6eHHS4uiTAsX/jlHA3/j0oVQBek73okdwU6RQ4330eYwcbwuUpPnIK3rvztbWW5jPsYLWbEdvw==", "requires": { "babel-runtime": "^6.26.0", "classnames": "^2.2.3", @@ -2775,9 +2775,9 @@ } }, "@types/jest": { - "version": "24.0.17", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.17.tgz", - "integrity": "sha512-1cy3xkOAfSYn78dsBWy4M3h/QF/HeWPchNFDjysVtp3GHeTdSmtluNnELfCmfNRRHo0OWEcpf+NsEJQvwQfdqQ==", + "version": "24.0.18", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.18.tgz", + "integrity": "sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ==", "dev": true, "requires": { "@types/jest-diff": "*" @@ -2836,9 +2836,9 @@ } }, "@types/react-dom": { - "version": "16.8.5", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.8.5.tgz", - "integrity": "sha512-idCEjROZ2cqh29+trmTmZhsBAUNQuYrF92JHKzZ5+aiFM1mlSk3bb23CK7HhYuOY75Apgap5y2jTyHzaM2AJGA==", + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.0.tgz", + "integrity": "sha512-OL2lk7LYGjxn4b0efW3Pvf2KBVP0y1v3wip1Bp7nA79NkOpElH98q3WdCEdDj93b2b0zaeBG9DvriuKjIK5xDA==", "dev": true, "requires": { "@types/react": "*" @@ -15045,6 +15045,16 @@ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz", "integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==" }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, "electron-to-chromium": { "version": "1.3.235", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.235.tgz", @@ -15106,6 +15116,11 @@ "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", @@ -15193,6 +15208,25 @@ "path-parse": "^1.0.6" } }, + "sass-loader": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.2.0.tgz", + "integrity": "sha512-h8yUWaWtsbuIiOCgR9fd9c2lRXZ2uG+h8Dzg/AGNj+Hg/3TO8+BBAW9mEP+mh8ei+qBKqSJ0F1FLlYjNBc61OA==", + "requires": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.0.1", + "neo-async": "^2.5.0", + "pify": "^4.0.1", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "schema-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.1.0.tgz", @@ -15207,6 +15241,14 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "requires": { + "kind-of": "^6.0.2" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -16139,21 +16181,23 @@ } }, "sass-loader": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.2.0.tgz", - "integrity": "sha512-h8yUWaWtsbuIiOCgR9fd9c2lRXZ2uG+h8Dzg/AGNj+Hg/3TO8+BBAW9mEP+mh8ei+qBKqSJ0F1FLlYjNBc61OA==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.3.1.tgz", + "integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==", + "dev": true, "requires": { "clone-deep": "^4.0.1", "loader-utils": "^1.0.1", "neo-async": "^2.5.0", "pify": "^4.0.1", - "semver": "^5.5.0" + "semver": "^6.3.0" }, "dependencies": { "clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, "requires": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -16163,22 +16207,26 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true }, "shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, "requires": { "kind-of": "^6.0.2" } diff --git a/web-app/package.json b/web-app/package.json index 7b74826a..655455ed 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -26,7 +26,7 @@ "extends": "react-app" }, "dependencies": { - "@alifd/next": "^1.16.7", + "@alifd/next": "^1.17.7", "@apollo/react-hooks": "^3.0.1", "apollo-boost": "^0.4.4", "graphql": "^14.4.2", @@ -47,16 +47,16 @@ "@storybook/addons": "^5.1.11", "@storybook/react": "^5.1.11", "@types/highlight.js": "^9.12.3", - "@types/jest": "^24.0.17", + "@types/jest": "^24.0.18", "@types/markdown-it": "0.0.8", "@types/node": "^12.7.2", "@types/react": "^16.9.2", - "@types/react-dom": "^16.8.5", + "@types/react-dom": "^16.9.0", "@types/storybook__react": "^4.0.2", "babel-loader": "^8.0.6", "babel-plugin-import": "^1.12.0", "node-sass": "^4.12.0", - "sass-loader": "^7.2.0", + "sass-loader": "^7.3.1", "typescript-eslint-parser": "^22.0.0" } } From 8c72738e6959ecf6431b9925161fcb70e3566e46 Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 21 Aug 2019 20:47:40 -0700 Subject: [PATCH 036/117] cleanup logs --- src/editor/ReactWebView.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index 1156c42a..4609232b 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -137,7 +137,7 @@ class ReactWebView { const styles = [ 'main.css', // get style chunk - Object.keys(manifest.files).find(f => f.match(/^static\/css\/.+\.css$/)) || '' + // Object.keys(manifest.files).find(f => f.match(/^static\/css\/.+\.css$/)) || '' ].map(style => getSrc(style)) // map over scripts @@ -165,8 +165,7 @@ class ReactWebView { React App - - + ${styles.map(styleUri => ``).join('\n')} @@ -180,8 +179,6 @@ class ReactWebView { ` - console.log(indexHtml) - return indexHtml } From d784c57593fc3e3d967ae2a323a9483cd7d7aa22 Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 21 Aug 2019 21:10:35 -0700 Subject: [PATCH 037/117] fix use effects --- web-app/src/App.tsx | 8 +++++--- web-app/src/Routes.tsx | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index 75e8954d..9c5e54dc 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -46,16 +46,18 @@ const App = () => { return () => { window.removeEventListener(listener, handleEvent) } - }) + }, []) // trigger progress when webview loaded React.useEffect(() => { send('WEBVIEW_LOADED') - }) + }, []) const value = { state, - } + } + + console.log(client) // TODO: refactor cond to user and accept first route as if/else if return ( diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index fdded7cb..58c79a4c 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -37,7 +37,7 @@ const Routes = ({ state }: Props) => { return () => { clearInterval(dimensionsInterval) } - }) + }, []) return (
From f4e9877d7122f92082f500644736942789702236 Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 21 Aug 2019 21:10:58 -0700 Subject: [PATCH 038/117] fix no route unclear object --- web-app/src/components/Router/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index a865b937..893ab405 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -15,7 +15,7 @@ const Router = ({ state, children }: Props) => { return child.props.children } } - console.warn(`No Route matches for ${state}`) + console.warn(`No Route matches for ${JSON.stringify(state)}`) return null } From 6a13fcd7fc611d30745ef81a149935aa7a51a685 Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 21 Aug 2019 21:11:14 -0700 Subject: [PATCH 039/117] update api url for src --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index b4851fcc..3f1de458 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -API_URL=http://localhost:3000/graphql \ No newline at end of file +API_URL=http://localhost:4000/graphql \ No newline at end of file From 39af55d36c0c71f70ff306e3ac42adf60e3063aa Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 21 Aug 2019 21:11:28 -0700 Subject: [PATCH 040/117] cleanup apollo server --- web-app/src/services/apollo/index.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web-app/src/services/apollo/index.ts b/web-app/src/services/apollo/index.ts index c874d569..dbca44f2 100644 --- a/web-app/src/services/apollo/index.ts +++ b/web-app/src/services/apollo/index.ts @@ -1,16 +1,16 @@ -import ApolloClient, { InMemoryCache } from 'apollo-boost' +import ApolloClient, {InMemoryCache} from 'apollo-boost' import typeDefs from './typeDefs' import resolvers from './resolvers' const client = new ApolloClient({ - uri: process.env.REACT_APP_GQL_URI, - headers: { - Authorization: process.env.GQL_AUTH_TOKEN, - }, - cache: new InMemoryCache(), - typeDefs, - resolvers, + uri: process.env.REACT_APP_GQL_URI, + headers: { + Authorization: process.env.REACT_APP_GQL_AUTH_TOKEN, + }, + cache: new InMemoryCache(), + typeDefs, + resolvers, }) export default client \ No newline at end of file From 8740c1d9fe4de3ec7a952785665722863e0697ae Mon Sep 17 00:00:00 2001 From: shmck Date: Thu, 22 Aug 2019 20:46:38 -0700 Subject: [PATCH 041/117] migrate to graphql-request on server --- package-lock.json | 54 ++-- package.json | 3 +- src/editor/commands/index.ts | 257 ++++++++--------- src/services/api/api.ts | 13 - src/services/api/gql/query/tutorial.gql | 15 - src/services/api/gql/tutorial.ts | 53 ++++ src/services/api/index.ts | 40 +-- src/state/actions/index.ts | 358 ++++++++++++------------ tsconfig.json | 4 +- web-app/src/App.tsx | 2 - 10 files changed, 414 insertions(+), 385 deletions(-) delete mode 100644 src/services/api/api.ts delete mode 100644 src/services/api/gql/query/tutorial.gql create mode 100644 src/services/api/gql/tutorial.ts diff --git a/package-lock.json b/package-lock.json index 973a215f..9f09d3a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -122,15 +122,6 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, - "axios": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", - "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", - "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" - } - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -280,6 +271,15 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "cross-fetch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.2.tgz", + "integrity": "sha1-pH/09/xxLauo9qaVoRyUhEDUVyM=", + "requires": { + "node-fetch": "2.1.2", + "whatwg-fetch": "2.0.4" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -437,14 +437,6 @@ "locate-path": "^3.0.0" } }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" - } - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -509,6 +501,19 @@ "iterall": "^1.2.2" } }, + "graphql-request": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-1.8.2.tgz", + "integrity": "sha512-dDX2M+VMsxXFCmUX0Vo0TopIZIX4ggzOtiCsThgtrKR4niiaagsGTDIHj3fsOMFETpa064vzovI+4YV4QnMbcg==", + "requires": { + "cross-fetch": "2.2.2" + } + }, + "graphql-tag": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", + "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==" + }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -598,11 +603,6 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" - }, "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", @@ -818,6 +818,11 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -1361,6 +1366,11 @@ "https-proxy-agent": "^2.2.1" } }, + "whatwg-fetch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/package.json b/package.json index af663e3f..614321fb 100644 --- a/package.json +++ b/package.json @@ -29,9 +29,10 @@ "watch": "tsc -watch -p ./" }, "dependencies": { - "axios": "^0.19.0", "dotenv": "^8.1.0", "graphql": "^14.4.2", + "graphql-request": "^1.8.2", + "graphql-tag": "^2.10.1", "vscode": "^1.1.36", "xstate": "^4.6.7" }, diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index c6a00255..92047d3f 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -1,149 +1,154 @@ -import { join } from 'path' +import {join} from 'path' import * as CR from 'typings' +import * as G from 'typings/graphql' import * as vscode from 'vscode' import ReactWebView from '../ReactWebView' -import { setStorage } from '../storage' -import { isEmptyWorkspace } from '../workspace' +import {setStorage} from '../storage' +import {isEmptyWorkspace} from '../workspace' import runTest from './runTest' const COMMANDS = { - START: 'coderoad.start', - TUTORIAL_LAUNCH: 'coderoad.tutorial_launch', - TUTORIAL_SETUP: 'coderoad.tutorial_setup', - OPEN_WEBVIEW: 'coderoad.open_webview', - SEND_STATE: 'coderoad.send_state', - SEND_DATA: 'coderoad.send_data', - RECEIVE_ACTION: 'coderoad.receive_action', - OPEN_FILE: 'coderoad.open_file', - RUN_TEST: 'coderoad.run_test', - TEST_PASS: 'coderoad.test_pass', - TEST_FAIL: 'coderoad.test_fail', + START: 'coderoad.start', + TUTORIAL_LAUNCH: 'coderoad.tutorial_launch', + TUTORIAL_SETUP: 'coderoad.tutorial_setup', + OPEN_WEBVIEW: 'coderoad.open_webview', + SEND_STATE: 'coderoad.send_state', + SEND_DATA: 'coderoad.send_data', + RECEIVE_ACTION: 'coderoad.receive_action', + OPEN_FILE: 'coderoad.open_file', + RUN_TEST: 'coderoad.run_test', + TEST_PASS: 'coderoad.test_pass', + TEST_FAIL: 'coderoad.test_fail', } interface CreateCommandProps { - context: vscode.ExtensionContext - machine: CR.StateMachine - storage: any - git: any - position: any + context: vscode.ExtensionContext + machine: CR.StateMachine + storage: any + git: any + position: any } const resetLayout = () => { - vscode.commands.executeCommand('vscode.setEditorLayout', { - orientation: 0, - groups: [{ groups: [{}], size: 0.6 }, { groups: [{}], size: 0.4 }], - }) + vscode.commands.executeCommand('vscode.setEditorLayout', { + orientation: 0, + groups: [{groups: [{}], size: 0.6}, {groups: [{}], size: 0.4}], + }) } -export const createCommands = ({ context, machine, storage, git, position }: CreateCommandProps) => { - // React panel webview - let webview: any +export const createCommands = ({context, machine, storage, git, position}: CreateCommandProps) => { + // React panel webview + let webview: any - return { - // initialize - [COMMANDS.START]: () => { + return { + // initialize + [COMMANDS.START]: () => { - let webviewState: 'INITIALIZING' | 'RESTARTING' - if (!webview) { - webviewState = 'INITIALIZING' - } else if (webview.loaded) { - // already loaded - vscode.window.showInformationMessage('CodeRoad already open') - return - } else { - webviewState = 'RESTARTING' - } + let webviewState: 'INITIALIZING' | 'RESTARTING' + if (!webview) { + webviewState = 'INITIALIZING' + } else if (webview.loaded) { + // already loaded + vscode.window.showInformationMessage('CodeRoad already open') + return + } else { + webviewState = 'RESTARTING' + } - setStorage(context.workspaceState) + setStorage(context.workspaceState) - // activate machine - webview = new ReactWebView(context.extensionPath) - if (webviewState === 'INITIALIZING') { - machine.activate() - } else if (webviewState === 'RESTARTING') { - setTimeout(() => { - // timeout hack to make data update on new windows - // @ts-ignore - machine.refresh() - }, 1000) - } - }, - // open React webview - [COMMANDS.OPEN_WEBVIEW]: (column: number = vscode.ViewColumn.Two) => { - // setup 1x1 horizontal layout - resetLayout() - const callback = () => { - machine.send('WEBVIEW_INITIALIZED') - } - webview.createOrShow(column, callback) - }, - // launch a new tutorial - // NOTE: may be better to move into action as logic is primarily non-vscode - [COMMANDS.TUTORIAL_LAUNCH]: async ({ tutorial, dispatch }: any) => { - console.log('launch tutorial') + // activate machine + webview = new ReactWebView(context.extensionPath) + if (webviewState === 'INITIALIZING') { + machine.activate() + } else if (webviewState === 'RESTARTING') { + setTimeout(() => { + // timeout hack to make data update on new windows + // @ts-ignore + machine.refresh() + }, 1000) + } + }, + // open React webview + [COMMANDS.OPEN_WEBVIEW]: (column: number = vscode.ViewColumn.Two) => { + // setup 1x1 horizontal layout + resetLayout() + const callback = () => { + machine.send('WEBVIEW_INITIALIZED') + } + webview.createOrShow(column, callback) + }, + // launch a new tutorial + // NOTE: may be better to move into action as logic is primarily non-vscode + [COMMANDS.TUTORIAL_LAUNCH]: async (tutorial: G.Tutorial) => { + console.log('launch tutorial') - await isEmptyWorkspace() + await isEmptyWorkspace() - await git.gitInitIfNotExists() + await git.gitInitIfNotExists() - // TODO: use actual tutorial repo - await Promise.all([git.gitSetupRemote(tutorial.meta.repo), storage.setTutorial(tutorial), storage.resetProgress()]) + if (!tutorial.repo || !tutorial.repo.uri) { + throw new Error('Tutorial repo uri not found') + } - machine.send('TUTORIAL_LOADED') - }, - [COMMANDS.TUTORIAL_SETUP]: async (tutorial: CR.Tutorial) => { - console.log('tutorial setup', tutorial) - // setup onSave hook - const languageIds = tutorial.meta.languages - console.log(`languageIds: ${languageIds.join(', ')}`) - vscode.workspace.onDidSaveTextDocument((document: vscode.TextDocument) => { - console.log('save document', document) - if (languageIds.includes(document.languageId) && document.uri.scheme === 'file') { - // do work - machine.send('TEST_RUN') - } - }) - }, - // open a file - [COMMANDS.OPEN_FILE]: async (relativeFilePath: string) => { - console.log(`OPEN_FILE ${JSON.stringify(relativeFilePath)}`) - try { - const workspaceRoot = vscode.workspace.rootPath - if (!workspaceRoot) { - throw new Error('No workspace root path') - } - const absoluteFilePath = join(workspaceRoot, relativeFilePath) - const doc = await vscode.workspace.openTextDocument(absoluteFilePath) - await vscode.window.showTextDocument(doc, vscode.ViewColumn.One) - // there are times when intialization leave the panel behind any files opened - // ensure the panel is redrawn on the right side first - webview.createOrShow(vscode.ViewColumn.Two) - } catch (error) { - console.log(`Failed to open file ${relativeFilePath}`, error) - } - }, - // send messages to webview - [COMMANDS.SEND_STATE]: (payload: { data: any; state: any }) => { - webview.postMessage({ type: 'SET_STATE', payload }) - }, - [COMMANDS.SEND_DATA]: (payload: { data: any }) => { - webview.postMessage({ type: 'SET_DATA', payload }) - }, - [COMMANDS.RECEIVE_ACTION]: (action: string | CR.Action) => { - // send received actions from web-app into state machine - machine.send(action) - }, - [COMMANDS.RUN_TEST]: () => { - runTest({ - onSuccess: () => machine.send('TEST_PASS'), - onFail: () => machine.send('TEST_FAIL'), - }) - }, - [COMMANDS.TEST_PASS]: () => { - vscode.window.showInformationMessage('PASS') - }, - [COMMANDS.TEST_FAIL]: () => { - vscode.window.showWarningMessage('FAIL') - }, - } + // TODO: use actual tutorial repo + await Promise.all([git.gitSetupRemote(tutorial.repo.uri), storage.setTutorial(tutorial), storage.resetProgress()]) + + machine.send('TUTORIAL_LOADED') + }, + [COMMANDS.TUTORIAL_SETUP]: async (tutorial: CR.Tutorial) => { + console.log('tutorial setup', tutorial) + // setup onSave hook + const languageIds = tutorial.meta.languages + console.log(`languageIds: ${languageIds.join(', ')}`) + vscode.workspace.onDidSaveTextDocument((document: vscode.TextDocument) => { + console.log('save document', document) + if (languageIds.includes(document.languageId) && document.uri.scheme === 'file') { + // do work + machine.send('TEST_RUN') + } + }) + }, + // open a file + [COMMANDS.OPEN_FILE]: async (relativeFilePath: string) => { + console.log(`OPEN_FILE ${JSON.stringify(relativeFilePath)}`) + try { + const workspaceRoot = vscode.workspace.rootPath + if (!workspaceRoot) { + throw new Error('No workspace root path') + } + const absoluteFilePath = join(workspaceRoot, relativeFilePath) + const doc = await vscode.workspace.openTextDocument(absoluteFilePath) + await vscode.window.showTextDocument(doc, vscode.ViewColumn.One) + // there are times when intialization leave the panel behind any files opened + // ensure the panel is redrawn on the right side first + webview.createOrShow(vscode.ViewColumn.Two) + } catch (error) { + console.log(`Failed to open file ${relativeFilePath}`, error) + } + }, + // send messages to webview + [COMMANDS.SEND_STATE]: (payload: {data: any; state: any}) => { + webview.postMessage({type: 'SET_STATE', payload}) + }, + [COMMANDS.SEND_DATA]: (payload: {data: any}) => { + webview.postMessage({type: 'SET_DATA', payload}) + }, + [COMMANDS.RECEIVE_ACTION]: (action: string | CR.Action) => { + // send received actions from web-app into state machine + machine.send(action) + }, + [COMMANDS.RUN_TEST]: () => { + runTest({ + onSuccess: () => machine.send('TEST_PASS'), + onFail: () => machine.send('TEST_FAIL'), + }) + }, + [COMMANDS.TEST_PASS]: () => { + vscode.window.showInformationMessage('PASS') + }, + [COMMANDS.TEST_FAIL]: () => { + vscode.window.showWarningMessage('FAIL') + }, + } } diff --git a/src/services/api/api.ts b/src/services/api/api.ts deleted file mode 100644 index c51faa37..00000000 --- a/src/services/api/api.ts +++ /dev/null @@ -1,13 +0,0 @@ -import axios from 'axios' - -require('dotenv').config() - -const api = axios.create({ - baseURL: process.env.API_URL, - method: 'POST', - headers: { - 'Content-Type': 'application/graphql', - } -}) - -export default api \ No newline at end of file diff --git a/src/services/api/gql/query/tutorial.gql b/src/services/api/gql/query/tutorial.gql deleted file mode 100644 index 444f4a8b..00000000 --- a/src/services/api/gql/query/tutorial.gql +++ /dev/null @@ -1,15 +0,0 @@ -query getTutorial($tutorialId: ID!) { - tutorial(id: $tutorialId) { - id - testRunner - codingLanguage - repo { - uri - branch - } - version { - version - coderoadVersion - } - } -} diff --git a/src/services/api/gql/tutorial.ts b/src/services/api/gql/tutorial.ts new file mode 100644 index 00000000..878ec554 --- /dev/null +++ b/src/services/api/gql/tutorial.ts @@ -0,0 +1,53 @@ +import gql from 'graphql-tag' + +const getTutorial = gql` + query getTutorial($tutorialId: ID!) { + tutorial(id: $tutorialId) { + id + testRunner + codingLanguage + repo { + uri + branch + } + version { + version + coderoadVersion + levels { + id + setup { + id + files + commits + commands + } + stages { + id + setup { + id + files + commits + commands + } + steps { + id + setup { + id + files + commits + commands + } + solution { + id + files + commits + } + } + } + } + } + } + } +` + +export default getTutorial \ No newline at end of file diff --git a/src/services/api/index.ts b/src/services/api/index.ts index dbcac727..007afc49 100644 --- a/src/services/api/index.ts +++ b/src/services/api/index.ts @@ -1,31 +1,17 @@ -import * as CR from 'typings' +import * as dotenv from 'dotenv' +import {GraphQLClient} from 'graphql-request' -// temporary tutorials -import basicTutorial from '../../tutorials/basic' +dotenv.config() -interface Options { - resource: string - params?: any -} +const url: string = process.env.API_URL || '' +const token: string = process.env.API_AUTH_TOKEN || '' // dev only -const tutorialsData: { [key: string]: CR.Tutorial } = { - [basicTutorial.id]: basicTutorial, -} +// ... or create a GraphQL client instance to send requests +const client: GraphQLClient = new GraphQLClient(url, { + headers: { + 'Content-Type': 'application/graphql', + 'Authorization': token + } +}) -// TODO: replace with fetch resource in ./api.ts -export default async function fetch(options: Options): Promise { - switch (options.resource) { - case 'getTutorialsSummary': - // list of ids with summaries - const data: { [id: string]: CR.TutorialSummary } = {} - for (const tutorial of Object.values(tutorialsData)) { - data[tutorial.id] = tutorial.data.summary - } - return data - case 'getTutorial': - // specific tutorial by id - return tutorialsData[options.params.id] - default: - throw new Error('Resource not found') - } -} +export default client \ No newline at end of file diff --git a/src/state/actions/index.ts b/src/state/actions/index.ts index bad7e107..291cef14 100644 --- a/src/state/actions/index.ts +++ b/src/state/actions/index.ts @@ -1,202 +1,204 @@ -import { assign } from 'xstate' +import {assign} from 'xstate' // NOTE: codesmell - importing machine -import { machine } from '../../extension' +import {machine} from '../../extension' import api from '../../services/api' import * as CR from 'typings' +import * as G from 'typings/graphql' +import tutorialQuery from '@gql/tutorial' import * as storage from '../../services/storage' import * as git from '../../services/git' -let currentTutorial: CR.Tutorial | undefined +let currentTutorial: G.Tutorial | undefined let currentProgress: CR.Progress = { - levels: {}, - stages: {}, - steps: {}, - complete: false, + levels: {}, + stages: {}, + steps: {}, + complete: false, } -const calculatePosition = ({ data, progress }: { data: CR.TutorialData, progress: CR.Progress }): CR.Position => { - const { levelList } = data.summary - // take next incomplete level or the final step - const levelId = levelList.find((id: string) => !progress.levels[id]) || levelList[levelList.length - 1] - const { stageList } = data.levels[levelId] - const stageId = stageList.find((id: string) => !progress.stages[id]) || stageList[stageList.length - 1] - const { stepList } = data.stages[stageId] - const stepId = stepList.find((id: string) => !progress.steps[id]) || stepList[stepList.length - 1] +const calculatePosition = ({data, progress}: {data: CR.TutorialData, progress: CR.Progress}): CR.Position => { + const {levelList} = data.summary + // take next incomplete level or the final step + const levelId = levelList.find((id: string) => !progress.levels[id]) || levelList[levelList.length - 1] + const {stageList} = data.levels[levelId] + const stageId = stageList.find((id: string) => !progress.stages[id]) || stageList[stageList.length - 1] + const {stepList} = data.stages[stageId] + const stepId = stepList.find((id: string) => !progress.steps[id]) || stepList[stepList.length - 1] - const nextPosition: CR.Position = { - levelId, - stageId, - stepId, - } + const nextPosition: CR.Position = { + levelId, + stageId, + stepId, + } - return nextPosition + return nextPosition } export default (dispatch: CR.EditorDispatch) => ({ - createWebview() { - dispatch('coderoad.open_webview') - }, - async newOrContinue() { - // verify that the user has a tutorial & progress - // verify git is setup with a coderoad remote - const [tutorial, progress, hasGit, hasGitRemote] = await Promise.all([ - storage.getTutorial(), - storage.getProgress(), - git.gitVersion(), - git.gitCheckRemoteExists(), - ]) - const canContinue = !!(tutorial && progress && hasGit && hasGitRemote) + createWebview() { + dispatch('coderoad.open_webview') + }, + async newOrContinue() { + // verify that the user has a tutorial & progress + // verify git is setup with a coderoad remote + const [tutorial, progress, hasGit, hasGitRemote] = await Promise.all([ + storage.getTutorial(), + storage.getProgress(), + git.gitVersion(), + git.gitCheckRemoteExists(), + ]) + const canContinue = !!(tutorial && progress && hasGit && hasGitRemote) - if (canContinue) { - // continue - currentTutorial = tutorial - currentProgress = progress - } + if (canContinue) { + // continue + currentTutorial = tutorial + currentProgress = progress + } - machine.send(canContinue ? 'CONTINUE' : 'NEW') - }, - async tutorialLaunch() { - // TODO: add selection of tutorial id - const tutorial: CR.Tutorial = await api({ resource: 'getTutorial', params: { id: '1' } }) - currentTutorial = tutorial - console.log('api') - console.log(tutorial) - dispatch('coderoad.tutorial_launch', { tutorial, dispatch }) - }, - tutorialSetup() { - dispatch('coderoad.tutorial_setup', currentTutorial) - }, - initializeNewTutorial: assign({ - position: (context: any): CR.Position => { - const { data } = context - const levelId = data.summary.levelList[0] - const stageId = data.levels[levelId].stageList[0] - const stepId = data.stages[stageId].stepList[0] - return { - levelId, - stageId, - stepId, - } - }, - }), - tutorialContinue: assign({ - // load initial data, progress & position - data(): CR.TutorialData { - console.log('ACTION: tutorialLoad.data') - if (!currentTutorial) { - throw new Error('No Tutorial loaded') - } - return currentTutorial.data - }, - progress(): CR.Progress { - console.log('ACTION: tutorialLoad.progress') - return currentProgress - }, - position(context: any): CR.Position { - console.log('ACTION: tutorialLoad.position') - if (!currentTutorial) { - throw new Error('No Tutorial loaded') - } - const { data } = currentTutorial - const position = calculatePosition({ data, progress: currentProgress }) + machine.send(canContinue ? 'CONTINUE' : 'NEW') + }, + async tutorialLaunch() { + const tutorial: G.Tutorial = await api.request(tutorialQuery, { + tutorialId: '1', // TODO: add selection of tutorial id + }) + currentTutorial = tutorial + console.log(tutorial) + dispatch('coderoad.tutorial_launch', tutorial) + }, + tutorialSetup() { + dispatch('coderoad.tutorial_setup', currentTutorial) + }, + initializeNewTutorial: assign({ + position: (context: any): CR.Position => { + const {data} = context + const levelId = data.summary.levelList[0] + const stageId = data.levels[levelId].stageList[0] + const stepId = data.stages[stageId].stepList[0] + return { + levelId, + stageId, + stepId, + } + }, + }), + tutorialContinue: assign({ + // load initial data, progress & position + data(): CR.TutorialData { + console.log('ACTION: tutorialLoad.data') + if (!currentTutorial) { + throw new Error('No Tutorial loaded') + } + return currentTutorial.data + }, + progress(): CR.Progress { + console.log('ACTION: tutorialLoad.progress') + return currentProgress + }, + position(context: any): CR.Position { + console.log('ACTION: tutorialLoad.position') + if (!currentTutorial) { + throw new Error('No Tutorial loaded') + } + const {data} = currentTutorial + const position = calculatePosition({data, progress: currentProgress}) - console.log('position', position) - return position - }, - }), - testStart() { - dispatch('coderoad.run_test') - }, - testPass(context: CR.MachineContext): void { - dispatch('coderoad.test_pass') - git.gitSaveCommit(context.position) - }, - testFail() { - dispatch('coderoad.test_fail') - }, - // @ts-ignore - progressUpdate: assign({ - progress: (context: CR.MachineContext): CR.Progress => { - console.log('progress update') - const { progress, position, data } = context - const nextProgress = progress + console.log('position', position) + return position + }, + }), + testStart() { + dispatch('coderoad.run_test') + }, + testPass(context: CR.MachineContext): void { + dispatch('coderoad.test_pass') + git.gitSaveCommit(context.position) + }, + testFail() { + dispatch('coderoad.test_fail') + }, + // @ts-ignore + progressUpdate: assign({ + progress: (context: CR.MachineContext): CR.Progress => { + console.log('progress update') + const {progress, position, data} = context + const nextProgress = progress - nextProgress.steps[position.stepId] = true - const { stepList } = data.stages[position.stageId] - const stageComplete = stepList[stepList.length - 1] === position.stepId - if (stageComplete) { - nextProgress.stages[position.stageId] = true - const { stageList } = data.levels[position.levelId] - const levelComplete = stageList[stageList.length - 1] === position.stageId - if (levelComplete) { - nextProgress.levels[position.levelId] = true - const { levelList } = data.summary - const tutorialComplete = levelList[levelList.length - 1] === position.levelId - if (tutorialComplete) { - nextProgress.complete = true - } - } - } - console.log('progress update', nextProgress) - storage.setProgress(nextProgress) - return nextProgress - }, - }), - stepLoadNext: assign({ - position: (context: any): CR.Position => { - const { data, position } = context - const { stepList } = data.stages[position.stageId] - const currentStepIndex = stepList.indexOf(position.stepId) + nextProgress.steps[position.stepId] = true + const {stepList} = data.stages[position.stageId] + const stageComplete = stepList[stepList.length - 1] === position.stepId + if (stageComplete) { + nextProgress.stages[position.stageId] = true + const {stageList} = data.levels[position.levelId] + const levelComplete = stageList[stageList.length - 1] === position.stageId + if (levelComplete) { + nextProgress.levels[position.levelId] = true + const {levelList} = data.summary + const tutorialComplete = levelList[levelList.length - 1] === position.levelId + if (tutorialComplete) { + nextProgress.complete = true + } + } + } + console.log('progress update', nextProgress) + storage.setProgress(nextProgress) + return nextProgress + }, + }), + stepLoadNext: assign({ + position: (context: any): CR.Position => { + const {data, position} = context + const {stepList} = data.stages[position.stageId] + const currentStepIndex = stepList.indexOf(position.stepId) - const nextStepId = currentStepIndex < stepList.length ? stepList[currentStepIndex + 1] : position.stepId + const nextStepId = currentStepIndex < stepList.length ? stepList[currentStepIndex + 1] : position.stepId - const nextPosition = { - ...context.position, - stepId: nextStepId, - } + const nextPosition = { + ...context.position, + stepId: nextStepId, + } - return nextPosition - }, - }), - loadLevel(context: CR.MachineContext): void { - const { data, position } = context - console.log('loadLevel') - console.log(position) - const { levels } = data - const level = levels[position.levelId] + return nextPosition + }, + }), + loadLevel(context: CR.MachineContext): void { + const {data, position} = context + console.log('loadLevel') + console.log(position) + const {levels} = data + const level = levels[position.levelId] - // run level setup if it exists - if (level && level.actions && level.actions.setup) { - git.gitLoadCommits(level.actions.setup, dispatch) - } - }, - stageLoadNext(context: CR.MachineContext) { - console.log('stageLoadNext') - const { position } = context - console.log(position) - }, - loadStage(context: CR.MachineContext): void { - const { data, position } = context - console.log('loadStage') - console.log(position) - const { stages } = data - const stage = stages[position.levelId] + // run level setup if it exists + if (level && level.actions && level.actions.setup) { + git.gitLoadCommits(level.actions.setup, dispatch) + } + }, + stageLoadNext(context: CR.MachineContext) { + console.log('stageLoadNext') + const {position} = context + console.log(position) + }, + loadStage(context: CR.MachineContext): void { + const {data, position} = context + console.log('loadStage') + console.log(position) + const {stages} = data + const stage = stages[position.levelId] - // run level setup if it exists - if (stage && stage.actions && stage.actions.setup) { - git.gitLoadCommits(stage.actions.setup, dispatch) - } - }, - // @ts-ignore - updatePosition: assign({ - position: (context: CR.MachineContext) => calculatePosition({ - data: context.data, - progress: context.progress, - }), - }), - stepLoadCommits(context: CR.MachineContext): void { - const { data, position } = context - const { setup } = data.steps[position.stepId].actions - git.gitLoadCommits(setup, dispatch) - }, + // run level setup if it exists + if (stage && stage.actions && stage.actions.setup) { + git.gitLoadCommits(stage.actions.setup, dispatch) + } + }, + // @ts-ignore + updatePosition: assign({ + position: (context: CR.MachineContext) => calculatePosition({ + data: context.data, + progress: context.progress, + }), + }), + stepLoadCommits(context: CR.MachineContext): void { + const {data, position} = context + const {setup} = data.steps[position.stepId].actions + git.gitLoadCommits(setup, dispatch) + }, }) diff --git a/tsconfig.json b/tsconfig.json index be561d2d..4ffebcd7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,9 @@ "experimentalDecorators": true, "emitDecoratorMetadata": true, "paths": { - "typings": ["../typings/index.d.ts"] + "typings": ["../typings/index.d.ts"], + "typings/graphql": ["../typings/graphql.d.ts"], + "@gql/*": ["services/api/gql/*"] }, "allowJs": true }, diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index 9c5e54dc..0f9ddf47 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -57,8 +57,6 @@ const App = () => { state, } - console.log(client) - // TODO: refactor cond to user and accept first route as if/else if return ( From 57768778f25a217a7120508a79b156ad964e2ff5 Mon Sep 17 00:00:00 2001 From: shmck Date: Thu, 22 Aug 2019 21:52:50 -0700 Subject: [PATCH 042/117] tutorial command progress --- package-lock.json | 5 +++++ src/editor/commands/index.ts | 10 ++++++---- tsconfig.json | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f09d3a8..3eceab9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -996,6 +996,11 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" }, + "ramda": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", + "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==" + }, "read-pkg": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index 92047d3f..cd603a44 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -96,14 +96,16 @@ export const createCommands = ({context, machine, storage, git, position}: Creat machine.send('TUTORIAL_LOADED') }, - [COMMANDS.TUTORIAL_SETUP]: async (tutorial: CR.Tutorial) => { + [COMMANDS.TUTORIAL_SETUP]: async (tutorial: G.Tutorial) => { + + // TODO: allow multiple coding languages in a tutorial console.log('tutorial setup', tutorial) // setup onSave hook - const languageIds = tutorial.meta.languages - console.log(`languageIds: ${languageIds.join(', ')}`) + const languageId = tutorial.codingLanguage + // console.log(`languageIds: ${languageIds.join(', ')}`) vscode.workspace.onDidSaveTextDocument((document: vscode.TextDocument) => { console.log('save document', document) - if (languageIds.includes(document.languageId) && document.uri.scheme === 'file') { + if (document.uri.scheme === 'file' && languageId === document.languageId) { // do work machine.send('TEST_RUN') } diff --git a/tsconfig.json b/tsconfig.json index 4ffebcd7..b6730a63 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,6 +21,7 @@ "paths": { "typings": ["../typings/index.d.ts"], "typings/graphql": ["../typings/graphql.d.ts"], + "@api": ["services/api/index"], "@gql/*": ["services/api/gql/*"] }, "allowJs": true From 47224c4fb7b1f6f665b75a071674059b6dc9a40e Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 12:54:16 -0700 Subject: [PATCH 043/117] update deps --- package-lock.json | 22 ++++++++++------------ package.json | 4 ++-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3eceab9f..053f380a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,10 +34,13 @@ } }, "@types/graphql": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-14.2.3.tgz", - "integrity": "sha512-UoCovaxbJIxagCvVfalfK7YaNhmxj3BQFRQ2RHQKLiu+9wNXhJnlbspsLHt/YQM99IaLUUFJNzCwzc6W0ypMeQ==", - "dev": true + "version": "14.5.0", + "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-14.5.0.tgz", + "integrity": "sha512-MOkzsEp1Jk5bXuAsHsUi6BVv0zCO+7/2PTiZMXWDSsMXvNU6w/PLMQT2vHn8hy2i0JqojPz1Sz6rsFjHtsU0lA==", + "dev": true, + "requires": { + "graphql": "*" + } }, "@types/mocha": { "version": "5.2.7", @@ -494,9 +497,9 @@ } }, "graphql": { - "version": "14.4.2", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.4.2.tgz", - "integrity": "sha512-6uQadiRgnpnSS56hdZUSvFrVcQ6OF9y6wkxJfKquFtHlnl7+KSuWwSJsdwiK1vybm1HgcdbpGkCpvhvsVQ0UZQ==", + "version": "14.5.3", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.5.3.tgz", + "integrity": "sha512-W8A8nt9BsMg0ZK2qA3DJIVU6muWhxZRYLTmc+5XGwzWzVdUdPVlAAg5hTBjiTISEnzsKL/onasu6vl3kgGTbYg==", "requires": { "iterall": "^1.2.2" } @@ -996,11 +999,6 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" }, - "ramda": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", - "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==" - }, "read-pkg": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", diff --git a/package.json b/package.json index 614321fb..c024f11b 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ }, "dependencies": { "dotenv": "^8.1.0", - "graphql": "^14.4.2", + "graphql": "^14.5.3", "graphql-request": "^1.8.2", "graphql-tag": "^2.10.1", "vscode": "^1.1.36", @@ -38,7 +38,7 @@ }, "devDependencies": { "@types/dotenv": "^6.1.1", - "@types/graphql": "^14.2.3", + "@types/graphql": "^14.5.0", "@types/mocha": "^5.2.7", "@types/node": "^12.7.2", "concurrently": "^4.1.2", From 7bbacd6d103fbeef1d3c32acaa0da5de54594106 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 12:54:28 -0700 Subject: [PATCH 044/117] update typings --- tslint.json | 2 +- typings/graphql.d.ts | 612 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 485 insertions(+), 129 deletions(-) diff --git a/tslint.json b/tslint.json index a4ffba90..dc7c70a8 100644 --- a/tslint.json +++ b/tslint.json @@ -19,6 +19,6 @@ "defaultSeverity": "warning", "linterOptions": { - "exclude": ["node_modules/**"] + "exclude": ["node_modules/**", "src/typings/graphql.d.ts"] } } diff --git a/typings/graphql.d.ts b/typings/graphql.d.ts index f58bb942..0d4217a1 100644 --- a/typings/graphql.d.ts +++ b/typings/graphql.d.ts @@ -1,208 +1,564 @@ -import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; +import {GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig} from 'graphql'; export type Maybe = T | null; -export type RequireFields = { [X in Exclude]?: T[X] } & { [P in K]-?: NonNullable }; +export type RequireFields = {[X in Exclude]?: T[X]} & {[P in K]-?: NonNullable}; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { - ID: string, - String: string, - Boolean: boolean, - Int: number, - Float: number, - /** - * A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the - * `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO - * 8601 standard for representation of dates and times using the Gregorian calendar. - **/ - DateTime: any, - /** Git commit hash */ - Commit: any, - /** The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */ - JSON: any, - /** The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */ - JSONObject: any, - /** The `Upload` scalar type represents a file upload. */ - Upload: any, -}; - - - -export type AuthenticateUserPayload = { - __typename?: 'AuthenticateUserPayload', - user: User, - token: Scalars['String'], + ID: string, + String: string, + Boolean: boolean, + Int: number, + Float: number, + /** + * A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the + * `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO + * 8601 standard for representation of dates and times using the Gregorian calendar. + **/ + DateTime: any, + /** Git commit hash */ + Commit: any, + /** The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */ + JSON: any, + /** The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). */ + JSONObject: any, + /** The `Upload` scalar type represents a file upload. */ + Upload: any, }; + + export enum CacheControlScope { - Public = 'PUBLIC', - Private = 'PRIVATE' + Public = 'PUBLIC', + Private = 'PRIVATE' } +export type CreateTokenInput = { + accessToken: Scalars['String'], +}; + +export type CreateTokenOutput = { + __typename?: 'CreateTokenOutput', + token: Scalars['String'], +}; + export enum EnumCodingLanguage { - Javascript = 'JAVASCRIPT' + Javascript = 'JAVASCRIPT' } export enum EnumTestRunner { - Jest = 'JEST' + Jest = 'JEST' } export type GithubUser = { - __typename?: 'GithubUser', - id: Scalars['ID'], - name?: Maybe, - email?: Maybe, - location?: Maybe, - avatarUrl?: Maybe, + __typename?: 'GithubUser', + id: Scalars['ID'], + name?: Maybe, + email?: Maybe, + location?: Maybe, + avatarUrl?: Maybe, }; export type Level = { - __typename?: 'Level', - id: Scalars['ID'], - title?: Maybe, - text?: Maybe, - stages?: Maybe>>, - setup?: Maybe, - status?: 'INCOMPLETE' | 'COMPLETE' | 'ACTIVE', + __typename?: 'Level', + id: Scalars['ID'], + title: Scalars['String'], + text: Scalars['String'], + stage?: Maybe, + stages: Array, + setup?: Maybe, +}; + + +export type LevelStageArgs = { + stageId: Scalars['ID'] }; export type Mutation = { - __typename?: 'Mutation', - authenticate?: Maybe, + __typename?: 'Mutation', + createToken?: Maybe, }; -export type MutationAuthenticateArgs = { - accessToken: Scalars['String'] +export type MutationCreateTokenArgs = { + input: CreateTokenInput }; export type Query = { - __typename?: 'Query', - tutorial?: Maybe, - tutorials?: Maybe>>, - user?: Maybe, - level?: Maybe, - stage?: Maybe, - step?: Maybe, - stepActions?: Maybe, + __typename?: 'Query', + tutorial?: Maybe, + tutorials?: Maybe>>, + user?: Maybe, + level?: Maybe, + stage?: Maybe, + step?: Maybe, + stepActions?: Maybe, }; export type QueryTutorialArgs = { - id: Scalars['ID'] + id: Scalars['ID'] }; export type QueryLevelArgs = { - id: Scalars['ID'] + id: Scalars['ID'] }; export type QueryStageArgs = { - id: Scalars['ID'] + id: Scalars['ID'] }; export type QueryStepArgs = { - id: Scalars['ID'] + id: Scalars['ID'] }; export type QueryStepActionsArgs = { - id: Scalars['ID'] + id: Scalars['ID'] }; export enum Role { - Admin = 'ADMIN', - User = 'USER' + Admin = 'ADMIN', + User = 'USER' } export type Stage = { - __typename?: 'Stage', - id: Scalars['ID'], - title?: Maybe, - text?: Maybe, - steps?: Maybe>>, - setup?: Maybe, - status?: 'INCOMPLETE' | 'COMPLETE' | 'ACTIVE', + __typename?: 'Stage', + id: Scalars['ID'], + title: Scalars['String'], + text: Scalars['String'], + step?: Maybe, + steps: Array, + setup?: Maybe, +}; + + +export type StageStepArgs = { + stepId: Scalars['ID'] }; export type Step = { - __typename?: 'Step', - id: Scalars['ID'], - title?: Maybe, - text?: Maybe, - setup?: Maybe, - solution?: Maybe, - status?: 'INCOMPLETE' | 'COMPLETE' | 'ACTIVE' + __typename?: 'Step', + id: Scalars['ID'], + title: Scalars['String'], + text: Scalars['String'], + setup: StepActions, + solution: StepActions, }; export type StepActions = { - __typename?: 'StepActions', - id: Scalars['ID'], - commits?: Maybe>>, - files?: Maybe>>, - commands?: Maybe>>, + __typename?: 'StepActions', + id: Scalars['ID'], + commits: Array, + files: Array, + commands: Array, }; export type Tutorial = { - __typename?: 'Tutorial', - id: Scalars['ID'], - repo?: Maybe, - createdBy?: Maybe, - createdAt?: Maybe, - updatedBy?: Maybe, - updatedAt?: Maybe, - codingLanguage?: Maybe, - testRunner?: Maybe, - title?: Maybe, - text?: Maybe, - releasedAt?: Maybe, - releasedBy?: Maybe, - version?: Maybe, - versions?: Maybe>>, + __typename?: 'Tutorial', + id: Scalars['ID'], + repo: TutorialRepo, + createdBy: User, + createdAt: Scalars['DateTime'], + updatedBy: User, + updatedAt: Scalars['DateTime'], + codingLanguage: EnumCodingLanguage, + testRunner: EnumTestRunner, + title: Scalars['String'], + text: Scalars['String'], + releasedAt?: Maybe, + releasedBy?: Maybe, + version: TutorialVersion, + versions: Array, + completed: Scalars['Boolean'], +}; + + +export type TutorialVersionArgs = { + version?: Maybe }; export type TutorialRepo = { - __typename?: 'TutorialRepo', - tutorialId: Scalars['ID'], - uri?: Maybe, - branch?: Maybe, - name?: Maybe, - owner?: Maybe, + __typename?: 'TutorialRepo', + tutorialId: Scalars['ID'], + uri: Scalars['String'], + branch: Scalars['String'], + name: Scalars['String'], + owner: Scalars['String'], }; export type TutorialVersion = { - __typename?: 'TutorialVersion', - tutorialId: Scalars['ID'], - version: Scalars['String'], - coderoadVersion?: Maybe, - createdAt?: Maybe, - createdBy?: Maybe, - publishedAt?: Maybe, - publishedBy?: Maybe, - levels?: Maybe>>, - level?: Maybe, - stage?: Maybe, - step?: Maybe, + __typename?: 'TutorialVersion', + tutorialId: Scalars['ID'], + version: Scalars['String'], + coderoadVersion: Scalars['String'], + createdAt: Scalars['DateTime'], + createdBy: User, + publishedAt?: Maybe, + publishedBy?: Maybe, + level?: Maybe, + levels: Array, + stage?: Maybe, + step?: Maybe, + completed: Scalars['Boolean'], +}; + + +export type TutorialVersionLevelArgs = { + levelId: Scalars['ID'] +}; + + +export type TutorialVersionStageArgs = { + stageId: Scalars['ID'] +}; + + +export type TutorialVersionStepArgs = { + stepId: Scalars['ID'] }; export type User = { - __typename?: 'User', - id: Scalars['ID'], - name?: Maybe, - email?: Maybe, - location?: Maybe, - avatarUrl?: Maybe, - createdAt?: Maybe, - updatedAt?: Maybe, - githubUser?: Maybe, + __typename?: 'User', + id: Scalars['ID'], + name?: Maybe, + email: Scalars['String'], + location?: Maybe, + avatarUrl?: Maybe, + createdAt: Scalars['DateTime'], + updatedAt: Scalars['DateTime'], + githubUser?: Maybe, }; export type TutorialSummaryFragment = ( - { __typename?: 'Tutorial' } - & Pick + {__typename?: 'Tutorial'} + & Pick ); + +export type ResolverTypeWrapper = Promise | T; + +export type ResolverFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => Promise | TResult; + + +export type StitchingResolver = { + fragment: string; + resolve: ResolverFn; +}; + +export type Resolver = + | ResolverFn + | StitchingResolver; + +export type SubscriptionSubscribeFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => AsyncIterator | Promise>; + +export type SubscriptionResolveFn = ( + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => TResult | Promise; + +export interface SubscriptionSubscriberObject { + subscribe: SubscriptionSubscribeFn<{[key in TKey]: TResult}, TParent, TContext, TArgs>; + resolve?: SubscriptionResolveFn; +} + +export interface SubscriptionResolverObject { + subscribe: SubscriptionSubscribeFn; + resolve: SubscriptionResolveFn; +} + +export type SubscriptionObject = + | SubscriptionSubscriberObject + | SubscriptionResolverObject; + +export type SubscriptionResolver = + | ((...args: any[]) => SubscriptionObject) + | SubscriptionObject; + +export type TypeResolveFn = ( + parent: TParent, + context: TContext, + info: GraphQLResolveInfo +) => Maybe; + +export type NextResolverFn = () => Promise; + +export type DirectiveResolverFn = ( + next: NextResolverFn, + parent: TParent, + args: TArgs, + context: TContext, + info: GraphQLResolveInfo +) => TResult | Promise; + +/** Mapping between all available schema types and the resolvers types */ +export type ResolversTypes = { + Query: ResolverTypeWrapper<{}>, + ID: ResolverTypeWrapper, + Tutorial: ResolverTypeWrapper, + TutorialRepo: ResolverTypeWrapper, + String: ResolverTypeWrapper, + User: ResolverTypeWrapper, + DateTime: ResolverTypeWrapper, + GithubUser: ResolverTypeWrapper, + EnumCodingLanguage: EnumCodingLanguage, + EnumTestRunner: EnumTestRunner, + TutorialVersion: ResolverTypeWrapper, + Level: ResolverTypeWrapper, + Stage: ResolverTypeWrapper, + Step: ResolverTypeWrapper, + StepActions: ResolverTypeWrapper, + Commit: ResolverTypeWrapper, + Boolean: ResolverTypeWrapper, + Mutation: ResolverTypeWrapper<{}>, + createTokenInput: CreateTokenInput, + CreateTokenOutput: ResolverTypeWrapper, + CacheControlScope: CacheControlScope, + JSON: ResolverTypeWrapper, + JSONObject: ResolverTypeWrapper, + Role: Role, + Upload: ResolverTypeWrapper, + Int: ResolverTypeWrapper, +}; + +/** Mapping between all available schema types and the resolvers parents */ +export type ResolversParentTypes = { + Query: {}, + ID: Scalars['ID'], + Tutorial: Tutorial, + TutorialRepo: TutorialRepo, + String: Scalars['String'], + User: User, + DateTime: Scalars['DateTime'], + GithubUser: GithubUser, + EnumCodingLanguage: EnumCodingLanguage, + EnumTestRunner: EnumTestRunner, + TutorialVersion: TutorialVersion, + Level: Level, + Stage: Stage, + Step: Step, + StepActions: StepActions, + Commit: Scalars['Commit'], + Boolean: Scalars['Boolean'], + Mutation: {}, + createTokenInput: CreateTokenInput, + CreateTokenOutput: CreateTokenOutput, + CacheControlScope: CacheControlScope, + JSON: Scalars['JSON'], + JSONObject: Scalars['JSONObject'], + Role: Role, + Upload: Scalars['Upload'], + Int: Scalars['Int'], +}; + +export type AuthDirectiveResolver>}> = DirectiveResolverFn; + +export type CacheControlDirectiveResolver>, + scope?: Maybe> +}> = DirectiveResolverFn; + +export interface CommitScalarConfig extends GraphQLScalarTypeConfig { + name: 'Commit' +} + +export type CreateTokenOutputResolvers = { + token?: Resolver, +}; + +export interface DateTimeScalarConfig extends GraphQLScalarTypeConfig { + name: 'DateTime' +} + +export type GithubUserResolvers = { + id?: Resolver, + name?: Resolver, ParentType, ContextType>, + email?: Resolver, ParentType, ContextType>, + location?: Resolver, ParentType, ContextType>, + avatarUrl?: Resolver, ParentType, ContextType>, +}; + +export interface JsonScalarConfig extends GraphQLScalarTypeConfig { + name: 'JSON' +} + +export interface JsonObjectScalarConfig extends GraphQLScalarTypeConfig { + name: 'JSONObject' +} + +export type LevelResolvers = { + id?: Resolver, + title?: Resolver, + text?: Resolver, + stage?: Resolver, ParentType, ContextType, RequireFields>, + stages?: Resolver, ParentType, ContextType>, + setup?: Resolver, ParentType, ContextType>, +}; + +export type MutationResolvers = { + createToken?: Resolver, ParentType, ContextType, RequireFields>, +}; + +export type QueryResolvers = { + tutorial?: Resolver, ParentType, ContextType, RequireFields>, + tutorials?: Resolver>>, ParentType, ContextType>, + user?: Resolver, ParentType, ContextType>, + level?: Resolver, ParentType, ContextType, RequireFields>, + stage?: Resolver, ParentType, ContextType, RequireFields>, + step?: Resolver, ParentType, ContextType, RequireFields>, + stepActions?: Resolver, ParentType, ContextType, RequireFields>, +}; + +export type StageResolvers = { + id?: Resolver, + title?: Resolver, + text?: Resolver, + step?: Resolver, ParentType, ContextType, RequireFields>, + steps?: Resolver, ParentType, ContextType>, + setup?: Resolver, ParentType, ContextType>, +}; + +export type StepResolvers = { + id?: Resolver, + title?: Resolver, + text?: Resolver, + setup?: Resolver, + solution?: Resolver, +}; + +export type StepActionsResolvers = { + id?: Resolver, + commits?: Resolver, ParentType, ContextType>, + files?: Resolver, ParentType, ContextType>, + commands?: Resolver, ParentType, ContextType>, +}; + +export type TutorialResolvers = { + id?: Resolver, + repo?: Resolver, + createdBy?: Resolver, + createdAt?: Resolver, + updatedBy?: Resolver, + updatedAt?: Resolver, + codingLanguage?: Resolver, + testRunner?: Resolver, + title?: Resolver, + text?: Resolver, + releasedAt?: Resolver, ParentType, ContextType>, + releasedBy?: Resolver, ParentType, ContextType>, + version?: Resolver, + versions?: Resolver, ParentType, ContextType>, + completed?: Resolver, +}; + +export type TutorialRepoResolvers = { + tutorialId?: Resolver, + uri?: Resolver, + branch?: Resolver, + name?: Resolver, + owner?: Resolver, +}; + +export type TutorialVersionResolvers = { + tutorialId?: Resolver, + version?: Resolver, + coderoadVersion?: Resolver, + createdAt?: Resolver, + createdBy?: Resolver, + publishedAt?: Resolver, ParentType, ContextType>, + publishedBy?: Resolver, ParentType, ContextType>, + level?: Resolver, ParentType, ContextType, RequireFields>, + levels?: Resolver, ParentType, ContextType>, + stage?: Resolver, ParentType, ContextType, RequireFields>, + step?: Resolver, ParentType, ContextType, RequireFields>, + completed?: Resolver, +}; + +export interface UploadScalarConfig extends GraphQLScalarTypeConfig { + name: 'Upload' +} + +export type UserResolvers = { + id?: Resolver, + name?: Resolver, ParentType, ContextType>, + email?: Resolver, + location?: Resolver, ParentType, ContextType>, + avatarUrl?: Resolver, ParentType, ContextType>, + createdAt?: Resolver, + updatedAt?: Resolver, + githubUser?: Resolver, ParentType, ContextType>, +}; + +export type Resolvers = { + Commit?: GraphQLScalarType, + CreateTokenOutput?: CreateTokenOutputResolvers, + DateTime?: GraphQLScalarType, + GithubUser?: GithubUserResolvers, + JSON?: GraphQLScalarType, + JSONObject?: GraphQLScalarType, + Level?: LevelResolvers, + Mutation?: MutationResolvers, + Query?: QueryResolvers, + Stage?: StageResolvers, + Step?: StepResolvers, + StepActions?: StepActionsResolvers, + Tutorial?: TutorialResolvers, + TutorialRepo?: TutorialRepoResolvers, + TutorialVersion?: TutorialVersionResolvers, + Upload?: GraphQLScalarType, + User?: UserResolvers, +}; + + +/** + * @deprecated + * Use "Resolvers" root object instead. If you wish to get "IResolvers", add "typesPrefix: I" to your config. +*/ +export type IResolvers = Resolvers; +export type DirectiveResolvers = { + auth?: AuthDirectiveResolver, + cacheControl?: CacheControlDirectiveResolver, +}; + + +/** +* @deprecated +* Use "DirectiveResolvers" root object instead. If you wish to get "IDirectiveResolvers", add "typesPrefix: I" to your config. +*/ +export type IDirectiveResolvers = DirectiveResolvers; +export interface IntrospectionResultData { + __schema: { + types: { + kind: string; + name: string; + possibleTypes: { + name: string; + }[]; + }[]; + }; +} + +const result: IntrospectionResultData = { + "__schema": { + "types": [] + } +}; + +export default result; From 0dd047f93bf359b8ef5546bb82e7fdbe619a4a2a Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 12:54:38 -0700 Subject: [PATCH 045/117] create Tutorial model --- src/services/tutorial/index.ts | 141 +++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 src/services/tutorial/index.ts diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts new file mode 100644 index 00000000..105a7b8b --- /dev/null +++ b/src/services/tutorial/index.ts @@ -0,0 +1,141 @@ +import * as G from 'typings/graphql' +import * as CR from 'typings' + +class Tutorial { + public repo: G.TutorialRepo + public config: {codingLanguage: G.EnumCodingLanguage, testRunner: G.EnumTestRunner} + private version: G.TutorialVersion + private position: CR.Position + private progress: CR.Progress + + constructor(tutorial: G.Tutorial) { + this.repo = tutorial.repo + this.config = { + codingLanguage: tutorial.codingLanguage, + testRunner: tutorial.testRunner, + } + // TODO: allow specific version, currently defaults to latest + this.version = tutorial.version + // set initial position + this.position = { + levelId: this.version.levels[0].id, + stageId: this.version.levels[0].stages[0].id, + stepId: this.version.levels[0].stages[0].steps[0].id, + } + // set empty initial progress + this.progress = { + levels: {}, + stages: {}, + steps: {}, + complete: false, + } + } + public load = () => { + // + } + public level = (levelId: string): G.Level | null => { + const level: G.Level | undefined = this.version.levels.find((l: G.Level) => l.id === levelId) + if (!level) { + console.warn(`LevelId not found: ${levelId}`) + return null + } + return level + } + public stage = (stageId: string): G.Stage | null => { + const level: G.Level | null = this.level(this.position.levelId) + if (!level) { + return null + } + const stage: G.Stage | undefined = level.stages.find((s: G.Stage) => s.id === stageId) + if (!stage) { + console.warn(`StageId not found: ${stageId}`) + return null + } + return stage + } + public step = (stepId: string): G.Step | null => { + const stage: G.Stage | null = this.stage(this.position.stageId) + if (!stage) { + return null + } + const step: G.Step | undefined = stage.steps.find((s: G.Step) => s.id === stepId) + if (!step) { + console.warn(`StepId not found: ${stepId}`) + return null + } + return step + } + public updateProgress = (): {position: CR.Position, progress: CR.Progress} => { + const {levelId, stageId, stepId} = this.position + this.progress.levels[levelId] = true + this.progress.stages[stageId] = true + this.progress.steps[stepId] = true + return { + position: this.position, + progress: this.progress, + } + } + public nextPosition = (): CR.Position => { + const {levelId, stageId, stepId} = this.position + // TODO: calculate and return next position + + // is next step + const stage: G.Stage | null = this.stage(stageId) + if (!stage) { + throw new Error('Stage not found') + } + const {steps} = stage + const indexOfStep = steps.findIndex((s: G.Step): boolean => s.id === stepId) + if (indexOfStep === -1) { + throw new Error('Step not found') + } + if (indexOfStep < steps.length - 1) { + + return { + levelId, + stageId, + stepId: steps[indexOfStep + 1].id + } + } + + // is next stage + const level: G.Level | null = this.level(levelId) + if (!level) { + throw new Error('Level not found') + } + const {stages} = level + const indexOfStage = stages.findIndex((s: G.Stage): boolean => s.id === stageId) + if (indexOfStage === -1) { + throw new Error('Stage not found') + } + if (indexOfStage < stages.length - 1) { + // next stage + const nextStage = stages[indexOfStage + 1] + return { + levelId, + stageId: nextStage.id, + stepId: nextStage.steps[0].id + } + } + + // is next level + const levels = this.version.levels + const indexOfLevel = levels.findIndex((l: G.Level): boolean => l.id === levelId) + if (indexOfLevel === -1) { + throw new Error('Level not found') + } + if (indexOfLevel < levels.length - 1) { + const nextLevel = levels[indexOfLevel + 1] + const nextStage = nextLevel.stages[0] + return { + levelId: nextLevel.id, + stageId: nextStage.id, + stepId: nextStage.steps[0].id, + } + } + + throw new Error('Could not calculate next position') + } +} + +export default Tutorial \ No newline at end of file From 97b878a829d3b7ecbf15cf6fa66537c1d480948b Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 13:17:19 -0700 Subject: [PATCH 046/117] initialize state machine with tutorial model --- src/extension.ts | 10 ++-- src/services/tutorial/index.ts | 26 +++++++-- src/state/index.ts | 104 +++++++++++++++++---------------- tslint.json | 3 +- 4 files changed, 83 insertions(+), 60 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 403bb522..def09157 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,15 +1,17 @@ import * as vscode from 'vscode' -import { setWorkspaceRoot } from './services/node' +import {setWorkspaceRoot} from './services/node' +import Tutorial from './services/tutorial' import StateMachine from './state' import Editor from './editor' +export const tutorial = new Tutorial() // state machine that governs application logic -export const machine = new StateMachine({ dispatch: vscode.commands.executeCommand }) +export const machine = new StateMachine({dispatch: vscode.commands.executeCommand, tutorial}) // vscode editor export const editor = new Editor({ - machine, - setWorkspaceRoot, + machine, + setWorkspaceRoot, }) // activate run on vscode extension initialization diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index 105a7b8b..d55decfe 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -1,20 +1,34 @@ import * as G from 'typings/graphql' import * as CR from 'typings' +interface TutorialConfig { + codingLanguage: G.EnumCodingLanguage + testRunner: G.EnumTestRunner +} + class Tutorial { public repo: G.TutorialRepo - public config: {codingLanguage: G.EnumCodingLanguage, testRunner: G.EnumTestRunner} + public config: TutorialConfig private version: G.TutorialVersion private position: CR.Position private progress: CR.Progress - constructor(tutorial: G.Tutorial) { + constructor() { + // initialize types, will be assigned when tutorial is selected + this.repo = {} as G.TutorialRepo + this.config = {} as TutorialConfig + this.version = {} as G.TutorialVersion + this.position = {} as CR.Position + this.progress = {} as CR.Progress + } + + public init = (tutorial: G.Tutorial) => { this.repo = tutorial.repo this.config = { codingLanguage: tutorial.codingLanguage, testRunner: tutorial.testRunner, } - // TODO: allow specific version, currently defaults to latest + // version containing level data this.version = tutorial.version // set initial position this.position = { @@ -29,9 +43,11 @@ class Tutorial { steps: {}, complete: false, } + + // set position, progress, tutorial locally } - public load = () => { - // + public load = (tutorial: G.Tutorial) => { + // TODO: load from localStorage } public level = (levelId: string): G.Level | null => { const level: G.Level | undefined = this.version.levels.find((l: G.Level) => l.id === levelId) diff --git a/src/state/index.ts b/src/state/index.ts index 0e37cf00..2da10916 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -1,4 +1,5 @@ -import { interpret, Interpreter } from 'xstate' +import {interpret, Interpreter} from 'xstate' +import Tutorial from '../services/tutorial' import * as CR from 'typings' import createMachine from './machine' @@ -7,61 +8,64 @@ import createMachine from './machine' // convert state into a readable string const stateToString = (state: string | object, str: string = ''): string => { - if (typeof state === 'object') { - const keys = Object.keys(state) - if (keys && keys.length) { - const key = keys[0] - return stateToString(state[key], str.length ? `${str}.${key}` : key) - } - return str - } else if (typeof state === 'string') { - return state - } - return '' + if (typeof state === 'object') { + const keys = Object.keys(state) + if (keys && keys.length) { + const key = keys[0] + return stateToString(state[key], str.length ? `${str}.${key}` : key) + } + return str + } else if (typeof state === 'string') { + return state + } + return '' } interface Props { - dispatch: CR.EditorDispatch + dispatch: CR.EditorDispatch + tutorial: Tutorial } class StateMachine { - private dispatch: CR.EditorDispatch - private machineOptions = { - devTools: true, - deferEvents: true, - execute: true, - } - private service: Interpreter - constructor({ dispatch }: Props) { - this.dispatch = dispatch - const machine = createMachine(dispatch) - this.service = interpret(machine, this.machineOptions) - // logging - .onTransition(state => { - if (state.changed) { - console.log(`STATE: ${stateToString(state.value)}`) - dispatch('coderoad.send_state', { state: state.value, data: state.context }) - } else { - dispatch('coderoad.send_data', { data: state.context }) - } - }) - } - public activate() { - // initialize - this.service.start() - } - public deactivate() { - this.service.stop() - } - public refresh() { - console.log('service refresh') - console.log(this.service.state) - const { value, context } = this.service.state - this.dispatch('coderoad.send_state', { state: value, data: context }) - } - public send(action: string | CR.Action) { - this.service.send(action) - } + private dispatch: CR.EditorDispatch + private tutorial: Tutorial + private machineOptions = { + devTools: true, + deferEvents: true, + execute: true, + } + private service: Interpreter + constructor({dispatch, tutorial}: Props) { + this.dispatch = dispatch + this.tutorial = tutorial + const machine = createMachine(dispatch) + this.service = interpret(machine, this.machineOptions) + // logging + .onTransition(state => { + if (state.changed) { + console.log(`STATE: ${stateToString(state.value)}`) + dispatch('coderoad.send_state', {state: state.value, data: state.context}) + } else { + dispatch('coderoad.send_data', {data: state.context}) + } + }) + } + public activate() { + // initialize + this.service.start() + } + public deactivate() { + this.service.stop() + } + public refresh() { + console.log('service refresh') + console.log(this.service.state) + const {value, context} = this.service.state + this.dispatch('coderoad.send_state', {state: value, data: context}) + } + public send(action: string | CR.Action) { + this.service.send(action) + } } export default StateMachine diff --git a/tslint.json b/tslint.json index dc7c70a8..484ae6aa 100644 --- a/tslint.json +++ b/tslint.json @@ -14,7 +14,8 @@ "triple-equals": true, "forin": false, "no-console": false, - "no-submodule-imports": false + "no-submodule-imports": false, + "no-object-literal-type-assertion": false }, "defaultSeverity": "warning", From 57675e5a964ecf886d4e740ca7f1d39a79a8fc32 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 14:15:59 -0700 Subject: [PATCH 047/117] tutorialModel progress --- src/editor/commands/index.ts | 24 +- src/editor/commands/loadSolution.ts | 41 ++-- src/editor/index.ts | 100 ++++----- src/extension.ts | 4 +- src/services/storage.ts | 83 +++---- src/services/tutorial/index.ts | 67 +++++- src/state/actions/index.ts | 40 ++-- src/state/context/index.ts | 20 -- src/state/index.ts | 8 +- src/state/machine.ts | 331 ++++++++++++++-------------- typings/index.d.ts | 238 ++++++++++---------- 11 files changed, 489 insertions(+), 467 deletions(-) delete mode 100644 src/state/context/index.ts diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index cd603a44..8862c046 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -22,11 +22,9 @@ const COMMANDS = { } interface CreateCommandProps { - context: vscode.ExtensionContext + vscodeExt: vscode.ExtensionContext machine: CR.StateMachine - storage: any git: any - position: any } const resetLayout = () => { @@ -36,7 +34,7 @@ const resetLayout = () => { }) } -export const createCommands = ({context, machine, storage, git, position}: CreateCommandProps) => { +export const createCommands = ({vscodeExt, machine, git}: CreateCommandProps) => { // React panel webview let webview: any @@ -55,10 +53,10 @@ export const createCommands = ({context, machine, storage, git, position}: Creat webviewState = 'RESTARTING' } - setStorage(context.workspaceState) + setStorage(vscodeExt.workspaceState) // activate machine - webview = new ReactWebView(context.extensionPath) + webview = new ReactWebView(vscodeExt.extensionPath) if (webviewState === 'INITIALIZING') { machine.activate() } else if (webviewState === 'RESTARTING') { @@ -80,32 +78,30 @@ export const createCommands = ({context, machine, storage, git, position}: Creat }, // launch a new tutorial // NOTE: may be better to move into action as logic is primarily non-vscode - [COMMANDS.TUTORIAL_LAUNCH]: async (tutorial: G.Tutorial) => { + [COMMANDS.TUTORIAL_LAUNCH]: async (repo: G.TutorialRepo) => { console.log('launch tutorial') await isEmptyWorkspace() await git.gitInitIfNotExists() - if (!tutorial.repo || !tutorial.repo.uri) { + if (!repo || !repo.uri) { throw new Error('Tutorial repo uri not found') } - // TODO: use actual tutorial repo - await Promise.all([git.gitSetupRemote(tutorial.repo.uri), storage.setTutorial(tutorial), storage.resetProgress()]) + await git.gitSetupRemote(repo.uri) machine.send('TUTORIAL_LOADED') }, - [COMMANDS.TUTORIAL_SETUP]: async (tutorial: G.Tutorial) => { + [COMMANDS.TUTORIAL_SETUP]: async (codingLanguage: G.EnumCodingLanguage) => { // TODO: allow multiple coding languages in a tutorial - console.log('tutorial setup', tutorial) + // setup onSave hook - const languageId = tutorial.codingLanguage // console.log(`languageIds: ${languageIds.join(', ')}`) vscode.workspace.onDidSaveTextDocument((document: vscode.TextDocument) => { console.log('save document', document) - if (document.uri.scheme === 'file' && languageId === document.languageId) { + if (document.uri.scheme === 'file' && codingLanguage === document.languageId) { // do work machine.send('TEST_RUN') } diff --git a/src/editor/commands/loadSolution.ts b/src/editor/commands/loadSolution.ts index 02ef752e..c1c883a6 100644 --- a/src/editor/commands/loadSolution.ts +++ b/src/editor/commands/loadSolution.ts @@ -1,21 +1,32 @@ import * as CR from 'typings' +import * as G from 'typings/graphql' import * as storage from '../../services/storage' -import { gitLoadCommits, gitClear } from '../../services/git' +import {gitLoadCommits, gitClear} from '../../services/git' export default async function loadSolution(dispatch: CR.EditorDispatch): Promise { - const [position, tutorial]: [CR.Position, CR.Tutorial | undefined] = await Promise.all([ - storage.getPosition(), - storage.getTutorial(), - ]) - if (!position) { - throw new Error('No tutorial position state found') - } - if (!tutorial) { - throw new Error('Local tutorial not found') - } - // eslint-disable-next-line - const { solution } = tutorial.data.steps[position.stepId].actions + const [position, tutorial]: [CR.Position, G.Tutorial | undefined] = await Promise.all([ + storage.getPosition(), + storage.getTutorial(), + ]) + if (!position) { + throw new Error('No tutorial position state found') + } + if (!tutorial || !tutorial.version || !tutorial.version.levels) { + throw new Error('Local tutorial not found') + } + // eslint-disable-next-line + + try { + const solution = tutorial.version + .levels.find((l: G.Level) => l.id === position.levelId) + .stages.find((s: G.Stage) => s.id === position.stageId) + .steps.find((s: G.Step) => s.id === position.stepId) + .solution + + await gitClear() + await gitLoadCommits(solution, dispatch) + } catch (error) { + throw new Error(error) + } - await gitClear() - await gitLoadCommits(solution, dispatch) } diff --git a/src/editor/index.ts b/src/editor/index.ts index 41003627..fca9104b 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -1,69 +1,67 @@ import * as vscode from 'vscode' import * as CR from 'typings' -import { createCommands } from './commands' +import {createCommands} from './commands' import * as storage from '../services/storage' import * as git from '../services/git' import * as position from '../services/position' interface Props { - machine: CR.StateMachine - setWorkspaceRoot(rootPath: string): void + machine: CR.StateMachine + setWorkspaceRoot(rootPath: string): void } class Editor { - // extension context set on activation - // @ts-ignore - private context: vscode.ExtensionContext - private machine: CR.StateMachine + // extension context set on activation + // @ts-ignore + private vscodeExt: vscode.ExtensionContext + private machine: CR.StateMachine - constructor({ machine, setWorkspaceRoot }: Props) { - this.machine = machine + constructor({machine, setWorkspaceRoot}: Props) { + this.machine = machine - // set workspace root for node executions - const { workspace } = vscode - const { rootPath } = workspace - if (!rootPath) { - throw new Error('Requires a workspace. Please open a folder') - } - setWorkspaceRoot(rootPath) - } - public activate = (context: vscode.ExtensionContext): void => { - console.log('ACTIVATE!') - this.context = context - // commands - this.activateCommands() + // set workspace root for node executions + const {workspace} = vscode + const {rootPath} = workspace + if (!rootPath) { + throw new Error('Requires a workspace. Please open a folder') + } + setWorkspaceRoot(rootPath) + } + public activate = (vscodeExt: vscode.ExtensionContext): void => { + console.log('ACTIVATE!') + this.vscodeExt = vscodeExt + // commands + this.activateCommands() - // setup tasks or views here - } - public deactivate = (): void => { - console.log('DEACTIVATE!') - // cleanup subscriptions/tasks - for (const disposable of this.context.subscriptions) { - disposable.dispose() - } - // shut down state machine - console.log('deactivate machine') - this.machine.deactivate() - } + // setup tasks or views here + } + public deactivate = (): void => { + console.log('DEACTIVATE!') + // cleanup subscriptions/tasks + for (const disposable of this.vscodeExt.subscriptions) { + disposable.dispose() + } + // shut down state machine + console.log('deactivate machine') + this.machine.deactivate() + } - // execute vscode command - public dispatch = (type: string, payload?: any) => { - vscode.commands.executeCommand(type, payload) - } + // execute vscode command + public dispatch = (type: string, payload?: any) => { + vscode.commands.executeCommand(type, payload) + } - private activateCommands = (): void => { - const commands = createCommands({ - context: this.context, - machine: this.machine, - storage, - git, - position, - }) - for (const cmd in commands) { - const command: vscode.Disposable = vscode.commands.registerCommand(cmd, commands[cmd]) - this.context.subscriptions.push(command) - } - } + private activateCommands = (): void => { + const commands = createCommands({ + vscodeExt: this.vscodeExt, + machine: this.machine, + git, + }) + for (const cmd in commands) { + const command: vscode.Disposable = vscode.commands.registerCommand(cmd, commands[cmd]) + this.vscodeExt.subscriptions.push(command) + } + } } export default Editor diff --git a/src/extension.ts b/src/extension.ts index def09157..473b424d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,10 +1,10 @@ import * as vscode from 'vscode' import {setWorkspaceRoot} from './services/node' -import Tutorial from './services/tutorial' +import Tutorial, {TutorialModel} from './services/tutorial' import StateMachine from './state' import Editor from './editor' -export const tutorial = new Tutorial() +export const tutorial: TutorialModel = new Tutorial() // state machine that governs application logic export const machine = new StateMachine({dispatch: vscode.commands.executeCommand, tutorial}) diff --git a/src/services/storage.ts b/src/services/storage.ts index d1df66fc..b52b07dc 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -1,77 +1,78 @@ import * as CR from 'typings' +import * as G from 'typings/graphql' import * as storage from '../editor/storage' // TUTORIAL const STORE_TUTORIAL = 'coderoad:tutorial' -export async function getTutorial(): Promise { - return storage.get(STORE_TUTORIAL) +export async function getTutorial(): Promise { + return storage.get(STORE_TUTORIAL) } -export async function setTutorial(tutorial: CR.Tutorial): Promise { - await storage.update(STORE_TUTORIAL, tutorial) +export async function setTutorial(tutorial: G.Tutorial): Promise { + await storage.update(STORE_TUTORIAL, tutorial) } // POSITION const STORE_POSITION = 'coderoad:position' -const defaultPosition = { levelId: '', stageId: '', stepId: '' } +const defaultPosition = {levelId: '', stageId: '', stepId: ''} export async function getPosition(): Promise { - const position: CR.Position | undefined = storage.get(STORE_POSITION) - return position || defaultPosition + const position: CR.Position | undefined = storage.get(STORE_POSITION) + return position || defaultPosition } export async function setPosition(position: CR.Position): Promise { - await storage.update(STORE_POSITION, position) + await storage.update(STORE_POSITION, position) } // PROGRESS const STORE_PROGRESS = 'coderoad:progress' -const defaultProgress = { levels: {}, stages: {}, steps: {}, hints: {}, complete: false } +const defaultProgress = {levels: {}, stages: {}, steps: {}, hints: {}, complete: false} export async function getProgress(): Promise { - const progress: CR.Progress | undefined = await storage.get(STORE_PROGRESS) - return progress || defaultProgress + const progress: CR.Progress | undefined = await storage.get(STORE_PROGRESS) + return progress || defaultProgress } export async function resetProgress(): Promise { - await storage.update(STORE_PROGRESS, defaultProgress) + await storage.update(STORE_PROGRESS, defaultProgress) } interface ProgressUpdate { - levels?: { - [levelId: string]: boolean - } - stages?: { - [stageid: string]: boolean - } - steps?: { - [stepId: string]: boolean - } + levels?: { + [levelId: string]: boolean + } + stages?: { + [stageid: string]: boolean + } + steps?: { + [stepId: string]: boolean + } } export async function setProgress(record: ProgressUpdate): Promise { - const progress = await getProgress() - if (record.levels) { - progress.levels = { - ...progress.levels, - ...record.levels, - } - } - if (record.stages) { - progress.stages = { - ...progress.stages, - ...record.stages, - } - } - if (record.steps) { - progress.steps = { - ...progress.steps, - ...record.steps, - } - } + const progress = await getProgress() + if (record.levels) { + progress.levels = { + ...progress.levels, + ...record.levels, + } + } + if (record.stages) { + progress.stages = { + ...progress.stages, + ...record.stages, + } + } + if (record.steps) { + progress.steps = { + ...progress.steps, + ...record.steps, + } + } - await storage.update(STORE_PROGRESS, progress) + await storage.update(STORE_PROGRESS, progress) } diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index d55decfe..e550fd0a 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -1,17 +1,37 @@ import * as G from 'typings/graphql' import * as CR from 'typings' +import * as storage from '../storage' +import api from '../api' +import tutorialQuery from '@gql/tutorial' +import {timingSafeEqual} from 'crypto' interface TutorialConfig { codingLanguage: G.EnumCodingLanguage testRunner: G.EnumTestRunner } -class Tutorial { +export interface TutorialModel { + repo: G.TutorialRepo + config: TutorialConfig + version: G.TutorialVersion + position: CR.Position + progress: CR.Progress + init(tutorial: G.Tutorial): void + load(tutorialId: string): void + level(levelId: string): G.Level | null + stage(stageId: string): G.Stage | null + step(stepId: string): G.Step | null + updateProgress(): {position: CR.Position, progress: CR.Progress} + nextPosition(): CR.Position + hasExisting(): Promise +} + +class Tutorial implements TutorialModel { public repo: G.TutorialRepo public config: TutorialConfig - private version: G.TutorialVersion - private position: CR.Position - private progress: CR.Progress + public version: G.TutorialVersion + public position: CR.Position + public progress: CR.Progress constructor() { // initialize types, will be assigned when tutorial is selected @@ -20,6 +40,16 @@ class Tutorial { this.version = {} as G.TutorialVersion this.position = {} as CR.Position this.progress = {} as CR.Progress + + Promise.all([ + storage.getTutorial(), + storage.getProgress(), + ]).then((data) => { + const [tutorial, progress] = data + console.log('load continue tutorial') + console.log(tutorial, progress) + }) + } public init = (tutorial: G.Tutorial) => { @@ -44,10 +74,35 @@ class Tutorial { complete: false, } - // set position, progress, tutorial locally + // set tutorial, position, progress locally + // TODO: base position off of progress + Promise.all([ + storage.setTutorial(tutorial), + storage.setPosition(this.position), + storage.setProgress(this.progress) + ]) } - public load = (tutorial: G.Tutorial) => { + + public async hasExisting(): Promise { + const [tutorial, progress] = await Promise.all([ + storage.getTutorial(), + storage.getProgress(), + ]) + + return !!(tutorial && progress) + } + + public async load(tutorialId: string) { // TODO: load from localStorage + const tutorial: G.Tutorial | null = await api.request(tutorialQuery, { + tutorialId, // TODO: add selection of tutorial id + }) + + if (!tutorial) { + throw new Error(`Tutorial ${tutorialId} not found`) + } + + await this.init(tutorial) } public level = (levelId: string): G.Level | null => { const level: G.Level | undefined = this.version.levels.find((l: G.Level) => l.id === levelId) diff --git a/src/state/actions/index.ts b/src/state/actions/index.ts index 291cef14..6fb05185 100644 --- a/src/state/actions/index.ts +++ b/src/state/actions/index.ts @@ -1,15 +1,13 @@ import {assign} from 'xstate' // NOTE: codesmell - importing machine import {machine} from '../../extension' -import api from '../../services/api' +import {TutorialModel} from '../../services/tutorial' import * as CR from 'typings' import * as G from 'typings/graphql' -import tutorialQuery from '@gql/tutorial' import * as storage from '../../services/storage' import * as git from '../../services/git' -let currentTutorial: G.Tutorial | undefined -let currentProgress: CR.Progress = { +const currentProgress: CR.Progress = { levels: {}, stages: {}, steps: {}, @@ -34,39 +32,37 @@ const calculatePosition = ({data, progress}: {data: CR.TutorialData, progress: C return nextPosition } -export default (dispatch: CR.EditorDispatch) => ({ +export default (dispatch: CR.EditorDispatch, tutorialModel: TutorialModel) => ({ createWebview() { dispatch('coderoad.open_webview') }, async newOrContinue() { - // verify that the user has a tutorial & progress + // verify that the user has an existing tutorial to continue + const hasExistingTutorial: boolean = await tutorialModel.hasExisting() + // verify git is setup with a coderoad remote - const [tutorial, progress, hasGit, hasGitRemote] = await Promise.all([ - storage.getTutorial(), - storage.getProgress(), + const [hasGit, hasGitRemote] = await Promise.all([ git.gitVersion(), git.gitCheckRemoteExists(), ]) - const canContinue = !!(tutorial && progress && hasGit && hasGitRemote) - if (canContinue) { - // continue - currentTutorial = tutorial - currentProgress = progress - } + const canContinue = !!(hasExistingTutorial && hasGit && hasGitRemote) + + // TODO: may need to clean up git remote if no existing tutorial machine.send(canContinue ? 'CONTINUE' : 'NEW') }, async tutorialLaunch() { - const tutorial: G.Tutorial = await api.request(tutorialQuery, { - tutorialId: '1', // TODO: add selection of tutorial id - }) - currentTutorial = tutorial - console.log(tutorial) - dispatch('coderoad.tutorial_launch', tutorial) + const tutorialId: string = '1' + // TODO: load tutorialId + await tutorialModel.load(tutorialId) + const repo: G.TutorialRepo = tutorialModel.repo + + dispatch('coderoad.tutorial_launch', repo) }, tutorialSetup() { - dispatch('coderoad.tutorial_setup', currentTutorial) + const codingLanguage: G.EnumCodingLanguage = tutorialModel.config.codingLanguage + dispatch('coderoad.tutorial_setup', codingLanguage) }, initializeNewTutorial: assign({ position: (context: any): CR.Position => { diff --git a/src/state/context/index.ts b/src/state/context/index.ts deleted file mode 100644 index 054f719f..00000000 --- a/src/state/context/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import basicTutorialData from '../../tutorials/basic' -import * as CR from 'typings' - -const tutorialContext: CR.MachineContext = { - position: { - levelId: '', - stageId: '', - stepId: '', - }, - progress: { - levels: {}, - stages: {}, - steps: {}, - complete: false, - }, - // TODO: load tutorial instead of preloading demo - data: basicTutorialData.data, -} - -export default tutorialContext diff --git a/src/state/index.ts b/src/state/index.ts index 2da10916..624827ba 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -1,5 +1,5 @@ import {interpret, Interpreter} from 'xstate' -import Tutorial from '../services/tutorial' +import {TutorialModel} from '../services/tutorial' import * as CR from 'typings' import createMachine from './machine' @@ -23,12 +23,11 @@ const stateToString = (state: string | object, str: string = ''): string => { interface Props { dispatch: CR.EditorDispatch - tutorial: Tutorial + tutorial: TutorialModel } class StateMachine { private dispatch: CR.EditorDispatch - private tutorial: Tutorial private machineOptions = { devTools: true, deferEvents: true, @@ -37,8 +36,7 @@ class StateMachine { private service: Interpreter constructor({dispatch, tutorial}: Props) { this.dispatch = dispatch - this.tutorial = tutorial - const machine = createMachine(dispatch) + const machine = createMachine(dispatch, tutorial) this.service = interpret(machine, this.machineOptions) // logging .onTransition(state => { diff --git a/src/state/machine.ts b/src/state/machine.ts index e8f3a0a8..6c0b2cec 100644 --- a/src/state/machine.ts +++ b/src/state/machine.ts @@ -1,174 +1,173 @@ -import { Machine } from 'xstate' +import {Machine} from 'xstate' import * as CR from 'typings' +import {TutorialModel} from '../services/tutorial' import createActions from './actions' import guards from './guards' -import initialContext from './context' -export const machine = (dispatch: CR.EditorDispatch) => - Machine( - { - id: 'root', - context: initialContext, - initial: 'SelectTutorial', - states: { - SelectTutorial: { - onEntry: ['createWebview'], - initial: 'Initial', - states: { - Initial: { - on: { - WEBVIEW_INITIALIZED: 'Startup', - }, - }, - Startup: { - onEntry: ['newOrContinue'], - on: { - CONTINUE: 'ContinueTutorial', - NEW: 'NewTutorial', - }, - }, - NewTutorial: { - initial: 'SelectTutorial', - states: { - SelectTutorial: { - on: { - TUTORIAL_START: 'InitializeTutorial', - }, - }, - InitializeTutorial: { - onEntry: ['tutorialLaunch'], - on: { - TUTORIAL_LOADED: '#tutorial', - }, - }, - }, - }, - ContinueTutorial: { - onEntry: ['tutorialContinue'], - on: { - TUTORIAL_START: '#tutorial-load-next', - }, - }, - }, - }, - Tutorial: { - id: 'tutorial', - initial: 'Initialize', - onEntry: ['tutorialSetup'], - on: { - WEBVIEW_INITIALIZED: '#tutorial-load-next' - }, - states: { - Initialize: { - onEntry: ['initializeNewTutorial'], - after: { - 0: 'Summary', - }, - }, - LoadNext: { - id: 'tutorial-load-next', - after: { - 0: [{ - target: 'Stage', - cond: 'hasNextStep', - }, - { - target: 'Stage', - cond: 'hasNextStage', - }, - { - target: 'Level', - cond: 'hasNextLevel', - }, - { - target: '#completed-tutorial', - }, - ], - }, - }, +export const machine = (dispatch: CR.EditorDispatch, tutorial: TutorialModel) => + Machine( + { + id: 'root', + initial: 'SelectTutorial', + states: { + SelectTutorial: { + onEntry: ['createWebview'], + initial: 'Initial', + states: { + Initial: { + on: { + WEBVIEW_INITIALIZED: 'Startup', + }, + }, + Startup: { + onEntry: ['newOrContinue'], + on: { + CONTINUE: 'ContinueTutorial', + NEW: 'NewTutorial', + }, + }, + NewTutorial: { + initial: 'SelectTutorial', + states: { + SelectTutorial: { + on: { + TUTORIAL_START: 'InitializeTutorial', + }, + }, + InitializeTutorial: { + onEntry: ['tutorialLaunch'], + on: { + TUTORIAL_LOADED: '#tutorial', + }, + }, + }, + }, + ContinueTutorial: { + onEntry: ['tutorialContinue'], + on: { + TUTORIAL_START: '#tutorial-load-next', + }, + }, + }, + }, + Tutorial: { + id: 'tutorial', + initial: 'Initialize', + onEntry: ['tutorialSetup'], + on: { + WEBVIEW_INITIALIZED: '#tutorial-load-next' + }, + states: { + Initialize: { + onEntry: ['initializeNewTutorial'], + after: { + 0: 'Summary', + }, + }, + LoadNext: { + id: 'tutorial-load-next', + after: { + 0: [{ + target: 'Stage', + cond: 'hasNextStep', + }, + { + target: 'Stage', + cond: 'hasNextStage', + }, + { + target: 'Level', + cond: 'hasNextLevel', + }, + { + target: '#completed-tutorial', + }, + ], + }, + }, - Summary: { - on: { - NEXT: 'Level', - }, - }, - Level: { - onEntry: ['loadLevel'], - on: { - NEXT: 'Stage', - BACK: 'Summary', - }, - }, - Stage: { - onEntry: ['loadStage', 'stepLoadCommits'], - initial: 'Normal', - states: { - Normal: { - on: { - TEST_RUN: 'TestRunning', - STEP_SOLUTION_LOAD: { - actions: ['callSolution'], - }, - }, - }, - TestRunning: { - onEntry: ['testStart'], - on: { - TEST_PASS: 'TestPass', - TEST_FAIL: 'TestFail', - }, - }, - TestPass: { - onEntry: ['testPass', 'progressUpdate'], - onExit: ['stepLoadNext'], - after: { - 1000: 'StepNext', - }, - }, - TestFail: { - onEntry: ['testFail'], - after: { - 0: 'Normal', - }, - }, - StepNext: { - after: { - 0: [ - { - target: 'Normal', - cond: 'hasNextStep', - actions: ['stepLoadCommits'], - }, - { - target: 'StageComplete', - }, - ], - }, - }, - StageComplete: { - on: { - STAGE_NEXT: { - target: '#tutorial-load-next', - actions: ['updatePosition'], - }, - }, - }, - }, - }, - Completed: { - id: 'completed-tutorial', - type: 'final', - }, - }, - }, - }, - }, - { - actions: createActions(dispatch), - guards, - activities: {}, - }, - ) + Summary: { + on: { + NEXT: 'Level', + }, + }, + Level: { + onEntry: ['loadLevel'], + on: { + NEXT: 'Stage', + BACK: 'Summary', + }, + }, + Stage: { + onEntry: ['loadStage', 'stepLoadCommits'], + initial: 'Normal', + states: { + Normal: { + on: { + TEST_RUN: 'TestRunning', + STEP_SOLUTION_LOAD: { + actions: ['callSolution'], + }, + }, + }, + TestRunning: { + onEntry: ['testStart'], + on: { + TEST_PASS: 'TestPass', + TEST_FAIL: 'TestFail', + }, + }, + TestPass: { + onEntry: ['testPass', 'progressUpdate'], + onExit: ['stepLoadNext'], + after: { + 1000: 'StepNext', + }, + }, + TestFail: { + onEntry: ['testFail'], + after: { + 0: 'Normal', + }, + }, + StepNext: { + after: { + 0: [ + { + target: 'Normal', + cond: 'hasNextStep', + actions: ['stepLoadCommits'], + }, + { + target: 'StageComplete', + }, + ], + }, + }, + StageComplete: { + on: { + STAGE_NEXT: { + target: '#tutorial-load-next', + actions: ['updatePosition'], + }, + }, + }, + }, + }, + Completed: { + id: 'completed-tutorial', + type: 'final', + }, + }, + }, + }, + }, + { + actions: createActions(dispatch, tutorial), + guards, + activities: {}, + }, + ) export default machine diff --git a/typings/index.d.ts b/typings/index.d.ts index f42a963c..37238898 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1,181 +1,169 @@ -import { send } from 'xstate' +import {send} from 'xstate' +import TutorialModel from '../src/services/tutorial' export interface TutorialLevel { - stageList: string[] - content: { - title: string - text: string - } - actions?: { - setup: TutorialAction - } + stageList: string[] + content: { + title: string + text: string + } + actions?: { + setup: TutorialAction + } } export interface TutorialStage { - stepList: string[] - content: { - title: string - text: string - } - actions?: { - setup: TutorialAction - } + stepList: string[] + content: { + title: string + text: string + } + actions?: { + setup: TutorialAction + } } export interface TutorialHint { - text: string - displayed?: boolean + text: string + displayed?: boolean } export interface TutorialAction { - commits: string[] - commands?: string[] - files?: string[] + commits: string[] + commands?: string[] + files?: string[] } export interface TutorialStepContent { - text: string - title?: string + text: string + title?: string } export interface TutorialStep { - content: TutorialStepContent - actions: { - setup: TutorialAction - solution: TutorialAction - } - hints?: TutorialHint[] + content: TutorialStepContent + actions: { + setup: TutorialAction + solution: TutorialAction + } + hints?: TutorialHint[] } export interface TutorialData { - summary: TutorialSummary - levels: { - [levelId: string]: TutorialLevel - } - stages: { - [stageId: string]: TutorialStage - } - steps: { - [stepId: string]: TutorialStep - } + summary: TutorialSummary + levels: { + [levelId: string]: TutorialLevel + } + stages: { + [stageId: string]: TutorialStage + } + steps: { + [stepId: string]: TutorialStep + } } export interface TutorialMeta { - version: string - repo: string - createdBy: string - createdAt: string - updatedBy: string - updatedAt: string - contributors: string[] - languages: string[] - testRunner: string + version: string + repo: string + createdBy: string + createdAt: string + updatedBy: string + updatedAt: string + contributors: string[] + languages: string[] + testRunner: string } export interface TutorialSummary { - title: string - description: string - levelList: string[] + title: string + description: string + levelList: string[] } export interface Tutorial { - id: string - meta: TutorialMeta - data: TutorialData + id: string + meta: TutorialMeta + data: TutorialData } export interface Progress { - levels: { - [levelId: string]: boolean - } - stages: { - [stageId: string]: boolean - } - steps: { - [stepId: string]: boolean - } - complete: boolean + levels: { + [levelId: string]: boolean + } + stages: { + [stageId: string]: boolean + } + steps: { + [stepId: string]: boolean + } + complete: boolean } // current tutorial position export interface Position { - levelId: string - stageId: string - stepId: string - complete?: boolean + levelId: string + stageId: string + stepId: string + complete?: boolean } // current tutorial state export interface Action { - type: string - payload?: any - meta?: any + type: string + payload?: any + meta?: any } export interface MachineContext { - position: Position - data: { - summary: TutorialSummary - levels: { - [levelId: string]: TutorialLevel - } - stages: { - [stageId: string]: TutorialStage - } - steps: { - [stepId: string]: TutorialStep - } - } - progress: Progress + tutorial: TutorialModel } export interface MachineEvent { - type: string - payload?: any + type: string + payload?: any } export interface MachineStateSchema { - states: { - SelectTutorial: { - states: { - Initial: {} - Startup: {} - NewTutorial: { - states: { - SelectTutorial: {} - InitializeTutorial: {} - } - } - ContinueTutorial: {} - } - } - Tutorial: { - states: { - Initialize: {} - Summary: {} - LoadNext: {} - Level: {} - Stage: { - states: { - Normal: {} - TestRunning: {} - TestPass: {} - TestFail: {} - StepNext: {} - StageComplete: {} - } - } - Completed: {} - } - } - } + states: { + SelectTutorial: { + states: { + Initial: {} + Startup: {} + NewTutorial: { + states: { + SelectTutorial: {} + InitializeTutorial: {} + } + } + ContinueTutorial: {} + } + } + Tutorial: { + states: { + Initialize: {} + Summary: {} + LoadNext: {} + Level: {} + Stage: { + states: { + Normal: {} + TestRunning: {} + TestPass: {} + TestFail: {} + StepNext: {} + StageComplete: {} + } + } + Completed: {} + } + } + } } export interface StateMachine { - activate(): void - deactivate(): void - send(action: string | Action): void + activate(): void + deactivate(): void + send(action: string | Action): void } export type EditorDispatch = (type: string, payload?: any) => void From a92d52fc757730712ec3babda640152c75328c45 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 15:17:43 -0700 Subject: [PATCH 048/117] heavy refactoring --- src/editor/commands/loadSolution.ts | 18 +- src/editor/index.ts | 2 - src/services/git/index.ts | 249 ++++++++++++++------------- src/services/position.ts | 65 ------- src/services/tutorial/index.ts | 37 ++-- src/state/actions/index.ts | 258 ++++++++++++---------------- src/state/guards/index.ts | 68 ++++---- src/state/index.ts | 2 +- src/state/machine.ts | 10 +- typings/graphql.d.ts | 8 +- typings/index.d.ts | 4 +- web-app/src/App.tsx | 44 ++--- 12 files changed, 333 insertions(+), 432 deletions(-) delete mode 100644 src/services/position.ts diff --git a/src/editor/commands/loadSolution.ts b/src/editor/commands/loadSolution.ts index c1c883a6..058f9500 100644 --- a/src/editor/commands/loadSolution.ts +++ b/src/editor/commands/loadSolution.ts @@ -1,9 +1,10 @@ import * as CR from 'typings' import * as G from 'typings/graphql' +import {TutorialModel} from '../../services/tutorial' import * as storage from '../../services/storage' import {gitLoadCommits, gitClear} from '../../services/git' -export default async function loadSolution(dispatch: CR.EditorDispatch): Promise { +export default async function loadSolution(dispatch: CR.EditorDispatch, tutorialModel: TutorialModel): Promise { const [position, tutorial]: [CR.Position, G.Tutorial | undefined] = await Promise.all([ storage.getPosition(), storage.getTutorial(), @@ -16,17 +17,10 @@ export default async function loadSolution(dispatch: CR.EditorDispatch): Promise } // eslint-disable-next-line - try { - const solution = tutorial.version - .levels.find((l: G.Level) => l.id === position.levelId) - .stages.find((s: G.Stage) => s.id === position.stageId) - .steps.find((s: G.Step) => s.id === position.stepId) - .solution + const step = tutorialModel.step() + const solution = step.solution - await gitClear() - await gitLoadCommits(solution, dispatch) - } catch (error) { - throw new Error(error) - } + await gitClear() + await gitLoadCommits(solution, dispatch) } diff --git a/src/editor/index.ts b/src/editor/index.ts index fca9104b..6f033db2 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -1,9 +1,7 @@ import * as vscode from 'vscode' import * as CR from 'typings' import {createCommands} from './commands' -import * as storage from '../services/storage' import * as git from '../services/git' -import * as position from '../services/position' interface Props { machine: CR.StateMachine diff --git a/src/services/git/index.ts b/src/services/git/index.ts index 1ec60bf4..c47aba71 100644 --- a/src/services/git/index.ts +++ b/src/services/git/index.ts @@ -1,35 +1,36 @@ +import * as G from 'typings/graphql' import * as CR from 'typings' -import { exec, exists } from '../node' +import {exec, exists} from '../node' import errorMessages from './errorMessages' const gitOrigin = 'coderoad' const stashAllFiles = async () => { - console.log('stashAllFiles') - // stash files including untracked (eg. newly created file) - const { stdout, stderr } = await exec(`git stash --include-untracked`) - if (stderr) { - console.error(stderr) - throw new Error('Error stashing files') - } + console.log('stashAllFiles') + // stash files including untracked (eg. newly created file) + const {stdout, stderr} = await exec(`git stash --include-untracked`) + if (stderr) { + console.error(stderr) + throw new Error('Error stashing files') + } } const cherryPickCommit = async (commit: string, count = 0): Promise => { - if (count > 1) { - console.warn('cherry-pick failed') - return - } - try { - const { stdout } = await exec(`git cherry-pick ${commit}`) - if (!stdout) { - throw new Error('No cherry-pick output') - } - } catch (error) { - console.log('cherry-pick-commit failed') - // stash all files if cherry-pick fails - await stashAllFiles() - return cherryPickCommit(commit, ++count) - } + if (count > 1) { + console.warn('cherry-pick failed') + return + } + try { + const {stdout} = await exec(`git cherry-pick ${commit}`) + if (!stdout) { + throw new Error('No cherry-pick output') + } + } catch (error) { + console.log('cherry-pick-commit failed') + // stash all files if cherry-pick fails + await stashAllFiles() + return cherryPickCommit(commit, ++count) + } } @@ -38,38 +39,38 @@ const cherryPickCommit = async (commit: string, count = 0): Promise => { SINGLE git cherry-pick %COMMIT% if fails, will stash all and retry */ -export async function gitLoadCommits(actions: CR.TutorialAction, dispatch: CR.EditorDispatch): Promise { - const { commits, commands, files } = actions - - for (const commit of commits) { - // pull a commit from tutorial repo - console.log(`try cherry-pick ${commit}`) - await cherryPickCommit(commit) - } - - if (commands) { - // TODO: run shell as task - for (const command of commands) { - const { stdout, stderr } = await exec(command) - if (stderr) { - console.error(stderr) - // langauge specific error messages from running commands - for (const message of Object.keys(errorMessages.js)) { - if (stderr.match(message)) { - // ignored error - throw new Error('Error running setup command') - } - } - } - console.log(`run command: ${command}`, stdout) - } - } - - if (files) { - for (const filePath of files) { - dispatch('coderoad.open_file', filePath) - } - } +export async function gitLoadCommits(actions: G.StepActions, editorDispatch: CR.EditorDispatch): Promise { + const {commits, commands, files} = actions + + for (const commit of commits) { + // pull a commit from tutorial repo + console.log(`try cherry-pick ${commit}`) + await cherryPickCommit(commit) + } + + if (commands) { + // TODO: run shell as task + for (const command of commands) { + const {stdout, stderr} = await exec(command) + if (stderr) { + console.error(stderr) + // langauge specific error messages from running commands + for (const message of Object.keys(errorMessages.js)) { + if (stderr.match(message)) { + // ignored error + throw new Error('Error running setup command') + } + } + } + console.log(`run command: ${command}`, stdout) + } + } + + if (files) { + for (const filePath of files) { + editorDispatch('coderoad.open_file', filePath) + } + } } /* @@ -78,96 +79,96 @@ export async function gitLoadCommits(actions: CR.TutorialAction, dispatch: CR.Ed */ export async function gitSaveCommit(position: CR.Position): Promise { - const { levelId, stageId, stepId } = position - const { stdout, stderr } = await exec(`git commit -am 'completed ${levelId}/${stageId}/${stepId}'`) - if (stderr) { - console.error(stderr) - throw new Error('Error saving progress to Git') - } - console.log('save with commit & continue stdout', stdout) + const {levelId, stageId, stepId} = position + const {stdout, stderr} = await exec(`git commit -am 'completed ${levelId}/${stageId}/${stepId}'`) + if (stderr) { + console.error(stderr) + throw new Error('Error saving progress to Git') + } + console.log('save with commit & continue stdout', stdout) } export async function gitClear(): Promise { - try { - // commit progress to git - const { stderr } = await exec('git reset HEAD --hard && git clean -fd') - if (!stderr) { - return - } - console.error(stderr) - } catch (error) { - console.error(error) - } - throw new Error('Error cleaning up current unsaved work') + try { + // commit progress to git + const {stderr} = await exec('git reset HEAD --hard && git clean -fd') + if (!stderr) { + return + } + console.error(stderr) + } catch (error) { + console.error(error) + } + throw new Error('Error cleaning up current unsaved work') } export async function gitVersion(): Promise { - const { stdout, stderr } = await exec('git --version') - if (!stderr) { - const match = stdout.match(/^git version (\d+\.)?(\d+\.)?(\*|\d+)/) - if (match) { - // eslint-disable-next-line - const [_, major, minor, patch] = match - return `${major}${minor}${patch}` - } - } - throw new Error('Git not installed. Please install Git') + const {stdout, stderr} = await exec('git --version') + if (!stderr) { + const match = stdout.match(/^git version (\d+\.)?(\d+\.)?(\*|\d+)/) + if (match) { + // eslint-disable-next-line + const [_, major, minor, patch] = match + return `${major}${minor}${patch}` + } + } + throw new Error('Git not installed. Please install Git') } async function gitInit(): Promise { - const { stderr } = await exec('git init') - if (stderr) { - throw new Error('Error initializing Gits') - } + const {stderr} = await exec('git init') + if (stderr) { + throw new Error('Error initializing Gits') + } } export async function gitInitIfNotExists(): Promise { - const hasGit = await gitVersion() + const hasGit = await gitVersion() - if (!hasGit) { - throw new Error('Git must be installed') - } + if (!hasGit) { + throw new Error('Git must be installed') + } - const hasGitInit = exists('.git') - if (!hasGitInit) { - await gitInit() - } + const hasGitInit = exists('.git') + if (!hasGitInit) { + await gitInit() + } } export async function gitAddRemote(repo: string): Promise { - const { stderr } = await exec(`git remote add ${gitOrigin} ${repo} && git fetch ${gitOrigin}`) - if (stderr) { - const alreadyExists = stderr.match(`${gitOrigin} already exists.`) - const successfulNewBranch = stderr.match('new branch') - - // validate the response is acceptable - if (!alreadyExists && !successfulNewBranch) { - console.error(stderr) - throw new Error('Error adding git remote') - } - } + const {stderr} = await exec(`git remote add ${gitOrigin} ${repo} && git fetch ${gitOrigin}`) + if (stderr) { + const alreadyExists = stderr.match(`${gitOrigin} already exists.`) + const successfulNewBranch = stderr.match('new branch') + + // validate the response is acceptable + if (!alreadyExists && !successfulNewBranch) { + console.error(stderr) + throw new Error('Error adding git remote') + } + } } export async function gitCheckRemoteExists(): Promise { - try { - const { stdout, stderr } = await exec('git remote -v') - if (stderr) { - return false - } - // string match on remote output - // TODO: improve the specificity of this regex - return !!stdout.match(gitOrigin) - } catch (error) { - return false - } + try { + const {stdout, stderr} = await exec('git remote -v') + if (stderr) { + return false + } + // string match on remote output + // TODO: improve the specificity of this regex + return !!stdout.match(gitOrigin) + } catch (error) { + return false + } } export async function gitSetupRemote(repo: string): Promise { - // check coderoad remote not taken - const hasRemote = await gitCheckRemoteExists() - // git remote add coderoad tutorial - // git fetch coderoad - if (!hasRemote) { - await gitAddRemote(repo) - } + // check coderoad remote not taken + const hasRemote = await gitCheckRemoteExists() + // git remote add coderoad tutorial + // git fetch coderoad + if (!hasRemote) { + await gitAddRemote(repo) + } } diff --git a/src/services/position.ts b/src/services/position.ts deleted file mode 100644 index 6f0e4312..00000000 --- a/src/services/position.ts +++ /dev/null @@ -1,65 +0,0 @@ -import * as CR from 'typings' -import * as storage from './storage' - -export async function getInitial(tutorial: CR.Tutorial): Promise { - const { data } = tutorial - - const levelId = data.summary.levelList[0] - const stageId = data.levels[levelId].stageList[0] - const stepId = data.stages[stageId].stepList[0] - - const position = { - levelId, - stageId, - stepId, - } - - storage.setPosition(position) - - return position -} - -export async function loadProgressPosition() { - const [tutorial, progress] = await Promise.all([storage.getTutorial(), storage.getProgress()]) - - if (!tutorial) { - throw new Error('No tutorial found') - } - - // already complete - if (progress.complete) { - return - } - - const { - data: { summary, levels, stages }, - } = tutorial - - // loop over levels to find first incomplete - const currentLevelId = summary.levelList.find((levelId: string) => !progress.levels[levelId]) - if (!currentLevelId) { - throw new Error('Current level not found') - } - - // loop over stages to find first incomplete - const currentStageId = levels[currentLevelId].stageList.find((stageId: string) => !progress.stages[stageId]) - if (!currentStageId) { - throw new Error('Current stage not found') - } - - // loop over steps to find first incomplete - const currentStepId = stages[currentStageId].stepList.find((stepId: string) => !progress.steps[stepId]) - if (!currentStepId) { - throw new Error('Current step not found') - } - - const position: CR.Position = { - levelId: currentLevelId, - stageId: currentStageId, - stepId: currentStepId, - } - - storage.setPosition(position) -} - -export async function getPrev(): Promise { } diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index e550fd0a..ecb1f5a5 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -18,9 +18,9 @@ export interface TutorialModel { progress: CR.Progress init(tutorial: G.Tutorial): void load(tutorialId: string): void - level(levelId: string): G.Level | null - stage(stageId: string): G.Stage | null - step(stepId: string): G.Step | null + level(levelId?: string): G.Level + stage(stageId?: string): G.Stage + step(stepId?: string): G.Step updateProgress(): {position: CR.Position, progress: CR.Progress} nextPosition(): CR.Position hasExisting(): Promise @@ -104,35 +104,26 @@ class Tutorial implements TutorialModel { await this.init(tutorial) } - public level = (levelId: string): G.Level | null => { - const level: G.Level | undefined = this.version.levels.find((l: G.Level) => l.id === levelId) + public level = (levelId: string): G.Level => { + const level: G.Level | undefined = this.version.levels.find((l: G.Level) => l.id === levelId || this.position.levelId) if (!level) { - console.warn(`LevelId not found: ${levelId}`) - return null + throw new Error('Level not found') } return level } - public stage = (stageId: string): G.Stage | null => { - const level: G.Level | null = this.level(this.position.levelId) - if (!level) { - return null - } - const stage: G.Stage | undefined = level.stages.find((s: G.Stage) => s.id === stageId) + public stage = (stageId?: string): G.Stage => { + const level: G.Level = this.level(this.position.levelId) + const stage: G.Stage | undefined = level.stages.find((s: G.Stage) => s.id === stageId || this.position.stageId) if (!stage) { - console.warn(`StageId not found: ${stageId}`) - return null + throw new Error('Stage not found') } return stage } - public step = (stepId: string): G.Step | null => { - const stage: G.Stage | null = this.stage(this.position.stageId) - if (!stage) { - return null - } - const step: G.Step | undefined = stage.steps.find((s: G.Step) => s.id === stepId) + public step = (stepId?: string): G.Step => { + const stage: G.Stage = this.stage(this.position.stageId) + const step: G.Step | undefined = stage.steps.find((s: G.Step) => s.id === stepId || this.position.stepId) if (!step) { - console.warn(`StepId not found: ${stepId}`) - return null + throw new Error('Step not found') } return step } diff --git a/src/state/actions/index.ts b/src/state/actions/index.ts index 6fb05185..62481a70 100644 --- a/src/state/actions/index.ts +++ b/src/state/actions/index.ts @@ -4,37 +4,12 @@ import {machine} from '../../extension' import {TutorialModel} from '../../services/tutorial' import * as CR from 'typings' import * as G from 'typings/graphql' -import * as storage from '../../services/storage' import * as git from '../../services/git' -const currentProgress: CR.Progress = { - levels: {}, - stages: {}, - steps: {}, - complete: false, -} -const calculatePosition = ({data, progress}: {data: CR.TutorialData, progress: CR.Progress}): CR.Position => { - const {levelList} = data.summary - // take next incomplete level or the final step - const levelId = levelList.find((id: string) => !progress.levels[id]) || levelList[levelList.length - 1] - const {stageList} = data.levels[levelId] - const stageId = stageList.find((id: string) => !progress.stages[id]) || stageList[stageList.length - 1] - const {stepList} = data.stages[stageId] - const stepId = stepList.find((id: string) => !progress.steps[id]) || stepList[stepList.length - 1] - - const nextPosition: CR.Position = { - levelId, - stageId, - stepId, - } - - return nextPosition -} - -export default (dispatch: CR.EditorDispatch, tutorialModel: TutorialModel) => ({ +export default (editorDispatch: CR.EditorDispatch, tutorialModel: TutorialModel) => ({ createWebview() { - dispatch('coderoad.open_webview') + editorDispatch('coderoad.open_webview') }, async newOrContinue() { // verify that the user has an existing tutorial to continue @@ -58,143 +33,138 @@ export default (dispatch: CR.EditorDispatch, tutorialModel: TutorialModel) => ({ await tutorialModel.load(tutorialId) const repo: G.TutorialRepo = tutorialModel.repo - dispatch('coderoad.tutorial_launch', repo) + editorDispatch('coderoad.tutorial_launch', repo) }, tutorialSetup() { const codingLanguage: G.EnumCodingLanguage = tutorialModel.config.codingLanguage - dispatch('coderoad.tutorial_setup', codingLanguage) + editorDispatch('coderoad.tutorial_setup', codingLanguage) }, - initializeNewTutorial: assign({ - position: (context: any): CR.Position => { - const {data} = context - const levelId = data.summary.levelList[0] - const stageId = data.levels[levelId].stageList[0] - const stepId = data.stages[stageId].stepList[0] - return { - levelId, - stageId, - stepId, - } - }, - }), - tutorialContinue: assign({ - // load initial data, progress & position - data(): CR.TutorialData { - console.log('ACTION: tutorialLoad.data') - if (!currentTutorial) { - throw new Error('No Tutorial loaded') - } - return currentTutorial.data - }, - progress(): CR.Progress { - console.log('ACTION: tutorialLoad.progress') - return currentProgress - }, - position(context: any): CR.Position { - console.log('ACTION: tutorialLoad.position') - if (!currentTutorial) { - throw new Error('No Tutorial loaded') - } - const {data} = currentTutorial - const position = calculatePosition({data, progress: currentProgress}) - - console.log('position', position) - return position - }, - }), + // initializeNewTutorial: assign({ + // position: (context: any): CR.Position => { + // const {data} = context + // const levelId = data.summary.levelList[0] + // const stageId = data.levels[levelId].stageList[0] + // const stepId = data.stages[stageId].stepList[0] + // return { + // levelId, + // stageId, + // stepId, + // } + // }, + // }), + // tutorialContinue: assign({ + // // load initial data, progress & position + // data(): CR.TutorialData { + // console.log('ACTION: tutorialLoad.data') + // if (!currentTutorial) { + // throw new Error('No Tutorial loaded') + // } + // return currentTutorial.data + // }, + // progress(): CR.Progress { + // console.log('ACTION: tutorialLoad.progress') + // return currentProgress + // }, + // position(context: any): CR.Position { + // console.log('ACTION: tutorialLoad.position') + // if (!currentTutorial) { + // throw new Error('No Tutorial loaded') + // } + // const {data} = currentTutorial + // const position = calculatePosition({data, progress: currentProgress}) + + // console.log('position', position) + // return position + // }, + // }), testStart() { - dispatch('coderoad.run_test') + editorDispatch('coderoad.run_test') }, - testPass(context: CR.MachineContext): void { - dispatch('coderoad.test_pass') - git.gitSaveCommit(context.position) + testPass(): void { + editorDispatch('coderoad.test_pass') + git.gitSaveCommit(tutorialModel.position) }, testFail() { - dispatch('coderoad.test_fail') + editorDispatch('coderoad.test_fail') }, // @ts-ignore - progressUpdate: assign({ - progress: (context: CR.MachineContext): CR.Progress => { - console.log('progress update') - const {progress, position, data} = context - const nextProgress = progress - - nextProgress.steps[position.stepId] = true - const {stepList} = data.stages[position.stageId] - const stageComplete = stepList[stepList.length - 1] === position.stepId - if (stageComplete) { - nextProgress.stages[position.stageId] = true - const {stageList} = data.levels[position.levelId] - const levelComplete = stageList[stageList.length - 1] === position.stageId - if (levelComplete) { - nextProgress.levels[position.levelId] = true - const {levelList} = data.summary - const tutorialComplete = levelList[levelList.length - 1] === position.levelId - if (tutorialComplete) { - nextProgress.complete = true - } - } - } - console.log('progress update', nextProgress) - storage.setProgress(nextProgress) - return nextProgress - }, - }), - stepLoadNext: assign({ - position: (context: any): CR.Position => { - const {data, position} = context - const {stepList} = data.stages[position.stageId] - const currentStepIndex = stepList.indexOf(position.stepId) - - const nextStepId = currentStepIndex < stepList.length ? stepList[currentStepIndex + 1] : position.stepId - - const nextPosition = { - ...context.position, - stepId: nextStepId, - } - - return nextPosition - }, - }), - loadLevel(context: CR.MachineContext): void { - const {data, position} = context - console.log('loadLevel') - console.log(position) - const {levels} = data - const level = levels[position.levelId] + progressUpdate() { + tutorialModel.updateProgress() + tutorialModel.nextPosition() + }, + // assign({ + // progress: (): CR.Progress => { + + // console.log('progress update') + // const {progress, position, data} = context + // const nextProgress = progress + + // nextProgress.steps[position.stepId] = true + // const {stepList} = data.stages[position.stageId] + // const stageComplete = stepList[stepList.length - 1] === position.stepId + // if (stageComplete) { + // nextProgress.stages[position.stageId] = true + // const {stageList} = data.levels[position.levelId] + // const levelComplete = stageList[stageList.length - 1] === position.stageId + // if (levelComplete) { + // nextProgress.levels[position.levelId] = true + // const {levelList} = data.summary + // const tutorialComplete = levelList[levelList.length - 1] === position.levelId + // if (tutorialComplete) { + // nextProgress.complete = true + // } + // } + // } + // console.log('progress update', nextProgress) + // storage.setProgress(nextProgress) + // return nextProgress + // }, + // }), + // stepLoadNext: assign({ + // position: (context: any): CR.Position => { + // const {data, position} = context + // const {stepList} = data.stages[position.stageId] + // const currentStepIndex = stepList.indexOf(position.stepId) + + // const nextStepId = currentStepIndex < stepList.length ? stepList[currentStepIndex + 1] : position.stepId + + // const nextPosition = { + // ...context.position, + // stepId: nextStepId, + // } + + // return nextPosition + // }, + // }), + loadLevel(): void { + const level: G.Level = tutorialModel.level() // run level setup if it exists - if (level && level.actions && level.actions.setup) { - git.gitLoadCommits(level.actions.setup, dispatch) + if (level && level.setup) { + git.gitLoadCommits(level.setup, editorDispatch) } }, - stageLoadNext(context: CR.MachineContext) { + stageLoadNext() { console.log('stageLoadNext') - const {position} = context - console.log(position) + tutorialModel.nextPosition() }, - loadStage(context: CR.MachineContext): void { - const {data, position} = context - console.log('loadStage') - console.log(position) - const {stages} = data - const stage = stages[position.levelId] + loadStage(): void { + const stage: G.Stage = tutorialModel.stage() // run level setup if it exists - if (stage && stage.actions && stage.actions.setup) { - git.gitLoadCommits(stage.actions.setup, dispatch) + if (stage && stage.setup) { + git.gitLoadCommits(stage.setup, editorDispatch) } }, // @ts-ignore - updatePosition: assign({ - position: (context: CR.MachineContext) => calculatePosition({ - data: context.data, - progress: context.progress, - }), - }), - stepLoadCommits(context: CR.MachineContext): void { - const {data, position} = context - const {setup} = data.steps[position.stepId].actions - git.gitLoadCommits(setup, dispatch) + // updatePosition: assign({ + // position: () => calculatePosition({ + // data: context.data, + // progress: context.progress, + // }), + // }), + stepLoadCommits(): void { + const step: G.Step = tutorialModel.step() + git.gitLoadCommits(step.setup, editorDispatch) }, }) diff --git a/src/state/guards/index.ts b/src/state/guards/index.ts index ffd9415e..fc2d8eb1 100644 --- a/src/state/guards/index.ts +++ b/src/state/guards/index.ts @@ -1,31 +1,41 @@ import * as CR from 'typings' +import {TutorialModel} from '../../services/tutorial' -export default { - hasNextStep: (context: CR.MachineContext): boolean => { - const { data, position, progress } = context - const steps = data.stages[position.stageId].stepList - const stageIncomplete = !progress.stages[position.stageId] - const isNotFinalStep = (!!position.stepId && (steps[steps.length - 1] !== position.stepId)) - const hasNext = stageIncomplete || isNotFinalStep - console.log('GUARD: hasNextStep', hasNext) - return hasNext - }, - hasNextStage: (context: CR.MachineContext): boolean => { - const { data, position, progress } = context - const stages = data.levels[position.levelId].stageList - const stageComplete = progress.stages[position.stageId] - const isNotFinalStage = !!position.stageId && stages[stages.length - 1] !== position.stageId - const hasNext = stageComplete && isNotFinalStage - console.log('GUARD: hasNextStage', hasNext) - return hasNext - }, - hasNextLevel: (context: CR.MachineContext): boolean => { - const { data, position, progress } = context - const levels = data.summary.levelList - const levelComplete = progress.levels[position.levelId] - const isNotFinalLevel = !!position.levelId && levels[levels.length - 1] !== position.levelId - const hasNext = levelComplete && isNotFinalLevel - console.log('GUARD: hasNextLevel', hasNext) - return hasNext - }, -} + +// TODO: refactor into a single calculation +export default (tutorialModel: TutorialModel) => ({ + hasNextStep: (): boolean => { + + const nextPosition: CR.Position = tutorialModel.nextPosition() + + const sameStage = nextPosition.stageId === tutorialModel.position.stageId + const sameStep = nextPosition.stepId === tutorialModel.position.stepId + + const hasNext: boolean = sameStage && sameStep + + console.log('GUARD: hasNextStep', hasNext) + return hasNext + }, + hasNextStage: (): boolean => { + const nextPosition: CR.Position = tutorialModel.nextPosition() + + const sameLevel = nextPosition.levelId === tutorialModel.position.levelId + const sameStage = nextPosition.stageId === tutorialModel.position.stageId + + const hasNext: boolean = sameLevel && sameStage + + console.log('GUARD: hasNextStage', hasNext) + return hasNext + }, + hasNextLevel: (): boolean => { + const nextPosition: CR.Position = tutorialModel.nextPosition() + + const sameLevel = nextPosition.levelId === tutorialModel.position.levelId + + const hasNext: boolean = sameLevel + + // TODO: ensure this accounts for end + console.log('GUARD: hasNextLevel', hasNext) + return hasNext + }, +}) diff --git a/src/state/index.ts b/src/state/index.ts index 624827ba..1438a4ae 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -33,7 +33,7 @@ class StateMachine { deferEvents: true, execute: true, } - private service: Interpreter + private service: Interpreter<{}, CR.MachineStateSchema, CR.MachineEvent> constructor({dispatch, tutorial}: Props) { this.dispatch = dispatch const machine = createMachine(dispatch, tutorial) diff --git a/src/state/machine.ts b/src/state/machine.ts index 6c0b2cec..74eadd16 100644 --- a/src/state/machine.ts +++ b/src/state/machine.ts @@ -3,10 +3,10 @@ import * as CR from 'typings' import {TutorialModel} from '../services/tutorial' import createActions from './actions' -import guards from './guards' +import createGuards from './guards' -export const machine = (dispatch: CR.EditorDispatch, tutorial: TutorialModel) => - Machine( +export const machine = (editorDispatch: CR.EditorDispatch, tutorialModel: TutorialModel) => + Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( { id: 'root', initial: 'SelectTutorial', @@ -164,8 +164,8 @@ export const machine = (dispatch: CR.EditorDispatch, tutorial: TutorialModel) => }, }, { - actions: createActions(dispatch, tutorial), - guards, + actions: createActions(editorDispatch, tutorialModel), + guards: createGuards(tutorialModel), activities: {}, }, ) diff --git a/typings/graphql.d.ts b/typings/graphql.d.ts index 0d4217a1..fc51b35f 100644 --- a/typings/graphql.d.ts +++ b/typings/graphql.d.ts @@ -69,6 +69,7 @@ export type Level = { stage?: Maybe, stages: Array, setup?: Maybe, + status: string }; @@ -135,6 +136,7 @@ export type Stage = { step?: Maybe, steps: Array, setup?: Maybe, + status: string }; @@ -149,6 +151,7 @@ export type Step = { text: Scalars['String'], setup: StepActions, solution: StepActions, + status: string }; export type StepActions = { @@ -555,9 +558,10 @@ export interface IntrospectionResultData { }; } +// @ts-ignore const result: IntrospectionResultData = { - "__schema": { - "types": [] + __schema: { + types: [] } }; diff --git a/typings/index.d.ts b/typings/index.d.ts index 37238898..60f7d0c4 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -114,9 +114,7 @@ export interface Action { meta?: any } -export interface MachineContext { - tutorial: TutorialModel -} +export interface MachineContext {} export interface MachineEvent { type: string diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index 0f9ddf47..61dba8e2 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -16,31 +16,31 @@ const App = () => { const initialState = { SelectTutorial: 'Initial ' } // set state machine state - const [state, setState] = React.useState(initialState) - - // update level/stage/step status based on user progress & position - // TODO: model server more effeciently - const [setStatus] = useMutation(SET_STATUS) - - // update state based on response from editor - const handleEvent = (event: ReceivedEvent): void => { - const message = event.data - // messages from core - const { progress, position } = message.payload.data - - if (message.type === 'SET_STATE') { - // SET_STATE - set state machine state - setState(message.payload.state) - - setStatus({ variables: { progress, position } }) - } else if (message.type === 'SET_DATA') { - // SET_DATA - set state machine context - setStatus({ variables: { progress, position } }) - } - } + const [state, setState] = React.useState(initialState) + + // update level/stage/step status based on user progress & position + // TODO: model server more effeciently + const [setStatus] = useMutation(SET_STATUS) // event bus listener React.useEffect(() => { + // update state based on response from editor + const handleEvent = (event: ReceivedEvent): void => { + const message = event.data + // messages from core + const { progress, position } = message.payload.data + + if (message.type === 'SET_STATE') { + // SET_STATE - set state machine state + setState(message.payload.state) + + setStatus({ variables: { progress, position } }) + } else if (message.type === 'SET_DATA') { + // SET_DATA - set state machine context + setStatus({ variables: { progress, position } }) + } + } + const listener = 'message' window.addEventListener(listener, handleEvent) return () => { From 46d1e27bec48176b2d52d91ea77f69a6be06a30e Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 15:54:20 -0700 Subject: [PATCH 049/117] fix launch errors --- src/editor/commands/index.ts | 5 +-- src/editor/commands/loadSolution.ts | 15 +-------- src/editor/storage.ts | 31 +++++++++++-------- .../api/gql/{tutorial.ts => getTutorial.ts} | 0 src/services/storage.ts | 2 +- src/services/tutorial/index.ts | 19 ++++++------ 6 files changed, 32 insertions(+), 40 deletions(-) rename src/services/api/gql/{tutorial.ts => getTutorial.ts} (100%) diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index 8862c046..7cfbccf8 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -3,7 +3,7 @@ import * as CR from 'typings' import * as G from 'typings/graphql' import * as vscode from 'vscode' import ReactWebView from '../ReactWebView' -import {setStorage} from '../storage' +import storage from '../storage' import {isEmptyWorkspace} from '../workspace' import runTest from './runTest' @@ -53,7 +53,8 @@ export const createCommands = ({vscodeExt, machine, git}: CreateCommandProps) => webviewState = 'RESTARTING' } - setStorage(vscodeExt.workspaceState) + // ini + storage.init(vscodeExt.workspaceState) // activate machine webview = new ReactWebView(vscodeExt.extensionPath) diff --git a/src/editor/commands/loadSolution.ts b/src/editor/commands/loadSolution.ts index 058f9500..24e8b939 100644 --- a/src/editor/commands/loadSolution.ts +++ b/src/editor/commands/loadSolution.ts @@ -1,23 +1,10 @@ import * as CR from 'typings' import * as G from 'typings/graphql' import {TutorialModel} from '../../services/tutorial' -import * as storage from '../../services/storage' import {gitLoadCommits, gitClear} from '../../services/git' export default async function loadSolution(dispatch: CR.EditorDispatch, tutorialModel: TutorialModel): Promise { - const [position, tutorial]: [CR.Position, G.Tutorial | undefined] = await Promise.all([ - storage.getPosition(), - storage.getTutorial(), - ]) - if (!position) { - throw new Error('No tutorial position state found') - } - if (!tutorial || !tutorial.version || !tutorial.version.levels) { - throw new Error('Local tutorial not found') - } - // eslint-disable-next-line - - const step = tutorialModel.step() + const step: G.Step = tutorialModel.step() const solution = step.solution await gitClear() diff --git a/src/editor/storage.ts b/src/editor/storage.ts index e8af1e36..a3595070 100644 --- a/src/editor/storage.ts +++ b/src/editor/storage.ts @@ -1,17 +1,22 @@ -import * as CR from 'typings' import * as vscode from 'vscode' -let storage: vscode.Memento - -// storage must be set initially -export function setStorage(workspaceState: vscode.Memento): void { - storage = workspaceState -} - -export function get(key: string): T | undefined { - return storage.get(key) +class Storage { + private storage: vscode.Memento + constructor() { + this.storage = {} as vscode.Memento + } + public init = (storage: vscode.Memento): void => { + console.log('setStorage workspace') + this.storage = storage + } + public get = (key: string): T | undefined => { + console.log(`called get ${key}`) + return this.storage.get(key) + } + public update = (key: string, value: string | object): Thenable => { + console.log(`called update on ${key}`) + return this.storage.update(key, value) + } } -export function update(key: string, value: string | object): Thenable { - return storage.update(key, value) -} +export default new Storage() diff --git a/src/services/api/gql/tutorial.ts b/src/services/api/gql/getTutorial.ts similarity index 100% rename from src/services/api/gql/tutorial.ts rename to src/services/api/gql/getTutorial.ts diff --git a/src/services/storage.ts b/src/services/storage.ts index b52b07dc..61eaeddd 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -1,6 +1,6 @@ import * as CR from 'typings' import * as G from 'typings/graphql' -import * as storage from '../editor/storage' +import storage from '../editor/storage' // TUTORIAL const STORE_TUTORIAL = 'coderoad:tutorial' diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index ecb1f5a5..95ae8acc 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -2,8 +2,7 @@ import * as G from 'typings/graphql' import * as CR from 'typings' import * as storage from '../storage' import api from '../api' -import tutorialQuery from '@gql/tutorial' -import {timingSafeEqual} from 'crypto' +import tutorialQuery from '../../services/api/gql/getTutorial' interface TutorialConfig { codingLanguage: G.EnumCodingLanguage @@ -41,14 +40,14 @@ class Tutorial implements TutorialModel { this.position = {} as CR.Position this.progress = {} as CR.Progress - Promise.all([ - storage.getTutorial(), - storage.getProgress(), - ]).then((data) => { - const [tutorial, progress] = data - console.log('load continue tutorial') - console.log(tutorial, progress) - }) + // Promise.all([ + // storage.getTutorial(), + // storage.getProgress(), + // ]).then((data) => { + // const [tutorial, progress] = data + // console.log('load continue tutorial') + // console.log(tutorial, progress) + // }) } From 98c9cc92e22d73077906d6190716876160ce723d Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 15:56:52 -0700 Subject: [PATCH 050/117] remove unusued loading tutorial --- src/tutorials/basic.ts | 180 --------------------------------- web-app/src/tutorials/basic.ts | 180 --------------------------------- 2 files changed, 360 deletions(-) delete mode 100644 src/tutorials/basic.ts delete mode 100644 web-app/src/tutorials/basic.ts diff --git a/src/tutorials/basic.ts b/src/tutorials/basic.ts deleted file mode 100644 index e514cdc7..00000000 --- a/src/tutorials/basic.ts +++ /dev/null @@ -1,180 +0,0 @@ -import * as CR from 'typings' - -const basic: CR.Tutorial = { - id: '1', - meta: { - version: '0.1.0', - repo: 'https://github.com/ShMcK/coderoad-tutorial-basic.git', - createdBy: 'shmck', - createdAt: 'Sat, 11 May 2019 18:25:24 GMT', - updatedBy: 'shmck', - updatedAt: 'Sat, 11 May 2019 18:25:24 GMT', - contributors: ['shmck'], - languages: ['javascript'], - testRunner: 'jest', - }, - data: { - summary: { - title: 'Basic Test', - description: 'A basic coding skills example', - levelList: ['level1Id', 'level2Id'], - }, - levels: { - level1Id: { - stageList: ['stage1Id', 'stage2Id'], - content: { - title: 'Operators', - text: 'A description of this stage', - }, - actions: { - setup: { - commits: ['aab5f3d'], - commands: ['npm install'], - } - } - }, - level2Id: { - stageList: ['a'], - content: { - title: 'Logic', - text: 'Some basic logic in level 2' - } - } - }, - stages: { - stage1Id: { - stepList: ['step1Id', 'step2Id', 'step3Id'], - content: { - title: 'Sum Stage', - text: 'A description of this stage', - }, - }, - stage2Id: { - stepList: ['1', '2'], - content: { - title: 'Second Stage', - text: 'Going into round 2' - } - }, - a: { - stepList: ['a1', 'a2'], - content: { - title: 'Part 1', - text: 'Going into round 1' - } - }, - }, - steps: { - step1Id: { - content: { - title: 'Sum', - text: 'Write a function `add` that adds two numbers together', - }, - actions: { - setup: { - commits: ['8fa5ad5'], - files: ['src/sum.js'], - }, - solution: { - commits: ['abe3123'], - }, - }, - hints: [], - }, - step2Id: { - content: { - title: 'Multiply', - text: 'Write a function `multiply` that multiplies two numbers together', - }, - actions: { - setup: { - commits: ['0e01df8'], - files: ['src/multiply.js'], - }, - solution: { - commits: ['1b9a520'], - }, - }, - hints: [], - }, - step3Id: { - content: { - title: 'Divide', - text: 'Write a function `divide` that divides', - }, - actions: { - setup: { - commits: ['40802cf'], - files: ['src/divide.js'], - }, - solution: { - commits: ['b321a3d'], - }, - }, - hints: [], - }, - 1: { - content: { - title: 'Modulo', - text: 'Modulo `%` it up' - }, - actions: { - setup: { - commits: ['4db40b4'], - files: ['src/modulo.js'], - }, - solution: { - commits: ['3580c9d'] - } - } - }, - 2: { - content: { - title: 'Power', - text: 'Power up with `**` powers' - }, - actions: { - setup: { - commits: ['abc1e2d'], - files: ['src/power.js'], - }, - solution: { - commits: ['5d28c25'] - } - } - }, - a1: { - content: { - title: 'Hello', - text: 'Return the word "hello"' - }, - actions: { - setup: { - commits: ['2faa934'], - files: ['src/word.js'], - }, - solution: { - commits: ['29f6b0d'] - } - } - }, - a2: { - content: { - title: 'Bye', - text: 'Return the word "bye"' - }, - actions: { - setup: { - commits: ['b1894dd'], - files: ['src/word.js'], - }, - solution: { - commits: ['0e83af8'] - } - } - }, - }, - }, -} - -export default basic diff --git a/web-app/src/tutorials/basic.ts b/web-app/src/tutorials/basic.ts deleted file mode 100644 index e514cdc7..00000000 --- a/web-app/src/tutorials/basic.ts +++ /dev/null @@ -1,180 +0,0 @@ -import * as CR from 'typings' - -const basic: CR.Tutorial = { - id: '1', - meta: { - version: '0.1.0', - repo: 'https://github.com/ShMcK/coderoad-tutorial-basic.git', - createdBy: 'shmck', - createdAt: 'Sat, 11 May 2019 18:25:24 GMT', - updatedBy: 'shmck', - updatedAt: 'Sat, 11 May 2019 18:25:24 GMT', - contributors: ['shmck'], - languages: ['javascript'], - testRunner: 'jest', - }, - data: { - summary: { - title: 'Basic Test', - description: 'A basic coding skills example', - levelList: ['level1Id', 'level2Id'], - }, - levels: { - level1Id: { - stageList: ['stage1Id', 'stage2Id'], - content: { - title: 'Operators', - text: 'A description of this stage', - }, - actions: { - setup: { - commits: ['aab5f3d'], - commands: ['npm install'], - } - } - }, - level2Id: { - stageList: ['a'], - content: { - title: 'Logic', - text: 'Some basic logic in level 2' - } - } - }, - stages: { - stage1Id: { - stepList: ['step1Id', 'step2Id', 'step3Id'], - content: { - title: 'Sum Stage', - text: 'A description of this stage', - }, - }, - stage2Id: { - stepList: ['1', '2'], - content: { - title: 'Second Stage', - text: 'Going into round 2' - } - }, - a: { - stepList: ['a1', 'a2'], - content: { - title: 'Part 1', - text: 'Going into round 1' - } - }, - }, - steps: { - step1Id: { - content: { - title: 'Sum', - text: 'Write a function `add` that adds two numbers together', - }, - actions: { - setup: { - commits: ['8fa5ad5'], - files: ['src/sum.js'], - }, - solution: { - commits: ['abe3123'], - }, - }, - hints: [], - }, - step2Id: { - content: { - title: 'Multiply', - text: 'Write a function `multiply` that multiplies two numbers together', - }, - actions: { - setup: { - commits: ['0e01df8'], - files: ['src/multiply.js'], - }, - solution: { - commits: ['1b9a520'], - }, - }, - hints: [], - }, - step3Id: { - content: { - title: 'Divide', - text: 'Write a function `divide` that divides', - }, - actions: { - setup: { - commits: ['40802cf'], - files: ['src/divide.js'], - }, - solution: { - commits: ['b321a3d'], - }, - }, - hints: [], - }, - 1: { - content: { - title: 'Modulo', - text: 'Modulo `%` it up' - }, - actions: { - setup: { - commits: ['4db40b4'], - files: ['src/modulo.js'], - }, - solution: { - commits: ['3580c9d'] - } - } - }, - 2: { - content: { - title: 'Power', - text: 'Power up with `**` powers' - }, - actions: { - setup: { - commits: ['abc1e2d'], - files: ['src/power.js'], - }, - solution: { - commits: ['5d28c25'] - } - } - }, - a1: { - content: { - title: 'Hello', - text: 'Return the word "hello"' - }, - actions: { - setup: { - commits: ['2faa934'], - files: ['src/word.js'], - }, - solution: { - commits: ['29f6b0d'] - } - } - }, - a2: { - content: { - title: 'Bye', - text: 'Return the word "bye"' - }, - actions: { - setup: { - commits: ['b1894dd'], - files: ['src/word.js'], - }, - solution: { - commits: ['0e83af8'] - } - } - }, - }, - }, -} - -export default basic From b358130948815e5811571e81546dc03015f3d4ab Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 16:10:06 -0700 Subject: [PATCH 051/117] fix send data to client --- src/extension.ts | 4 ++++ src/services/tutorial/index.ts | 21 ++++++++++++++++++++- src/state/index.ts | 8 +++----- web-app/src/App.tsx | 5 ++--- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 473b424d..1531a77e 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -14,6 +14,10 @@ export const editor = new Editor({ setWorkspaceRoot, }) +// TODO: refactor tutorial & editor relationships +// code here is a bit smelly +tutorial.setClientDispatch(editor.dispatch) + // activate run on vscode extension initialization export const activate = editor.activate diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index 95ae8acc..fcaa5094 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -9,6 +9,11 @@ interface TutorialConfig { testRunner: G.EnumTestRunner } +interface PositionProgress { + position: CR.Position + progress: CR.Progress +} + export interface TutorialModel { repo: G.TutorialRepo config: TutorialConfig @@ -20,9 +25,10 @@ export interface TutorialModel { level(levelId?: string): G.Level stage(stageId?: string): G.Stage step(stepId?: string): G.Step - updateProgress(): {position: CR.Position, progress: CR.Progress} + updateProgress(): PositionProgress nextPosition(): CR.Position hasExisting(): Promise + setClientDispatch(editorDispatch: CR.EditorDispatch): void } class Tutorial implements TutorialModel { @@ -31,9 +37,13 @@ class Tutorial implements TutorialModel { public version: G.TutorialVersion public position: CR.Position public progress: CR.Progress + private clientDispatch: (props: PositionProgress) => void constructor() { // initialize types, will be assigned when tutorial is selected + this.clientDispatch = (props: PositionProgress) => { + throw new Error('Tutorial client dispatch yet initialized') + } this.repo = {} as G.TutorialRepo this.config = {} as TutorialConfig this.version = {} as G.TutorialVersion @@ -51,6 +61,10 @@ class Tutorial implements TutorialModel { } + public setClientDispatch(editorDispatch: CR.EditorDispatch) { + this.clientDispatch = ({progress, position}: PositionProgress) => editorDispatch('SEND_DATA', {progress, position}) + } + public init = (tutorial: G.Tutorial) => { this.repo = tutorial.repo this.config = { @@ -73,6 +87,11 @@ class Tutorial implements TutorialModel { complete: false, } + this.clientDispatch({ + position: this.position, + progress: this.progress + }) + // set tutorial, position, progress locally // TODO: base position off of progress Promise.all([ diff --git a/src/state/index.ts b/src/state/index.ts index 1438a4ae..21e88e53 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -42,9 +42,7 @@ class StateMachine { .onTransition(state => { if (state.changed) { console.log(`STATE: ${stateToString(state.value)}`) - dispatch('coderoad.send_state', {state: state.value, data: state.context}) - } else { - dispatch('coderoad.send_data', {data: state.context}) + dispatch('coderoad.send_state', {state: state.value}) } }) } @@ -58,8 +56,8 @@ class StateMachine { public refresh() { console.log('service refresh') console.log(this.service.state) - const {value, context} = this.service.state - this.dispatch('coderoad.send_state', {state: value, data: context}) + const {value} = this.service.state + this.dispatch('coderoad.send_state', {state: value}) } public send(action: string | CR.Action) { this.service.send(action) diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index 61dba8e2..a3d6e8b6 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -28,15 +28,14 @@ const App = () => { const handleEvent = (event: ReceivedEvent): void => { const message = event.data // messages from core - const { progress, position } = message.payload.data if (message.type === 'SET_STATE') { // SET_STATE - set state machine state setState(message.payload.state) - - setStatus({ variables: { progress, position } }) + } else if (message.type === 'SET_DATA') { // SET_DATA - set state machine context + const { progress, position } = message.payload.data setStatus({ variables: { progress, position } }) } } From b6ec3e8b0628b1c55f60126491cb2e848dab3463 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 16:45:08 -0700 Subject: [PATCH 052/117] cleanup env vars & fix request --- .env | 1 - .gitignore | 4 ++++ src/environment.ts | 11 +++++++++++ src/services/api/gql/getTutorial.ts | 4 +--- src/services/api/index.ts | 12 ++++-------- src/services/tutorial/index.ts | 4 ++-- 6 files changed, 22 insertions(+), 14 deletions(-) delete mode 100644 .env create mode 100644 src/environment.ts diff --git a/.env b/.env deleted file mode 100644 index 3f1de458..00000000 --- a/.env +++ /dev/null @@ -1 +0,0 @@ -API_URL=http://localhost:4000/graphql \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3c9d2046..435152fd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,10 @@ node_modules .vscode-test/ *.vsix +# local +.env +.env.local + # output directory out build diff --git a/src/environment.ts b/src/environment.ts new file mode 100644 index 00000000..2e6886ab --- /dev/null +++ b/src/environment.ts @@ -0,0 +1,11 @@ +import * as path from 'path' +import * as dotenv from 'dotenv' + +dotenv.config({ + path: path.join(__dirname, '../.env') +}) + +export const api = { + url: process.env.API_URL || '', + token: process.env.API_AUTH_TOKEN || '', // dev only +} \ No newline at end of file diff --git a/src/services/api/gql/getTutorial.ts b/src/services/api/gql/getTutorial.ts index 878ec554..b2ce9154 100644 --- a/src/services/api/gql/getTutorial.ts +++ b/src/services/api/gql/getTutorial.ts @@ -1,6 +1,4 @@ -import gql from 'graphql-tag' - -const getTutorial = gql` +const getTutorial = ` query getTutorial($tutorialId: ID!) { tutorial(id: $tutorialId) { id diff --git a/src/services/api/index.ts b/src/services/api/index.ts index 007afc49..4b302b52 100644 --- a/src/services/api/index.ts +++ b/src/services/api/index.ts @@ -1,16 +1,12 @@ -import * as dotenv from 'dotenv' import {GraphQLClient} from 'graphql-request' +import * as environment from '../../environment' -dotenv.config() - -const url: string = process.env.API_URL || '' -const token: string = process.env.API_AUTH_TOKEN || '' // dev only // ... or create a GraphQL client instance to send requests -const client: GraphQLClient = new GraphQLClient(url, { +const client: GraphQLClient = new GraphQLClient(environment.api.url, { headers: { - 'Content-Type': 'application/graphql', - 'Authorization': token + 'Content-Type': 'application/json', + 'Authorization': environment.api.token } }) diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index fcaa5094..bac54478 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -62,7 +62,7 @@ class Tutorial implements TutorialModel { } public setClientDispatch(editorDispatch: CR.EditorDispatch) { - this.clientDispatch = ({progress, position}: PositionProgress) => editorDispatch('SEND_DATA', {progress, position}) + this.clientDispatch = ({progress, position}: PositionProgress) => editorDispatch('coderoad.send_data', {progress, position}) } public init = (tutorial: G.Tutorial) => { @@ -112,7 +112,7 @@ class Tutorial implements TutorialModel { public async load(tutorialId: string) { // TODO: load from localStorage - const tutorial: G.Tutorial | null = await api.request(tutorialQuery, { + const {tutorial}: {tutorial: G.Tutorial | null} = await api.request(tutorialQuery, { tutorialId, // TODO: add selection of tutorial id }) From bf0ad9b0884b6460bdda0abc3a74ad5869d548b4 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 16:50:53 -0700 Subject: [PATCH 053/117] clenaup typings --- src/editor/ReactWebView.ts | 6 +++--- src/editor/commands/index.ts | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index 4609232b..77620f50 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -21,7 +21,6 @@ class ReactWebView { private panel: vscode.WebviewPanel private extensionPath: string private disposables: vscode.Disposable[] = [] - private onReceive: any // TODO: properly type public constructor(extensionPath: string) { this.extensionPath = extensionPath @@ -42,6 +41,7 @@ class ReactWebView { if (action === 'WEBVIEW_LOADED') { this.loaded = true } else { + console.log('onReceive', action) vscode.commands.executeCommand('coderoad.receive_action', action) } } @@ -56,7 +56,7 @@ class ReactWebView { } // prevents new panels from going ontop of coderoad panel - vscode.window.onDidChangeActiveTextEditor((textEditor) => { + vscode.window.onDidChangeActiveTextEditor((textEditor?: vscode.TextEditor) => { console.log('onDidChangeActiveTextEditor') console.log(textEditor) if (!textEditor || textEditor.viewColumn !== vscode.ViewColumn.Two) { @@ -64,7 +64,7 @@ class ReactWebView { } }) // // prevents moving coderoad panel on top of left panel - vscode.window.onDidChangeVisibleTextEditors((textEditor) => { + vscode.window.onDidChangeVisibleTextEditors((textEditor: vscode.TextEditor[]) => { console.log('onDidChangeVisibleTextEditors') updateWindows() }) diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index 7cfbccf8..75c052f4 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -135,6 +135,7 @@ export const createCommands = ({vscodeExt, machine, git}: CreateCommandProps) => }, [COMMANDS.RECEIVE_ACTION]: (action: string | CR.Action) => { // send received actions from web-app into state machine + console.log('receive action', action) machine.send(action) }, [COMMANDS.RUN_TEST]: () => { From 0ad9d2c5b665ec678452313555d5ffa2c6a78079 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 17:28:17 -0700 Subject: [PATCH 054/117] add additional logging --- src/services/git/index.ts | 4 +++ src/services/tutorial/index.ts | 2 ++ src/state/actions/index.ts | 16 ++-------- web-app/src/App.tsx | 8 +++-- web-app/src/Routes.tsx | 27 +++++++++++++--- web-app/src/containers/Tutorial/index.tsx | 39 ----------------------- 6 files changed, 38 insertions(+), 58 deletions(-) delete mode 100644 web-app/src/containers/Tutorial/index.tsx diff --git a/src/services/git/index.ts b/src/services/git/index.ts index c47aba71..2d1a8957 100644 --- a/src/services/git/index.ts +++ b/src/services/git/index.ts @@ -42,6 +42,10 @@ const cherryPickCommit = async (commit: string, count = 0): Promise => { export async function gitLoadCommits(actions: G.StepActions, editorDispatch: CR.EditorDispatch): Promise { const {commits, commands, files} = actions + console.log(`load commits: ${commits.join(', ')}`) + console.log(`commands: ${commands.join(', ')}`) + console.log(`files ${files.join(', s')}`) + for (const commit of commits) { // pull a commit from tutorial repo console.log(`try cherry-pick ${commit}`) diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index bac54478..d135c2b4 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -87,6 +87,8 @@ class Tutorial implements TutorialModel { complete: false, } + console.log('this.position', JSON.stringify(this.position)) + this.clientDispatch({ position: this.position, progress: this.progress diff --git a/src/state/actions/index.ts b/src/state/actions/index.ts index 62481a70..4935476f 100644 --- a/src/state/actions/index.ts +++ b/src/state/actions/index.ts @@ -39,19 +39,9 @@ export default (editorDispatch: CR.EditorDispatch, tutorialModel: TutorialModel) const codingLanguage: G.EnumCodingLanguage = tutorialModel.config.codingLanguage editorDispatch('coderoad.tutorial_setup', codingLanguage) }, - // initializeNewTutorial: assign({ - // position: (context: any): CR.Position => { - // const {data} = context - // const levelId = data.summary.levelList[0] - // const stageId = data.levels[levelId].stageList[0] - // const stepId = data.stages[stageId].stepList[0] - // return { - // levelId, - // stageId, - // stepId, - // } - // }, - // }), + initializeNewTutorial: () => { + console.log('initializeNewTutorial') + }, // tutorialContinue: assign({ // // load initial data, progress & position // data(): CR.TutorialData { diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index a3d6e8b6..1d2d9579 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -13,10 +13,11 @@ interface ReceivedEvent { } const App = () => { - const initialState = { SelectTutorial: 'Initial ' } + const initialState = { SelectTutorial: 'Initial' } // set state machine state const [state, setState] = React.useState(initialState) + const [debuggerInfo, setDebuggerInfo] = React.useState({}) // update level/stage/step status based on user progress & position // TODO: model server more effeciently @@ -36,6 +37,9 @@ const App = () => { } else if (message.type === 'SET_DATA') { // SET_DATA - set state machine context const { progress, position } = message.payload.data + if (process.env.REACT_APP_DEBUG) { + setDebuggerInfo({ progress, position }) + } setStatus({ variables: { progress, position } }) } } @@ -60,7 +64,7 @@ const App = () => { return (
- {process.env.REACT_APP_DEBUG && } + {process.env.REACT_APP_DEBUG && }
diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 58c79a4c..fb8af220 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -1,10 +1,14 @@ import * as React from 'react' +import { send } from './utils/vscode' import Router from './components/Router' import LoadingPage from './containers/LoadingPage' import ContinuePage from './containers/Continue' import NewPage from './containers/New' -import TutorialPage from './containers/Tutorial' +import SummaryPage from './containers/Tutorial/SummaryPage' +import LevelSummaryPage from './containers/Tutorial/LevelPage' +import StageSummaryPage from './containers/Tutorial/StagePage' +import CompletedPage from './containers/Tutorial/CompletedPage' const { Route } = Router @@ -54,10 +58,25 @@ const Routes = ({ state }: Props) => { - - + + -
+ + + + + + + + + + + + + + + +
) } diff --git a/web-app/src/containers/Tutorial/index.tsx b/web-app/src/containers/Tutorial/index.tsx deleted file mode 100644 index 0709af3a..00000000 --- a/web-app/src/containers/Tutorial/index.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import * as React from 'react' -import { send } from '../../utils/vscode' - -import Router from '../../components/Router' -import LoadingPage from '../LoadingPage' -import SummaryPage from './SummaryPage' -import LevelSummaryPage from './LevelPage' -import StageSummaryPage from './StagePage' -import CompletedPage from './CompletedPage' - -const { Route } = Router - -interface Props { - state: any -} - -const Tutorial = (props: Props) => { - return ( - - - - - - - - - - - - - - - - - - ) -} - -export default Tutorial From f462b39c92e75564f80360b2f972ca9eef59896d Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 25 Aug 2019 22:09:28 -0700 Subject: [PATCH 055/117] heavy refactor --- src/editor/commands/index.ts | 31 ++++----------- src/editor/index.ts | 2 - src/editor/storage.ts | 4 +- src/services/tutorial/index.ts | 47 +++++++++++------------ src/state/actions/index.ts | 24 +++++++++--- src/state/machine.ts | 2 +- web-app/src/App.tsx | 12 +++--- web-app/src/components/Debugger/index.tsx | 14 ++++--- 8 files changed, 65 insertions(+), 71 deletions(-) diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index 75c052f4..7aa5e775 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -4,13 +4,12 @@ import * as G from 'typings/graphql' import * as vscode from 'vscode' import ReactWebView from '../ReactWebView' import storage from '../storage' -import {isEmptyWorkspace} from '../workspace' import runTest from './runTest' +import {isEmptyWorkspace} from '../workspace' const COMMANDS = { START: 'coderoad.start', - TUTORIAL_LAUNCH: 'coderoad.tutorial_launch', - TUTORIAL_SETUP: 'coderoad.tutorial_setup', + TEST_RUNNER_SETUP: 'coderoad.test_runner_setup', OPEN_WEBVIEW: 'coderoad.open_webview', SEND_STATE: 'coderoad.send_state', SEND_DATA: 'coderoad.send_data', @@ -24,7 +23,6 @@ const COMMANDS = { interface CreateCommandProps { vscodeExt: vscode.ExtensionContext machine: CR.StateMachine - git: any } const resetLayout = () => { @@ -34,13 +32,15 @@ const resetLayout = () => { }) } -export const createCommands = ({vscodeExt, machine, git}: CreateCommandProps) => { +export const createCommands = ({vscodeExt, machine}: CreateCommandProps) => { // React panel webview let webview: any return { // initialize - [COMMANDS.START]: () => { + [COMMANDS.START]: async () => { + + await isEmptyWorkspace() let webviewState: 'INITIALIZING' | 'RESTARTING' if (!webview) { @@ -77,24 +77,7 @@ export const createCommands = ({vscodeExt, machine, git}: CreateCommandProps) => } webview.createOrShow(column, callback) }, - // launch a new tutorial - // NOTE: may be better to move into action as logic is primarily non-vscode - [COMMANDS.TUTORIAL_LAUNCH]: async (repo: G.TutorialRepo) => { - console.log('launch tutorial') - - await isEmptyWorkspace() - - await git.gitInitIfNotExists() - - if (!repo || !repo.uri) { - throw new Error('Tutorial repo uri not found') - } - - await git.gitSetupRemote(repo.uri) - - machine.send('TUTORIAL_LOADED') - }, - [COMMANDS.TUTORIAL_SETUP]: async (codingLanguage: G.EnumCodingLanguage) => { + [COMMANDS.TEST_RUNNER_SETUP]: async (codingLanguage: G.EnumCodingLanguage) => { // TODO: allow multiple coding languages in a tutorial diff --git a/src/editor/index.ts b/src/editor/index.ts index 6f033db2..799d8dc5 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -1,7 +1,6 @@ import * as vscode from 'vscode' import * as CR from 'typings' import {createCommands} from './commands' -import * as git from '../services/git' interface Props { machine: CR.StateMachine @@ -53,7 +52,6 @@ class Editor { const commands = createCommands({ vscodeExt: this.vscodeExt, machine: this.machine, - git, }) for (const cmd in commands) { const command: vscode.Disposable = vscode.commands.registerCommand(cmd, commands[cmd]) diff --git a/src/editor/storage.ts b/src/editor/storage.ts index a3595070..b63c8562 100644 --- a/src/editor/storage.ts +++ b/src/editor/storage.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode' -class Storage { +class EditorStorage { private storage: vscode.Memento constructor() { this.storage = {} as vscode.Memento @@ -19,4 +19,4 @@ class Storage { } } -export default new Storage() +export default new EditorStorage() diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index d135c2b4..03355b04 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -9,7 +9,8 @@ interface TutorialConfig { testRunner: G.EnumTestRunner } -interface PositionProgress { +interface MessageData { + tutorial?: {id: string} position: CR.Position progress: CR.Progress } @@ -20,12 +21,11 @@ export interface TutorialModel { version: G.TutorialVersion position: CR.Position progress: CR.Progress - init(tutorial: G.Tutorial): void - load(tutorialId: string): void + launch(tutorialId: string): void level(levelId?: string): G.Level stage(stageId?: string): G.Stage step(stepId?: string): G.Step - updateProgress(): PositionProgress + updateProgress(): void nextPosition(): CR.Position hasExisting(): Promise setClientDispatch(editorDispatch: CR.EditorDispatch): void @@ -37,11 +37,11 @@ class Tutorial implements TutorialModel { public version: G.TutorialVersion public position: CR.Position public progress: CR.Progress - private clientDispatch: (props: PositionProgress) => void + private clientDispatch: (props: MessageData) => void constructor() { // initialize types, will be assigned when tutorial is selected - this.clientDispatch = (props: PositionProgress) => { + this.clientDispatch = (props: MessageData) => { throw new Error('Tutorial client dispatch yet initialized') } this.repo = {} as G.TutorialRepo @@ -62,10 +62,18 @@ class Tutorial implements TutorialModel { } public setClientDispatch(editorDispatch: CR.EditorDispatch) { - this.clientDispatch = ({progress, position}: PositionProgress) => editorDispatch('coderoad.send_data', {progress, position}) + this.clientDispatch = ({progress, position}: MessageData) => editorDispatch('coderoad.send_data', {progress, position}) } - public init = (tutorial: G.Tutorial) => { + public async launch(tutorialId: string) { + const {tutorial}: {tutorial: G.Tutorial | null} = await api.request(tutorialQuery, { + tutorialId, // TODO: add selection of tutorial id + }) + + if (!tutorial) { + throw new Error(`Tutorial ${tutorialId} not found`) + } + this.repo = tutorial.repo this.config = { codingLanguage: tutorial.codingLanguage, @@ -90,6 +98,7 @@ class Tutorial implements TutorialModel { console.log('this.position', JSON.stringify(this.position)) this.clientDispatch({ + tutorial: {id: tutorial.id}, position: this.position, progress: this.progress }) @@ -111,19 +120,6 @@ class Tutorial implements TutorialModel { return !!(tutorial && progress) } - - public async load(tutorialId: string) { - // TODO: load from localStorage - const {tutorial}: {tutorial: G.Tutorial | null} = await api.request(tutorialQuery, { - tutorialId, // TODO: add selection of tutorial id - }) - - if (!tutorial) { - throw new Error(`Tutorial ${tutorialId} not found`) - } - - await this.init(tutorial) - } public level = (levelId: string): G.Level => { const level: G.Level | undefined = this.version.levels.find((l: G.Level) => l.id === levelId || this.position.levelId) if (!level) { @@ -147,15 +143,16 @@ class Tutorial implements TutorialModel { } return step } - public updateProgress = (): {position: CR.Position, progress: CR.Progress} => { + public updateProgress = () => { const {levelId, stageId, stepId} = this.position this.progress.levels[levelId] = true this.progress.stages[stageId] = true this.progress.steps[stepId] = true - return { - position: this.position, + + this.clientDispatch({ progress: this.progress, - } + position: this.position, // TODO: calculate next position + }) } public nextPosition = (): CR.Position => { const {levelId, stageId, stepId} = this.position diff --git a/src/state/actions/index.ts b/src/state/actions/index.ts index 4935476f..20757bad 100644 --- a/src/state/actions/index.ts +++ b/src/state/actions/index.ts @@ -1,4 +1,3 @@ -import {assign} from 'xstate' // NOTE: codesmell - importing machine import {machine} from '../../extension' import {TutorialModel} from '../../services/tutorial' @@ -30,18 +29,33 @@ export default (editorDispatch: CR.EditorDispatch, tutorialModel: TutorialModel) async tutorialLaunch() { const tutorialId: string = '1' // TODO: load tutorialId - await tutorialModel.load(tutorialId) + await tutorialModel.launch(tutorialId) + + // git setup const repo: G.TutorialRepo = tutorialModel.repo - editorDispatch('coderoad.tutorial_launch', repo) + console.log('launch tutorial') + + await git.gitInitIfNotExists() + + if (!repo || !repo.uri) { + throw new Error('Tutorial repo uri not found') + } + + await git.gitSetupRemote(repo.uri) + + machine.send('TUTORIAL_LOADED') }, - tutorialSetup() { + testRunnerSetup() { const codingLanguage: G.EnumCodingLanguage = tutorialModel.config.codingLanguage - editorDispatch('coderoad.tutorial_setup', codingLanguage) + editorDispatch('coderoad.test_runner_setup', codingLanguage) }, initializeNewTutorial: () => { console.log('initializeNewTutorial') }, + tutorialContinue() { + console.log('tutorial continue') + }, // tutorialContinue: assign({ // // load initial data, progress & position // data(): CR.TutorialData { diff --git a/src/state/machine.ts b/src/state/machine.ts index 74eadd16..0fa7be7b 100644 --- a/src/state/machine.ts +++ b/src/state/machine.ts @@ -54,7 +54,7 @@ export const machine = (editorDispatch: CR.EditorDispatch, tutorialModel: Tutori Tutorial: { id: 'tutorial', initial: 'Initialize', - onEntry: ['tutorialSetup'], + onEntry: ['testRunnerSetup'], on: { WEBVIEW_INITIALIZED: '#tutorial-load-next' }, diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index 1d2d9579..32c5b06e 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -17,7 +17,10 @@ const App = () => { // set state machine state const [state, setState] = React.useState(initialState) - const [debuggerInfo, setDebuggerInfo] = React.useState({}) + const [debuggerInfo, setDebuggerInfo] = React.useState({ + progress: { levels: {}, stages: {}, steps: {}, complete: false}, + position: { levelId: '', stageId: '', stepId: ''}, + }) // update level/stage/step status based on user progress & position // TODO: model server more effeciently @@ -38,6 +41,7 @@ const App = () => { // SET_DATA - set state machine context const { progress, position } = message.payload.data if (process.env.REACT_APP_DEBUG) { + console.log(`Position: ${position.levelId}/${position.stageId}/${position.stepId}`) setDebuggerInfo({ progress, position }) } setStatus({ variables: { progress, position } }) @@ -56,15 +60,11 @@ const App = () => { send('WEBVIEW_LOADED') }, []) - const value = { - state, - } - // TODO: refactor cond to user and accept first route as if/else if return (
- {process.env.REACT_APP_DEBUG && } + {process.env.REACT_APP_DEBUG && }
diff --git a/web-app/src/components/Debugger/index.tsx b/web-app/src/components/Debugger/index.tsx index 7d6329c3..8a54bdbc 100644 --- a/web-app/src/components/Debugger/index.tsx +++ b/web-app/src/components/Debugger/index.tsx @@ -1,15 +1,17 @@ import * as React from 'react' +import * as CR from 'typings' interface Props { - value: any + state: object + position: CR.Position + progress: CR.Progress } -const Debugger = ({ value }: Props) => ( +const Debugger = ({ state, position, progress }: Props) => (
-

state: {JSON.stringify(value.state)}

-

position: {JSON.stringify(value.position)}

-

progress: {JSON.stringify(value.progress)}

-

data: {JSON.stringify(value.data)}

+

state: {JSON.stringify(state)}

+

position: {JSON.stringify(position)}

+

progress: {JSON.stringify(progress)}

) From 1253177e0410b9bb9fdb0ca29197cdf88c6a095d Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 31 Aug 2019 17:05:43 -0700 Subject: [PATCH 056/117] Refactor editor dispatch uses --- src/extension.ts | 10 ++---- src/services/git/index.ts | 2 +- src/services/tutorial/index.ts | 37 +++++++--------------- src/state/actions/index.ts | 3 +- src/state/index.ts | 29 ++++++++++------- src/state/machine.ts | 4 +-- typings/index.d.ts | 11 ++++++- web-app/src/App.tsx | 2 +- web-app/src/components/Cond/index.tsx | 17 ---------- web-app/src/components/Cond/utils/state.ts | 19 ----------- web-app/src/components/Router/index.tsx | 5 ++- 11 files changed, 50 insertions(+), 89 deletions(-) delete mode 100644 web-app/src/components/Cond/index.tsx delete mode 100644 web-app/src/components/Cond/utils/state.ts diff --git a/src/extension.ts b/src/extension.ts index 1531a77e..3c0c1499 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -4,9 +4,9 @@ import Tutorial, {TutorialModel} from './services/tutorial' import StateMachine from './state' import Editor from './editor' -export const tutorial: TutorialModel = new Tutorial() +export const tutorialModel: TutorialModel = new Tutorial(vscode.commands.executeCommand) // state machine that governs application logic -export const machine = new StateMachine({dispatch: vscode.commands.executeCommand, tutorial}) +export const machine = new StateMachine(tutorialModel, vscode.commands.executeCommand) // vscode editor export const editor = new Editor({ @@ -14,12 +14,8 @@ export const editor = new Editor({ setWorkspaceRoot, }) -// TODO: refactor tutorial & editor relationships -// code here is a bit smelly -tutorial.setClientDispatch(editor.dispatch) - // activate run on vscode extension initialization export const activate = editor.activate -// deactive run on vscode extension shut down +// deactivate run on vscode extension shut down export const deactivate = editor.deactivate diff --git a/src/services/git/index.ts b/src/services/git/index.ts index 2d1a8957..3db43e81 100644 --- a/src/services/git/index.ts +++ b/src/services/git/index.ts @@ -58,7 +58,7 @@ export async function gitLoadCommits(actions: G.StepActions, editorDispatch: CR. const {stdout, stderr} = await exec(command) if (stderr) { console.error(stderr) - // langauge specific error messages from running commands + // language specific error messages from running commands for (const message of Object.keys(errorMessages.js)) { if (stderr.match(message)) { // ignored error diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index 03355b04..c48cc932 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -9,12 +9,6 @@ interface TutorialConfig { testRunner: G.EnumTestRunner } -interface MessageData { - tutorial?: {id: string} - position: CR.Position - progress: CR.Progress -} - export interface TutorialModel { repo: G.TutorialRepo config: TutorialConfig @@ -28,7 +22,7 @@ export interface TutorialModel { updateProgress(): void nextPosition(): CR.Position hasExisting(): Promise - setClientDispatch(editorDispatch: CR.EditorDispatch): void + syncClient(): void } class Tutorial implements TutorialModel { @@ -37,19 +31,21 @@ class Tutorial implements TutorialModel { public version: G.TutorialVersion public position: CR.Position public progress: CR.Progress - private clientDispatch: (props: MessageData) => void + public syncClient: () => void - constructor() { + constructor(editorDispatch: CR.EditorDispatch) { // initialize types, will be assigned when tutorial is selected - this.clientDispatch = (props: MessageData) => { - throw new Error('Tutorial client dispatch yet initialized') - } + this.repo = {} as G.TutorialRepo this.config = {} as TutorialConfig this.version = {} as G.TutorialVersion this.position = {} as CR.Position this.progress = {} as CR.Progress - + this.syncClient = () => editorDispatch('coderoad.send_data', { + tutorial: {id: this.version.tutorialId}, + progress: this.progress, + position: this.position, + }) // Promise.all([ // storage.getTutorial(), // storage.getProgress(), @@ -61,10 +57,6 @@ class Tutorial implements TutorialModel { } - public setClientDispatch(editorDispatch: CR.EditorDispatch) { - this.clientDispatch = ({progress, position}: MessageData) => editorDispatch('coderoad.send_data', {progress, position}) - } - public async launch(tutorialId: string) { const {tutorial}: {tutorial: G.Tutorial | null} = await api.request(tutorialQuery, { tutorialId, // TODO: add selection of tutorial id @@ -97,11 +89,7 @@ class Tutorial implements TutorialModel { console.log('this.position', JSON.stringify(this.position)) - this.clientDispatch({ - tutorial: {id: tutorial.id}, - position: this.position, - progress: this.progress - }) + this.syncClient() // set tutorial, position, progress locally // TODO: base position off of progress @@ -149,10 +137,7 @@ class Tutorial implements TutorialModel { this.progress.stages[stageId] = true this.progress.steps[stepId] = true - this.clientDispatch({ - progress: this.progress, - position: this.position, // TODO: calculate next position - }) + this.syncClient() } public nextPosition = (): CR.Position => { const {levelId, stageId, stepId} = this.position diff --git a/src/state/actions/index.ts b/src/state/actions/index.ts index 20757bad..dc1263f6 100644 --- a/src/state/actions/index.ts +++ b/src/state/actions/index.ts @@ -1,4 +1,3 @@ -// NOTE: codesmell - importing machine import {machine} from '../../extension' import {TutorialModel} from '../../services/tutorial' import * as CR from 'typings' @@ -6,7 +5,7 @@ import * as G from 'typings/graphql' import * as git from '../../services/git' -export default (editorDispatch: CR.EditorDispatch, tutorialModel: TutorialModel) => ({ +export default (tutorialModel: TutorialModel, editorDispatch: CR.EditorDispatch) => ({ createWebview() { editorDispatch('coderoad.open_webview') }, diff --git a/src/state/index.ts b/src/state/index.ts index 21e88e53..051de61d 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -21,28 +21,31 @@ const stateToString = (state: string | object, str: string = ''): string => { return '' } -interface Props { - dispatch: CR.EditorDispatch - tutorial: TutorialModel -} class StateMachine { - private dispatch: CR.EditorDispatch private machineOptions = { devTools: true, deferEvents: true, execute: true, } private service: Interpreter<{}, CR.MachineStateSchema, CR.MachineEvent> - constructor({dispatch, tutorial}: Props) { - this.dispatch = dispatch - const machine = createMachine(dispatch, tutorial) + + constructor(tutorialModel: TutorialModel, editorDispatch: CR.EditorDispatch) { + const machine = createMachine(tutorialModel, editorDispatch) + + // format state as a string and send it to the client + this.syncState = (state: any): void => { + const stateValue: CR.MessageState = stateToString(state.value) + console.log(`STATE: ${stateValue}`) + editorDispatch('send_data', stateValue) + } + + // callback on all state changes this.service = interpret(machine, this.machineOptions) // logging .onTransition(state => { if (state.changed) { - console.log(`STATE: ${stateToString(state.value)}`) - dispatch('coderoad.send_state', {state: state.value}) + this.syncState(state) } }) } @@ -56,12 +59,14 @@ class StateMachine { public refresh() { console.log('service refresh') console.log(this.service.state) - const {value} = this.service.state - this.dispatch('coderoad.send_state', {state: value}) + this.syncState(this.service.state) } public send(action: string | CR.Action) { this.service.send(action) } + // @ts-ignore + private syncState(state: any): void + } export default StateMachine diff --git a/src/state/machine.ts b/src/state/machine.ts index 0fa7be7b..bc1be2e2 100644 --- a/src/state/machine.ts +++ b/src/state/machine.ts @@ -5,7 +5,7 @@ import {TutorialModel} from '../services/tutorial' import createActions from './actions' import createGuards from './guards' -export const machine = (editorDispatch: CR.EditorDispatch, tutorialModel: TutorialModel) => +export const machine = (tutorialModel: TutorialModel, editorDispatch: CR.EditorDispatch) => Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( { id: 'root', @@ -164,7 +164,7 @@ export const machine = (editorDispatch: CR.EditorDispatch, tutorialModel: Tutori }, }, { - actions: createActions(editorDispatch, tutorialModel), + actions: createActions(tutorialModel, editorDispatch), guards: createGuards(tutorialModel), activities: {}, }, diff --git a/typings/index.d.ts b/typings/index.d.ts index 60f7d0c4..61dbb84a 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -164,4 +164,13 @@ export interface StateMachine { send(action: string | Action): void } -export type EditorDispatch = (type: string, payload?: any) => void +interface MessageData { + tutorial?: {id: string} + position: Position + progress: Progress +} + +type MessageState = string + + +export type EditorDispatch = (type: string, payload?: MessageData | MessageState) => void diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index 32c5b06e..54b8b25e 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -23,7 +23,7 @@ const App = () => { }) // update level/stage/step status based on user progress & position - // TODO: model server more effeciently + // TODO: model server more efficiently const [setStatus] = useMutation(SET_STATUS) // event bus listener diff --git a/web-app/src/components/Cond/index.tsx b/web-app/src/components/Cond/index.tsx deleted file mode 100644 index 73f2375a..00000000 --- a/web-app/src/components/Cond/index.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import * as React from 'react' -import { stateMatch } from './utils/state' - -interface Props { - state: any - path: string - children: React.ReactElement -} - -const Cond = (props: Props) => { - if (!stateMatch(props.state, props.path)) { - return null - } - return props.children -} - -export default Cond diff --git a/web-app/src/components/Cond/utils/state.ts b/web-app/src/components/Cond/utils/state.ts deleted file mode 100644 index f2bb1289..00000000 --- a/web-app/src/components/Cond/utils/state.ts +++ /dev/null @@ -1,19 +0,0 @@ -export function stateMatch(state: any, statePath: string) { - let current = state - const paths = statePath.split('.') - let complete = false - try { - for (const p of paths) { - if (p === current && !complete) { - // handle strings - complete = true - } else { - // handle objects - current = current[p] - } - } - } catch (error) { - return false - } - return current !== undefined -} diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index 893ab405..21a3a53e 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -1,12 +1,15 @@ import * as React from 'react' import Route from './Route' -import { stateMatch } from '../Cond/utils/state' interface Props { state: string children: any } +const stateMatch = (state: string, path: string) => { + return !!(new RegExp(`^${state}`).exec(path)) +} + // router finds first state match of const Router = ({ state, children }: Props) => { const childArray = React.Children.toArray(children) From c32d6700bb8d14ce0e8a8dff591f503ea00e59d6 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 31 Aug 2019 17:41:17 -0700 Subject: [PATCH 057/117] add jest --- jest.config.js | 7 + package-lock.json | 4360 +++++++++++++++++++++++++++++++++++++++++++-- package.json | 6 +- 3 files changed, 4203 insertions(+), 170 deletions(-) create mode 100644 jest.config.js diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..44342108 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + roots: ['/src'], + transform: { + '^.+\\.tsx?$': 'ts-jest', + }, + testPathIgnorePatterns: ['node_modules', 'src/test'], +} diff --git a/package-lock.json b/package-lock.json index 053f380a..60ec84ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,118 @@ "@babel/highlight": "^7.0.0" } }, + "@babel/core": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.5.5.tgz", + "integrity": "sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.5.5", + "@babel/helpers": "^7.5.5", + "@babel/parser": "^7.5.5", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.5.tgz", + "integrity": "sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==", + "dev": true, + "requires": { + "@babel/types": "^7.5.5", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helpers": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.5.5.tgz", + "integrity": "sha512-nRq2BUhxZFnfEn/ciJuhklHvFOqjJUD5wpx+1bxUF2axL9C+v4DE/dmp5sT2dKnpOs4orZWzpAZqlCy8QqE/7g==", + "dev": true, + "requires": { + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5" + } + }, "@babel/highlight": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", @@ -24,6 +136,321 @@ "js-tokens": "^4.0.0" } }, + "@babel/parser": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz", + "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==", + "dev": true + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/traverse": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.5.tgz", + "integrity": "sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.5.5", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.5.5", + "@babel/types": "^7.5.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@cnakazawa/watch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", + "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "@jest/console": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "dev": true, + "requires": { + "@jest/source-map": "^24.9.0", + "chalk": "^2.0.1", + "slash": "^2.0.0" + } + }, + "@jest/core": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", + "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/reporters": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.9.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-resolve-dependencies": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "jest-watcher": "^24.9.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "slash": "^2.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "@jest/environment": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", + "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "dev": true, + "requires": { + "@jest/fake-timers": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/fake-timers": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/reporters": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.4.2", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + } + }, + "@jest/source-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/istanbul-lib-coverage": "^2.0.0" + } + }, + "@jest/test-sequencer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" + } + }, + "@jest/transform": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", + "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.9.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.9.0", + "jest-regex-util": "^24.9.0", + "jest-util": "^24.9.0", + "micromatch": "^3.1.10", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + } + }, + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/babel__core": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.2.tgz", + "integrity": "sha512-cfCCrFmiGY/yq0NuKNxIQvZFy9kY/1immpSpTngOnyIbD4+eJOG5mxphhHDv3CHL9GltO4GcKr54kGBg3RNdbg==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.0.2.tgz", + "integrity": "sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", + "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", + "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, "@types/dotenv": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz", @@ -42,6 +469,46 @@ "graphql": "*" } }, + "@types/istanbul-lib-coverage": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", + "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", + "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", + "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "24.0.18", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.18.tgz", + "integrity": "sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ==", + "dev": true, + "requires": { + "@types/jest-diff": "*" + } + }, + "@types/jest-diff": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz", + "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", + "dev": true + }, "@types/mocha": { "version": "5.2.7", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", @@ -54,6 +521,63 @@ "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==", "dev": true }, + "@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "@types/yargs": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.2.tgz", + "integrity": "sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.0.0.tgz", + "integrity": "sha512-wBlsw+8n21e6eTd4yVv8YD/E3xq0O6nNnJIquutAsFGE7EyMKz7W6RNT6BRu1SmdgmlCZ9tb0X+j+D6HGr8pZw==", + "dev": true + }, + "abab": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.1.tgz", + "integrity": "sha512-1zSbbCuoIjafKZ3mblY5ikvAb0ODUbqBnFuUb7f6uLeQhhGJ0vEV4ntmtxKLT2WgXCO94E07BjunsIw1jOMPZw==", + "dev": true + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-globals": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.3.tgz", + "integrity": "sha512-vkR40VwS2SYO98AIeFvzWWh+xyc2qi9s7OoXSFEGIP/rOJKzjnhykaZJNnHdoq4BL2gGxI5EZOU16z896EYnOQ==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "dev": true + } + } + }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "dev": true + }, "agent-base": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", @@ -73,6 +597,12 @@ "uri-js": "^4.2.2" } }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", @@ -88,6 +618,16 @@ "color-convert": "^1.9.0" } }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -97,6 +637,36 @@ "sprintf-js": "~1.0.2" } }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -110,11 +680,35 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "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==", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -125,33 +719,204 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "babel-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", + "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", + "dev": true, + "requires": { + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.9.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + } }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "babel-plugin-istanbul": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "dev": true, "requires": { - "tweetnacl": "^0.14.3" + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "babel-plugin-jest-hoist": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", + "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", + "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@types/babel__traverse": "^7.0.6" } }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "babel-preset-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", + "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.9.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "dev": true + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz", + "integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -163,12 +928,44 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -185,6 +982,35 @@ "supports-color": "^5.3.0" } }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -196,12 +1022,28 @@ "wrap-ansi": "^2.0.0" } }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -230,6 +1072,12 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -269,6 +1117,29 @@ } } }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -296,6 +1167,21 @@ "which": "^1.2.9" } }, + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -304,6 +1190,30 @@ "assert-plus": "^1.0.0" } }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, "date-fns": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", @@ -324,16 +1234,99 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, + "diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "dev": true + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, "dotenv": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz", @@ -348,6 +1341,12 @@ "safer-buffer": "^2.1.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -366,6 +1365,31 @@ "is-arrayish": "^0.2.1" } }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -384,18 +1408,51 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "escodegen": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", + "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + } + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "exec-sh": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", + "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", + "dev": true + }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -411,26 +1468,214 @@ "strip-eof": "^1.0.0" } }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expect": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "^2.0.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -440,6 +1685,12 @@ "locate-path": "^3.0.0" } }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -455,189 +1706,1741 @@ "mime-types": "^2.1.12" } }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + }, + "graphql": { + "version": "14.5.3", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.5.3.tgz", + "integrity": "sha512-W8A8nt9BsMg0ZK2qA3DJIVU6muWhxZRYLTmc+5XGwzWzVdUdPVlAAg5hTBjiTISEnzsKL/onasu6vl3kgGTbYg==", + "requires": { + "iterall": "^1.2.2" + } + }, + "graphql-request": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-1.8.2.tgz", + "integrity": "sha512-dDX2M+VMsxXFCmUX0Vo0TopIZIX4ggzOtiCsThgtrKR4niiaagsGTDIHj3fsOMFETpa064vzovI+4YV4QnMbcg==", + "requires": { + "cross-fetch": "2.2.2" + } + }, + "graphql-tag": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", + "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==" + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "handlebars": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" + }, + "hosted-git-info": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", + "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "requires": { + "agent-base": "4", + "debug": "3.1.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", + "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "dev": true, + "requires": { + "handlebars": "^4.1.2" + } + }, + "iterall": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", + "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" + }, + "jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", + "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", + "dev": true, + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.9.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 + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "jest-cli": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", + "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", + "dev": true, + "requires": { + "@jest/core": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^13.3.0" + } + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "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" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "jest-changed-files": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + } + }, + "jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" + } + }, + "jest-diff": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "jest-docblock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", "dev": true, "requires": { - "pump": "^3.0.0" + "detect-newline": "^2.1.0" } }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "jest-each": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "dev": true, "requires": { - "assert-plus": "^1.0.0" + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" } }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "jest-environment-jsdom": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", + "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", + "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0", + "jsdom": "^11.5.1" } }, - "graphql": { - "version": "14.5.3", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.5.3.tgz", - "integrity": "sha512-W8A8nt9BsMg0ZK2qA3DJIVU6muWhxZRYLTmc+5XGwzWzVdUdPVlAAg5hTBjiTISEnzsKL/onasu6vl3kgGTbYg==", + "jest-environment-node": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", + "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "dev": true, "requires": { - "iterall": "^1.2.2" + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0" } }, - "graphql-request": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-1.8.2.tgz", - "integrity": "sha512-dDX2M+VMsxXFCmUX0Vo0TopIZIX4ggzOtiCsThgtrKR4niiaagsGTDIHj3fsOMFETpa064vzovI+4YV4QnMbcg==", + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true + }, + "jest-haste-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "dev": true, "requires": { - "cross-fetch": "2.2.2" + "@jest/types": "^24.9.0", + "anymatch": "^2.0.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.7", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3", + "walker": "^1.0.7" } }, - "graphql-tag": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", - "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==" + "jest-jasmine2": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", + "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.9.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0", + "throat": "^4.0.0" + } }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" + "jest-leak-detector": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", + "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", + "dev": true, + "requires": { + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "jest-matcher-utils": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "dev": true, "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "jest-mock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0" + } }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" + "jest-pnp-resolver": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", + "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", + "dev": true }, - "hosted-git-info": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", - "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", "dev": true }, - "http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "jest-resolve": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "dev": true, "requires": { - "agent-base": "4", - "debug": "3.1.0" + "@jest/types": "^24.9.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "jest-resolve-dependencies": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", + "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", + "dev": true, "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "@jest/types": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.9.0" } }, - "https-proxy-agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", - "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", + "jest-runner": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", + "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", + "dev": true, "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-leak-detector": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" } }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "jest-runtime": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", + "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", + "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^13.3.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 + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "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" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } } }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "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=", + "jest-serializer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", "dev": true }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "jest-snapshot": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", + "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "expect": "^24.9.0", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.9.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "jest-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + } }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + } }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "jest-watcher": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", + "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.9.0", + "string-length": "^2.0.0" + } }, - "iterall": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", - "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } }, "js-tokens": { "version": "4.0.0", @@ -660,6 +3463,46 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -681,6 +3524,23 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -692,13 +3552,59 @@ "verror": "1.10.0" } }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, "lcid": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "dev": true, "requires": { - "invert-kv": "^2.0.0" + "invert-kv": "^2.0.0" + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" } }, "locate-path": { @@ -717,6 +3623,54 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, "map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", @@ -726,6 +3680,21 @@ "p-defer": "^1.0.0" } }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, "mem": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", @@ -737,6 +3706,33 @@ "p-is-promise": "^2.0.0" } }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, "mime-db": { "version": "1.40.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", @@ -769,6 +3765,27 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -815,6 +3832,44 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -826,6 +3881,31 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-notifier": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -838,6 +3918,15 @@ "validate-npm-package-license": "^3.0.1" } }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -853,11 +3942,82 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "nwsapi": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", + "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==", + "dev": true + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -866,6 +4026,38 @@ "wrappy": "1" } }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, "os-locale": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", @@ -883,6 +4075,15 @@ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -913,6 +4114,12 @@ "p-limit": "^2.0.0" } }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -929,6 +4136,18 @@ "json-parse-better-errors": "^1.0.1" } }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -952,6 +4171,15 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -963,12 +4191,78 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, "prettier": { "version": "1.18.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", "dev": true }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + }, + "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 + } + } + }, + "prompts": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", + "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.3" + } + }, "psl": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.3.0.tgz", @@ -999,6 +4293,12 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" }, + "react-is": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz", + "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", + "dev": true + }, "read-pkg": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", @@ -1010,6 +4310,66 @@ "pify": "^3.0.0" } }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + }, + "dependencies": { + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + } + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -1037,6 +4397,26 @@ "uuid": "^3.3.2" } }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "request-promise-native": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "dev": true, + "requires": { + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1063,6 +4443,48 @@ "path-parse": "^1.0.6" } }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true + }, "rxjs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", @@ -1077,10 +4499,50 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true }, "semver": { "version": "5.7.0", @@ -1093,6 +4555,29 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -1108,17 +4593,170 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "sisteransi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", + "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, "source-map-support": { "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", @@ -1128,6 +4766,12 @@ "source-map": "^0.6.0" } }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, "spawn-command": { "version": "0.0.2-1", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", @@ -1166,6 +4810,15 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -1188,6 +4841,49 @@ "tweetnacl": "~0.14.0" } }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + } + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -1207,6 +4903,12 @@ "ansi-regex": "^3.0.0" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", @@ -1221,6 +4923,92 @@ "has-flag": "^3.0.0" } }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + }, + "dependencies": { + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + } + } + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -1237,12 +5025,61 @@ } } }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "tree-kill": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", "dev": true }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "ts-jest": { + "version": "24.0.2", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-24.0.2.tgz", + "integrity": "sha512-h6ZCZiA1EQgjczxq+uGLXQlNgeg02WWJBbeT8j6nyIBRQdglqbvzDoHahTEIiS6Eor6x8mK6PfZ7brQ9Q6tzHw==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "buffer-from": "1.x", + "fast-json-stable-stringify": "2.x", + "json5": "2.x", + "make-error": "1.x", + "mkdirp": "0.x", + "resolve": "1.x", + "semver": "^5.5", + "yargs-parser": "10.x" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", @@ -1298,12 +5135,93 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, "typescript": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", "dev": true }, + "uglify-js": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true, + "optional": true + } + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -1312,6 +5230,12 @@ "punycode": "^2.1.0" } }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, "url-parse": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", @@ -1321,6 +5245,22 @@ "requires-port": "^1.0.0" } }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", @@ -1369,11 +5309,61 @@ "https-proxy-agent": "^2.2.1" } }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, "whatwg-fetch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -1389,6 +5379,12 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", @@ -1441,6 +5437,32 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, "xstate": { "version": "4.6.7", "resolved": "https://registry.npmjs.org/xstate/-/xstate-4.6.7.tgz", diff --git a/package.json b/package.json index c024f11b..f7acde1b 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "postinstall": "node ./node_modules/vscode/bin/install", "machine": "node ./out/state/index.js", "storybook": "cd web-app && npm run storybook", - "test": "npm run build && node ./node_modules/vscode/bin/test", + "test:ext": "npm run build && node ./node_modules/vscode/bin/test", + "test": "jest", "vscode:prepublish": "npm run build", "watch": "tsc -watch -p ./" }, @@ -39,10 +40,13 @@ "devDependencies": { "@types/dotenv": "^6.1.1", "@types/graphql": "^14.5.0", + "@types/jest": "^24.0.18", "@types/mocha": "^5.2.7", "@types/node": "^12.7.2", "concurrently": "^4.1.2", + "jest": "^24.9.0", "prettier": "^1.18.2", + "ts-jest": "^24.0.2", "tslint": "^5.19.0", "tslint-config-prettier": "^1.18.0", "typescript": "^3.5.3" From 38869212dee54bbcd476a7f1c7048dce4bdec78d Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 31 Aug 2019 17:41:24 -0700 Subject: [PATCH 058/117] fix stateToString function --- src/state/index.ts | 20 +++---------------- src/state/utils/stateToString.test.ts | 28 +++++++++++++++++++++++++++ src/state/utils/stateToString.ts | 15 ++++++++++++++ 3 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 src/state/utils/stateToString.test.ts create mode 100644 src/state/utils/stateToString.ts diff --git a/src/state/index.ts b/src/state/index.ts index 051de61d..063b883e 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -2,26 +2,11 @@ import {interpret, Interpreter} from 'xstate' import {TutorialModel} from '../services/tutorial' import * as CR from 'typings' import createMachine from './machine' +import stateToString from './utils/stateToString' // machine interpreter // https://xstate.js.org/docs/guides/interpretation.html -// convert state into a readable string -const stateToString = (state: string | object, str: string = ''): string => { - if (typeof state === 'object') { - const keys = Object.keys(state) - if (keys && keys.length) { - const key = keys[0] - return stateToString(state[key], str.length ? `${str}.${key}` : key) - } - return str - } else if (typeof state === 'string') { - return state - } - return '' -} - - class StateMachine { private machineOptions = { devTools: true, @@ -35,9 +20,10 @@ class StateMachine { // format state as a string and send it to the client this.syncState = (state: any): void => { + console.log(state) const stateValue: CR.MessageState = stateToString(state.value) console.log(`STATE: ${stateValue}`) - editorDispatch('send_data', stateValue) + editorDispatch('coderoad.send_state', stateValue) } // callback on all state changes diff --git a/src/state/utils/stateToString.test.ts b/src/state/utils/stateToString.test.ts new file mode 100644 index 00000000..1190678b --- /dev/null +++ b/src/state/utils/stateToString.test.ts @@ -0,0 +1,28 @@ +// +// Note: This example test is leveraging the Mocha test framework. +// Please refer to their documentation on https://mochajs.org/ for help. +// + +// The module 'assert' provides assertion methods from node +import stateToString from './stateToString' + +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +// import * as vscode from 'vscode' +// import * as myExtension from '../extension' + +// Defines a Mocha test suite to group tests of similar kind together +describe('StateToString', () => { + + test('no levels deep', () => { + expect(stateToString('first')).toBe('first') + }) + // Defines a Mocha unit test + test('one level deep', () => { + expect(stateToString({first: 'second'})).toBe('first.second') + }) + + test('two levels deep', () => { + expect(stateToString({first: {second: 'third'}})).toBe('first.second.third') + }) +}) diff --git a/src/state/utils/stateToString.ts b/src/state/utils/stateToString.ts new file mode 100644 index 00000000..5f690a6e --- /dev/null +++ b/src/state/utils/stateToString.ts @@ -0,0 +1,15 @@ +const stateToString = (state: string | object, str: string = ''): string => { + if (typeof state === 'object') { + const keys = Object.keys(state) + if (keys && keys.length) { + const key = keys[0] + return stateToString(state[key], str.length ? `${str}.${key}` : key) + } + return str + } else if (typeof state === 'string') { + return str.length ? `${str}.${state}` : state + } + return '' +} + +export default stateToString From 63f28db395add9c4e11321a05dafec20beada5c5 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 31 Aug 2019 17:47:56 -0700 Subject: [PATCH 059/117] fix jest mismatch build errors --- package-lock.json | 8 ++++---- package.json | 3 +-- src/test/extension.test.ts | 16 ++++++++-------- tsconfig.json | 2 +- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 60ec84ba..c5709641 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2839,13 +2839,13 @@ "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" }, "jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", - "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.8.0.tgz", + "integrity": "sha512-o0HM90RKFRNWmAWvlyV8i5jGZ97pFwkeVoGvPW1EtLTgJc2+jcuqcbbqcSZLE/3f2S5pt0y2ZBETuhpWNl1Reg==", "dev": true, "requires": { "import-local": "^2.0.0", - "jest-cli": "^24.9.0" + "jest-cli": "^24.8.0" }, "dependencies": { "ansi-regex": { diff --git a/package.json b/package.json index f7acde1b..da11be7e 100644 --- a/package.json +++ b/package.json @@ -41,10 +41,9 @@ "@types/dotenv": "^6.1.1", "@types/graphql": "^14.5.0", "@types/jest": "^24.0.18", - "@types/mocha": "^5.2.7", "@types/node": "^12.7.2", "concurrently": "^4.1.2", - "jest": "^24.9.0", + "jest": "24.8.0", "prettier": "^1.18.2", "ts-jest": "^24.0.2", "tslint": "^5.19.0", diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 75db3826..193dd793 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -4,7 +4,7 @@ // // The module 'assert' provides assertion methods from node -import * as assert from 'assert' +// import * as assert from 'assert' // You can import and use all API from the 'vscode' module // as well as import your extension to test it @@ -12,10 +12,10 @@ import * as assert from 'assert' // import * as myExtension from '../extension' // Defines a Mocha test suite to group tests of similar kind together -suite('Extension Tests', function() { - // Defines a Mocha unit test - test('Something 1', function() { - assert.equal(-1, [1, 2, 3].indexOf(5)) - assert.equal(-1, [1, 2, 3].indexOf(0)) - }) -}) +// suite('Extension Tests', function() { +// // Defines a Mocha unit test +// test('Something 1', function() { +// assert.equal(-1, [1, 2, 3].indexOf(5)) +// assert.equal(-1, [1, 2, 3].indexOf(0)) +// }) +// }) diff --git a/tsconfig.json b/tsconfig.json index b6730a63..e62adc7c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,5 +26,5 @@ }, "allowJs": true }, - "exclude": ["node_modules", ".vscode-test", "build", "resources", "web-app"] + "exclude": ["node_modules", ".vscode-test", "build", "resources", "web-app", "*.js", "*.test.ts"] } From 0d50ab683ad3b16de4a48951ec778cf74bd14b5c Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 31 Aug 2019 17:49:13 -0700 Subject: [PATCH 060/117] update deps --- package-lock.json | 24 +++++++++--------------- package.json | 6 +++--- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index c5709641..1286d646 100644 --- a/package-lock.json +++ b/package-lock.json @@ -509,16 +509,10 @@ "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", "dev": true }, - "@types/mocha": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", - "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", - "dev": true - }, "@types/node": { - "version": "12.7.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz", - "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==", + "version": "12.7.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.3.tgz", + "integrity": "sha512-3SiLAIBkDWDg6vFo0+5YJyHPWU9uwu40Qe+v+0MH8wRKYBimHvvAOyk3EzMrD/TrIlLYfXrqDqrg913PynrMJQ==", "dev": true }, "@types/stack-utils": { @@ -2329,9 +2323,9 @@ "dev": true }, "graphql": { - "version": "14.5.3", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.5.3.tgz", - "integrity": "sha512-W8A8nt9BsMg0ZK2qA3DJIVU6muWhxZRYLTmc+5XGwzWzVdUdPVlAAg5hTBjiTISEnzsKL/onasu6vl3kgGTbYg==", + "version": "14.5.4", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.5.4.tgz", + "integrity": "sha512-dPLvHoxy5m9FrkqWczPPRnH0X80CyvRE6e7Fa5AWEqEAzg9LpxHvKh24po/482E6VWHigOkAmb4xCp6P9yT9gw==", "requires": { "iterall": "^1.2.2" } @@ -5145,9 +5139,9 @@ } }, "typescript": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", - "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz", + "integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==", "dev": true }, "uglify-js": { diff --git a/package.json b/package.json index da11be7e..1f78d872 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "dotenv": "^8.1.0", - "graphql": "^14.5.3", + "graphql": "^14.5.4", "graphql-request": "^1.8.2", "graphql-tag": "^2.10.1", "vscode": "^1.1.36", @@ -41,14 +41,14 @@ "@types/dotenv": "^6.1.1", "@types/graphql": "^14.5.0", "@types/jest": "^24.0.18", - "@types/node": "^12.7.2", + "@types/node": "^12.7.3", "concurrently": "^4.1.2", "jest": "24.8.0", "prettier": "^1.18.2", "ts-jest": "^24.0.2", "tslint": "^5.19.0", "tslint-config-prettier": "^1.18.0", - "typescript": "^3.5.3" + "typescript": "^3.6.2" }, "engines": { "vscode": "^1.34.0" From 44cf7d73b67005f3dc53deccc6f4d32840276b2f Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 31 Aug 2019 17:57:25 -0700 Subject: [PATCH 061/117] cleanup client state --- src/state/index.ts | 5 ++--- typings/index.d.ts | 7 +++++-- web-app/src/App.tsx | 2 +- web-app/src/components/Debugger/index.tsx | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/state/index.ts b/src/state/index.ts index 063b883e..b4277c50 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -20,10 +20,9 @@ class StateMachine { // format state as a string and send it to the client this.syncState = (state: any): void => { - console.log(state) - const stateValue: CR.MessageState = stateToString(state.value) + const stateValue: string = stateToString(state.value) console.log(`STATE: ${stateValue}`) - editorDispatch('coderoad.send_state', stateValue) + editorDispatch('coderoad.send_state', {state: stateValue}) } // callback on all state changes diff --git a/typings/index.d.ts b/typings/index.d.ts index 61dbb84a..0e24792e 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -170,7 +170,10 @@ interface MessageData { progress: Progress } -type MessageState = string +interface MessageState { + state: string +} -export type EditorDispatch = (type: string, payload?: MessageData | MessageState) => void +// todo: type each string param and payload +export type EditorDispatch = (type: string, payload?: MessageData | MessageState | any) => void diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index 54b8b25e..fcc4788c 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -13,7 +13,7 @@ interface ReceivedEvent { } const App = () => { - const initialState = { SelectTutorial: 'Initial' } + const initialState = 'SelectTutorial.Initial' // set state machine state const [state, setState] = React.useState(initialState) diff --git a/web-app/src/components/Debugger/index.tsx b/web-app/src/components/Debugger/index.tsx index 8a54bdbc..268909f9 100644 --- a/web-app/src/components/Debugger/index.tsx +++ b/web-app/src/components/Debugger/index.tsx @@ -2,14 +2,14 @@ import * as React from 'react' import * as CR from 'typings' interface Props { - state: object + state: string position: CR.Position progress: CR.Progress } const Debugger = ({ state, position, progress }: Props) => (
-

state: {JSON.stringify(state)}

+

state: {state}

position: {JSON.stringify(position)}

progress: {JSON.stringify(progress)}

From 957d05b1a7f0ef9ba1990f43649a23e376df0943 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 31 Aug 2019 19:44:26 -0700 Subject: [PATCH 062/117] rename select to start --- src/state/machine.ts | 4 ++-- typings/index.d.ts | 2 +- web-app/src/App.tsx | 2 +- web-app/src/Routes.tsx | 8 ++++---- web-app/src/components/Error/index.tsx | 2 +- web-app/src/containers/New/index.tsx | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/state/machine.ts b/src/state/machine.ts index bc1be2e2..d673bc05 100644 --- a/src/state/machine.ts +++ b/src/state/machine.ts @@ -9,9 +9,9 @@ export const machine = (tutorialModel: TutorialModel, editorDispatch: CR.EditorD Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( { id: 'root', - initial: 'SelectTutorial', + initial: 'Start', states: { - SelectTutorial: { + Start: { onEntry: ['createWebview'], initial: 'Initial', states: { diff --git a/typings/index.d.ts b/typings/index.d.ts index 0e24792e..861a5c32 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -123,7 +123,7 @@ export interface MachineEvent { export interface MachineStateSchema { states: { - SelectTutorial: { + Start: { states: { Initial: {} Startup: {} diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index fcc4788c..ecae47c7 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -13,7 +13,7 @@ interface ReceivedEvent { } const App = () => { - const initialState = 'SelectTutorial.Initial' + const initialState = 'Start.Initial' // set state machine state const [state, setState] = React.useState(initialState) diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index fb8af220..54dedbc0 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -46,16 +46,16 @@ const Routes = ({ state }: Props) => { return (
- + - + - + - + diff --git a/web-app/src/components/Error/index.tsx b/web-app/src/components/Error/index.tsx index 124c4934..cffa3f08 100644 --- a/web-app/src/components/Error/index.tsx +++ b/web-app/src/components/Error/index.tsx @@ -15,7 +15,7 @@ interface Props { } const ErrorView = ({ error }: Props) => { - console.log('ERROR:', error) + console.log(error) return (

Error

diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 560da00b..8b142258 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -34,7 +34,7 @@ const NewPageContainer = () => { return ( - send('TUTORIAL_START')} tutorialList={data.tutorials} /> + send('TUTORIAL_START')} tutorialList={data.tutorials} /> ) } From 0133ab8b64d410dfae1073f118d6473aabf21f05 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 1 Sep 2019 10:12:30 -0700 Subject: [PATCH 063/117] migrate git into tutorial model --- src/editor/ReactWebView.ts | 31 ++- src/editor/commands/index.ts | 6 +- src/editor/commands/runTest.ts | 246 +++++++++--------- src/services/git/index.ts | 4 +- src/services/tutorial/index.ts | 53 +++- src/state/actions/index.ts | 52 +--- .../New/TutorialList/TutorialItem.tsx | 4 +- .../src/containers/New/TutorialList/index.tsx | 16 +- web-app/src/containers/New/index.tsx | 5 +- web-app/src/services/apollo/mutations.ts | 4 +- web-app/stories/New.stories.tsx | 6 +- 11 files changed, 224 insertions(+), 203 deletions(-) diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index 77620f50..9c86c072 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -12,9 +12,7 @@ const getNonce = (): string => { } -/** - * Manages React webview panels - */ +// Manages webview panel class ReactWebView { // @ts-ignore public loaded: boolean @@ -28,7 +26,7 @@ class ReactWebView { // Create and show a new webview panel this.panel = this.createWebviewPanel(vscode.ViewColumn.Two) - // Set the webview's initial html content + // Set the webview initial html content this.panel.webview.html = this.getHtmlForWebview() // Listen for when the panel is disposed @@ -37,12 +35,21 @@ class ReactWebView { // Handle messages from the webview const onReceive = (action: string | CR.Action) => { - // await loading of webview in React before proceeding with loaded state - if (action === 'WEBVIEW_LOADED') { - this.loaded = true - } else { - console.log('onReceive', action) - vscode.commands.executeCommand('coderoad.receive_action', action) + const actionType: string = typeof action === 'string' ? action : action.type + switch (actionType) { + case 'WEBVIEW_LOADED': + // await loading of webview in React before proceeding with loaded state + this.loaded = true + break + case 'TUTORIAL_START': + console.log('TUTORIAL_START called') + console.log(action) + break + // add other cases + default: + // send to state machine + console.log('onReceive', action) + vscode.commands.executeCommand('coderoad.receive_machine_action', action) } } this.panel.webview.onDidReceiveMessage(onReceive, null, this.disposables) @@ -55,7 +62,7 @@ class ReactWebView { }) } - // prevents new panels from going ontop of coderoad panel + // prevents new panels from going on top of coderoad panel vscode.window.onDidChangeActiveTextEditor((textEditor?: vscode.TextEditor) => { console.log('onDidChangeActiveTextEditor') console.log(textEditor) @@ -115,7 +122,7 @@ class ReactWebView { const config = { // Enable javascript in the webview enableScripts: true, - // And restric the webview to only loading content from our extension's `media` directory. + // And restrict the webview to only loading content from our extension's `media` directory. localResourceRoots: [vscode.Uri.file(path.join(this.extensionPath, 'build'))], // prevents destroying the window when it is in the background retainContextWhenHidden: true, diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index 7aa5e775..a0a8a00a 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -13,7 +13,7 @@ const COMMANDS = { OPEN_WEBVIEW: 'coderoad.open_webview', SEND_STATE: 'coderoad.send_state', SEND_DATA: 'coderoad.send_data', - RECEIVE_ACTION: 'coderoad.receive_action', + RECEIVE_MACHINE_ACTION: 'coderoad.receive_machine_action', OPEN_FILE: 'coderoad.open_file', RUN_TEST: 'coderoad.run_test', TEST_PASS: 'coderoad.test_pass', @@ -102,7 +102,7 @@ export const createCommands = ({vscodeExt, machine}: CreateCommandProps) => { const absoluteFilePath = join(workspaceRoot, relativeFilePath) const doc = await vscode.workspace.openTextDocument(absoluteFilePath) await vscode.window.showTextDocument(doc, vscode.ViewColumn.One) - // there are times when intialization leave the panel behind any files opened + // there are times when initialization leave the panel behind any files opened // ensure the panel is redrawn on the right side first webview.createOrShow(vscode.ViewColumn.Two) } catch (error) { @@ -116,7 +116,7 @@ export const createCommands = ({vscodeExt, machine}: CreateCommandProps) => { [COMMANDS.SEND_DATA]: (payload: {data: any}) => { webview.postMessage({type: 'SET_DATA', payload}) }, - [COMMANDS.RECEIVE_ACTION]: (action: string | CR.Action) => { + [COMMANDS.RECEIVE_MACHINE_ACTION]: (action: string | CR.Action) => { // send received actions from web-app into state machine console.log('receive action', action) machine.send(action) diff --git a/src/editor/commands/runTest.ts b/src/editor/commands/runTest.ts index 4a6627c6..bcc0dbb0 100644 --- a/src/editor/commands/runTest.ts +++ b/src/editor/commands/runTest.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode' -import { exec } from '../../services/node' +import {exec} from '../../services/node' import * as storage from '../../services/storage' // ensure only latest run_test action is taken @@ -8,135 +8,135 @@ let currentId = 0 // quick solution to prevent processing multiple results // NOTE: may be possible to kill child process early const shouldExitEarly = (processId: number): boolean => { - return currentId !== processId + return currentId !== processId } -let _channel: vscode.OutputChannel +let channel: vscode.OutputChannel const getOutputChannel = (name: string): vscode.OutputChannel => { - if (!_channel) { - _channel = vscode.window.createOutputChannel(name) - } - return _channel + if (!channel) { + channel = vscode.window.createOutputChannel(name) + } + return channel } interface Props { - onSuccess(): void - onFail(): void + onSuccess(): void + onFail(): void } -export default async function runTest({ onSuccess, onFail }: Props): Promise { - // increment process id - let processId = ++currentId - - const outputChannelName = 'Test Output' - - // TODO: validate test directory from package.json exists - // let testFile = path.join('test'); - // if (!await exists(testFile)) { - // return emptyTasks; - // } - - // TODO: verify test runner for args - const testArgs = ['--json'] - - // if .git repo, use --onlyChanged - // const hasGit = path.join('.git'); - // if (await exists(hasGit)) { - // testArgs.push('--onlyChanged') - // } - - let commandLine = `npm test -- ${testArgs.join(' ')}` - - try { - // capture position early on test start - // in case position changes - const [position, { stdout }] = await Promise.all([storage.getPosition(), exec(commandLine)]) - if (shouldExitEarly(processId)) { - // exit early - return - } - - if (stdout) { - let lines = stdout.split(/\r{0,1}\n/) - console.log('SUCCESS LINES', lines) - for (let line of lines) { - if (line.length === 0) { - continue - } - - const regExp = /^{\"numFailedTestSuites/ - const matches = regExp.exec(line) - if (matches && matches.length) { - console.log('MATCHES SUCCESS') - const result = JSON.parse(line) - - if (result.success) { - console.log('SUCCESS') - if (shouldExitEarly(processId)) { - // exit early - return - } - console.log('call onSuccess') - onSuccess() - } else { - console.log('NOT SUCCESS?') - } - } - } - } - } catch (err) { - if (shouldExitEarly(processId)) { - // exit early - return - } - // error contains output & error message - // output can be parsed as json - const { stdout, stderr } = err - console.log('TEST FAILED', stdout) - - if (!stdout) { - console.error('SOMETHING WENT WRONG WITH A PASSING TEST') - } - // test runner failed - const channel = getOutputChannel(outputChannelName) - - if (stdout) { - let lines = stdout.split(/\r{0,1}\n/) - - for (let line of lines) { - if (line.length === 0) { - continue - } - - const dataRegExp = /^{\"numFailedTestSuites"/ - const matches = dataRegExp.exec(line) - - if (matches && matches.length) { - const result = JSON.parse(line) - const firstError = result.testResults.find((t: any) => t.status === 'failed') - - if (firstError) { - if (shouldExitEarly(processId)) { - // exit early - return - } - console.log('ERROR', firstError.message) - console.log('call onFail') - onFail() - } else { - console.error('NOTE: PARSER DID NOT WORK FOR ', line) - } - } - } - } - - if (stderr) { - channel.show(false) - channel.appendLine(stderr) - } - // if (err.stdout) { - // channel.appendLine(err.stdout); - // } - } +export default async function runTest({onSuccess, onFail}: Props): Promise { + // increment process id + const processId = ++currentId + + const outputChannelName = 'Test Output' + + // TODO: validate test directory from package.json exists + // let testFile = path.join('test'); + // if (!await exists(testFile)) { + // return emptyTasks; + // } + + // TODO: verify test runner for args + const testArgs = ['--json'] + + // if .git repo, use --onlyChanged + // const hasGit = path.join('.git'); + // if (await exists(hasGit)) { + // testArgs.push('--onlyChanged') + // } + + const commandLine = `npm test -- ${testArgs.join(' ')}` + + try { + // capture position early on test start + // in case position changes + const [position, {stdout}] = await Promise.all([storage.getPosition(), exec(commandLine)]) + if (shouldExitEarly(processId)) { + // exit early + return + } + + if (stdout) { + const lines = stdout.split(/\r{0,1}\n/) + console.log('SUCCESS LINES', lines) + for (const line of lines) { + if (line.length === 0) { + continue + } + + const regExp = /^{\"numFailedTestSuites/ + const matches = regExp.exec(line) + if (matches && matches.length) { + console.log('MATCHES SUCCESS') + const result = JSON.parse(line) + + if (result.success) { + console.log('SUCCESS') + if (shouldExitEarly(processId)) { + // exit early + return + } + console.log('call onSuccess') + onSuccess() + } else { + console.log('NOT SUCCESS?') + } + } + } + } + } catch (err) { + if (shouldExitEarly(processId)) { + // exit early + return + } + // error contains output & error message + // output can be parsed as json + const {stdout, stderr} = err + console.log('TEST FAILED', stdout) + + if (!stdout) { + console.error('SOMETHING WENT WRONG WITH A PASSING TEST') + } + // test runner failed + const channel = getOutputChannel(outputChannelName) + + if (stdout) { + const lines = stdout.split(/\r{0,1}\n/) + + for (const line of lines) { + if (line.length === 0) { + continue + } + + const dataRegExp = /^{\"numFailedTestSuites"/ + const matches = dataRegExp.exec(line) + + if (matches && matches.length) { + const result = JSON.parse(line) + const firstError = result.testResults.find((t: any) => t.status === 'failed') + + if (firstError) { + if (shouldExitEarly(processId)) { + // exit early + return + } + console.log('ERROR', firstError.message) + console.log('call onFail') + onFail() + } else { + console.error('NOTE: PARSER DID NOT WORK FOR ', line) + } + } + } + } + + if (stderr) { + channel.show(false) + channel.appendLine(stderr) + } + // if (err.stdout) { + // channel.appendLine(err.stdout); + // } + } } diff --git a/src/services/git/index.ts b/src/services/git/index.ts index 3db43e81..8166024b 100644 --- a/src/services/git/index.ts +++ b/src/services/git/index.ts @@ -39,7 +39,7 @@ const cherryPickCommit = async (commit: string, count = 0): Promise => { SINGLE git cherry-pick %COMMIT% if fails, will stash all and retry */ -export async function gitLoadCommits(actions: G.StepActions, editorDispatch: CR.EditorDispatch): Promise { +export async function gitLoadCommits(actions: G.StepActions, openFile: (file: string) => void): Promise { const {commits, commands, files} = actions console.log(`load commits: ${commits.join(', ')}`) @@ -72,7 +72,7 @@ export async function gitLoadCommits(actions: G.StepActions, editorDispatch: CR. if (files) { for (const filePath of files) { - editorDispatch('coderoad.open_file', filePath) + openFile(filePath) } } } diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index c48cc932..e629995f 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -1,5 +1,6 @@ import * as G from 'typings/graphql' import * as CR from 'typings' +import * as git from '../../services/git' import * as storage from '../storage' import api from '../api' import tutorialQuery from '../../services/api/gql/getTutorial' @@ -23,6 +24,7 @@ export interface TutorialModel { nextPosition(): CR.Position hasExisting(): Promise syncClient(): void + triggerCurrent(type: 'STEP' | 'STAGE' | 'LEVEL'): void } class Tutorial implements TutorialModel { @@ -32,6 +34,7 @@ class Tutorial implements TutorialModel { public position: CR.Position public progress: CR.Progress public syncClient: () => void + public openFile: (file: string) => void constructor(editorDispatch: CR.EditorDispatch) { // initialize types, will be assigned when tutorial is selected @@ -46,6 +49,7 @@ class Tutorial implements TutorialModel { progress: this.progress, position: this.position, }) + this.openFile = (file: string) => editorDispatch('coderoad.open_file', file) // Promise.all([ // storage.getTutorial(), // storage.getProgress(), @@ -56,8 +60,9 @@ class Tutorial implements TutorialModel { // }) } - public async launch(tutorialId: string) { + console.log('launch tutorial') + const {tutorial}: {tutorial: G.Tutorial | null} = await api.request(tutorialQuery, { tutorialId, // TODO: add selection of tutorial id }) @@ -67,6 +72,11 @@ class Tutorial implements TutorialModel { } this.repo = tutorial.repo + + if (!this.repo || !this.repo.uri) { + throw new Error('Tutorial repo uri not found') + } + this.config = { codingLanguage: tutorial.codingLanguage, testRunner: tutorial.testRunner, @@ -87,9 +97,13 @@ class Tutorial implements TutorialModel { complete: false, } + // setup git, git remote + await git.gitInitIfNotExists() + await git.gitSetupRemote(this.repo.uri) + console.log('this.position', JSON.stringify(this.position)) - this.syncClient() + await this.syncClient() // set tutorial, position, progress locally // TODO: base position off of progress @@ -98,6 +112,7 @@ class Tutorial implements TutorialModel { storage.setPosition(this.position), storage.setProgress(this.progress) ]) + // machine.send('TUTORIAL_LOADED') } public async hasExisting(): Promise { @@ -106,9 +121,18 @@ class Tutorial implements TutorialModel { storage.getProgress(), ]) - return !!(tutorial && progress) + // verify git is setup with a coderoad remote + const [hasGit, hasGitRemote] = await Promise.all([ + git.gitVersion(), + git.gitCheckRemoteExists(), + ]) + // TODO: may need to clean up git remote if no existing tutorial + + const canContinue = !!(tutorial && progress && hasGit && hasGitRemote) + + return canContinue } - public level = (levelId: string): G.Level => { + public level = (levelId?: string): G.Level => { const level: G.Level | undefined = this.version.levels.find((l: G.Level) => l.id === levelId || this.position.levelId) if (!level) { throw new Error('Level not found') @@ -131,6 +155,27 @@ class Tutorial implements TutorialModel { } return step } + public triggerCurrent = (type: 'STEP' | 'STAGE' | 'LEVEL') => { + let target: G.Step | G.Stage | G.Level | null = null + switch (type) { + case 'STEP': + target = this.step() + break + case 'STAGE': + target = this.stage() + break + case 'LEVEL': + target = this.level() + break + default: + throw new Error(`Type ${type} not found`) + } + if (!target || !target.setup) { + // no stepAction + return + } + git.gitLoadCommits(target.setup, this.openFile) + } public updateProgress = () => { const {levelId, stageId, stepId} = this.position this.progress.levels[levelId] = true diff --git a/src/state/actions/index.ts b/src/state/actions/index.ts index dc1263f6..17f71dd7 100644 --- a/src/state/actions/index.ts +++ b/src/state/actions/index.ts @@ -2,7 +2,6 @@ import {machine} from '../../extension' import {TutorialModel} from '../../services/tutorial' import * as CR from 'typings' import * as G from 'typings/graphql' -import * as git from '../../services/git' export default (tutorialModel: TutorialModel, editorDispatch: CR.EditorDispatch) => ({ @@ -12,38 +11,7 @@ export default (tutorialModel: TutorialModel, editorDispatch: CR.EditorDispatch) async newOrContinue() { // verify that the user has an existing tutorial to continue const hasExistingTutorial: boolean = await tutorialModel.hasExisting() - - // verify git is setup with a coderoad remote - const [hasGit, hasGitRemote] = await Promise.all([ - git.gitVersion(), - git.gitCheckRemoteExists(), - ]) - - const canContinue = !!(hasExistingTutorial && hasGit && hasGitRemote) - - // TODO: may need to clean up git remote if no existing tutorial - - machine.send(canContinue ? 'CONTINUE' : 'NEW') - }, - async tutorialLaunch() { - const tutorialId: string = '1' - // TODO: load tutorialId - await tutorialModel.launch(tutorialId) - - // git setup - const repo: G.TutorialRepo = tutorialModel.repo - - console.log('launch tutorial') - - await git.gitInitIfNotExists() - - if (!repo || !repo.uri) { - throw new Error('Tutorial repo uri not found') - } - - await git.gitSetupRemote(repo.uri) - - machine.send('TUTORIAL_LOADED') + machine.send(hasExistingTutorial ? 'CONTINUE' : 'NEW') }, testRunnerSetup() { const codingLanguage: G.EnumCodingLanguage = tutorialModel.config.codingLanguage @@ -85,7 +53,7 @@ export default (tutorialModel: TutorialModel, editorDispatch: CR.EditorDispatch) }, testPass(): void { editorDispatch('coderoad.test_pass') - git.gitSaveCommit(tutorialModel.position) + // git.gitSaveCommit(tutorialModel.position) }, testFail() { editorDispatch('coderoad.test_fail') @@ -141,23 +109,14 @@ export default (tutorialModel: TutorialModel, editorDispatch: CR.EditorDispatch) // }, // }), loadLevel(): void { - const level: G.Level = tutorialModel.level() - // run level setup if it exists - if (level && level.setup) { - git.gitLoadCommits(level.setup, editorDispatch) - } + tutorialModel.triggerCurrent('LEVEL') }, stageLoadNext() { console.log('stageLoadNext') tutorialModel.nextPosition() }, loadStage(): void { - const stage: G.Stage = tutorialModel.stage() - - // run level setup if it exists - if (stage && stage.setup) { - git.gitLoadCommits(stage.setup, editorDispatch) - } + tutorialModel.triggerCurrent('STAGE') }, // @ts-ignore // updatePosition: assign({ @@ -167,7 +126,6 @@ export default (tutorialModel: TutorialModel, editorDispatch: CR.EditorDispatch) // }), // }), stepLoadCommits(): void { - const step: G.Step = tutorialModel.step() - git.gitLoadCommits(step.setup, editorDispatch) + tutorialModel.triggerCurrent('STEP') }, }) diff --git a/web-app/src/containers/New/TutorialList/TutorialItem.tsx b/web-app/src/containers/New/TutorialList/TutorialItem.tsx index 71a3e0bb..f7e22370 100644 --- a/web-app/src/containers/New/TutorialList/TutorialItem.tsx +++ b/web-app/src/containers/New/TutorialList/TutorialItem.tsx @@ -4,14 +4,14 @@ import { Button } from '@alifd/next' interface Props { title?: string text?: string - onNew(): void + onSelect(): void } const TutorialItem = (props: Props) => (

{props.title || 'Title'}

{props.text || 'Description'}

- +
) diff --git a/web-app/src/containers/New/TutorialList/index.tsx b/web-app/src/containers/New/TutorialList/index.tsx index c40dbacd..b06fff85 100644 --- a/web-app/src/containers/New/TutorialList/index.tsx +++ b/web-app/src/containers/New/TutorialList/index.tsx @@ -1,24 +1,34 @@ import * as React from 'react' +import * as CR from 'typings' import * as T from 'typings/graphql' import TutorialItem from './TutorialItem' interface Props { tutorialList: T.Tutorial[] - onNew(id: string): void + onNew(Action: CR.Action): void } -const TutorialList = (props: Props) => ( +const TutorialList = (props: Props) => { + const onSelect = (tutorial: T.Tutorial) => props.onNew({ + type: 'TUTORIAL_START', + payload: { + id: tutorial.id, + version: tutorial.version, + } + }) + return (
{props.tutorialList.map((tutorial: T.Tutorial) => ( props.onNew(tutorial.id)} + onSelect={() => onSelect(tutorial)} title={tutorial.title || ''} text={tutorial.text || ''} /> ))}
) + } export default TutorialList diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 8b142258..0483d9f7 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -1,6 +1,7 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' import * as T from 'typings/graphql' +import * as CR from 'typings' import queryTutorials from './queryTutorials' import { send } from '../../utils/vscode' @@ -10,7 +11,7 @@ import TutorialList from './TutorialList' interface Props { tutorialList: T.Tutorial[] - onNew(tutorialId: string): void + onNew(action: CR.Action): void } export const NewPage = (props: Props) => ( @@ -34,7 +35,7 @@ const NewPageContainer = () => { return ( - send('TUTORIAL_START')} tutorialList={data.tutorials} /> + ) } diff --git a/web-app/src/services/apollo/mutations.ts b/web-app/src/services/apollo/mutations.ts index f4a0c5ce..2d3f1bcf 100644 --- a/web-app/src/services/apollo/mutations.ts +++ b/web-app/src/services/apollo/mutations.ts @@ -1,7 +1,7 @@ -import { gql } from 'apollo-boost' +import {gql} from 'apollo-boost' export const SET_STATUS = gql` - mutation ToggleTodo($progress: Progress!, $position: Position) { + mutation SetStatus($progress: Progress!, $position: Position) { setStatus(progress: $progress, position: $position) @client } ` \ No newline at end of file diff --git a/web-app/stories/New.stories.tsx b/web-app/stories/New.stories.tsx index 4952ea37..f8a9eeee 100644 --- a/web-app/stories/New.stories.tsx +++ b/web-app/stories/New.stories.tsx @@ -10,15 +10,15 @@ import NewContainer from '../src/containers/New' storiesOf('New', module) .add('Tutorial', () => { - const tutorial: T.Tutorial = { + const tutorial = { id: '1', title: 'Tutorial 1', text: 'The first one', } - return + return }) .add('TutorialList', () => { - const tutorialList: T.Tutorial[] = [ + const tutorialList = [ { id: '1', title: 'Tutorial 1', From 50cad589f3342128b5463556a09059411d682a5f Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 1 Sep 2019 11:16:40 -0700 Subject: [PATCH 064/117] setup initial start/loaded actions --- src/editor/ReactWebView.ts | 5 +++ src/services/tutorial/index.ts | 12 ++++- web-app/src/App.tsx | 7 ++- .../src/containers/New/TutorialList/index.tsx | 45 +++++++++++-------- .../containers/Tutorial/LevelPage/index.tsx | 8 ++-- .../containers/Tutorial/StagePage/index.tsx | 8 ++-- .../containers/Tutorial/SummaryPage/index.tsx | 4 +- web-app/src/services/current/index.ts | 38 ++++++++++++++++ 8 files changed, 98 insertions(+), 29 deletions(-) create mode 100644 web-app/src/services/current/index.ts diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index 9c86c072..b5f246bf 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -1,6 +1,7 @@ import * as path from 'path' import * as CR from 'typings' import * as vscode from 'vscode' +import {tutorialModel} from '../extension' const getNonce = (): string => { let text = '' @@ -44,6 +45,10 @@ class ReactWebView { case 'TUTORIAL_START': console.log('TUTORIAL_START called') console.log(action) + if (typeof action === 'string' || !action.payload || !action.payload.id) { + throw new Error('No tutorial id on tutorial start action') + } + tutorialModel.launch(action.payload.id) break // add other cases default: diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index e629995f..7ab284a0 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -1,6 +1,7 @@ import * as G from 'typings/graphql' import * as CR from 'typings' import * as git from '../../services/git' +import {machine} from '../../extension' import * as storage from '../storage' import api from '../api' import tutorialQuery from '../../services/api/gql/getTutorial' @@ -60,13 +61,16 @@ class Tutorial implements TutorialModel { // }) } - public async launch(tutorialId: string) { + public launch = async (tutorialId: string) => { console.log('launch tutorial') + machine.send('TUTORIAL_START') const {tutorial}: {tutorial: G.Tutorial | null} = await api.request(tutorialQuery, { tutorialId, // TODO: add selection of tutorial id }) + console.log('tutorial', tutorial) + if (!tutorial) { throw new Error(`Tutorial ${tutorialId} not found`) } @@ -83,6 +87,8 @@ class Tutorial implements TutorialModel { } // version containing level data this.version = tutorial.version + console.log('version', this.version) + // set initial position this.position = { levelId: this.version.levels[0].id, @@ -112,7 +118,9 @@ class Tutorial implements TutorialModel { storage.setPosition(this.position), storage.setProgress(this.progress) ]) - // machine.send('TUTORIAL_LOADED') + + console.log('tutorial loaded') + machine.send('TUTORIAL_LOADED') } public async hasExisting(): Promise { diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index ecae47c7..1c89f534 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -4,6 +4,7 @@ import * as CR from 'typings' import client from './services/apollo' import { SET_STATUS } from './services/apollo/mutations' +import currentTutorial from './services/current' import Debugger from './components/Debugger' import Routes from './Routes' import { send } from './utils/vscode' @@ -39,11 +40,15 @@ const App = () => { } else if (message.type === 'SET_DATA') { // SET_DATA - set state machine context - const { progress, position } = message.payload.data + console.log('DATA') + const { progress, position } = message.payload if (process.env.REACT_APP_DEBUG) { console.log(`Position: ${position.levelId}/${position.stageId}/${position.stepId}`) setDebuggerInfo({ progress, position }) } + console.log('set currentTutorial') + currentTutorial.set({ position }) + console.log('setStatus') setStatus({ variables: { progress, position } }) } } diff --git a/web-app/src/containers/New/TutorialList/index.tsx b/web-app/src/containers/New/TutorialList/index.tsx index b06fff85..896aa365 100644 --- a/web-app/src/containers/New/TutorialList/index.tsx +++ b/web-app/src/containers/New/TutorialList/index.tsx @@ -1,5 +1,6 @@ import * as React from 'react' +import currentTutorial from '../../../services/current' import * as CR from 'typings' import * as T from 'typings/graphql' import TutorialItem from './TutorialItem' @@ -10,25 +11,31 @@ interface Props { } const TutorialList = (props: Props) => { - const onSelect = (tutorial: T.Tutorial) => props.onNew({ - type: 'TUTORIAL_START', - payload: { - id: tutorial.id, - version: tutorial.version, - } - }) + const onSelect = (tutorial: T.Tutorial) => { + currentTutorial.set({ + tutorialId: tutorial.id, + version: tutorial.version.version, + }) + props.onNew({ + type: 'TUTORIAL_START', + payload: { + id: tutorial.id, + version: tutorial.version.version, + } + }) + } return ( -
- {props.tutorialList.map((tutorial: T.Tutorial) => ( - onSelect(tutorial)} - title={tutorial.title || ''} - text={tutorial.text || ''} - /> - ))} -
-) - } +
+ {props.tutorialList.map((tutorial: T.Tutorial) => ( + onSelect(tutorial)} + title={tutorial.title || ''} + text={tutorial.text || ''} + /> + ))} +
+ ) +} export default TutorialList diff --git a/web-app/src/containers/Tutorial/LevelPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx index 4eb5c2e8..bfba1e5c 100644 --- a/web-app/src/containers/Tutorial/LevelPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/index.tsx @@ -2,6 +2,7 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' import * as T from 'typings/graphql' +import currentTutorial from '../../../services/current' import ErrorView from '../../../components/Error' import Level from './Level' import queryLevel from './queryLevel' @@ -26,11 +27,12 @@ interface ContainerProps { } const LevelSummaryPageContainer = (props: ContainerProps) => { + const { tutorialId, version, position: { levelId } } = currentTutorial.get() const { loading, error, data } = useQuery(queryLevel, { variables: { - tutorialId: '1', - version: '0.1.0', - levelId: '1', + tutorialId, + version, + levelId, }, }) diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index 7c9a2fe7..f20dcdc3 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -1,6 +1,7 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' +import currentTutorial from '../../../services/current' import ErrorView from '../../../components/Error' import Stage from './Stage' import queryStage from './queryStage' @@ -10,11 +11,12 @@ interface PageProps { } const StageSummaryPageContainer = (props: PageProps) => { + const { tutorialId, version, position: { stageId } } = currentTutorial.get() const { loading, error, data } = useQuery(queryStage, { variables: { - tutorialId: '1', - version: '0.1.0', - stageId: '1', + tutorialId, + version, + stageId, }, }) if (loading) { diff --git a/web-app/src/containers/Tutorial/SummaryPage/index.tsx b/web-app/src/containers/Tutorial/SummaryPage/index.tsx index ea229382..c8fce580 100644 --- a/web-app/src/containers/Tutorial/SummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/SummaryPage/index.tsx @@ -3,6 +3,7 @@ import { useQuery } from '@apollo/react-hooks' import querySummary from './querySummary' import Summary from './Summary' +import currentTutorial from '../../../services/current' import ErrorView from '../../../components/Error' interface PageProps { @@ -10,9 +11,10 @@ interface PageProps { } const SummaryPage = (props: PageProps) => { + const { tutorialId } = currentTutorial.get() const { loading, error, data } = useQuery(querySummary, { variables: { - tutorialId: '1', + tutorialId, }, }) diff --git a/web-app/src/services/current/index.ts b/web-app/src/services/current/index.ts new file mode 100644 index 00000000..9541c202 --- /dev/null +++ b/web-app/src/services/current/index.ts @@ -0,0 +1,38 @@ +import * as CR from 'typings' + +interface CurrentTutorialParams { + tutorialId: string + version: string + position: CR.Position +} + +interface SetCurrentTutorialParams { + tutorialId?: string + version?: string + position?: CR.Position +} + +class CurrentTutorial { + private tutorialId = '' + private version = '' + private position: CR.Position = {levelId: '', stageId: '', stepId: ''} + public set({tutorialId, version, position}: SetCurrentTutorialParams) { + this.tutorialId = tutorialId || this.tutorialId + this.version = version || this.version + this.position = position || this.position + } + public get(): CurrentTutorialParams { + return { + tutorialId: this.tutorialId, + version: this.version, + position: this.position, + } + } + public clear() { + this.tutorialId = '' + this.version = '' + this.position = {levelId: '', stageId: '', stepId: ''} + } +} + +export default new CurrentTutorial() From e062d66bce44dac6736536fda62e9cd55a19674d Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 1 Sep 2019 19:27:14 -0700 Subject: [PATCH 065/117] cleanup editor - experimental --- src/editor/commands/index.ts | 19 ++--- src/editor/index.ts | 13 +-- src/extension.ts | 9 +- src/services/api/gql/getTutorial.ts | 51 ----------- src/services/api/index.ts | 13 --- src/services/tutorial/index.ts | 80 ++---------------- web-app/src/App.tsx | 14 +-- web-app/src/containers/Continue/index.tsx | 8 +- .../containers/Tutorial/LevelPage/index.tsx | 30 +++++-- web-app/src/services/apollo/index.ts | 5 -- web-app/src/services/apollo/mutations.ts | 7 -- web-app/src/services/apollo/resolvers.ts | 53 ------------ web-app/src/services/apollo/typeDefs.ts | 15 ---- web-app/src/services/current/index.ts | 21 ++++- {src => web-app/src}/state/State.png | Bin {src => web-app/src}/state/actions/index.ts | 0 {src => web-app/src}/state/guards/index.ts | 0 {src => web-app/src}/state/index.ts | 0 {src => web-app/src}/state/machine.ts | 1 - .../src}/state/utils/stateToString.test.ts | 0 .../src}/state/utils/stateToString.ts | 0 web-app/src/utils/vscode.ts | 11 ++- 22 files changed, 83 insertions(+), 267 deletions(-) delete mode 100644 src/services/api/gql/getTutorial.ts delete mode 100644 src/services/api/index.ts delete mode 100644 web-app/src/services/apollo/mutations.ts delete mode 100644 web-app/src/services/apollo/resolvers.ts delete mode 100644 web-app/src/services/apollo/typeDefs.ts rename {src => web-app/src}/state/State.png (100%) rename {src => web-app/src}/state/actions/index.ts (100%) rename {src => web-app/src}/state/guards/index.ts (100%) rename {src => web-app/src}/state/index.ts (100%) rename {src => web-app/src}/state/machine.ts (98%) rename {src => web-app/src}/state/utils/stateToString.test.ts (100%) rename {src => web-app/src}/state/utils/stateToString.ts (100%) diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index a0a8a00a..88b74652 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -22,7 +22,6 @@ const COMMANDS = { interface CreateCommandProps { vscodeExt: vscode.ExtensionContext - machine: CR.StateMachine } const resetLayout = () => { @@ -32,7 +31,7 @@ const resetLayout = () => { }) } -export const createCommands = ({vscodeExt, machine}: CreateCommandProps) => { +export const createCommands = ({vscodeExt}: CreateCommandProps) => { // React panel webview let webview: any @@ -59,7 +58,7 @@ export const createCommands = ({vscodeExt, machine}: CreateCommandProps) => { // activate machine webview = new ReactWebView(vscodeExt.extensionPath) if (webviewState === 'INITIALIZING') { - machine.activate() + // machine.activate() } else if (webviewState === 'RESTARTING') { setTimeout(() => { // timeout hack to make data update on new windows @@ -73,7 +72,7 @@ export const createCommands = ({vscodeExt, machine}: CreateCommandProps) => { // setup 1x1 horizontal layout resetLayout() const callback = () => { - machine.send('WEBVIEW_INITIALIZED') + // machine.send('WEBVIEW_INITIALIZED') } webview.createOrShow(column, callback) }, @@ -87,7 +86,7 @@ export const createCommands = ({vscodeExt, machine}: CreateCommandProps) => { console.log('save document', document) if (document.uri.scheme === 'file' && codingLanguage === document.languageId) { // do work - machine.send('TEST_RUN') + // machine.send('TEST_RUN') } }) }, @@ -119,13 +118,13 @@ export const createCommands = ({vscodeExt, machine}: CreateCommandProps) => { [COMMANDS.RECEIVE_MACHINE_ACTION]: (action: string | CR.Action) => { // send received actions from web-app into state machine console.log('receive action', action) - machine.send(action) + // machine.send(action) }, [COMMANDS.RUN_TEST]: () => { - runTest({ - onSuccess: () => machine.send('TEST_PASS'), - onFail: () => machine.send('TEST_FAIL'), - }) + // runTest({ + // onSuccess: () => machine.send('TEST_PASS'), + // onFail: () => machine.send('TEST_FAIL'), + // }) }, [COMMANDS.TEST_PASS]: () => { vscode.window.showInformationMessage('PASS') diff --git a/src/editor/index.ts b/src/editor/index.ts index 799d8dc5..a86fe53f 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -1,20 +1,13 @@ import * as vscode from 'vscode' -import * as CR from 'typings' +import {setWorkspaceRoot} from './services/node' import {createCommands} from './commands' -interface Props { - machine: CR.StateMachine - setWorkspaceRoot(rootPath: string): void -} - class Editor { // extension context set on activation // @ts-ignore private vscodeExt: vscode.ExtensionContext - private machine: CR.StateMachine - constructor({machine, setWorkspaceRoot}: Props) { - this.machine = machine + constructor() { // set workspace root for node executions const {workspace} = vscode @@ -40,7 +33,6 @@ class Editor { } // shut down state machine console.log('deactivate machine') - this.machine.deactivate() } // execute vscode command @@ -51,7 +43,6 @@ class Editor { private activateCommands = (): void => { const commands = createCommands({ vscodeExt: this.vscodeExt, - machine: this.machine, }) for (const cmd in commands) { const command: vscode.Disposable = vscode.commands.registerCommand(cmd, commands[cmd]) diff --git a/src/extension.ts b/src/extension.ts index 3c0c1499..8ec80193 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,18 +1,11 @@ import * as vscode from 'vscode' -import {setWorkspaceRoot} from './services/node' import Tutorial, {TutorialModel} from './services/tutorial' -import StateMachine from './state' import Editor from './editor' export const tutorialModel: TutorialModel = new Tutorial(vscode.commands.executeCommand) -// state machine that governs application logic -export const machine = new StateMachine(tutorialModel, vscode.commands.executeCommand) // vscode editor -export const editor = new Editor({ - machine, - setWorkspaceRoot, -}) +export const editor = new Editor() // activate run on vscode extension initialization export const activate = editor.activate diff --git a/src/services/api/gql/getTutorial.ts b/src/services/api/gql/getTutorial.ts deleted file mode 100644 index b2ce9154..00000000 --- a/src/services/api/gql/getTutorial.ts +++ /dev/null @@ -1,51 +0,0 @@ -const getTutorial = ` - query getTutorial($tutorialId: ID!) { - tutorial(id: $tutorialId) { - id - testRunner - codingLanguage - repo { - uri - branch - } - version { - version - coderoadVersion - levels { - id - setup { - id - files - commits - commands - } - stages { - id - setup { - id - files - commits - commands - } - steps { - id - setup { - id - files - commits - commands - } - solution { - id - files - commits - } - } - } - } - } - } - } -` - -export default getTutorial \ No newline at end of file diff --git a/src/services/api/index.ts b/src/services/api/index.ts deleted file mode 100644 index 4b302b52..00000000 --- a/src/services/api/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {GraphQLClient} from 'graphql-request' -import * as environment from '../../environment' - - -// ... or create a GraphQL client instance to send requests -const client: GraphQLClient = new GraphQLClient(environment.api.url, { - headers: { - 'Content-Type': 'application/json', - 'Authorization': environment.api.token - } -}) - -export default client \ No newline at end of file diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index 7ab284a0..a05a2ef3 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -3,8 +3,6 @@ import * as CR from 'typings' import * as git from '../../services/git' import {machine} from '../../extension' import * as storage from '../storage' -import api from '../api' -import tutorialQuery from '../../services/api/gql/getTutorial' interface TutorialConfig { codingLanguage: G.EnumCodingLanguage @@ -17,15 +15,12 @@ export interface TutorialModel { version: G.TutorialVersion position: CR.Position progress: CR.Progress - launch(tutorialId: string): void - level(levelId?: string): G.Level - stage(stageId?: string): G.Stage - step(stepId?: string): G.Step + launch(tutorial: G.Tutorial): void updateProgress(): void nextPosition(): CR.Position hasExisting(): Promise syncClient(): void - triggerCurrent(type: 'STEP' | 'STAGE' | 'LEVEL'): void + triggerCurrent(stepActions: G.StepActions): void } class Tutorial implements TutorialModel { @@ -51,40 +46,27 @@ class Tutorial implements TutorialModel { position: this.position, }) this.openFile = (file: string) => editorDispatch('coderoad.open_file', file) - // Promise.all([ - // storage.getTutorial(), - // storage.getProgress(), - // ]).then((data) => { - // const [tutorial, progress] = data - // console.log('load continue tutorial') - // console.log(tutorial, progress) - // }) - } - public launch = async (tutorialId: string) => { + public launch = async (tutorial: G.Tutorial) => { console.log('launch tutorial') machine.send('TUTORIAL_START') - const {tutorial}: {tutorial: G.Tutorial | null} = await api.request(tutorialQuery, { - tutorialId, // TODO: add selection of tutorial id - }) - console.log('tutorial', tutorial) - if (!tutorial) { - throw new Error(`Tutorial ${tutorialId} not found`) - } - this.repo = tutorial.repo if (!this.repo || !this.repo.uri) { throw new Error('Tutorial repo uri not found') } + await git.gitInitIfNotExists() + await git.gitSetupRemote(this.repo.uri) + this.config = { codingLanguage: tutorial.codingLanguage, testRunner: tutorial.testRunner, } + // version containing level data this.version = tutorial.version console.log('version', this.version) @@ -104,10 +86,7 @@ class Tutorial implements TutorialModel { } // setup git, git remote - await git.gitInitIfNotExists() - await git.gitSetupRemote(this.repo.uri) - console.log('this.position', JSON.stringify(this.position)) await this.syncClient() @@ -140,49 +119,8 @@ class Tutorial implements TutorialModel { return canContinue } - public level = (levelId?: string): G.Level => { - const level: G.Level | undefined = this.version.levels.find((l: G.Level) => l.id === levelId || this.position.levelId) - if (!level) { - throw new Error('Level not found') - } - return level - } - public stage = (stageId?: string): G.Stage => { - const level: G.Level = this.level(this.position.levelId) - const stage: G.Stage | undefined = level.stages.find((s: G.Stage) => s.id === stageId || this.position.stageId) - if (!stage) { - throw new Error('Stage not found') - } - return stage - } - public step = (stepId?: string): G.Step => { - const stage: G.Stage = this.stage(this.position.stageId) - const step: G.Step | undefined = stage.steps.find((s: G.Step) => s.id === stepId || this.position.stepId) - if (!step) { - throw new Error('Step not found') - } - return step - } - public triggerCurrent = (type: 'STEP' | 'STAGE' | 'LEVEL') => { - let target: G.Step | G.Stage | G.Level | null = null - switch (type) { - case 'STEP': - target = this.step() - break - case 'STAGE': - target = this.stage() - break - case 'LEVEL': - target = this.level() - break - default: - throw new Error(`Type ${type} not found`) - } - if (!target || !target.setup) { - // no stepAction - return - } - git.gitLoadCommits(target.setup, this.openFile) + public triggerCurrent = (stepActions: G.StepActions) => { + git.gitLoadCommits(stepActions, this.openFile) } public updateProgress = () => { const {levelId, stageId, stepId} = this.position diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index 1c89f534..18a4a9e0 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -1,9 +1,8 @@ import * as React from 'react' -import { ApolloProvider, useMutation } from '@apollo/react-hooks' +import { ApolloProvider } from '@apollo/react-hooks' import * as CR from 'typings' import client from './services/apollo' -import { SET_STATUS } from './services/apollo/mutations' import currentTutorial from './services/current' import Debugger from './components/Debugger' import Routes from './Routes' @@ -22,10 +21,6 @@ const App = () => { progress: { levels: {}, stages: {}, steps: {}, complete: false}, position: { levelId: '', stageId: '', stepId: ''}, }) - - // update level/stage/step status based on user progress & position - // TODO: model server more efficiently - const [setStatus] = useMutation(SET_STATUS) // event bus listener React.useEffect(() => { @@ -40,16 +35,15 @@ const App = () => { } else if (message.type === 'SET_DATA') { // SET_DATA - set state machine context - console.log('DATA') + console.log('SET_DATA updated') const { progress, position } = message.payload if (process.env.REACT_APP_DEBUG) { console.log(`Position: ${position.levelId}/${position.stageId}/${position.stepId}`) setDebuggerInfo({ progress, position }) } console.log('set currentTutorial') - currentTutorial.set({ position }) - console.log('setStatus') - setStatus({ variables: { progress, position } }) + currentTutorial.set({ position, progress }) + } } diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index 00279ac6..afbd8ff4 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -3,6 +3,7 @@ import { useQuery } from '@apollo/react-hooks' import { Button, Card } from '@alifd/next' import * as T from 'typings/graphql' +import currentTutorial from '../../services/current' import { send } from '../../utils/vscode' import LoadingPage from '../LoadingPage' import queryTutorial from './queryTutorial' @@ -29,11 +30,12 @@ export const ContinuePage = (props: Props) => ( const Loading = () => const ContinuePageContainer = () => { - // TODO: load specific tutorialId + // TODO: load specific tutorialId + const { tutorialId, version } = currentTutorial.get() const { data, loading, error } = useQuery(queryTutorial, { variables: { - tutorialId: 1, - version: '0.1.0', + tutorialId, + version, }, }) diff --git a/web-app/src/containers/Tutorial/LevelPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx index bfba1e5c..012dc8a9 100644 --- a/web-app/src/containers/Tutorial/LevelPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' -import * as T from 'typings/graphql' +import * as G from 'typings/graphql' import currentTutorial from '../../../services/current' import ErrorView from '../../../components/Error' @@ -8,7 +8,7 @@ import Level from './Level' import queryLevel from './queryLevel' interface LevelProps { - level: T.Level + level: G.Level send(action: string): void } @@ -27,14 +27,19 @@ interface ContainerProps { } const LevelSummaryPageContainer = (props: ContainerProps) => { - const { tutorialId, version, position: { levelId } } = currentTutorial.get() + const { tutorialId, version, position, progress } = currentTutorial.get() + + console.log('load level summary') const { loading, error, data } = useQuery(queryLevel, { variables: { tutorialId, version, - levelId, + levelId: position.levelId, }, - }) + }) + + console.log('load level data') + console.log(JSON.stringify(data)) if (loading) { return
Loading Levels...
@@ -44,7 +49,20 @@ const LevelSummaryPageContainer = (props: ContainerProps) => { return } - const { level } = data.tutorial.version + const { level } = data.tutorial.version + + level.stages.forEach((stage: G.Stage) => { + if (stage.id === position.stageId) { + stage.status = 'ACTIVE' + } else if (progress.stages[stage.id]) { + stage.status = 'COMPLETE' + } else { + stage.status = 'INCOMPLETE' + } + }) + + console.log('check level') + console.log(JSON.stringify(level)) return } diff --git a/web-app/src/services/apollo/index.ts b/web-app/src/services/apollo/index.ts index dbca44f2..34af23d8 100644 --- a/web-app/src/services/apollo/index.ts +++ b/web-app/src/services/apollo/index.ts @@ -1,16 +1,11 @@ import ApolloClient, {InMemoryCache} from 'apollo-boost' -import typeDefs from './typeDefs' -import resolvers from './resolvers' - const client = new ApolloClient({ uri: process.env.REACT_APP_GQL_URI, headers: { Authorization: process.env.REACT_APP_GQL_AUTH_TOKEN, }, cache: new InMemoryCache(), - typeDefs, - resolvers, }) export default client \ No newline at end of file diff --git a/web-app/src/services/apollo/mutations.ts b/web-app/src/services/apollo/mutations.ts deleted file mode 100644 index 2d3f1bcf..00000000 --- a/web-app/src/services/apollo/mutations.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {gql} from 'apollo-boost' - -export const SET_STATUS = gql` - mutation SetStatus($progress: Progress!, $position: Position) { - setStatus(progress: $progress, position: $position) @client - } -` \ No newline at end of file diff --git a/web-app/src/services/apollo/resolvers.ts b/web-app/src/services/apollo/resolvers.ts deleted file mode 100644 index b34b5545..00000000 --- a/web-app/src/services/apollo/resolvers.ts +++ /dev/null @@ -1,53 +0,0 @@ -const resolvers = { - Mutation: { - setStatus: (_root: any, variables: any, { cache, getCacheKey }: any) => { - // TODO: optimize status setting to act on diffs - - // set local cache - function set(typename: string, id: string, status: 'ACTIVE' | 'COMPLETE') { - const writeId = getCacheKey({ __typename: typename, id }) - const data = { status } - cache.writeData({ id: writeId, data }) - } - - const { progress, position } = variables - - // set level progress & active - for (const levelId of Object.keys(progress.levels)) { - set('Level', levelId, 'COMPLETE') - } - set('Level', position.levelId, 'ACTIVE') - - // set stage progress & active - for (const stageId of Object.keys(progress.stages)) { - set('Stage', stageId, 'COMPLETE') - } - set('Stage', position.stageId, 'ACTIVE') - - // set step progress & active - for (const stepId of Object.keys(progress.steps)) { - set('Step', stepId, 'COMPLETE') - } - set('Step', position.stepId, 'ACTIVE') - - return null - }, - }, - Level: { - status() { - return 'INCOMPLETE' - } - }, - Stage: { - status() { - return 'INCOMPLETE' - } - }, - Step: { - status() { - return 'INCOMPLETE' - } - } -} - -export default resolvers \ No newline at end of file diff --git a/web-app/src/services/apollo/typeDefs.ts b/web-app/src/services/apollo/typeDefs.ts deleted file mode 100644 index 2142f0b7..00000000 --- a/web-app/src/services/apollo/typeDefs.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { gql } from 'apollo-boost' - -const typeDefs = gql` - input Progress { - levels: JSONObject - stages: JSONObject - steps: JSONObject - } - input Position { - levelId: String - stageId: String - stepId: String - } -` -export default typeDefs \ No newline at end of file diff --git a/web-app/src/services/current/index.ts b/web-app/src/services/current/index.ts index 9541c202..3d3f2cb9 100644 --- a/web-app/src/services/current/index.ts +++ b/web-app/src/services/current/index.ts @@ -1,37 +1,56 @@ +// import * as React from 'react' import * as CR from 'typings' +// const CurrentContext = React.createContext({ +// tutorialId: '', +// version: '', +// position: {levelId: '', stageId: '', stepId: ''}, +// progress: { +// levels: {}, +// stages: {}, +// steps: {}, +// complete: false +// } +// }) + interface CurrentTutorialParams { tutorialId: string version: string position: CR.Position + progress: CR.Progress } interface SetCurrentTutorialParams { tutorialId?: string version?: string position?: CR.Position + progress?: CR.Progress } class CurrentTutorial { private tutorialId = '' private version = '' private position: CR.Position = {levelId: '', stageId: '', stepId: ''} - public set({tutorialId, version, position}: SetCurrentTutorialParams) { + private progress: CR.Progress = {levels: {}, stages: {}, steps: {}, complete: false} + public set({tutorialId, version, position, progress}: SetCurrentTutorialParams) { this.tutorialId = tutorialId || this.tutorialId this.version = version || this.version this.position = position || this.position + this.progress = progress || this.progress } public get(): CurrentTutorialParams { return { tutorialId: this.tutorialId, version: this.version, position: this.position, + progress: this.progress, } } public clear() { this.tutorialId = '' this.version = '' this.position = {levelId: '', stageId: '', stepId: ''} + this.progress = {levels: {}, stages: {}, steps: {}, complete: false} } } diff --git a/src/state/State.png b/web-app/src/state/State.png similarity index 100% rename from src/state/State.png rename to web-app/src/state/State.png diff --git a/src/state/actions/index.ts b/web-app/src/state/actions/index.ts similarity index 100% rename from src/state/actions/index.ts rename to web-app/src/state/actions/index.ts diff --git a/src/state/guards/index.ts b/web-app/src/state/guards/index.ts similarity index 100% rename from src/state/guards/index.ts rename to web-app/src/state/guards/index.ts diff --git a/src/state/index.ts b/web-app/src/state/index.ts similarity index 100% rename from src/state/index.ts rename to web-app/src/state/index.ts diff --git a/src/state/machine.ts b/web-app/src/state/machine.ts similarity index 98% rename from src/state/machine.ts rename to web-app/src/state/machine.ts index d673bc05..7afcb33a 100644 --- a/src/state/machine.ts +++ b/web-app/src/state/machine.ts @@ -36,7 +36,6 @@ export const machine = (tutorialModel: TutorialModel, editorDispatch: CR.EditorD }, }, InitializeTutorial: { - onEntry: ['tutorialLaunch'], on: { TUTORIAL_LOADED: '#tutorial', }, diff --git a/src/state/utils/stateToString.test.ts b/web-app/src/state/utils/stateToString.test.ts similarity index 100% rename from src/state/utils/stateToString.test.ts rename to web-app/src/state/utils/stateToString.test.ts diff --git a/src/state/utils/stateToString.ts b/web-app/src/state/utils/stateToString.ts similarity index 100% rename from src/state/utils/stateToString.ts rename to web-app/src/state/utils/stateToString.ts diff --git a/web-app/src/utils/vscode.ts b/web-app/src/utils/vscode.ts index 97cc804d..87b82c1c 100644 --- a/web-app/src/utils/vscode.ts +++ b/web-app/src/utils/vscode.ts @@ -1,9 +1,16 @@ -import { Action } from 'typings' +import {Action} from 'typings' declare var acquireVsCodeApi: any +// @ts-ignore +window.acquireVsCodeApi = () => ({ + postMessage(event: string) { + console.log('postMessage', event) + } +}) + const vscode = acquireVsCodeApi() export function send(event: string | Action) { - return vscode.postMessage(event) + return vscode.postMessage(event) } From 8bafa1ffd07d8ae3fe9d1387a8ff8a73c6aac80e Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 1 Sep 2019 20:11:08 -0700 Subject: [PATCH 066/117] setup for state machine initial --- web-app/src/App.tsx | 7 +- web-app/src/Routes.tsx | 8 +- web-app/src/containers/Continue/index.tsx | 4 +- web-app/src/containers/New/index.tsx | 4 +- web-app/src/services/apollo/index.ts | 4 +- .../services/apollo/queries/tutorialConfig.ts | 13 + .../services/apollo/queries/tutorialRepo.ts | 16 ++ web-app/src/state/State.png | Bin 513402 -> 0 bytes web-app/src/state/actions/index.ts | 191 ++++--------- web-app/src/state/guards/index.ts | 60 ++-- web-app/src/state/index.ts | 11 +- web-app/src/state/machine.ts | 270 +++++++++--------- web-app/src/state/utils/stateToString.ts | 1 + web-app/src/utils/vscode.ts | 15 +- 14 files changed, 282 insertions(+), 322 deletions(-) create mode 100644 web-app/src/services/apollo/queries/tutorialConfig.ts create mode 100644 web-app/src/services/apollo/queries/tutorialRepo.ts delete mode 100644 web-app/src/state/State.png diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index 18a4a9e0..f816e842 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -6,7 +6,6 @@ import client from './services/apollo' import currentTutorial from './services/current' import Debugger from './components/Debugger' import Routes from './Routes' -import { send } from './utils/vscode' interface ReceivedEvent { data: CR.Action @@ -55,9 +54,9 @@ const App = () => { }, []) // trigger progress when webview loaded - React.useEffect(() => { - send('WEBVIEW_LOADED') - }, []) + // React.useEffect(() => { + // editorDispatch('WEBVIEW_LOADED') + // }, []) // TODO: refactor cond to user and accept first route as if/else if return ( diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 54dedbc0..cc1ab96b 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { send } from './utils/vscode' +import { editorDispatch } from './utils/vscode' import Router from './components/Router' import LoadingPage from './containers/LoadingPage' @@ -65,13 +65,13 @@ const Routes = ({ state }: Props) => { - + - + - + diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index afbd8ff4..923c2f98 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -4,7 +4,7 @@ import { Button, Card } from '@alifd/next' import * as T from 'typings/graphql' import currentTutorial from '../../services/current' -import { send } from '../../utils/vscode' +// import { editorDispatch } from '../../utils/vscode' import LoadingPage from '../LoadingPage' import queryTutorial from './queryTutorial' import ErrorView from '../../components/Error' @@ -51,7 +51,7 @@ const ContinuePageContainer = () => { { - send('TUTORIAL_START') + console.log('TUTORIAL_START') }} /> ) diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 0483d9f7..2c0e6a70 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -4,7 +4,7 @@ import * as T from 'typings/graphql' import * as CR from 'typings' import queryTutorials from './queryTutorials' -import { send } from '../../utils/vscode' +import { editorDispatch } from '../../utils/vscode' import LoadingPage from '../LoadingPage' import ErrorView from '../../components/Error' import TutorialList from './TutorialList' @@ -35,7 +35,7 @@ const NewPageContainer = () => { return ( - + ) } diff --git a/web-app/src/services/apollo/index.ts b/web-app/src/services/apollo/index.ts index 34af23d8..6fb3d296 100644 --- a/web-app/src/services/apollo/index.ts +++ b/web-app/src/services/apollo/index.ts @@ -1,11 +1,13 @@ import ApolloClient, {InMemoryCache} from 'apollo-boost' +export const cache = new InMemoryCache() + const client = new ApolloClient({ uri: process.env.REACT_APP_GQL_URI, headers: { Authorization: process.env.REACT_APP_GQL_AUTH_TOKEN, }, - cache: new InMemoryCache(), + cache, }) export default client \ No newline at end of file diff --git a/web-app/src/services/apollo/queries/tutorialConfig.ts b/web-app/src/services/apollo/queries/tutorialConfig.ts new file mode 100644 index 00000000..23ce4ba6 --- /dev/null +++ b/web-app/src/services/apollo/queries/tutorialConfig.ts @@ -0,0 +1,13 @@ +import {gql} from 'apollo-boost' + +const getTutorialConfig = gql` + query getTutorialConfig($tutorialId: ID!) { + tutorial(id: $tutorialId) { + id + testRunner + codingLanguage + } + } +` + +export default getTutorialConfig \ No newline at end of file diff --git a/web-app/src/services/apollo/queries/tutorialRepo.ts b/web-app/src/services/apollo/queries/tutorialRepo.ts new file mode 100644 index 00000000..3c8dfd6c --- /dev/null +++ b/web-app/src/services/apollo/queries/tutorialRepo.ts @@ -0,0 +1,16 @@ +import {gql} from 'apollo-boost' + +const getTutorialRepo = gql` + query getTutorialRepo($tutorialId: ID!) { + tutorial(id: $tutorialId) { + id + repo { + uri + name + branch + } + } + } +` + +export default getTutorialRepo \ No newline at end of file diff --git a/web-app/src/state/State.png b/web-app/src/state/State.png deleted file mode 100644 index 30baf2be6ba657d1f9ee87acf80426e7dba5c9ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 513402 zcma&O1yodD7dB3VgM>;qBArUtFo3k=Fm#G^H%Z13tTn;C_uO;NK6^j=+57A}K}rfzSO5|L0s;b-jPzR-1O$v#1O(J`3^e!=w(_+H z1cawD=HlW?GUDP?N)EOr=2pfC2+~1O>gXEa9)e_T6&W)qhV+xBpy7faxLPQPd7neV zQJ%|wdm`Fi%u=v8ErBwMuZwRF8^gyHJTJ#MzgK!|Y^=*Nsq`@tX{Ua{PuGxSx>8InXptE*%&Jfj~46as7kt z{QReJrQ&*qx_kZyeF;UXA18>QW$FRE?yD=@2LOUzYfLWyf$CbU>FhUB-gCu(Nf6o# zKaKqMDGQzS_BacjymA@YMNlIt!kdt;NMq#Gxu<7^V%|Kfux8Y^9Y=p&KmQZTP;9D~xyN!K&*a`c|kz>8T)} z*-K5;&*dhQHQIF}8Bwul_9d@4d9dGmeOU-bW%Brs<2v0{>lM+m)JmTmub;o zLfi^q@ArzGM>1pZ_j4&b>HuaG*5`zFkzCDke#eJzu}nj(+{I>b2O{hzNfywO-{Gs9 z`^bJz_&t8O@cc=g_^s_%37Nd@#Mc&Se6$4bt-r(_&$gRYVVQtgmfNwXy78X$-da-BktOK&=0(8CcNt}& z9?5JA9sMSouXS?MR9jS&M|iI?_!fa89BM^{!bZ{`E|qT~ ziBuAlN_30(9k)C1P7G2Zri5{p5?HlefZ46mPmnL<@ax5w6H%^i-xho(_8z-Ryh9?3 z_J=P6fpzP@(h_fSLb14ClZ3qg5|hRGLFOraz_W}m&)!PSqTsY59}>A?LEFeLI_?6> z@A{Gt{f0!{-qtE?zM4&@(|dK3O+i3}BVg!SXTKk;owRE=E-56AB|oYZug?kDPn z-}gy3j&FOYRb=w(z1uBo_u5$c&bmfY_F1Vvp8df6+E$Z1tuU?E#?qVYJxA?a9M|Tx z_H@vbH01=6gL+7DS43NlG82~6p-WcRtt+n_*on9&#$$=B%AUV6gg zFAvYca)R=9GiR&jtGdo2-HSmQnVup@15R5kaeUgUKi{|UwuE;?9ZH40uWP8kLQK64 z&D95&#N{6#w>BQe*c>4uAcbLLV^dtq5jH*lba#%RH1jY#Rr2{@`8z`5Osje~U`#;g zBQ*lkEsz+&$N;+#id@)5?&gbti`4py4;MWGL=p>VVEMeGiDvSd-+-C{bJu_F`k%yh&nkU)7TI)!=N9=lk!^n=e5QKk7s`Qa)Q(gpk@(EDo$!fR z>vy78h%(}D!mZwZW(eo+exFIE8KO$99WJm+xJu=K#2@BFRr5Vi8s`{r_2oSS7B{G0 zNzm!(c5pe&jO$6#XOj%hq4$+2x}j?6Rhu@I&xE0RZ%Z8 zu-6cX_U|eEs6ng-9eae7nXYJSP({9^uj&|5lK@+NXhC)ayy zdmejYdm4M3Bfc`jDpK@B>wOWbR+N@U)quJ1=rw30habjQ*~5iu&2Npq$G69`$DO25 zlMy&HvW0rOb}Dc!bB%oMVI6R8W?ftj@@RIca>+Qy-y;;jBiAOc9#Bnsp9Dy{6Nqtk zcV?`2sVCD--WQs)nDedYb-pn&&P~oy-czo3uUXy{@(8`3>}ij6dB?^X zR`Nc7=RRyxyBVUQXU%uE=<64ngyA z%K;xrajFWSC?~_JeP$T?kV94 z-tvuU!kLMg1;>^yx#~JAkVTT%H8Yy{3!Y(uiM4t ziRW&1ayZy>|`&?K}SjsaWGbDSlTfglm ziqB`CufIx^|L{sdZZ_(Yhmp%%VtDRD;0Fl@%dZN(t3T?0xaJw=6@UflL*w{dmpiy3 zx$LzZ1sH{Cy*%6>G7n{T=$sYL<8=hCI`M88CBOrU+;Q=|XWd*$=8fhzoEXG;#0_tN zN6T(ijrZ?tOyo@{Q`+GufJgds2;~pL1?1$ik~nWo3lm`U!O_++ zG{=m`>qyA8hAo+PN}f4x8bqoZx|iN2y}$1y+$AE?X`!4&~ZWqtR*KmCMDxzzO z4)w~+Y3;K^?+7v*F(vR$ zT4~fRfunM_-JQ+Ol1WD5v$zj<06cnAc;$J96;tcS{ggg<4{nxntI?fW4bxwX+Kc?P zQ>^5sT+ZniQnsrTtk@UsKL&n~+8FRl%GvhZ-gb%G*HR7}XWsU3QJkNZjZTE#OY*%_GsH_iJ$qoiay`^{1-rT$ zrIL(~>v|}(Ejq9ujEF+h{)cgHnEve8{vR+oq3hm=i=q;dC))%M5<1$n+P7lG^3 zI?iXN3dzPP!Y*uwvr8xU8#sE0O+!wwoA)cUC35KAC)azR1Xt}9qge_U?b5Vq`G8C|U?&e1AvDl#Q&2^D#)-|yNfzE!+Ai1a@2 zX7d6LXD^wNcBjN#)15oF{AeQctlF(Q+99_UTBtnlx)5Gy0M!6vmA=vir32g8ocr2A-DwE56awtf~LsG&CTS|NOF*>jz zJ{V0=$nV0}x1=9|stVyylZTJ5)ZXs!geP{_8X#~^FowSd3A_@fS6*gs^O#||4zWj)|$=mgYA1`HaBZK z_|*sqLT&=^uhzy+hE#6WRyK|TZo)7Bxk3Q`{m)_cmsI~;;$$iOQbS&eO5E1Ln2MW? zi;d$Y5I{vmCFJnIL_p=OdNNI$!6{ae>WMRa zJ;==8DyqUik^U?W{No1x#_+FC_;=*XT9z+1ZU_h<1ev#@s&0t8bLh3?kf!^iDEDCx zDqLByPeXFg-Jhw(fBN!;>hqU1r1a$`_dUQxKH&^%@n;RQbZLC$dyL@%&?fmSTrDb) zyP%AM!m<8A{8hi6$N8?8>;OOin&A8glkvhh&6BvKey`*^V9S_gh&~x65(d>Lgh#zq zYEgwQp1uqpv5-=Di-3rN3wp%c&kjQ}d))3Nap>bZq51@3Mm;tp(+vPAFu&%W4%0-*ebkR^<)ny+ z#6Ne^bgcSVA?$!s>kP@TLIC_bi>UT;j}>?^?a(YJ^!i!%mexTu?B!#JR|=AA*67`Bb9Q5-CK?4LeX8>F6S zau_2NTC!oxagMo!cNL5wILt{ZvIEFrTY&MS$^L6qJ-Bme60Cf zut%GH2FmfT`1C;b?MPdiaPTWB(nkR_96Q6FcL!R0rD)DoY?g=1_3Npb_+!;x8R^PE z{(h-|e6Z$4cTZng*duj*hz1otSRpakk!Qjln3}$%3;6iamQu+V1+u}XS>c7mU-gRr zv4%FZhsq)i-VqJHZnr+-fhKB2kUe^$=ScRk*_(z1s5+^^zlJ zXyVRD-$Tde$F7qR>N1r)x8I-sVJGZ38Uk)UFUcw^ zj=~gD;oPvDk)*?Mf}oSffTWoelzSAjrDEPh;V7SF86LV@j11fG5^!azdOk&`a(-JeTIy_CsT$>uG_nvW*w|(HfGvaCT4Aib5+l z^d6%vl{p}?>^zs0f3FnQYHn{|$RN85dt<{(6nl#fIkeNgy=t3`;tqJa3p>jv~!o7J#IRkmTAo0-17!~y=}cyHnq65*rb4l*Y|Z*v**LlDW7XT zM-nU|9<&Eb`Y8pWdTKd_XsuZGpN*d;;5*KrkDwOmtTC^^Dnx#W;g^G7`{6;}wDoL<)N3aRR;#+pvaHVW=;rpvvoQvJsrJse% z3KD@PT%#oVoC>xlY%Lyk$sU}l0$M8pmjM2hIqOW)6%i@R2Hb8olx1A` zD(1DD_M5Tl24kuXU48P6<*k$1U5Ns*NfTrd+DN9bZ=}?PKBG1S0~r&wKdGLyu!>b#h!JFdws%GL5PE$cXEm`g4H+z8@a zyy}%OjGGSgn9uAI=FblIZd~i zF7_iNd3~msYFfjLG;}E`Ew)}{*9^y6`umPX_Um-shkV26}a*t(ilTkm+&kZxl(Mi@npN zZ+YFP9s!GeF26zdZCC%99_(bGM1L>mSk~Qo6B#Ui>u9l^9UZEOn5GE?WnQEkK)l-G z51+cz8=+s=@7!#B#j+|q@p`DcS2Pj`ke58gTuQIGtvY=g0t~N=d?0(eJt6o`9g+g9 zVM5Nc^_FFW;JDAUpcAtn4^rm{=!=-9 zL$s-Y-RZV)38yu7eyd}irLi4taD`)95Ke+wK0WFiyqC%yNqMALPBWJ$#}IHlV3h&o z^cxPc@Ycic6KZ@^O%l&iqf{K|=5#(+MNG+VMH$W~Jbzieq?%zxVF+dR{BRur%J443 zoj0kS9S_Phd~?e1 z%H8PgBJ|^kZd8@nB3e*KB-O@4alh=pKI9+fi@q5Gi)W;u^>4In-||Ub*$u&sXKp_M z`xud&vQ$>_Rk+dT!pArt4PGSs@N6@bs}(qmxmdgQfkMT20Ls5FM4zydKHb?lKQzRU z=dOf9vgV{@7v5s-1>)CAC0Pu|r-w3t0@)Kk9GlsP?KdJ#5c7JvBtrK5!*s^7Y%8wr zKywzGC7mKrC{zCI)v?M&E{+4kX2#uZx&=$5r_$P80?v^UyT9M)!IW!s!;PLYk+B4U zRZmLEVfR3DZy&T-ES#xR=dS&;oe1jJuhHT)6x-)Vzi3fEAImu+^S5}xaSnD=m@lfsOp6UK`q$H7D; zTB)#1Q2*A=wdN^%p@u-Js+@1m|at2N`D(aRRMm>NbMk^9M-V?k}_;2-NI4y9n#j*HgE!# zzS}zT-^bU7NW^lt7hu8(HvBlR#UvMGqgQX@%%ZLB@hYy6$7pp+c_vdD@(se)?YFS zF1wq%2C8P{b5-BAsRQf!)XQM1(psv^GX_S!jx`(l>eSg=8yh^T2BNviqV%+heTR?r? z^>so5e}mA@EXEwwDM=_9YGCp)*q~!2ez}d0@(B849@t;eitc=WfBPQpnv4w72lsfG z{N8fON9V6-I8*7)M2BLmGSm(y9_4AlAkEW*g66R@hy{1Nlw@RFXVKYd?gKOPC%wZQ zSh2~XBjMy5;_?9FEvyY>{%y`_#b?=r&{jyf5=e%kifQ$B33inx5Go(#ygA<1+N8>8 zUPsxrps%rezlN;jKIkB990sGV%yLzrlG^e)(1VK--)G&}l@3JhsyrPQF?% zZ-=~wGQ)0aaZVXLGuKFb<^mTqqUD_-Tt%vzM0aD)pkxKAqobELZsUp{*K(d!Z1Vv` z_jZtF+@-4hn8d=an8fB~AhxPio9()i^+gjGY4j~gIIFqa-?PuBhtVDI##Qhs{7p_N zEKwcqx4P0~W%C^}8CzXuJ}Bk7WZLJ-!p7#W%|();{8LVoT@OVmo0yUK&#N^alSUXi zLLx}cbKdYwaceP~nXb2{lF|UIHCCBLdGw(>%ph zEEdYN(T)jEZ}~ooO^=6w$kOw;KiBFv7CBmpw2YU*3AJXDoT!;rj+^FIK^)65o}DnJ*=(bzbEu*nOrxvsubY(qqn{7b8?5+hWkfmTSfwiZ9uT z*T0Kt=6H5+?E2%%Wub{F3wL@LDl*bh!Ek?FNve(8{qeZS{bD1B;K~4ejLn@iYS@f4 z%%KlqpzP+K4lH$g%uHpU=M3uc9Yjq)5Pa(7rS;7h|Ar*0Aw#T#y34yt__05#uHxr`X7uy1w1dn2r6l zhW}m_l|l9XXfU(v+u<*KkNfk&aL2S7&w2H4WxYUsuLYt%5t^}Rw#aqrNMyx!5)+}h zxeS$*W`X{^NLPPi!<%==S&NbL6KHMM{+1m+a}V1pt|KSG;*eKWl%;F9H4p3JVw+5G znRcr4#K)`gd@V`agDW_GGt$5TrQV{RC;LY|)Pn3Q%UlbX-GOjnaTu6klS2QQ3|QNo zI{XFECFY}o2s#7A_-wTB19j_#=@sXir>nDzZEP2VIt2NV7zfDOPoMax-qE!%;5p2D zIf{RhG7Lim;-9QFNj1QLiw?ypBwKqDSW7=FqRhDP#{sBv5mqu7%^F#7QzV0|U9A|M zRBQ_Zf*4qyhbbDx9f)&>Z2f=$MxI`baBit>%}k5B_xqR ztzaa6_hb>Ezyi8%bRZ~fS-DG|c*%uCgu^e_Nhdh}mG04{*u`7CTYeW)k)+rI`ig3d zRkPlT;GCFj?vW~-kx{~T0vOi;Ci!_LvSt2YkB*Cx6VI%0ppU@^4{_V za*izae1SI25uTHgw~}l>%%E@hD}{8XA#_Q>S)i)F)GvHgh@Pjbzel@BV7Ab3dOq`w z6%XIHhjJ-`+MGL8nfRA7G#?i-e^J|UjVg9zR(F}Qx;`9Ssh}qBb&l1A?QsbC`8yR^ zChM%0G_fQ|Zpi^ZaoMXru)IwNUP*vOgl{|F)CeWHZ-FSOrUw_)A%@Fq^*MxfTg^z} zXEPql2ChS^)B~N_ruA2-akK}L8_BCpHJS_R7{`#HN-l0-lfJx%F@C_R%jUTF9NoP1 zFWM{NJ#kT9p_<8l-D;-Bo$ua&yvXbjC()-=O(W?Ib;z! zt$o;KEX^47jc%(ZCMbSg8pQN2jnn5ZncX3I6nD)vsLipE5E>GOlQ$yf02lYLXN$$n zI7JCOog+2Et$Q-sifd6e)T=?6I%(&&z!9RPPkF1c@5>f1xp{VlMNO7o>Ytsb!tkC~ z#Q%pF@8IRn4rfJnr;})&03^Pho2@jSlV4HxZP)c#&4B(w|AJX~gkEmYH_$BB`+Wwh zj|rA5rtp!<^c{vnZg0OXu-h^4A>%beKsxAKD=5R$?n5$;!)Buhp%*}6sEs5m)LwfMKR_#HMzVdZ*GMS}Z8e<49rPXQ0&V zPpGCAF30F6cguI_)|MlGq8XHIP$w49?Kl9ZYO+$%LVYqbY*3IPHv>16)dI{R0hY>Z z4H1itACMh$+&>x7XXML}*eF2i1?V%HTruer(>HaZP-5^~?HJm$=6X+^zJtdx^`ZIs zxxK++BK2Ve@>yKn=r&I5A&Ny_w;-2UJ5Ve@CdylNPU2#`QYY*!zU7Z9;>|V&K!FB^ zL|T|GFYzjHGiO(YgDz;LR_UWu8estySE{Wo<>?lF{_ZA|FKS zLmJpwXb_$(v-A=Y^KlSet+Ip`ZVUKH*_}DP61**?ll{kF*R8wlDb+OT3+2h)+f#}f z673D_1(#Ty->=5(od)3m$zX7bE^-!|O*K-nP5$j@kZ0(I6`r_zD8x>oMJ*&5#+iBM zP3FOHxYi|0C1v{=^?$n@=u7Bn;AFZuWE$g86`Dqjh{A-z!Uwjeng~B2JRr2zP8gr# z3D3A~`*xvr381|X!)an*h%kBCdxGsyAX6_nU>`(#{#cLsWvwV@%;s#1P{E31#%nnafvRhPO9%&YAO#Dg{p;`A=K_~J*3)|S1`UiwkU zAvKA723N;}@)^E-*N0%HMWOW^A@^?edf2HV!PD}U{P>Cn9B&2#PCBgP$=C8(P8lh~ z+r)o(Ccd_+zp1SVYjpnMY7B07P${(Gq0Wo^EwXh^L6=O$~K0wP?>yMEpxi^8lNpCx}>j{ zV>rF|gKuYiSKde7u<9!FIcsG8^Kigu<62I%ibQlrpLzpr^Yw24<@(SM)%ba{*bHv*U-kOtex^{JkSU|RNi}QTnez9?33Mwi)Uh{|;mT2DkV@rG68NqGW3>1l%O{mZ zj@+oDWFlG70}x|!e0&gAmK*^J$%{2zPJ+ql?R^A{_s9>~nT#n;P;QWS(&2Gyv4qQ}*Xc!5=NO!X`AOCa2#=Ys49GRbHba^QKajR{?Wa3dV> zOLNKAY+_y63CnvmLEY*r_zXr$g8&9yK;^JtWGY`D?h8sI-pk&r!%^aUFpUhH%kmRp47HUH? zl)MyuOeD|Q6EBoEnkL*e{~I<8FQ^hwO689W{Uh}8WPMk70v1c4tmIi-o;}0Eyw=cI z)PjglR{CAEPSd96^xwNFW>5muRhpa@J?Z4S355toV^^-<7kyM15JiAGGY=(_NjEE2 zd07sY2zpUD{gBWuKif8`S4Z7UQ}8LUiGF zBK$TL0*zLo$c~d;qsN=8Xq5V8j4AjkL}G%u7D*mHI|-Ed$i421po`$@qWka`X%@!?=mv&Cji6$%BhE1++NY zTYY7WU{!!(&Mue`fiX40WL((dobKvTp%7nzleas>en6F3wFdVF)aPy=1y9i^8 z{>sa%;>Q#Ty+!hW61(d*hWl=BWcWlb>3D*XyvGJI%^(!ZwO#@i2x5f`R~D(i$8Yt& zqJ7a_hFBy|l(WsfT%#AB!k9$pI_e_2;Ys)y#heyRx5AVXb^R-b7|cCc_2%hE8!lk=1{F2BNq}<7{E+=J-krH` z{8%>o<&fgEvgazSYZI*d;>>@A?oXgDz-k-k(cI3pK+XM-w@u&cyE%mw^jhehdyJwb zB({=~d%Z+g;Q3ru`fKy<6w;($bZ~Wi4_8O=|ES}cz?0Rwq?!WkREtz74|SK0X+k{jA7 zSLQ1* zQ1N=>%3%l>PbhoKvRLfE-{H@(jH^10bTE+w4_4ijOCmrA=nbwSv}pSN(=$0qcUeNT zzePGIMA)o3?@-8DK`=U0P((h;(Y3L%T@g|>$re*|bFsC?b8&)ZF#vkR4i~hTHI?Ca z1b&E3XJV9%GaCbVq9*3%PijB;1(z2@)QoPTrBuc7Ck7yg3QE?wTEv9k#4q*|mvClsh znfIy9I})t{$6A=hQjSOVNg@jfY;mj`k+iGf?xIOph0nD*D5GfX56433)E|O*z})|? z>ppy4l?ggw6&lBM?!~o?{PZ@ANnp38Q-L$Ako}0QlQ}tWZxCzK9W7mGv7`RHhtsq# z{v$xh6!G^alwy?vmgz``F`>_Z5E_{h8 zwuM4n^<{tTf#x3^0RIOEY$o71@QT>`dQI(+oRF7xqn-7B*Qv&-Y1UpIu$iz;s@8x> z8GoP`mw@7MeaSx2W3)5d#B5Ng z{*RcgsGBB!eXJZ7XE1RoqaYbuyxv6h-C1r#q+ux(l!M2xrkIbz{-1TO(T1;c_*3C) zv0xr&mU-5s7gdr8Jx95sgwkz%^(xQ1V z`<$;MyyPmYk_O-5RomaIC7pbr>7W6ZmF?La*C11fxgbMnFGA!-*Ku}Qp9*n2#Fu< z_ao3i6bYVLqE{e|OOVWWXP_^z0)MY(^tWQd?x`(&J=Ie@<~xrV_7$WKw=kvrFrNQN z-c^SxhtKjw@^7?ATD#HdR*ukOL$I1Mbxydr4i7};G z_P?pH6BxP-8bEMeu6(u>)Q9{A$dxhsZt4_LM` z5@pZI{!6QPa8@V%E8d2LG|5usl=?8kA4`z;Y9rC74rDC&)>u)9-&wbvUocy@k-T$# zwzF|Q=c<2Ek#bj9@w7xP)aYz`%;tP|YJXhY*4gX&)IO3<-oazHOlqlui-)J4P~Q_K ze0$iIb^t%Wm#vVbHR(E*580nGO>tHfI(qA--mqI9Jo7%76>!6oQ`X!(uj?{pOl{rx zaDP)WRu%6kQujNayKm0Ei@dnFc!1oYo7(2`aH*d^3i!W~XAYEVL1h~A9q0+h3qP{9 zun}dT$3A`{cu$ zj^kpQXdiI1h%PeuL~0r+KI{SJFdj(cFLphcx0$WASAcvTH-T|4eB2;+ZGR@k=da{4 zZBBpDuy9v=7$FzK<}7l56gC&aJ5RJebV=W829|>q_S;vrIXHU;6i2@HsqxeYQ^ar7@4z>sNOOC8 z%yW_mo}xV^S_Ixq4F-r1%hJy%IY*l&f9yEcVjpdL(5Qjnt}ioL8sOtxWLlbVQsxK{-RRZl|PW9*g)*=5jqI z0gGMAWjnptCnbtLn7zl@Eu~$S;n6kQpXj<8zx$Yu zn=Ro#{(pum+=!4BFgeND{wyKWXLR@jk(9cOfboTF8{f44{37$J5Z3~_gId7M+16a2 zJcag#!o1Osxn{YNhWAubQHI`EefssxC5><1QJ)@#`OMzkv^;pkc;m2=dwQTceDGNE zC#;uat82$17vOq_T)k7=5RJu-{dViqy|{?k5S8nCoM}Cd=OVJP7sT9j{de5{W=0tH z2qf<-EX?~fqa4UOx3vihZAMr9zO@#kk3IH@PBEDb=*mjYd-uQN|N3lD6=)#GlS&E} z%R&Tx)?0=re|qCgQpK2LM7KswDmW4v;5;5{{bOHu{5v_^{0NaW*E2i&PyQWPo(W*C zP9m@vyhw)m)Zka|^l^9|thMr4yc>jlzYgFAhGziy;m?wInh2bRXHN>O#~RJf);YG} zNw-{&mCW+YSdF9^X-x21mViQ$v~YlzsW-@BlB zx)3Kig~ZKd?`!jm?_r+pUMr*v3_A@DYqG8<{k(ytp<;pn1#;(6Wn(X``Vkm3F*-Et z{x6Utm+DSsn&~sdou#DE-Sf&Yj>Rq`!$LM#?A4pGoMNUVsi?&LGsb0ec#$<@g36uw zf9CBhh~f}2^p41(GVjifml!k}VWU8=``Y|-`4v@ahiFGYRBqN zWSpm9eEGOH9gM1Q0Cwd=H9V#KRA$r_Aj>e_vL0_a`;C}$HdJtblkQ#Y;=J2Rh!qQ< z#|jQhh70#9&QTjFKJ&t7qhL)D;g$0lTU%X=V&lv*&mHXrzzD_Gb^iMBti+(O=|CdK z+E~l|8GFu=Re2Ac!eHLkk7bEw+m^d(?P@E{*a-9Av9A^IKkT<`B`zaOZE}u#B600`HE^Lv1R_W4~^H+Oh;Ir7f7PzT3Kb z%EWkLgitjc&?ta{W(D$v5TSFvjb6U z_ZW#0%e;#D4*1~q@f1je-0UuSGkk*Mv*k9J{4#wkud?a}u64{C-Ld88s4Wi{kYBF>tBSy73muO<2JPaVK60;aFW}|k{%gg8G)|wlBcJd`jz!mU6Z?n zA=%j}G%-NZRasC`GwX(#;cz77ess?3Vy*`_qvg!MARH=22v<3Am$y(vRNLmu4)y?^ zJ2Ri{yqtR81{UwegjCa20);NxH7auPbrNpHh zR$M?8f`kGX%zgefKezE>-ox-Z8OP_cjT+;_5*8}K`Lrdw>j3{odyKPOG>iQoXWRgH znc_F$)Z(p<2hBJ8#&`L9o3{r(4>$Y84f_CmozvYvE+XHV-BLYwdC=#+;--V$`&ld9 zk?0hopTqT5PGDY?)4L0m!;SA!6i@I!V)L)!UhLWW2%=C2V3DqS-|grJE(TsRQP~d) zU-)gs;?0&y94P#XfZyum*W9#qkzGJ5rF%`i;<@HKK?bTS_#gu8zmf63@sptNI#qV< zWz3nREw5^&S-4&2ol6U(AenYz_0K-7tA{(M3h(J5XKwtli{^_a+|sW&+jaQ0unlqQ zl$N_aTTO$v6RH^R)ZDv{l?+xhBNYImRH!z1eq|CV|m7l zhk+dO(ZIp#&66D5xMZoNM7JPh{)elS2V!7~d(P3--Srt}O3Q)ghM>*qCXBig2hN=^sXapX9PnuCNMNPts z9@)@HW4I$#rut3bAL)I6lF|UzYaojKF~t8gQLRJzA^Xghi;}Lw5*|zauQ*r31DX#_ z%%c&jrn|ah#$J2XA{FCJcyeQL+(I55ovTCdT6;07~3Q1 zh6&?aD5r{!Y2>qBm#ayHaSjTN>{Sc`)3o7^=#yW57{jfSwQ{cb*t^k^DtOh+DG`SO zD0e;mhN1SbEX?aSxz{OdDXf)I3(v21zka8esf>Xt9TfhV#GMY3qa2l#{*`9wB}~6u z1(jk>>Ov_i;*U#L6%4A!x9OxtpHs&M=O|$P!jrGbRQi^@Qo9n`CnihKtxOw#cd;O% zYEb5ihwi}TANiR-jCYq^BG^mJz9T2MaMtk@tkN-};Itn)8|wFAKosP9U5^AiN-W z(6|Dx3r%Um5t(JAG7A1IH|?_sMgJTGj0Bu?za8^D9l+yLX4pve#V#KaJ0n81z*~o1 z>U-=}DfLJW=G+59x4fn||0&}r4`~Qan|*g{lW$rv*_~o^T{JHf zb=|kJre5>>?=6#Qy;Kvbu7zUtOGJ2nadZDVsrNyH0PT5oTl9IPetMhDbo4H)9`>K# z0yt%@(m?4NkSl&p&TiSgK(pQTCr?@X$s5zgqUS%^GHbH#pynUx^1^<5(;;%KS-w55 zck(Jwl%@wmZ|JP)r6M>&-D_N_q(q7>>lyB9izSwVS*s^ss!}QQEoLX!0G3e5M`DVz zgH^&oV@k(RvYm{4&UjhrB{Y9_)unc^Hv|I8#>A-5`>R2p03g7?Oc?a0&P+e?lmjaX^Qomy0s9a+8 zm7V+n?p#TdU;F4BfFS{RYOq-6J2wkv(uP(xfbf>^WTgS%JHzNnREa0;yCg3A<@QAj ziuiIF@c*Iit)r?y-?iZpL0}WoAh`iaK~RzIlx`FdkdW>a5Re9u?(W)jmw=R%be9Nh zq(QpjefFF)^P6+t_0G)q=eHLBI68~X6Zdo7SKK5rF=q9NZ03K7CGs~y0OJ6r0*=sG z8?Q_4I>(JsoK58kVh?8mqEVXD%iX4->u#?rsk6_p*@(RJQM^D;f`=EgQ!PYDe7y9k zD0P-vECT7G&++NyhL>0(vQ5U_XWqu^%)7K+E^MFg%tF#O1Q=Oz%oQq3YWn0ZSk|wZ z#YZ9KC>Iqki`=MpWD9x8KC@0A7~ zoIT}Z=D#OGy-$9pRW@vr0u0*O2JB+VLm5h)S1$e2VY032@f3=WqXos^r!7$P#aK_n zK9|)X$k{OBVVlqLtbZ~cAgQ~5s&aum88bh9a@FQom8El^3Y0p_FM=B?lwW%<&VOs~ zo7e>@I6%8R>d?77+Fhj&FL7YldjezXrVpPx;)eBQm486ug1yPw$Ri*bHqZ|QIP%GM z_ZVK6NVM(nZLX~^%*-^2mK9R5?gk+;RSq(0y*_aO&xK-pOKBzqh_TLE(=TJ=hCENI zmK05Yc@d)6v-ll)-+%u_K7pP3^~)u+&@q@RBPK4G7iQbH=XuKKVx~1BW~g3IFGLr) zz|~s25l$c;G30f7>J@0xd)mME=u1W)D~!7e0NH>iJtIWTs5*zL=@)7RD%l(LY6D&E zL=ZS8IXAnXwVF4*uA`N|fEv09z@!*M+2-u~SzCa$-46n{L zGwn8lP>FOb6g4#~N!b!%1#)QQKH^ie3#fBHxt7f&OTK_Hrev9AhVgC|uz&TvFF2jL z@#vXZ#U?9A2f-8|JL^@K;a*p?eklYbszEQ(X`5}-u}29M?Mz?X?yA*D>Ej6m>M+bh zuVp>JKS+?A;@R)SU+85>Cl8yAQNO6mWUApr*HCS@hX$1vU;ua{2;6m(DK)`bhgOXVo=nfrf)&^dN?`?oU0!3a_Uk2xtrXL9hI@6yLePRuDKLQJaz@5dmW;WVT=Z{`BIypbBi zeqD$KHkkEM5K_pfl>H;T{n6~=`@;dTxAE^kbd?g9t^OKURrJq@C@q3;COwv>4$ulo zyPbHcheeHfu2mCr#RGZq+T(aa{|a`Ml@W1l{CA$6z5oyJ-njLP=!_a`oXE&^>h= zN$xvYX{$<_xdE2&U`%>rruFuEuL<-G-SR2iPhMGkW^28&=VriGHA|^79)PH_Gw~lF z@beCUtC>+DNNnN!2QLy-`eE$7Vtc#WRYTaS(uEhYH!~}103GmEJ}Fp0;ZW}Es|_b^^pz8vf2L7(d4EaWchc{L-$QQX%|=Xwmnh}2^4_F`ZMZs?WI=c=R*HwJ zkPINSX76EPIS@&RnOQOHQ|^ZZW^!N~XI8mz$vyR)(sA+s5YJ50TUzLKcWLP#d@~sn zNWi1tSm1BZoL35I749aqeE&}J`~e^JCq~{hjM*3;e*Xt4wzU+&mwBkKs6Pm!VyxF4 z{)I;h@J{KA2*vsy_K>Saz>8y{x=kEw!+4aMZ?|>3I<-13&~99})x4$&o_T@}XH3W_ z4B$YCAVRrI5T_g)`A&HPQ{7CNT{tAHh$i@C1*AMi$=%j7cik5+b>F)caAe6)X%WoM zIL}#CF#};w_AU=Zk@2W%#yB~4L5dH;RA3*9bYII7Mz;XifJMwqEEGP1P30dyVpJ8- zuahqN^JG+N(zV)vQ|IVC(YK%?jMYoR9c}0u!0mmaN_Im2wAM{KoTsUK?-|s#Bb%6O z;lu)EdDyCNq}o!e26-RJsmAQ(4|Q0SHUIqXwpH>=N}pW*ZZ0&MxfWz_vu~0FEdepJ zB$$44lz&(Uxr89;yj$|ucVkZW?Bg|OfiM;#g?z7T=P>;G$qwv`PC^tj)ja@MhgIGI z8~`C>5`LKf&irX}zuwg{F?CGUQUF;1Q`2_Kz7_yUc4`a8@Se!bgRm=>2-=rL#sum4 zR@Zat+}jai*yv+#3m5eRDTuyi*@m(Z`YFFKpRG1qauo0t47cYy=%E#pprIHxDPWAK zsvU%g_R6#|%Dd)m$~NXPs}=G_`0zBAwa{Yo|N4USaFkE=ofI|Kb+X29(%^;yMGGzQ@}|?+}9GcyqE3x15thiyx13tP46$h$n~7DTg}Fe<%+pHEQN0?Yu7M>+9T>*~VYs^9^SZy3#2ul^3V#X+ieJ7hyCX#2 zDY&$feztx{SmzQ;82*ec$0auYVx(gxf`^GXEh7nplOtIfg8+NXv9l_gnl7{XgF`c{ zwPp@W?~P{QvWvq|{ml$Q=l{krEiYsiYv2O^ zzDf}h2;ZADQ^_;rc@bak)TLj7rhq)}U{p;D!e1yF-u?y_Ry86?=5NkjIX12Xsq0m` z!~aj9hma8hx8xcmh9+=6y_zg;3X}`ud@m^3YDkCwl5XyTx{)AZpCTr+SK);Mq&wO& zlyo%LQMZkH3qF=>JZ~D z57-5Rvo=A&Dljq#g1i9U7WMqTL_Qa5G+suW%-@C;_;%of0;jJ}g>Dap^qDDZtf~e$ zcTZbyJ@~)D=IrQ5Q?)Hf^R6V8nZ+S^y}Wwfj9y_oT!cN!z-UY(5D3HHshQGUa^1Pg zs)1cHK79JNF9xT&;pSpXj8V)Rr`bzBG?!Ug%cf>R!+JDFx=p1Un2sZF+fb>n#*A#NH|6j~5ChesoN|E0r7or1mqW@HZlV4briL;INF>x-p% z6DqG@rX%%2N16BiU9yHlzm`hu$=`Ys{F-qblNb9Xk(nC8*1~-i*_2mWd7EFL1vRls z-Ek=S5Qk!G4d5Y;?r4nJ#c7sTll^41+C{M$gw@0Ih#~_b3DfHQd);ri1tGe@BC=nH zdR8iUYRecrD=CaJY?b#fS2*Eb6-lmCQm|&=6XJ`<0`4JGZo8DzMT|W_;?X!4i#4le%-9D#3okM=2VuA-w1eZDeWH z^~qe|Mj%0FFtNW3L8&q{y8)zV%@nwo{Mg?{=Y3M4i=AXi@|4TOkx$NriRP!d!T5Hn z$J#Gh+%(kL05Z*PuU1NG*#rWW141R~R}9SEf{}ic=URZ*P8)>ad@}1jGs=pPF*G#P zTunYB{aN(uf9L;M%hf`cq^_3fp zsbepRzmYfn$eg%76yI`0=ko1Ix8Kl@sn#2(Qv|>&kA|HV%qo2!|JwKWDr&|KiaDx% zd)a`0W=gS)!WlI$_S6|we#hPz?^N7T{cIK8Ohvi;4E1p@>9U0hLlu}zN5PV@_#s*A z59^Q9+&%l{J*d#ZJFW)(@ntS6oQAZS#F>3#weCoD53x)2o)JJ9)~-F$JC}LKFp-y{ zV!H-pObm~sw?$^*1V-z{-sGWM-l&vl>Pj4@>i#@HJrjK=aS16iHP3#3Cf@!vrCo0ZoGP$W$aE`y$SP@b-sEY0~N*95o|rf~O7icX`|fL6zh{RtGW3 zcb23b#hO*~IxY)@EF1$7%$tnGS^JDe`yqN)G-@}&L#npoBA6%=YSej%Ee zT5^?TcncVv_9q_S9b4r&XC7|VnvP_#=OsQf3D^{Zy~zF$20LT4%=su%Yf26X*0RgZ zm#w6NO|YD2p#5fHsp1@j5#^j-02~_dVHRkSKfeP7!jhLOnP>-aEtrG}9D?fkqb8zW z{}APx)yvR;O1Vtg)SvKGGyn9f?X}$0!R1ZD} z((gJ@)2O<1lIAC05$GzF=dXWn?AE(EAU*}4p2N?OBXk;@Z+qAXDz&Gm3fbU!TMabt zKpB?vJDN%oV4z6gQMb^|2orl2v`^C{m5}-LwQULRlH<>?A5nVWl+*Q&C!R4| zKAc)`o@3oAbuV%Y6I8wUT(}ul`hd;2h*<{m!?ck}K03DxRNCt7jc%j-4|1OYATWaw ztSi4IS8od@4n6LBROaY51zG$IdYJoTi3nnJ7kq2i`R7-Bk09`B|0*3Z!knX-;npYW znkv7fZ;g$PJMk6$KB~ZepcJ9a; z?gIoIDYF|tK)}=_S$8jx)cr~PIe>&XP47+aZ>0NvzY7Oa>0Y4K8^fg9F2Et6W&tKf zM5lmjM@@o9$$Tx_hL;@1U|m*Q;%)(<4pm+mC6ECMolDKG|IU83I^+X6pwRR&iSR~i z)N{pSr8%CD<;Lrh`iRNPYvv|zTrb#mU{Ql+>?tIX@y*-Yim@Xd(Ck7OcuSRnYh90HbuQNfxaE82mJ-4nr7kFnL-jfZ%c#}6% zU2Bi)+T~Ntw zKR97*nG@PO+FGT)H6~1P6hKLIyhUgjvsfX!nT1~nSjN_5VsnoyFN(|mK4??jiV&yw zRiz#ZNnBD-+kETY^D`5sCztmO)eu3WGu?LSjL1{wN+pRqO0mtXW|~Sn3JQyT-Z>R^ zQ4V~$6!aO3nSVJ{YY@12uP9kY%XoF_`(JY(5|KJ(?u&+N` z>^5f`^L*HV2&z$F>G-P+HIOOQ(h?BCK?wSQoj$R^CtQ?+S8=GgkG0AK@C`4S>a*BK z>wxNHi;nVK@T4N#U+D$HspN-_-_9Y&E0vBVPnI_n(yk2IDUb<+wJ`=63>BA$z&Z-^W3ZlK*>AO`d?duqH7BdKqi zNcziAplzZ=a;T33;Vp4t5L_!Uv!s&Cy;h+!CfkR!D8*{j-R&ey(6J-ggHiv?L4M$gEyLKRz=ex7dGj{*rV%&K& z{8?DxqN(au;QMVc5fR4HI)mHwmew8cg3TddF> z%ASz{g75VJ3wEe+Kx{ihe6S$qj7R$F3XY#k0IMr8qzofp%y zd6X*0G|jTwaBj2F9GobX2B3cMRRI4$)%wR57YL?|%? z84W;^>~L~al=sSAQ_dyyw{AHfuxSJ`Eyrsat7pdF&?Yp}Tz@`jdjG1(U?31E21?g? z8r(8N_Q1ZxEpL`P{0&fAWO-_jnqF0ByX1Wc_fc&OY}Ze}7|+k5%#|0o{p@)FjEXEu<1+nw_mF~Gw~EIuwp$={n>0ot22y zRI~ec!7*3(W+e(jrf#KMp(Im0*9>o<7mb1cQ6LVNu~er2=5wslY6Xe zxU*i+GHKP&OLtIY3cy z2ozOo8`t6y?)#T&*f1iW@e!_)Kh)h9*{V2KW_MC_1WX^HSo7^ef=ehEpQE32q|M5&|2QK0o^=%EO$d7^MgUHh4W^!-8O=z`92$K5 zqCkxjVAKNMLC_{|DF|I3_2HX}{H+54v6Q?O!iV5K6Y{bmWiDo3-`40rrMPo5!mi^| zBj1AU{#{ef=s=dyjN7dH^OJ3Xp>dIyr))OGR-Q(BTCVt%?j=IL*?JB#bi2a;>B8 z7OE4#dOhnWGgaI*9qbDZ=BxdIqu(**gTJx)!jnHONgcvr9$n|%7Bmsr9lgZaDE3h` zZz|c?TScH!H2=_LfYT^EL}2O)&KsHI+40QnF1bB-8XK}*d-%i#7+IWlp1EAul#BR= z0eizi@(1KMZ|n~%b#Go(rc=mXGI^8Cwl9swXA1lVY7N!>uzwNx zlga=N67<--5*dh?+CBSm*;b`Fn}y!8327mUs$5q>`|&0-8 z7OeK3w^{c$Q+p>qOY*!q4`aoGVdNE#|ZWMFsSqVNx*d9vmea>KfNOZe-fS5 zXyD1B<7V^`<9+zL?C|TSX-AGoJnBLW)}KNu7{=Dmxmen_aveD7i4Q_fAi4&QQ$Ja%%a#ICD$0+OHWEW zGgws}@F-WHhs^pxcu3`AGvp^NX$MKs;3Vi4$h=x#M4#2{{%IfP;|B$$_BVwDFJ>dV zcD-JH9c3tkoMJ5HRKvy7Dhu&N)g^mSQns?&pZvp`0}jOT+ z!XB_ucB6}h_&nD#saLgDU_5!_smaIutu&-KzQSY2KLM>Ohy*IZ(DST3LJ^C8@oyIW z4MG)U*2jk}=D3oEOuSM?L*mKnA@$y6i&#}P=Qsc3e(6eqx7_?tF|Sj8npM4p3B`W2 zcD>%?!Dh~Ljl)M+)SLasAnr3?bV!Dznf|?b9$w+J3m1@_fWmS9#p=7@m_Ch&*7!VP zGkQ`~bA8XsoBSG+qR};Cm`IGtn|Kk2}As#(o zw`a&qP{O3aT3%<^OagmhK2FV|TtJU8yDnVVT+G8mF!<>*2dfxto-Z;Bhw7H|pBn-i zffJqRuyN<;|+y3)!2v{FP zvLf!0{wSrUpt*Xy3|F}5cN%4jWA(SHyb7flB$e^l#sLYJbrJ;PYSjMYFwsY-%Etfm z2K8O3!KhY*O6A!-CyTAGSZs^7=Tht0m`UeLYuWm}#`XMBj zr19U3%wKt@7Y9)*vjKzLd(!v^IK{G=bS-odDd*=HYUXXFCf^xricjXR9Zdb)&A2u2_cZ?Rr9C4V0_=#J^I%H( z*x7O7xQeSIaVBw3TS}JY==aYROr<F&;9i@#(M1s9RK1DhS=^W0PRHa}O58vHgAn)XGs zBTU5MbDRBR7Z!Hz@~D12c6JXdDSO-V&kF@oj?i*@CpMSUxw{sq_HLS(`OaXxmv*5f zHlclE8>+9AFqGjD;<9Trd!HCOV_bqztb zFXn%BmWDyO@1l9Y9_vjWOZDG3r$8&<$PVIQY`mcV`c=H%0XwpNpAhNxzrdNYAA}W#+!py+ zkxB>=75VUwI^&d&4QI4jVSr=MR(m5;b3&x8Ir zR{tL^H$dT!4`C#XNQhaM&uZ>P{^1Azf8Mk&wY_?{@1`xx%*>daZlC{5c4@)AgNyS&zf4Jx@ZcQZN>n5yG9=IwOzDg8dinR)s-5PH zWzp>`*Ui(>fGO_h=8lX_v|PZh6ttQKl#RD4oc8fO`hXrTY@YnUDRVUJmYcJ9ZI z!XbFc}kqN>7y(a%_iT?9P?*MA3h(gCav$`6xR?LTB<4Wep zZ}?sc+I3d7F;Iq((v#qSxmF+0I56*^+mrs(D9oZ6&O(;sh*l3aN;`7^qlT+;k$E&7 zYZU+OT8U@qqrHe2W3Q7TB=jbtdy|z|Ec5WNGkt8*Dw&n8r#Gv}K;DsrMGhVUMf|{rYm(da_tEEHD=&bghBy z&Pl-igyrJw{R861uh$WTcXt$r?GNF){jX$AgQ@sUO`W04HsZhiLF z_hxs^?#UIA!=D2V_l2&?4W+Yox|+9UYb?4ZJZ`T~7ZC14A~s#}J}uxrSt!@*7u?j;HioK&Hj1KaLe6URXPHPnyO-1{HZZ_;)Vm?&0DTW>B>#Jqr$+X0v?9N9TwcC$bPT114# zM3lr_V?2O>)kG=a=C>?#_Tz5g;q<2zYO#QNunbMkJF}|_x1l!gI}omO?t>>EJkL6) z8Z*TLf1boQwY#!?{v`@L4txGIwZM3N3IY`0kGH1E=4qT#5JxTtFX5_9<@8&O|E?1o z_>C{N4cgU?{@TkZyt*bN$lN--rK=Y%TR$XEw&1m7-zQ2Is(dXLOAFaePJC7$N$``y z$A0KiXv=+mX0=QyCNEF-_Rc<0=-6!J3tbnwgGidg@~z62%ZLPV!%|0JyxXhjtLcks z9ytQ>{JRu5tdS&`c5NuceuFrJikB*s8`L41|_6c|>J8F&p67q53+tUH5nm(FBv-t>5`KGL%TF;r(p zW02`{M2JdV_sr>>Mk_!mFA4v0C9h z_j3>3WIaE-U5oofyhskksPfzqwrIjplzG!J)sW}<_tPnfp!6Go*`~W(8yjv;$}82i zRZtNDpd4fMzh=|4R&@w1h#>$$@TnT0Qih}PM1U2?p-D@J_4E9GBI%qz82j$ zw9v1iWbq-hD(20mML0TDQAhEuS6#T?Jv7eCYF*xoc-iEOz;HS|`E;K!Qm7ReS62yj zW9=6(tLx!Wvhzn9V;%Z>*PAaXhSZ>rfxB=gDJ& zkw1Z{-!CP2fa?N}l;XWwIVN$9zSB58>PWBO&mghme*qmWZNja^eXurd8195-&?o&( z;}_Vl`sKC(|Fd}2I{Wa#)#jU-Ay1+U7)ut@&NdLgHI$|Ln>BeKOM&-~98vR3`hU#F%8~$zT#Gb!b5TmBEWAIe)-;U1$((l-f?>|)jH1x;x;&aY5jty z^A3ol?r`TXsjh3_SMkFRZ1K3fC-p4AC0E)fMFxHI9WIWyC~{oMS$flX7td}*9dW(C z>`RDQql@|4J-3R1FS``vm%#~#yD7QWy-%s0bQ4dvNu|u_zvFWGktfihrs0e&&aNn@ z`-AB6eU8mG&v40DQ?>=ERJZ+ zLlmCZk21T4`1U?S#ly3uD$A6Sd8SX$em(FfW5`pl40>*vkN?3!?xRs@!_OofNg=`7 zai^4SZY!%8S|kcy@~AcDntA(!R*;|4_j{y2EG^f2TvO&z!t6^8YUx_oI>~kE$YG3y5 zUENGUwEihm*;#gk`8CLvU@FzUuesl;^nBxMu{`10oKdv=JV>Pq)D7}(btcQ|vURq? zksfhp#GPvSq(H1cVGle6*O;Dihu{wGD~T_jQ&k`S2Q1R=@Tehzy;o&J1(nn}C{t=sr1!N;&SKZLb6*6Tu2 z$`248UFJ(;#5$QWBANN5U{mnc|L)7kfl0(yhnN$H44&<;_+~Hi-YLEjUl&g?2yGjB z|MQtO2z6;0!l`kMm_vW5DEg3-Zw~Pv$~~SJR8?PkSSA@5h|F{1XvXv(Xl#}Io1l$2 z$^Ll7^sM+-J(mS1U%k}A2oRaaLX7nA>v<+;Bk{YBk7q4KH5M&w;xmRnGBvnFFwOX% zEEY4BZ}mU;N?2An(B>Jq{-UCB|_z(rrVw#YV1x;dA0iAnOLm|Js5a0{Y?9(>f*! zT)!2r?C2pstq2o_1f)# zR%dQEbM0;j*6O=R#iVc#=vB5a{5TZYJ7m**PB&pvx3g7CIoqXQ&i1OYec^nQ|8&&7 z=+w))sl{4p2)nc{o%!Rz@p6~d0gJ~k#gzew8%<_wLz?9 zO7IbEW+7vF@)%j3c})n==xntg?PmZTSX zZKlcul~bqD5gqqk0ftqcbTqv`8n;}3f9*>>kLNFm2NlVfHR;#IS7>!e=IVIgUN5*TV$}*c3nDpGDOV&%b26`$<#>4?J{gWT)2#?Mt1GVi z?zVe0rg(oXx7lwed>~~KRo^O7X7kJQVVAaZ)-0SU^838>_b-<>+KTmPW;~g4QzaYB zf*aY3KFIrHTnd4KJDJURYh~5nyAHy$!|fGjrT7`D3r+ivwx-yEKEER}W2m)RB08VR%$s%n5o+n7rC*u<+JH zL_b(0``1RiF5nV^ZV#M1SMyiJX!^fTEC5Cd)VsYYgCxx)DkPh7QvP>LgK>`0tZ{lG zu!XK{>xKj`k;OI_Z*S_7x$O+t$>qy^#Yn}{8hFBiDd5LLsgZDl^m`})Eced9oP%wG z%#{ycJMP}+$N9uhitkAO##WUpWyf#+3eF((fcN>gAJI^TK&3|j%RHy~qNZN=nWG!S z@I51W`pIHW{+!44E;W+EK@0#l)6Ig0b_#x#=RY1>U*Dw8i$(uzn#yCd+dE^*!kI39 zRj9X*l&DZD+g&psw&m=gUA)lcbRtTUSLNosDSGNdybIORgrl%nW)GEC5icE`_{38S z@(xLP#8BpaJ4lL)h`S8ft5Nj$VLYhELt`E-lDd%R%h$BO$8t2{9>?AJjB2hRFd06D zdtd$l*Mo>v+f_crr68TRD4XpzV!+M+xck~EJiU@VB^`ge%I>~YBD~`0;uGEO_o+4i z%9+~hMx6!cj>d-4n1-aNJ5y#GPHN?!U zgbShyoJ;A~_{&7ItW7($+Sb*K%fwkOcoV3Bf?>MIyl{Uqg(ZQL>5iSIy_U>oe7@AB zTj0z`VYvFy=G(EZHcMaaZ!3y_a@((WV{a>|XWvVwPv!)&Z&vL`hTH|Lphs#$q+6Df zOvT!~8&`VrDbZjBTu#9#s(5e`5!Sz4<{i8*CszPZ$xZs^u-&I}yg* zyyPqj{lXOIBnmRN5JI?`)}Fz+wikxa!&$Xzvvt1Z^JN~m;4AH)VB!Ge`o&}zywTM6 zfP7R>EGs=&WDe2atV?AT1E(3Mxa)G#=tc6juEYBVD`s^2jC?f=K+cW(!1@ThC#4XC z+RM2A)rSz`!S#z36aJV5fFpPl`%)J@^$tm0(AzYRlbMt|Qs7x`0M^SH9{{$e|{bIwyF%FbsV9%`fypNi+4_j-&ixC?G#1z(G2B(i(h z72wbH-2Tcz(S2C;^eOgS)CN5K#DxrN9e(pnKds4Y`3h$ykYCDbtUHu)^7;5kn5*?B zY+XdxNPM;*!}Cn4nhIGsUVxicd|03AEsb~*xx|1zUvLm_$EBm=rALlQ5AiddL@}@5 z8I>FKP9Jhf*QXcv^SQ9)$m>BQ_jbxC#+=1e8e(sIa05mcxFC{mI4cP_ba}%7K|(h( z$g`xEh2I*n(3;tmMgwosC#V)RTRVZ|#OP!8?ikYg-2%M-wEWTUIdor+n+QGovv0Ccko3?HmUd~0ot1XLZ$$3bG7tE z`O%dTfbgVcK6WIXexWhTfXOM`Dc0`oF`@plL5kA#VRc<`h2@%wG@r4b4ThaiK?qMJ zT~9ERna&??t1$8`{hh4fH_3RZe&X79$dVXC=sOjo+NOpaD<`cpJU;A%%7?SMcVKZL z?+ZjyvWm)8Vs@^8AxKU*@}DRL8l~0xWiE)r1TWU1k7cSt3Ofj2zFtBY`i8Nkw|s?> zMPWJE>fHin6=W@H@AoGP?+gDz3mGI0)a!nPqQ*XvoStj zPhUQ!eLW-9@mp-8|9lKI{{a<8stochBbZYVle8$v+b^G5#lcX$u_wWP_cKX;S-3_A zfugV5*+zn!Bc|%p++gV-PJk~}P8*54zx~3s3^Ep@Va8sLEt%R_<|Liwk)u9d+pqF1 z2w>5_n6A!fK)-;h+ z5B1Y;2y6ZPx;#xk&ITSI<=lfg3KPB&qmxCiTc})HWQyY?B}h?=d>d@Z=^(DI@O^;F zOly{S^0D#(b;t^powC-)t)Uw&H2a{ZVji|=V{LERJtV81MiEA0PJKbs?G)o$a8w%-ie)scgJa)I$WOwO(3k ziwm6X;0BG|`%-69%X#w1(*=1=+zI}SiKruHw)I!?;uXDkipaKt5#)CvE$wrFKT1^aN#j?3M*H=F_!78$(68CH{$+u_YM}+AbYv$t|PT?TEcT^ zk$66jx9(=8`o0P-OvF6|{e5-!`kek3UneNhqn^SXc{&k=1L?6fb6lX$XgyR9L#wt% zI!TUqiv7!}u3VqA)noD@hk3V!YCXv1-{>ON!=(7l7;bnqaz|JSi76e5xM$Yu*us?S(K@tq3b;*?(W_yQ%a~| z%6NdL@|L8IAb|f6_X5m#N04IYDt9vO2D=U(uCjrMEC6sL!LKODC<1vdNpgd+!l5Xa z#F;~Y`zAVB`S$a*+=|}^WbG6Wj!_(+AK%134IPyi(<-!Oe(WI7z6MDLtMW_S5S(*= zy5Pu=lz4tKrc$9x3+f(yWaf6FPMOn1FRuioPY%~d`9fGul9s*+>9}p5oc$?iJjKQ3 zx>4}!pV2sgfuGbYjWwDH=9`GDmg|OT5DHI?ojjZ#VrtaDXR6Ul z1$mU!b%Ma)A9(p8I?3?C>o<3CP4{fA9EBqu_Mnp-N&ThTbKIfn2mjIw+tWq3ljc&T z?akrXz4C(S>E;+PLF5vJEdJ!4K}u0s3$GlLgs1pze!6EPAJ8!zR6D*JkZdZ++#*GK zGRD^qgF&WZd?<4lDGr0^RunWRw7OD3YQ@m}ao&hl6@6K{9gbw|k8ZEbAB!kdT$Q!n zxCOoo#RE$&*eBMX9w zgf4)IFiV#4A@6xK;RBS#nhe-eiHu`hK=4h*(*0E{1Ef$c#J&a0HVcfb=ALY1;7~R*)E}|Z?TqmsboZHP$3amINpc1IEG!6c^aCBn zHiYl`F_nCCr3{>mhoUyhfGSu+FZ?jEdr@~iEv<4`exD}lZGp5()Ko>iu5OC&7ypga z+Jp9}$GS!a8wiRv?bn#{%((jEw8I;m!dGGO`K-=11G;#fTrE0V&adl|xAtg%Wo(Jq zb`YqXe&%E&o-uY28klJDOvL{~ zv9GThX0_Fe9`{gZ4KXyYo6KbvME zR1_w2Q`HJ8s7TV#NQ!(GJCb(THoP=kqn)L`@611_(H^i;EX5&eK(Iq82)mDcUOi6k zL(aE{n5Z{QUr|_ubL1djP4Pm!n;Ns#UzA~V2q4F}`LBkr}0wd0*E>M}Q*Lisc z0!%$ix_03>&y}$UjmSsnU&|y{emq>ssddH}w8%QQ)q4SIz3zHYxmgEe_+?LzY80qT zzP~df|0UWAC)5ARrn+X7V|!b>2khBo+oRL9tVB4qk0PlPC4&^m{eFl)r;d79%NTru zHe$A1zz+rp%a(^*X-(#U<9dTK==&zklz*Joih0h6FX#qh>9*xtP>mf6v5z`_l$$zP zWul0~Aw59XQxR>vFO|>*T?fJe^HDeZ2R{)S%%re6-)h79)A7{Hpq_v`_b|8fs2G@f zGQ-hEutywC@%O)tl*&|o+H=Z9GzZ&Z7MfO|J5Wn5=)?D(l>WUti2q;RK`c#ATLR4m zmSh=Ec_AspNitN6TU4?yjPyAy!@IKrd@v;e2VJuLkP&~prv&U1GoMK;?`$8K!f%r@|q+jZ%VN24IbZKT>u3_w3<|$wbzevZFs=FA^fZ`!;-W} z)F(y4^Mamc30j)CkzcC?&)#I0n3$J%G{5cN|M``PS;Ax=vPjdr{k}UzosXnNu$8S9 zrVG>O%DwVm=cLt#4Y2k+SkGQgsb{89dVQbfX8vF_1xF%iCmCyZIczqsE*w&=MNY6b z1*8h_pgi*C5W$Yrvc00YdSgU`{bKvo!SXLTeE1az4BLZY7>o7>WRiKy>{1*C!G(r) zN%**d1bp9a0Y(pu3?=f23S!|_u`9r%r_5&>dreK=_C1fn7V!BEhzJ+M0rh=R3dyHm zt?uy&^}FH0aW23BPOAH~HcNhQf|Z+kBMZb=;k>~I(jRGU=uvn+K@d%I8vdBy-76}| zuRlW~#M}dFv9PVgc|Oss3jVsEiEl-`Dec}(I#Rv*u;)pm)_hR*g-JiiNx;&!IOcWwTHSb?ybxmw|*01^eWGi!qX^2mH?)FFK>sp=%Ul-zLM?(+1<>tH>(~qQ!JLN7kJWeC8rQR+Il)_Ue1ScZN3>6>?pSp_Dy?r1 zr4-<;wgJFLl(O^5_Ot!?*jNC7tq=rKOwIo!kZxN3ZvsgM7tVhAND>bQ=YDdZRe$>d zovgWn2=*ExXMv{PgZBhG6@!DRQmKQvrY@)ta|1pQ6sJWT^;=D4xX>}#p_<1Uyo z;u><5k5Wnk9POmem=fGB3wUxweaH`>XAgwlMiSq$9IvvuV8mUqp*aw_i9`rFMaR(f zY;2*h>QRmfiFcdX55w+*b2H;;Yr^H6ENFpdRX?~W#MwXa3+dsg5>?3>MzE|S z%z)4O6G&g!s;c^m&mctms0ivAEgKIvfjtW`1;+^y=d&%3LLEWJb;iL;6izRAj2Na# zv9xlS>xK&-_SDy6EKLsB_~Lz6O#5q|_s6aDPr~@&=JF7Gl8pusZ!2BmAH;*(J|-VS zPy#`n9Y2tGxe}a1POyf2o~M=Q0`>#_FYJdfGE}(wogbXYDRLvXe6_+sRvzto|1kL# zf>^2K138`7TAf75JP2_BC*Eay`ic1PA`nbO2`*n@sw&(f9hc@o^HX@$n0pGVQ{z6n z96#*Q7v|V$EmX}9FvnveT$0yvXJ>kssTX{QD##jvk6(++ne9}vh+q>I$N!R z9C)r*p%EZ_57eTwY)CY}dFL#$h06TJslx#qC@&!p!PXx`7wU~svNH!ae(4~1_7F@> zgiD5uZm>J94=X9QtKf-J*Yj+JSoZl!}tb}VrvS_MAAEpfMK*9DZ- z32Z;wo`sdKR{$dbp~Aw^?~f0wM$Q)SCdpE79S%bc=;lTB4s7%x^jm&8W(&sGeC^EK zSaazGMkF<{~VkQt*^oXSl$Vq|s2itzBuRLkNUmd-njuudiBy=$y7NP6*%KHz{ z1xISC;O7>!plpZb)6yG1W=lt>B4W4Z>iU?cUB80Wk|hjhj!iEtL|9N3PZUWNvUAkZ2dOj zXH1FMGYU69w(M<4&X}?<9JUtTJ6giB3pI8vop;-?V*;X#&}@Gkw8r9b`m%!2ms11( z#4L|ZWB5?{VQbK@^0s};BD;X`iR;vd6tf4tGn9>K!s_0MFOknt`7$nesZZNC-mr;Z z%<7lB`zFSKU#PB*Myqhp6@CQk4$%wj%GMD0908LGZIq5`h|=_4Itj6ojW229PSuR9 z%+GL|M3b1nyeNGCcG+5|z1_+wQ}O;6e2euz1*^#VwPv(sqe$3vglBATQ|$E0o6KLq{`qgMP#H zq@JK<*`Z{05_9W-2!RzKcB!goI$+rpL`2JmIA8-Dgf00>QsCO z)%60dunOhl5IcjD6C;3_#U7RgQWh;Wl|h#<01U}T+45pulDo#9pdlIH9O^VhEur$6 za0|JVAzzh=$Y8hLJc>lVWGO`Q@hTnPFr&Xo49s(lR|X2SyaGz3@VPq6|(Fop{+m2(x7CEj1PaJEJUiTui}XY8&qtYHM1YzV?T*>)F@66a4vr<_QAlV0!-LJDNGqb z*PV95>wsn#X5CJ@>iDLVGGLuO(8(O1Wmp%Lh+JU4Gz}+4jgNQ3Ca=n>>D4c1kdY%V z-jCEF%;hy5%fXJn%fLjn6~7eBe&*Zu{HYI8Odvn>D=jm|z}nNU-0{zb9H0xzv&755 zi5B|f#AA#^S;U-<$Lvq+B6yqR)`QBo zifa4Gn<5Jlt~=jKi6ludYMr&CKm0N0GlWk;0bb1i{b5H$Jq0Um_-^Ta6FBAzE_Fo0 zp$Cl#I7>I5i0*K+oF+b_*`;Tm@>MO`p*bXn|!TOhomMl*$J5e-*w;iI~zq=KV9 zl76Vn?4Opb?u~sip%LM8KkU1eq7GbL92sXA%tZLyr7%J$5kt`8^u*-2rc4~kV>|BI zG8a}QJ^AQqORSS#F+x!e&}=JHanWsKM%n;pA~F5x4l2g3Xmtl*s+*$PGXGB6oV5B( z@j!oP3aXNfS|JC=%+}Wa?`1Xz;UhE*X$_T_d9wMyk1xzReU2URGctslByl95x3xH<-ULZVUgLH&|?P z>SnBKe)hVzN^jZi2F;FaarA%eO!tsgxoc0%e^iuuAvTa(hiOf7>0rBV5qE;d5f03w zEmOjFd8ua#_z7At5ecDuA63zG@<3KM-_Ri70=u!)3CFD2^3*#NKizw%s(tE@#9t?W z&dBHEo_u?L`}TCy4re&Pq%sg08r&fb&Nm!SVgB@lX$ON-Yx1IV3yK%(+Bc+8?^qrB z+^9+fM^f~Em1IRazm6?xf=3gDc?cMQ8b5_knp*gT?biC~AL60g!o|?LawJGI7AS+bY4#3M^bINJ7T(tR-5)8%NT-4D|Ar00B?mTw zL6#UBNOLyhak)c9TFW=^Je-_N(s`s(G@{*sgP#z_PZMhKg`JxwLH#Osc;!rqfA-5U)JY+(6(tv7>l+SwnY zWTvRvE_CfiR!KV2alAV+_wwNQtZlh`rvJQ;PbDtT6kr2qDcQQIs0YTdKG!;3iNvY( z;;uxX+`*&H{O0PoPff1fnP~Vnq`aMqoBIAK_1BE5on`-D=ETn!w#O*o;W5V!5#%n) z6kT*QuWU-Dja4hVyh*bvS}PlY>xDS&L+a&)bz0l|m4{znM9qLxpIow-`e}>JM;aG^ zrs#bZ*KXNKFP97(lE89+j}GHFSxlZQVUZR?yILkGp0DU?b3UNyUL+Jx!aEpAytJn@ zuUU{*oORgpW5n{&64aScpMZkt~uwZ*XoNd^Adbnw;Bi%oF)(hq<-$ zNXuqE=6_%!zri9?n0L&LrXZzcp`jmV11XU_1zfNr*}q3jR{xv=t<3i&emGfCpOzfj z3D5T8-^MKO_l-8Dl6iY3Z`cx1eqaq%@Ke4ohB?}=@l|SjnI>G2Gf>EJ-u;yQ8_RM1 zuMru$VG|&2LdyfD)9miAxi%5lE^r7Ri3;3P6t+M{W*s7+(u2X1YDzk-idztx@`mNg zZPn@hxWQ;C=EwAadf+X*jf{-7FWBsJVSNqUzhjL>s9%dW-xWy~L)ILkXuB?mrOY1T zj)CwwcKxq{{{IdUq5%%4gYKL+cpVG%T{<+sgj(Zot}kH^R`&N7em%bv&KuynNqkpi z@hJOc0)enTwr2KSnh%3ul&O=$Ab?BToxA9hmHsUCJ{~1;|99a}eFkizVrQW1@^$Kx zC=ojons8nDt^Q|L{VA@7Qk)4WL{7utimegP3P84z*69 zPw(O*618)n*Dn}VK3x5^_oL-|T+<^4Zz8UWd;zzjz z>SJ9jCClqXZUJryO@L!j zWo7&nvQ&%TiqZNwcaZLy3oHfFh%1v&Pelxl0Ob^t)_??F-yL8o^^S0(8(%frD=J~Q zf>-$k?DiRSA_PxN$WWGii zVT$c193gb-qeF3^$O=%V=z7l7_MB%E&Laei7o~$Zu%Rw5RDXPQ+cT|DN8;6p;0G%a zRU_|}B&lvH=-{pWt}(4ZOXIxJeaM+0px>J{awtWT5y zb%p;e{I)+9u>5a`6MR9J0$9j3bD-&x6n81_TD73kYcIdfyLO?R^Myop=3VPXPxk># zcL7x;P(L9cwDa!KI&KzuS0(j|s0^6$rN%Zg+@8)+^VqeN(Ib)y@LZ}6|+`|5{2wqAH-X#WVus-y;Igz_SA^k`6oqIFb0iJ!~-od`D<&LfMjECYLh z>p^4Wvjd5RI=u7jl}lE0H!nm@6Mte2%3J-=_eNew-~w7Z)a)H zL4jbmpW7wweu(!B2K1loc;=k-10nj3c`?s!;64|qHi3sfi?y5RcRqqVBN@2qQTkKe z3w>GKac+`ucrx|CeMPYk3D?d3v5j z=;G63zQbRmO*|v8#WmvUq|4A-_7&?)tmum^Ox%RfBzJQYE)%BaG}+ijaZegVv40tB zeOneP#TBw(IL0hz8!`&$FCwyUo@FcmL#Wr5i(5fO<>Rk4SBsKrncxgJ(Ql~Onf|$7u-p6J z)VF>=x(&pX7$c8tKL0pQ4PBZJ7^~KpQ&||Uaqq&((%M!W zzuGbDklGg8p?LL_>QaaXlLr%7rNM&Ip~N~QzTazh0TF# z;+vzEX{@5I-j%4BZ#K~+WI_hqu8${tB2ofH=qp>q$kELnQJCW#P|jsri2st4w8SLh zqz$|shsf4t?ph?Le3njhTN#7@G*-Y5g$W3b45N>zC|eraJLxpg^z5jo z7O&KyX5ga!T4PWAs*vn?LKH02k$RBi*0^aH(+|ahWJ;uhW!aI@f@2qFTdE?H&^&27 zKu#|2OSP$02uJDDvWYa51pXuFyKr70dly9W4U_i zg3WHvKE>Y5PHnT+<*!bF7$WW~K^op78Q_bN`A82=EggCV!7gS$#`XSU_||ZAIG{x= z+DA0gN1Kh7WsxU-`Rw_UGxSj`fomy-O3(eYcEVAn@hnKF4g4r$0q*IZDQ zo(D~bUuu3_x!A^E2cy|yUqxWAxS4JV7gaqZw6XXYdox&mm^5@V6|75eZ%Xi8vFoyISun2y`AkbZ%rMV)GzMr8#J@U9Y zz*12!tVAA~dqn)%^a0Lp&4% z{ZiwNsT|hf5hqdDL$6Nyq1T>Dfb6>sd;RU9*BZ4#NK(wdBhl=d-FKmb`aBh#*@_3? zk9izzP}|7+yd2FR8@jIGi+GK-m&p+V=;i`DwG=JD&VId3nqr%TpFjI)R#k$l@X3u0Rk&&+5Qs& zNK}0N;y*wgLCJv+SYB5H8bO`Q(OM1MhZFRT>i{9E77$pU)#TNg@}$>h<~;>(=Z9pf zV#v(<#W{1t#CHOU4G}6r;PK{(r%Ez^A%374BU1zuHwd3NnpK?rvs(O;0A5iHo+?R( ztv|CE$Q*Cb#xD0jt$ciok?T*bfCb*r^dE2NOrXJdm>SOgs|MVGK31*jlAZ>uiJ~MD zUhC9pkY~(xN75v0=dbw8evs}Rf|LF%qC^`=YFS-W^YX%TO?6pcJcEJG9N<{1D32+Z z=J>a$N?qMzz#9Id{P; ztN#0y872Te6b=dwoO?8Zy+mup*qR8p{3Uam;eZaj*kwB@_hRF2I{cjj2qPXFudL;p z6;`Q!P0C$g(9n+W1#1HPj(jSj!^^t?mD0b;Iy6@;#-G9e`QM+hIPj!4K8!a?!O{!i zx0N8;aPGD}2@ZhFE>-C<)`eT8mN_k9SCevke-fL~Y-&eT-=~ez2?V`4EoIgrq@Nr@z zRPo!NZ;luce^10FLtjm|N*VvAO-({HE_fuo6Sprj8o+n6pyBIJ|FfE=zfuN#OyRT3 zx&-Em%dxDQuSbp~za|1IO&uT#f6H0Muvd(a`JGAh(hiMuTEve(zAP#G_0*6|+3`UF z=}+%$%U4+L@Lo!y=o>Um=>plHNtOT=6uNGLVxNRm=6@a(_@ROs(c(LbA&Aa?w8{`+|A<7VnsueHx5;jv5vOmk`V!Pi}3WV2x4w)aEZ z^SXcezU@1DI2R7viy7CLX}L1^vqDMErw&#+3Wbt;FFD7m&*)(zDB#zf3<`LPvO#{a zaSgg@eFRoNHM4{N41!OAvG9V=5_isE3%G zQw?={BuW;!a)du`nA|#kouWs`91f2XxH(;?_IBf7$Qz(PwtFCik|f~d2!{-B4QD(rBK7$)t&kD3#xEb5SFHCe^*f&NW1mq`p40Q~`f)7+ zx?m>e(M^q*IQL^O4Y)*t7XhV0?1!vwpWyxi|+loXQN-F{9eZD#JmXtq;h%lRK4fb$Js|Kq>=C6Uqy(6)aIO9DKL=5i;(D)46P zw}5q}0x5$qW8NNLN+ZA|u>g zwF^?`zew@-nB}h)6XN$JCUBplenJpm2<89Q_tqj|()<7%4r4_l%RE@%dlHP5g)3AnWT|N9*b0>G2)TvbwFg+$0ta zDJ5tpb=lZmVY4A+4Wex;==l+B5Uce}x^EPoDE<2xl7j4eIc@#;e!MxJZ@QEyc_7kp znoGQc-W$hbm7E~pRMZA5riK59!bk+9ppEj>y>yMGM2#y;5aEeagh5L{IYpF%Tjy_x zNZEHV2o`?gaplYdY-G5034uq}L5I%M@+gWA!tNK<-+>q~cq-l7pvO?;d3yt%iX#%w z9oQ`jg`2`QRWCeO??l}vZ)F;(vYKZ%%_aV^q;(9~l*#!gJxzmvmCJ~2!h9RQZy!KPz4M+IoTMU*vQg!O_z@t4si z2k<*djb*!_Gz2l*xEz8?Aqd)FwXYLZx7G|cEjXQu3cL)}S2}n-J=c&=10KM#p6Z%04qN!6E+x&}w2{`p}+8zPc! z_wl&CP`Uf!n}BNmt6V4*{N`HYfqA#@4O-;|d_P{G?I#zjasW_w;qCe8gJ4lEkZz&V z|Ba!YPNWPV@$qs4+PnTH=}ROkA(SZA{e^YFFuE2P!SM^%uRHWA7$m0KFu{{ch7Y>a znKBQ7;>1GULC*8+z#x-XY@Bwm%^Y6RI)n4unK#7)4sdwuH%5!!M;A!Y%(@(R(FIQI zNPg`_*Hw6XfAJ=|+LJG;xKJyVl%@NYhB1W%M|#qAtgHQfD*QekjAJ1C4{^AXF@KnT zeg8{j(m@53O3j*61Ygp7b4Vljtx3@UQ~{py!z7*8uXq;=qyl;9k(v~??` zh<*HKbI$$rO+YC*Lsm;!&HMcG47?NxIK<&t{(}=l$@r04N$Lwj7dC9fPfiNo=5WTD zvtK;xyNbxI>Y15T4k>SiB?-C)U7q_q`7-u3X-|cGsxD(1P^@$(!|wlnokOA!=Le6q z>Sr2$-RSY`e!pwU$5yYB+i)BD(^$voG&3n7%z*VQizOnh*;2s0{88Z@rH!7FbE1Y? zV8BBE>>xoZ8wpV@@x_1F2G9)9(WX&Ofp71J4;Z!=0dC3HD|dXKOeG_v+GAX;Sn|@F zGY;`{OO?&i`#PsR@(TjOnf$-vfER-Mmn+Nu_$OV9nn8GbwGKbjvzc$AO|L=Hhc{0J z2e7QrD1^NHM`6P}%A54VXty&!)B_m+O9T;0StBloP339)tbj@2n)l}NWT%ZA`UGx3 z*XDn}Zp%ls^$6H zXoPYW2(La?bz;hnjsU&w2|W>&@h0uWW%A^wBC2XAY>ks1vqhHM-0rs16~F7SP-z6R z0nNA0&c{&{)#~W6tB-vc`MNCTCoH!8_<-p~LC=gjg`#c2!KeD7SHcObVMoTmxb7up zhYb{;-@_>8pXdSqA(a&;)#pLWdqH*#Z5*WMLDBlTuWl7HyEKLJN(;bqd_R;Tsx3al z5gL~Z;+;wmzGA4E3K4vxDp(-)a~}e13yMux%y)stFFrx}2MJVSVY6g#WMCQChY$bV zhXs@<`+>FqGKzNENn+)Dsk2B2x1^kL7YqDtj%IDfyYBQ;7llW!J#gkmPZfg~mWo7) zsT&k23?O;zOQ}B(qk#k!2w4m6V(pJ5nbnuvBe&TL{(696nU6=ITs54Wj%(9go;~+Y zM^WCb@aMW~HUkBk3<3SqJ4O1Jhz$cZcxKPw=jvtx!mv%Ur&HwRGG4x4LjAHM5s-tZ zbtxX}HEO)`#Hq4?v1@yM>?5;nMobH?t{|d|%oQ?_&f!8mut(!hMZFVS*lU9IV1O|E|JOZ&J$#n+{pU?^k0~#h>2G3UWD_ zG_rGw9M}WM_K6*k%31>b1anSi%FnsY!7cP8FnHEoWYdOqZ*(yAi|TKBNF2f*X4a?< zxv5Njl<^n?Ouul9xA2#9zIJY(TlyCTxy}K%Izdhz{ToiFMWH=d-bjy=!d`<7R@MCT z_iL3Vzn`53(j8LtCTHWUgp0-A{X=6+RXNR=`J(=@S%dBVpDIexrDSh*gO)hWe_08> zdC*j7{`*h=n-Nz^BQ#+v(k$oZmqZakdpYG|&LWukxQis{wrnm_6K%JhV|%2|O7waO z(zjWD7fojLIyW)AwZu&{SC;L$Bc~p8T{2*^qW!g5bt>O9UYpDRbBei$g|)19A*J=N z^hC`9(SCAb3TS)UsO#uU9tUttml(3XH;GtALS5~2d32yJ4&(22`Tahma2JwVTzhc$ zFyCba3wE^|)GFCQME7_9_vjOeoRI4V={m>N&a zaKjZ^fLaY@Nw@s)DPXwG+9^Hs>pLhvs!3}Qs2z3E<|AgB=Xw`x#_9NOyVof%xGH;c zw1eP_<0EcQ(!x*k!ilTgLKdZlEdLd_tKdfb*$Wjc@vZhX8Qsu%DYJSJ*(>z85Hr(K z#*7AEQ}R$vm?6Vzq)5lQ_%~Ft!V&QVb4AEF$cYkwyLi#qdT(+6=jZH>v`Ea|xoX?3E!e`|wHjs(CvJz(uR!QnHu4u&3L$+?0 zN~jnnl(U12NZ^U13YopIYi%6fssQ)Ph|xk#9vtj3Zt&B;-8KfX=z%>jDd(5fHLN4NTLLglzMhq=W+v97hf)zylFz0=SUALCd>$d8 zz6yW!pNntKD~;}%!EdmphbgugcSVa{Ob+ky1&Dn^zzH31#clR^HN}e!=oPH z>Hd&zp7R1@umy#lx~4?%B_@UPDMd1nJQ>QA!iOnzf7e-XAmV5-l7A!ud=zVm#r8fc zhFV&Vqh}#&HHMNQG`JFM8gPacQ3f3La=c>Udpyte)nX8T;_J5TWQAnu3L1{>J64;| zp#ZUIhA@H*{`BkTlrj-*9RxJVJqZkZVN1P*_>QqcZ*sQ(pYP=^-~M0svO1Gca3Yp= zSQciO0^##RHEn|L13I0(=2zf;b5>@xH%q~L`H?L@L5Da_7h$+J8UIJ?iLl4GN2>-) z_$<{G(3I^ogFcl5fJ`j_$nsXPT68o6Ok4tl@4VZ%4ty=K*AK?-9{h=w$#^3>%=jJc z#Rq({>JF3D@ip#m_zPA$!#0;C@9%t>&iacWbRTkf&(@LTLjaAIo_`U20HsxOy?`l8 zFOz{hj5)dN)w&v*?Wu>TOAl2zX1&k^h2g^QPGHfd|5irUUA}^ z(tIVw<$k~)b`6$#M)nRk3JQ}xG$6@5SZU6jIrYr#dJ!=?l_LHo1ywmflqw;-{12g- z7d5K(ADV#j*^@K-i$h7w31Of-X*H z6m?vj#d8tUu%<35@h}Kq{^Hm$v7TzeNAk!maN2C;IOYYTKBf1P6~p|j{FRYG!YNAC zCCWwCkGC-Gl_^IDX_ec#?I}3i>*!=+eV5J~wtf^QkUTY3$jw#)i}jyq4)!1yq$KkQ zz}MOy9^yTiO2JaD=~`uBt7(Yi7JnwOBmB1(z#-wK*1Fn>OoV>LrWKQj^7Sm3 ziIWbWH>p(g~V=*K{J1u6vQT zgD|yYE zayR|sxFS;v0U-53UREJ9*0(RsKP-t5R@+igWa||klYVm%GPUcK%j=M9HWY*1hEPjMB zGj@BGR%y3UUwyx2C~l_T3#->ix?*6`3!hwiW?=CtGj6%N?T7|MF?)Cv`{R=qMI{q~ zlrHX(E`E8W`}nllZM9?iqX|R%xkW?Va)AhfW$aXy6~)x)iF#iw6{Se@Y2=S?r!vqr zb^;2L{!X1B6aMTZi8k=tP_T>K_0d^6@J<_F=u7jw?>XjAVz~}lFT2EyBA$$qT>&iy8>i7hb53AJdYEd2NMA#YkYVKp#itWtD>4#WMXLY-T`D#_#SJ=-pSGQdlNY6EEOB4gK1sjm?}0z%IragZ%% z1;3#-=V{}Zaz95b3W>IN;wv;35VimAiG%RX@S#CVDgwzzyb-L2QQlZPSq;7(iyz2R zmTbRj;EPD)0!gDBz(~!}J#sWI=8w*~?+FFO>=wuD`L?_ZAahj1zDjhQGD(xCQ&+vx z`3)-_^f-AE@PUE#pn(Aq&RpB;3?oa}GLz|>PMq#H5*5J_uC3PoDEvW5UWn_AhlteQ zvz(P-4hta6X6E(gcEAqQ*V?whUHLjZ$_>seuw9M(Uj5y;0V=!@U8J^m9`-42hc9@5 zFDHGC^W>B9PI8ZnJhf;5S=&Z93af{f%-CE@bK>=4vA_ zDbsx~*Y4{!50o=0JRWX>`SE?pv0C6f$Pj1=n8Qsgz8T+aneU$6Kgl*0!<<;%vr+SH z+VDKQXMVW5-;woD<>bdt0=BFOy~8e-{+cYN{NS{F!9N3tg&zX99l*mo8=QYEJ6Y9N zAK*Ce4X*0i`QYrDb}ZgC=@DD_CSvsUmBP2fCZm6s3oSSh=Fxn4foP_kvno5g6>!jY zN-!@AA`y0T4ty-(ISp4lB>?KuS3W3Y_7Rs&x0g-QY&FbXN8|=4z7yJ>v+h^R6j&Zi zENb4QG^MsZ*MPVdkso*J%Hi@Q*=03bFAS(Vg(kwYB3iUKi_bIUo^pQ|3(^sI!%rD2 zg9hOZMlx~237aLuaBnAIy@!=i){{WrU8>(L-^G-q#b~w>K~vhm^-_I2(3>=*0BC74 z`O3A63hvb(wT_WF?rFSN&qwxx@Qv4%A5(TOn%*Ny^E=7LVS>d~*#3;g8>W4-G8t)P z$IHKcv^Q&@vCH!^xuN|Hx8*xa)z6q_HKiFB)rt~zYn5D^(lq?y&JzI1--Nm(lJ$@u z_-xJsg}GzNhP!m*37EI=<**C)mF+qpu>)vue^lOgC~96S9YkJ~(I)sfo1}mfunT;Z zD-D_62Q7Rsc7Sd#ImI6(1NihVAZ7JTQoJUFH7th-%wT!!`>+?T!L=(-;qnhZnPao* zV%6nX%pZHy*(^}LO&<`{wBT69TS=^({(zqr@_C@(N(4_OubJLqxmSZP2{={0v;X?gZ=2p`cI1rV2~JL& z$%I-C<7?OX%eREi-605YSR;1x*cX|!!*U2827mj*XDL)ZQ*kdcSQ&Qpsl+hdf?b*( zMltl%#_5BS=G7>?q4a*b9biB4c74$! zYBF5Cb;&PTtgD=*(!*a*3lS?rx@+|T|gSWH@YNs;Mh}6eM|*5tSSl>Hu4cb1K+!bxBN-$$`u7}vz{?k>NyE>p zWTG9XFaUExN6MUcfss9j?s(pSIU5nvm)jn7mrg*hlNrx_JJ=`mNHRj=8ogl|eP^&M zbqJgVD>T1Ta1O7pp%3@UkNK!)jKT45 zHgJ*1pZ)7sU?}%Qs}0^>80#H#-(P4+3z5L&qm6#?E~EgQ;sW-xV4m2pJ0P%!VQ3vH ztJJ!F43}WO&ojer4e*5ttsYrJI`gkJEmm`A^awE);2JNORQOADxTHW6bAp|j#$4?f zCBqRYX6(WR|1`U+`X1M(#j+NR9#4ssU!+=!mSlk#xH#FugpStZXkj9L#FrWR6{lM8;FN{dbqO2frm?agcV ziIA`K`9Bvx-)^=X@w*%vfaV=)6}+(Wa-5lJI~QqR5TSsH@3a90`xVk>qehQ&J&HECx6c`zjTe0 zH8%l#?!6Q+cprnCv+LSJ(vg#C8Yu)x+)kIJGT2Lr363#;x-pE$}=%VlxbbDwL zXlv!dfKBFiN*`ntd&&kAFA;;_;qGmK#WoF>gj;l#)BhaEP#M7DDGPj3ixLps9cBv`$pdNUE?>>_*wt9FNIe-4zaJiEtK5H&A z5k|8JiiCSjcRM7Jm-zIgi$Ah8I)|1toRBsLyg%ID-=zR%l-0#Eo0xAe#oYuO3Ey0oEjxP<^0n{Lo<`1d z6k(y<-?Q4LNzMl80Nbf%FPAMv;C|aL^N<2@7>axy=!%yckN*q>G zxWbsMMNMyV>h)B0Ri&AuMJz<-jm%{mGiVzb1e?B9i)3njJp32%4ey)D;5IwTfq|rF zKkT;eki&4N&nXGyQpE)om7skhZ1@Cae)%jsU!b_5a}z$(+D}->4vbpuDmL<9tXzb3I!OsROmy*RVnPgr{R)rvm8TRY4ORr}60%Gpg2^?l8Y&M=Xi zvxStlaB1=)ig#zL{UU>oSHW6Xk#>Y12A{MjAN&%rwyFuA8Cvz)SVga5Cpy4z9)okAvW{Liz ztx`a3E_!&!NF<5HzVXW$&4Afu3gDPH9}#a|i4Lj13mOCh=+dn4o$ z$WT!5w|-jH{Yv#g_m?27(pOjX`34AjMBKXgBau?i$rTNjpbZ;Z%cRjAr9cpcVg|0p z$g62droV)jat1{ek_z|*0PNT&rPoR+7s~7Xmjh0Xc>K@TQ)!@!fd0J#!uqYRoBfje z!AEV3ds|v*9)1+AA;SE)FYEld#M;j#+H?}_0#w1E zA&f6I3I|Pd)8IBCtd|IK}a^Yw?j#%S|&{8&~vYV^>S(-aRE>Mf$-Mw50;_l|}Wn8VLiW z<+D?NH^HVEvu&zPeKa}VkQ~pE8UvSJ^;pm)g5C(l+@P1$669Vg@mwsurg(iqJgCl; zt8n9X>C##9tR{taZW4DTTKw&Q5OEqbceY_br@;;R+)d)VvW?M9o4D=OQFcsArJIG9 z+xbU6`a;>t;YP#MWV)&99x>s{;u$(vBt;&#M~?W76LQ=lL(7D>JYvcn;UEL?_7=y( zg;Ppt8>;zEF%&ZV;IzIuYt z%N%7v^sW4n5I7f6=Y!H?UDlnt54t@!pxeM=Z+*0_K!Kq?cDqf36%u%&?{8u5+vX)j z4OeQ&VRPX{rn;}kazf$$Yq%w%%4~tphbHO!49#X6-&ueZ3g%POvzw9gnM7~W&A7pZ z{wkp@!n(B;&in#{xr#v-&)&oB?s7i6JZ1qa;8WoC*#$H3Du#Zb;(c?-Ub{;phXwWB zsoyaGp+>rf`-jloERsn*O&FCI5ju4h^Q9Y* zHxTsjF?P1|@K_E5(!(=EvJq`U2Ff^1HT4p#>6j;XfqC97^i-Gs3GVbc>*^_bHufON z3C^iMQ}da-lpV9mVIzzP=qDkeY{$a2PPOm`SrV~5nS<@BZ({!g* zbKQO7(bs!>lx*=`{}uYZuI#n%nulKm&MafTl!f(7bv{!scNnW7(Pig8-D1>Nk-HRl4m_pk9`eY~CMl~y)JP0(WVkq8H~JuO>LZK*p~oOx zap?gU*#t~zE*B=2W<}?T-1*K1_gO#14SzUNphweIr1MU+y-HndS2@$)6D=CYJqyM307Ktl`zDKKI}&J;08-0OqQaVN1Aj=7b&WnHs_^{T9KY*ldnJhVk!R{U7@>4QyEvUp%d!|Kc^iHXs85NZYS zw}u;x}W@QkR2BPUOM$`h4x$?-ZGf>q>e-v-C6Ke~`Ff>l`sm4TSL0k;xKylm+d7|i@4 zH4Fr3&HRr!pf3I($!Jc!sah_NCETF^y%&kEkXWrMx?VbF+=-rRXpa@y&I}uW{Kk4a z0&Irc0yCYMn9trDuhHh~!}FoY@83Eld0~qJV(rKf?iuu=2a5M21=MUqQS+P~Uz{W@ z)xCsq4`R$S;fB)xw7sqAA{|8qG30HYji#x`fG(32k6ALANrK(<)pfAasQkB-vf#b@ zOQ>cmham^orAA*iuGgIzT0&q!8v)M62ah_vN&DK$!{Q>sT-yzyMvHZ#>5)NFA+V@Z z$R6S0Pbt)7BZ!EbJho*?yVpA$TXCu&k?0o^Njds%x8^G-#|y50*51(tY+Vloc5u6B z8kb!ItNq>|TGE>;q(vKqAglp#8FZWx#(?)!GZK`o?*$uP)$BcX#j>NQv9f`3H^QzQ z4==^jF;Op_MIyHoLlC`j_Ov`S<0bE*K>7CW{saMdo%^7U{f2dsC$W}#2ud4#<}*(| zcZu3*yiK!oUjC3<<&(KD_TF2lBC27D(xU@8*eSLyQ#wmJ$^j;QJY|4GBTI<=(zT`c zi@D;f%9*{40a`x=Hxyagm=Lu#cQ&x&5@+)D=1))RUR(Mmp3PaaUUg!xhP6LIMCYXv zU3-r$8cxVTygYz>xGu?yU6f2SGQX+ur z_N)9)nO1QZU=hX%R+vY%m<3f9-}m@t5%VZY z823EwaP-jx*0Z4VtG$^^aFh}_@b*=SO(s6n=Dcz8<;6&@6e||gMwK8;3}_R1Ko+N>0=GwWv@f9&~iH{eQT6>!>Khu4{aP5NS|422et}K?WE^ z0a3~TX%G-8=@?*e6s0?*TTls+hM|-gx*N%%rG}Cr{M|h7_pRr9e{23?Em(7Nuj@Kz zpMCZ|=QEkxLQ8XHf^)-)aOFIHNtXeNd3EJ>wypj;*N#9Hty4^N|F(e&dHg*!trz9^9U4 z5L56v#plTatEhg-v?e0x`!6x;V!XF|TKDBEf){sdtI;4z6 zh&^0;*5IzhsW#W@(o`6wT~wYcq*E>>r{DcPsmuV?(EBATyGn^T^xe)N7Pay|gC6Pg zVyYKXHnuj}Cr8xWLpj?@& zGoL4|JTzXtVD72l8CcEDU3LlJ#$gm4LeJV&CEdsVE6rKgT(o+l9x4cL1{SwnAGk%S z^=WTz@pr4Fx&$rT;&IKNn7D*N|=(JZEKa>QZxSlSMs>j8*bd zm%1tXTEc>AUb=%o!k>#@elc6iC>1DN+eK-B+V|ngx7wz@3L~C7sIik zC*q+eid)xMLc1RsfV+&~=Jz0ULg z@=v?UzBAdblNz;Ua!aVUaIPqwi6AiBnb5T6zoLc}PkV2h=tgsYe};_@5BqusjP$+u z_vbe`#&g0)^m5}yaGv^eQ+lU)15*~^n@{d*+kZJR$hPd1*RUs}BJZqi7H#U_ ztp6-ZHUCcy;x>JEG}AD6n3pgg=ZQxc?**vW(?3 zPpkPnLW(tP`>YGay(q)KEB}X_pmx~3b%vG}&vfy}IHDxX&)l?{)IQHCeQ0VIep4PJ zjA*j1xCZMaqpd)SVIB;xuw^X%Zwac}@Q9HLlw9HMV(Bx?W7qAh&WR)z|`` zMrR9xwJn?E1EjZHAEu2ffRY@F`Kazd;q)3NaOh37{z*a?LIlmW5#PUh5GNa`9QA^Q$b8_m4F$)j|z>-a=Da* zGRyNvgZ;?VAS~Y%6TPxcbPpSn6&YWPqBz_r@|hk`2K30#*m&)NCSE&GOjT<#b5DRu znf-&r4X2oX2JwTmA}TQIDaE52bye!SFJa3EUBT5!exOizK3VqtxmUlFdvpg9Pv|;u z{tmtXrY$mZDHMUMoJ;N8T4@v>f=X zre<+8o3A1WvcmvlG=~$dw1~mCZ^LVG+mG2=5F50QSRuM0PH*$OYDVHaF~F~KVgA%Q z$5cORp7afk8s-2UgIKlPv}nL0P8+%ivsJ!Dk@TLfe|U1+W?^;_ONc<2UsM(?s&G*z~Vp9(ySqGBZ>uf0go>P_IirU zI0N)KflyoYXnS3r6c!wSJB^xqwhO|&a2!mAqE~OA+1yBpmd6}Q@=ZYq2+xK>gs3Jv zzq1AJ$)aL^#i|VjF|3eHFdw_Zxk9NU0l#31&pt#+<{gQdosRJv40IsI0sXeDloy?SJ-z))R!SUI z2h`Py6IE{vtFU)pn^jk3`ssHsC}Zo(sWGa_o#IQ&lbwvpHy9_9JDVI>V1)_K$Yp{5 zdGr<{ODj)8i=#AyR5VI~C5HaqCte)9X_v*HJ$l}+**!x39NGM%vh#dd!J~mxm^~qJ>+}D613PFF@XbY zE9G!QGx&`U^N^kdC<|!ok424xs9|l=!*S1<2tQqT%>xBFZoML|V|uZY$%-$D#mSO0 z&w^b+LdObEUL>bNj^A`mf*DQ=9Q+_V@ifeJ%PrW@>g- zrsg3BZ?_-PtU3m~s>cwY$nu5$J5||3^c(nZT%Zey`unk#< zb;WpF*z|mj+>6P}fD*UKyqz<&U^dfpgM2sxM&ZekScQ>BkY}{ckU?%0gL!?1#9Gxn zh+XC#k{d^{R%VDO?|H^Mg!DKN5t?m-498A};2JPSM9)#zgET_s(my`t?Fy~oytvQ# zy(}sD)48schl3)@;M`VCoL_s;w6+Y~-X15pmxiTIQ6TcPSER#8a1_0*=?^j%ZgYCJqPVAyXOj_W4f4rUrD zv0NiLRmEH>Ys;589?022X_RZL_pAm&+cFklr5_(QSerOy00Zvu&|2erza%pDG6TCn~_lsS}Mkl<;BH zAFQ^;%T6#3s(1>&7NhE7e5}omyitJ4xCM&lQughEtX0Fu+A4@!W#5Bwl{}MhwnR%7 znEEB^Zez4EfEJKvczblZQmAx5JR%+;0wy@JB--I!w&6amj_7ndI*}z+7h(lw-~rMl z6hH9uP&l(jB;37j85sVc%L2@V17;cHdkw|;XCy)j6X+g4h1Q9gVSq(dI(}aDUAbts zj#ZHM==DCao}wO~kB|ju%hETL+6#&F&a?O6E$)z0OghP9IOvo`iDHc+PTD2%oj@LD zTeUI~wsLX~e&Tal2aNew7T4HFqiH+BucU->(YSob5zv^U$muquvN!|DwYkbFLj?^oBr+Qvg<2mVaWnzvtA;PdYG zPhW1|NlCxXA=~L6_IYsJ>$g`O1qdt7Eyb&p9qM2|zZlvjje;@mcK+V+s!4EKPkaE9 zM?*bsUl`J5P{C+so(a$+xb`9?pj$Bd$;s}L-aLltB2e+hx)F$V7bgVdtKF|nbn7{{ zd__rdlhe9WjAN$zo^*{p3N!--yxoX2Py!qWk_E5&sNt+EJG`FZSP37s%bzo%vQ4U- zYP#>PSW3X0&2OyKD}dz76RjOLKAE!;)>SzPgG7@OI!_e}(}Y`mUU~3?;$(DAhFVqY zwG{3GS`B*s$pfkZMf_3$^@}^zZv=N6_0Z|aqsF_%H)B*+Hw}*MY)lWn8Zqei`pcNFzC$5;(Qi@xhid`(YW#%abqFV1nWcfIYb0CroyXQjRCnD@Ug$<YwOLcII3rhv0~@N$aP9bt)%+w$eW)VIbD}VXq$03 zATWR=1<1pKMGpFtok^r;xS4c$lo;zJLkR)_9r>h0{^Z;>47xI_X3`lvVSZ{4r`*^Q^9*8@!wr<;DCh-r>he+ZjjAJ9$wf9 zPO5d}y+?1q4O>3`+!uFv|L}VSxq-G-I_4*{607DsqXE7OZ1v5*xBNLAH#mYZVPW)X zu2l5Z_rsNJRM#{*)d2FH=b05j1$PybFcDMhkhWzO_Sfe%hFx;;#p~5oF%K-v_CPZ= zQnfG;)8B6`bA1$9{Je4Rqv+$7gcp47C?BjLIn0(e?H*-}D#_IX zfOtNai#|P`-DAwjW1a)|YN4%-(u3G+X&+88!>qLG&l?x+k#!-_D}Oe>hX^B(z+wLG zd|$r1KDc*ciA$YzP_1~Z`~t-MWi59r+lG0K(r+gmJ^Kf?B)@$vkZp(4f>Z-*ESg+nOM+pVFKwo zS}7$FD8yXL9(Xb~UKb*}VYiiYCFw?zR}|5h1%RB^xqQv%-FNENJ~uV{pSbH%rVxzC z_`O-|_*zn{TXScu-nvZmL9j#GPRuJQzFsY=)IKdx66Z&x#u!kq+rP<8O?ID0JO(oc zL3{-g75t2dJ7PMZx@uNfup=s#BtH@A7SZfqS1@83kD9WbeJSkF$XAyMnB!_%}FI zpxOI(t;IyCsU7WvR|x2C1xrXLWJeyH{+U`B!+p0M;y!N>rZ`osFr#3%sE}E364#17 ze`F51_S&(U0dn{5@uU^wTz9Y6x9<0cXXwWjy|m*`R_!KYhzH(?Gp^izZm#Mqs>$#H zIV<@YVeK6L0%ZeaV?_b5RqeSIiG@{5kl~uxNVh$lG=kmfw^wG%8d&$dL$)b4g6>cz z_Yvkyh4qv}dt^)rR=)l9$53*0fUshxn!GH&mih2N_g{Ie=Wfr8x+XlAMS+JiXDYyI zs6=bUCUVeS_7Y4at8=jb6!^MSqKJ$>aGtQH6`XnbTdIgK(nhX%K-VNwq<>9ow|@Gs zGX5KTFp%;!Grw1}H~nujdhQzv{aQPpBx%-z!68LYY7Vcu#+DvJO6f^xjy zIsFw|KUEA6LoBj`C#!j?95$l^z7z}M2w{s3Zgl#CtMpIB40$yv6DEY>|HJdepY4{` z!wzB$B2DMhh>>&Mimfwa|nz8Ei zC#2Au=AK;ig5<{}(rGtio{p36eS8(wAb30d(#i)zpS>Sf)YaAa%a$7Fxd7ZVgc#BI@2^|w}3SKj%{ z_BLUfl?sU4>{C|o-cV^U{MU;RA`Nc8%qXV!K_RnDsZQTIV6IrM;9|{Ev-0QRzT#fr zf{E{=+0EZV$wxyh!^B&bz8yB2j=Kn8jr-1YP&8^*1uN6U0>dAjbzc0^3juRVf z7kk`D?pi;w%Qbkj`?)bSglC|~+T_d?1;Vw}1xSM25_%v?)SUbiBc{e3HRro7!Vv~>S-v=N9=hwn-UzyZ z^t^0t>>TdF&b zm0?BD2cZ_UFZ4jDcOaiIv8KV#kA^$H@Lgp3U7rTZq`&r&QB@b#WZB%&S8W4idN)`; zlYCcW+G&pCkvww3AKdw|+yg-${)7y>?{j>S^39`j4msRnrd0i0$2Gy?rl_Eav&rq; zpWSXo@?-jI1y^8NI@5JrAByt_1ZLX1S!HXDWvbQ@59im-*B6dp=6ge~i(|2*q97%! z*v5zG4`{Srslx9KZ8G>e`*G7|9{A<>J&zREi`)+Tiv(nH_3J+kW}r`1qYvfLPF5y% z;`2Y1Yfi%BKDy7X99m*uWUwBC1cXxGHZ(o7&?g(zI%Sw6*mCwJxYrsU2#$c^Y2G8^ zArlbJ*fx0jVrY5qBuIQ3d17^58N0hEWr`YIf8;sG*tZXsjPL~f;fdXKd~am}12{I7 zkMo6=%rKS^LfTWcg0th$m!pK-+7;xeW(?SuTrb;X$@V*^NspfPjIQ`R#b zKNi%)=wB4(e@X$x3aWyP!;)sdou%ISl4Zq3GMyJITyrdm(mb4-y+CHragZ4wDE=ac zKQ!YxVCP6Hk$iC17gfUH#!w|dbgkplPnIv+b9!%#Q;(pETWSb60df4LVn9iukE{4w z>VV-^MUvOVkPQCz%2qK>guQ{hDS8`lnAMVr_MaYg_mda&5#BTcULVO24DIs8fiYvB;<4h)@c!_H-^AAdib{7sV)W8 zw^r;~=!K|UV=g9wC~!)JN-`OG^xQdJ!@Amtg+wae7apc^GAv*t(HLw;Q>knQIm6&Y zOreLay_6XwK@@`w+pAojpv*X4ItrmE* zQdm7Rrco0a@5~SDY|we@r_*SxF;gQ(%^&o5x>9F>geZhI^8r3IxAq8xTeq!kEAV@t z@UAs_h*SKW+R5-XWuw*0wJo+AcgK@WRbjOWa%cPfMArrzP{3}n+aT2>>&*=yha3%> z#*#wi6jh^;ikO2#S}UFwl8JhcEHd{m144lQ+oU}>V6R;}s}tm#F=T8u9YxGpFNAFb zCkBD!hlf)-cxG=2#(yMl;lA*FI9=d$<9G0%BfFddxQ>lw!Ydz96?ObD;}Y+CAgKVweHs11~vI(1RcZU?rnkJR>GC~h$ufT zkZlsJ0zIY}fjaMcoFuZYmA0~$@OU*R=dcRUwA(f&g5()yBTgbj8{-L%|3*058t) zrOH9(9)y(=E8bs7|4WrByHpqr@mDj48r;W-=T+r=Qgy=l$!QrF^Zh8jN4?1xv2`4z zG)+N37X6zH@sbzTF-!L6fAuGV3D(Co0sT7-k{`*RUvej7Dq}KMGrnOPVf}~MSLDzz zz_d&7m#W=CE#99$OQOUjVi$;)bGig0lSuW#xRkoLgTB64*MVxPn{g$a6ISe+{ivO}Ak^Fh30olkPpLUd->c{TsTrZb%})gP>wJ8(FTv zb2l3iLIk6$Dk)>0YJT~c2K2e?>9Pkt>!t8gPxJ>ec9LLIco$dx(!3C^ll#}g5EUU_ zb?8I#h?N+tCj*W3-=c+w_nHK;#{BjDolTSiTR2eTj>_2u{F;EY7^r_bVUrWFXt)Nc zBcf{zaNlx#B6)rQal=`;Sy`}}@$JRDd+o^cqiy5g?SBsxWwF1rrK?FQ5Rl?l3n#i& z2l!c%#Q1&)xCr{!%H>9;zEFps+9_iVi9W-Q(D^s|0of*;DoHlUnKk+7FF|TN25p@0 zNv&r78kt`@ouVQf&8E@BfJ`9&sK<;2Ht|q1>G67&zv%o0`5_EON1ef(GWb}?qww;; zp!Q*Fo(E9@SPfQ}-P*FeV`?_*Ggha5+H6e)m2RhO%GNire*j;w7SzEN2O?VeX10CY zMz6yr3hOpN)=}8{l&^PXQ+%pehs~mgQ7ey>NC-R8aM^g?c)qpGQIPyYspkui!@e9k z+#G+xn>T+$)}B#C(DqTf&>ithhlGVJ8LVm)D{go530acImr%~V=}usO)BeOFFPJyW z;|4X~^inQ|8zv0|YoW#}uG^dE08nRsqX(d#Js3=XzK)6aRw8|YbFFeeA(7KlTft}I zUx-l)kf)TitM=#CKa$^=1}%}rt6a8IqoC*NqA)b$f-<4umK|7n-S(p5!Q;$^b$zs9 zeezsI?Q*zHX%TWPhyESP-;+|8_5OT61RHDCyu1agHwy3o3hu+?vfQpPvj!I&cNS*D z)AufEe0MNaWejz3ZU*#`nsV+RiiYV744#-~LIi>hz5Lnu2>tlW#5?X~c4M3%zbA3f z^Ec#dP0x4*ZNx9X$5;bvv=C9>19bjni`H0_DF1l<0ow)1P#U=x4}bUdUX;KP%Ub~K zppq1E2`!&u>px|8E$~+!%Et0S;_U(z?jHY#w@AiGw0@$4bt-*rKiaRnC?UcwPSJ+^ z`pe7?`0?yaR(s^bJrCcD$9c2=9d3wr%=xKHF^l2XlEjOo{xd4$lqede$4q~OFLB^B zqJwg}UJUt2O;ioX3G?_xpq2^9=rppJJWdI!i2-f|TYdkmrylS~4{lGEnv0S-O2InE zl~<=cDDdE@eUo0>La>_*UNQaix4x$lV@J{BA;p$LUzf-6v;Tul#-9{EDBIWjAdwOb zGtK}%O0@V_H4FUBICoWsALRu?r%f*O)_P3_3HD1L4>q?$wgy%Kbi-?%jf1&A1{g(q z^4Fb|G>1#h*L1vj^NPaB^q+oB{c|IOeb*13H#ofY$gs>tGlK!^Z(HcsKnJTXpz`5VDaKVpm(rAD6BSuiw1Z4oJ$;1%J!_Sv;;d$2)(l-?oFl&b;3Vntf{)F zUMks9Zdc_w-Cq86*QSPKHIJM#-S|wU)iw*eEi2%5s;=-u+rIZzX%}xWcF1!zs^hg+ z5NOj)XF${R!fYgD=TVJO$?Q@ZZWRR} z+*|W?x96`BG}a3^hdt%XWo7M^v`*D1IE5Tj7&Bks=(`gLBF<2Qqi&4^s)7hZVl86S zSmx{+k-je{9;Z z4AyL-ARGQh-6jVWuo9S(@UZ72DSSPoQoBXjvfM<{(cMe4%6_2phJjzmZO0A~b+^O1 zUH;B56egjT57jmnRdwFuvFwVYphekrp2wPz8Oa+jS?h(C524v)L&f;_sq=5Q$Sa-;`Zn zg*koj->|EPchK((Z7dDPWKK{b29wB8x0EfI!>@UuV$OdjH;wAkWIlLn>`EMRYdE=n z;^p;>?bFR&;d?%>rW-znxa@EF;ulRrA^<|dikjU<9OVDPx`%+8Bh+hlhK>n>^AW{Z&1qTpZ(ZPB<8y-a0Ce2B_l2Qvji5Q9q$oYkFAE%euyb79QLuZkr@ox%(6VjBPR~urP5|rZ9 zX{K0qhx>4<2AVuhSxQk3%W~fWJ_{B^;(fJm`#fN~U>j)lQ5tU?AAUPnkg0g#Xi~UC z=pPK9MofA4=Vd8E9auWnig>O3eDT{EHG_&d$pH=XF7RGV7;eOXtTVCdtg&ld@MgBV) z>Nx74AQ&wBxYKfiHw2Uf30ke#*)ZP;HA@xo#@PyC&^j)VnRsob{y<8iuBR2!mm$v&pvPY)4=p)g{yTxtLN zVb+}%5v39bE`4y!^xY8tqt<0qPrbnJ@tL>^o>)jMR3);#eAY#7o4_B~`c);a{f#HZ zsIQ4=R5_&_PjhrD%nJVN9dUkoB^1q|_OR%$fBC#8h$|u`^IPk;HCx12MMFo@V(u&$ z)Gj;_q#Lz(`V;m%LpU|h-$JmMT|&xeP=%KbA#H7g=E%p83|7xAB=V79Xhr9h5K$+; zV3gO{d>&r7J@GPU-s89Yo)&LwL3=aix(grQ_B#_$1imbtk^Mshsl0K^AqB;8Aoc(a zrP81m=HQ(>$UG^Q;8&ln;z(4EP{YIgoJ2?wi-}T#qIjV)&g&C+k&zRTz-QcdiW5wi z%Fc_??a9tE_L}s!{>BdtsQF?;S$$<|8EpBhiqhh}7Q>&?ANeG=`6X?Ev9Z({3*_lO zyINkDEuc)`=R|E^kX__+cw?5?M^J4#JgB}eg_)^Mx;gagk_&^#uKVr)EwNVHjS&BSH0pi6L|Nao7>EZZ6d0RBs;i#}%NnqawMGn3L{%g#lDz1tiwpd{YeE zK#dtI8~DKk{^Ny|K$jdyH@;u^tU}|_$)-Ye$-k?t zRQqML3*Mx0k65b`b^7v|$5C88n6(B5lDI2$nCyMMB~6x{{QIF2yCvqUmcv?UIVgQi zxevQ#Hm#KXb^8)4y9zoC!wAD96Sf%h;H9dWA0OzOr>oUr!aFdTlqg$FJ5OHuS1AIS z+QYjK8+Dm%HmtH)gO1~{whV}<^5Xqhy))RMpAKKPgu{&afvyjy1-Cql0&BA&|F|v8 zlT0@nlRlCYviOPB?I`Elk!sEfRyVU+oG4Xll~RKD`+^Ry2By48{EPg1Os_CnZLACa zfs1kfkEM|FkTUk-=;t$R zk*ePRHH-Oc@h>8ag{$$j4s@rfsd5DQmYfc=@u)+_gG0{DydxU(^^uLkT*5|YZ)X=R z4FHNvgmx9yh6Xm<_83ux=Me*{9o?23%qxRY>$dpOlfh+*$`j0*BK@bw|CoV-3CJYr z4;3y)n<2Cle&1zAL}0*45hs`}Rxmc_QAA!P`^@v;{u~{j zW?~9Sb;&3pu)K9HslsO9s3=VL;)9`J%7Tj)6M_P%5@Vb_r%CiZpNfHq>nG)B;Y_B-Dq<7Z3U^bXYROl) zY<8$$;A>xl8hvU#GipmF)wxh-X(*;uXW4CD9bj;s8JWHksMF- zS}YVVMA^ao9{l0r zmoBYu^8uILvohv`t!)F6{cF$d#Z-j184Y*?S#6CwkW&Xjyf| zUvF$0x-VK=cw(ebZqcCOH)?)0;)rZC?++e&XDQa<+pyYt=>r>;lOd!>mY1sXh$X?+ zqK)f!4YpA=SuAz1ai@!^_#c=d6F%;z6fk z7Rh!KlEvFTN;_MbnL2M~nd*~mdlyQ|V4@`46UnfV9Qdn9V*>=0b>Fc0(eW0*tedR; zhXv!xT&uWZ!8n-FzcfhsyGCxIRMysZ%e+5|L=znRI>P64?zYsXh!0>|&P?Jkj_H|o<3Qd>!ZLdsubIx|T@v*!Pf%=sE$2qxo4B%91C_j+2c zpJxWy6W(rP*&Fcu>Lq_N+e?RD1j}Mn)w9zZps z9+(_p(lPEGayq`l@xyRQ4`J#cbpL)S0iU*JJlBJ!gThnRR@gMy*L`{Bf7#U&iiUz8 zk8`b?9t2#3pQP-7c`5cZ4UZ)p{fq#842T*{VBjPll$UN)=^Ql1=&-y!j%2nS8;H;X z#V@i)npx-LTXkdP2vcy%DG7#8X3VzR%2+afPW~h%(HV`|N9J9+`o|du>$b+@gw46X zECLG1cHbUg#$Pgl45qVnPkLA_F|fZTlg_Cc>}Ee~k5MA?2`&)_v=p6Y48@9danRfvQi zcH+Tm(y|g|5vN!on-tkdTPJ_(SzD#lz_)9C4&#SI+QrO}`P30YmS>5JPFdg`=gEJ$ zQQh_>+=t$5Jaex4W+qP`ak{RQKL#Le!3U$-D=j|n|0@IdkI0UrJ@~u*LkHK}qSVIO zGJDsDRUB`?_;$+KqpY#DHjCBur z3ATyV3EW!MA<{oUNqF00;`x1s)^nLh9Iij2zCTWTP_WguYlrB+|E|WT<^I6=%$Hp&;QxtTxFyPRiF3t!tm%?Kpm2fL|~faa9{33$aeo?!uoW*V1==h7a}q#Ml9uQ*z}u0{9os< z6h<^u7I22VF=D3Gseu45iFJv%ujC64nL2(aGZKNkgVt)*MS=|}o5CS(p!aY|^Liun zIEnD6-#5zHrL-z*w3FsMt0Kb9rOUY&bpC+_#^-Fa?eDBRhN(xhKb7#=W{j4M^G3Ac$ootrH=6gv@Pg;wEOyOTyg6M zs_0q}J2umDer{U27H=50c2$E6o5BBZK zkaeUwzJD0qGS;Amy7Bv4z<%*ck1BIaUX!5@#|4}SJEVh6CVhpBYfyU6^+e$*)fVwm z0_`W#zk(6JC}Ze_i`i{s(I-_TSn($Q&QH@w?UA4VA=yx z|0+TAFMchT6Pw5L-ZtUEq2b;xXuWYrX}i~s32HHnY2H!YcBVn?DpRK!K%OJ|rOSrd z{r18-8@medAL>$y2JfHae-enCWyA;8E4ZOBKBt-Gbu zP7{y>d25`_D9*5TJhNjPp@M%^DHXK%TkjO?&?ZSU?GMG~5}gG4kYM8zkYHWES11n5|AZyVMEP5*w;qBjMIvfbJ@KijH_%e8{{2*T zh3BjWvm)G;rh`uL=>zkFXh5~%q(5#l@2Xnvt!@VeU*{0f3@p1#xRYi%$yhZ_yl`{5 zMB)ex#u{a|D9_QJtP$8-9?D11!v*p51Ir(`iQa_)zMWg*m04P_cSu0?AbH5v2o0f1 zhnl=RtKIWhF#WN!(D(oa2$jG{3?pMywM}+j40Q(py!j=Q4iR|3(V>wktvUWBn- z^nT3(lDjMKx{kwIN`VZ*;X;7p zOx(I|cRAQO##7*IX2iC`lvbrXWxBc6=)|T#@mhs>2qA3&j@-l>A1r zqw-6YMm<0@*0P$2fZ{$Jn()_21xzwd_IJ<-^o4!qzIN6Vr)*{c1Y$qj*o8v8xwnyvFpF~ zfp#Cu6aCmY7!*zDY_7nd@GIdFX z(41OQCSlrba=Hv}ny83n?< zH8L{=oRx~eZgEW01H3UUK*!lPj5GnTa=*otE}*Kko;%*$HU)80&^+XX@qy4FzQdP} zrtN`D8Eo}l0GQ!2-5vtYqkVLwD>Dpc z&#!*)y8FVpnzP}U!Ewn?z{X>|^03NHhU{@Nh#fGn;quM9lph)6tL0BW?n^k!SAFY{ z+DXzMj#!?4cy%B+Vi8JBTMd@~Z3S+`J9bc8+7x>jEhl3nW&xyeBlwpzBI={%&ZaO{ z)}C&1hYo02x|DN}H*f{oS#ESop(aS0cPEph50}NQk*X%pjX<+W#MQh2uC>@tTz<7e@!hNMh1(KvgI71(m4%&5yBX_=ng zoo*7wRA{Os(AjC@&%6UrbHL+ZZi3};;K6|&ieKq()$WB}ob;!04ISP==>8ua3Wo;c|%DrO|$D@f)Om5GoIu?3Oz%uasAL?p%XQY2B#4fu3O zc5n)^c?_zM`TUGw&d-8CEPEex6BFf@#fdr-;n39pIw_7;BCPM=V{Nau^G{HU&R8aFP*M7n+ic)T?C<0K~T=s_=w8V#Z;{O$>o0=v(ZOTMO!=j{9>)Y z8X>X)*@gc;3sHyXHgqcPh|gUotCgtM%RSiO&d%8DU(JNOOm_%k(!qxsj57ic=_^w} z^4%r#mF-ORYl^!mpvV>dki*+8k3imTyOy_Mwi?RRfJ_zz5?y8lh>o{rW9NdLy5CC1 z?{&aw!AgM6y|UOVT^%xa0uW@b59+9-oaMTom@%F=EemZ}`41C z!x;f{<2j#uiV9xSP2K@=yaSpIw(kG9NU12WzitmQ?~;bImh&OEl@wBJhbAUI9ZT}@ zky{?K*Z7PVJ+$D{$OgM5W#W6$=~)pV`FUq_y5T%!kV(fVHEJF3un~ZPBxw!#qyYu>+uAYSqw&nTM}_vU>9N>%5@A3F6n&VPN)AW_9$l zH2``7?A66#&hWbIVT$EBpYd{ve=#6iTA{aJMBd64-nIrbPa+>@Kkv77Dlkt-Q3I3^ zp}a(OY-PAs3u3GX@vwm6eB6W>Ps0okVk&OVxC;VOe1uc4foA@H1(6AK!auo+-e1gN6QC?sQ?ZX>jr#8r72{sxXxBGgen zV&KoUdq2rLjSD6jh%AC)$E$T1x@iW8;Jvu)6s)B3)kf(qhaMW(+TZ199b-GO{_g1V zYANh0@-8U@a=aol5q<(J%rm&e9&1zkP5!EPFx@f|fN$FZfR7-)!R zzx-Ohp9bTC0EriJ8z2eZHKCg!z2hMHI**yt{|P;*6ZD`Ph>k`u*6>i#(MvzqFn3fcz7CY=-AQ9V4>ZsmuhHobLlfP}%H;=u5c9aZ_~X_6 z^@<`|ZvpIQ8edG}`G3{j3SPo{*fasyNFamZ4FIKz9>O^1$CmcH{|lwEtdmccM?lHa_>bCAC08cA_M^ zxl3{s@;lg#*JkA2RoI#_hM>^tosn={gyTJ{Zf$yJ{{D|P1Z+`vnS?Ay%+sjyyolS) z6wbF1Q9lUxl&gC|xk$h(H9bX_H%@&ZcQ9J0@dw%>Jop6~a0e)IME{aap~ zbKlqX8SnA=_^d`eRiSqu&!le%@^x7yMSkR$cIhNDJJ#$!#lZ``A_RFja78fn7SHOj0gSdpaa#X`W_7Fv(*Ma#}~i)^m^f7fTXS zn=u_6Ax21X0I6PB4>;!8SDs||yhlpM$vy7d*y=(!Nu8vS_{3U6G&Ru=CJv67_gLk! z37AajNa0z?&%9uM#P+6#<*18=voj5SOXdR4P0cK#qWqk*jXVtpJ&O~d3l(%V`Fw#x zWJKspS7Lsj!TNCi>GT492}PueC6ZA!%JHfmqXn~FiIKaFU!IBR zp1p3A)^o-CiYn%Pz{}gHP}yfx^Cc$Fd8SSe94kD)!yx0*Hxasq=_SnQWMraJfTAwF zu43^W9bi23+>=ivG_D^||4jWtF=3Zinin(M`tZBMTim2KI75d|M+#owli~+HFODCc zoIjY6jNMJq=N~dP7~iIvcz_Pnt4I=CnMV(Q7Vi*{UQ^PVQJwKGHEXY-(UsaVjdg6f zZsOT$#N49;R_K`{YBpQ#6AwmL0b-x|*8F&N?Ks!HJ3Ju*GmDx6dnOXQH){+7Qr2tL zHXqFBBBj}A6V#DHqxOxBE$o3S;=clF0Gov=+NNB8+*y4zQq3uN8~z>MXwYjc1v zaEtgNd?C(d+TT3jb6HeAp5Ml`<+k?+`H=x(H){@7zw}Sg@iY>oZ$4O5uXg)&aDHZE zh8bVBns~C8_|$gp3>HO3Xk)o&sL}{K%&OkcqSEE60@hAvFeZK`-0zCL!Us#@3BBW4 zJ>6L!gT_e-ESn#mNlWK_>D86sIC^*bsY(ejn%042G>!Z}C46|z3t}waKJ$fz*C7iT zT{KU(1U%Qqy!x_q`&NdFc_r^6Rqi0?1ol-Y%*eFvoGVNHv-crAmrPD~2uZbI%-mtA z@VSGEKJ%!8`|I2mT)d21HqZ+gRyyzR2haDcx->|9le%#2+S$i9Nxrs|HS)kE_tQb= zlU!J7qr!PHN>^$jHCzq7O@PHBTeI|z7US1}_H9s{+rsnW8&elTpdLB|B7RrSq-qud zY@?ue!{(-NE=~RYSx2SO;|cQx3wvbM=!fq9X>ek`O#pO5bvS4OItpW)GTb|$KwDMw zRwWBpkKr;NYzWys{G4vZY-iV0^tUe{!U&^@{*Un;Nc+NH*OT4-yKdJk16-{_$s4G| zM-lyjV;i|y-t_gI)Dm1B!7U^1eb zHV09X%g2h(=dMh!n_!Be;+s}89pkrLZ(BmCFtfd)x}Uy-nFKTLQASwX2eYYyRzZ5W z*9HN9w9cUJGh*T~z-g<>Z1xVW277JoJ~G0^8hSkV5 z;`WT-@vhr(fZm~@@TdLn%x~nFYnc9Uv+Om>-O-zBh>{QdRC3J#!6c0Hg7oV3KX)gQ z2A5ro@vCD^ljj`l0H5i^axmCXpYR;0e=8iF%Ug8r*uwac4-#5bPqtK@!LAHT=iMp4 zbTm&3uijqss+EoV$ZnRA7HUw1Sg4!`+lU9Vr<7#Aav+;KvWfMq{MhaU4g@x+dhhpy z`+T|7`;{FTY)Yl~K$Q?HgvHsRyl=!y>vd3`{SfUBM!s@4t;tF6KXLBYFil%gB-nDO z7#S0=+B2yLb0x33kBsY4k;st%^OPGpCZY^WqMoSN%G(@>Xr-J1Ww!iRCb4j$TMVou z^Rok9D+Be&C}4yGxQA&kNn^ewtEdX9D+LS1a~^{QCk%vpmYeC`nO0UnJ0Z{mpFUhjJT@mtZjKIg-RjPRlO>xY z;|fkXPhgA-74sTslw1;f2*U30M!Xlr*@eT+4i+2g%n6ruUzWJ;)|5m);0%_(?pKvC zTFfI%{sRjp*#D^|9De}9@s6qYEnomZBMO#Zi@W-GzWfBzwYr|91_?HV5@1IVH z-qPet^FOwH%M>k9@3??Df<{{`E0BWoK3w@PkVN@Ay&zF!ez!Sv@}`Izc{qoD{Y9t^ z0z-{S@Lgk#Lo>}Bljg_1Az=P5PXI^xAHJqYqz>f+yMiUn}ZgM0b z1kxC9aJed}Wp7-k=i_8P+DQ{^Xq+Lt&h2S#aTumfW&`@*yfxQ&xYUgheY)8*XENAJ zhz)KR<@A_J9}F2kcw$4W$V`M3qg!z)*s#febkZi%N<}v5$1f>RjtyIdChOt?YX%oB z+&{?GM6q&}9FAI|07p#tAy&fNJwO|HD zr)f&%(Ke^}xcKqzOb<=SR^Bng%l@eM*dz*Ql=U6Y98=_0wV=ySGJy3fq#U*K!mV6I z2<&=OY>pJ->^ci{8_%}y@0|k(&3KN!Bj6Ec7G+%oJ z1%8$Angn7j%BHGTD9Sl;j6W?WqNjq0A>4cjy)yqEY z0pz9(YrS-Wb)Z(O4VEm9@CTUEw+0GA8{Aj@W6+Zp3GP|7n8aSj-Z3G(d5&<#G1opG z>xd+YfepX&V;a{=HHwH7oD9y%YtE6yN>Z@;B}bAlJe);Igxp)b|EDCM0L7-|m<_kH z)WLZlcbw2Oe2DC@H;N!$Wh2zGgDb_bqeBk+x3-sU;xz?q*x1C94c7!SM@N&mwF$RQXwmnO-acK)|*C}D<+OsgZ=nnv~Jh8 zge1S(9$G$#C)Ojwl zrUzLt-Uaq;lhymuaz|TF67r>*Hy>`!&#}n_OJO+$T@}7(d2F+bp}T_As;#mV@H6zP zu8oyj^-+ZPWBnK@EpKwb*LqaWVBZNe&5Dq9xC1P)ym#33^Z;hVEOMnS4jr%Q9o0H7%ObR(zG;APUAGVNhVyU8}QZ0T>yH-kJu z6P<7N7jAd~1*9o*+j2YmH%!v04kN7NUW?yUj7#rG$vV7VC>>%K7&n)gNb%1>BLL$+ z`9odkcWX$bP{A?+CS$3D#`))|*LV>bwIyuRozQxoEl$Zi!N7C_dF@XtVYZQeG0?*u z13_yTO%*aB(<)c0A~Fc(XXZ!lH0#TegQ3K-ZOy&)?X5D9bls53Av_^TbqiT ze-)A^U8Ep)xr-?n{7#1AsFAo&+yD|Xc?noltlON({SNlEteXEW(x`W&5ZdRVeFh7= za^uQo|3xIbiD}Ira~~4=j;G8>adMn1I)j^#ckjk4k=hS)F;G?qwtH*K^RL|b9xj_P z1TL*Qcesy>(8pSK)inlNsuD8R-UhhoM(VJwjgr0%pZ1|FzUx_3 zO0G<7x0!U;x86uG#_>;Em6*(h(!etia_?L+MW6->)il#SFVk@34j`*|3qIlbZx_F5 z0ebT$pyGwuQbcS>>OJx09y{a&s00LZtiwbOE2i||6Fs@JNnt} zcTakI;^9mw!y$eZZ*8B`g^n(Mzy3<3Ksd18DSw!iVq2@(!a-Z5g(lQx<~FCiHh0Tq z*N1~QaGHwo4XG_uMx1RAJjkG&Z&^mvY^%HS!Q=}Xpew__}ZoZM#s=G7z`PmM(tHp4lP#FDpe_iU}f6j`DV)ir{P@6}-=U*F;5v|qLRgd(Nrq&zh`<_%*x1_(R{ zo6n)R$v@@hTXm;J>)zSPHj)S)t8fm1OLU_|f2U!XX3xL;b(_a#!KfnL!dU@8 zY))RqQ0<9Dvs)yXHBPOa9Iri%ktAV_vCHDCeHLlc4)mhyhXJy@PF*z+LjOE(jlvoKkR1-^??&9m z&(;0%EGFw{m#obsR1+9cE7u*8{0-x00^oVp@Dp?fDAg=~5Lr%8t@&!Xa?e!$B+-OL z+zm_{pV8LqHi6NF`r#*ofrN2ziPRHTL}PVSLrC#x?H;COTtSO`Sg}!p8b*!0h{xsH zoXXY+9f^~u%zRhD@TVU_4l0zb5iBxsU|K`}!dP?!ACl%iZO;_;u3yhd$udE+LkHUz zb?J%__wF`?>xS-30xZ0wZXe90`katr`eiBW+VAWmzY-ZSx7F2|s@1f-XVQ3_rBa79 zVE&G{Z0wWunjTfH`XWYDJr|!Uw9AO^6Yp!BoQ+7SY+@fylWKk`!$Kl7du28`Z((kI znySF8fy)Pl#LLDGyn2i27*B=~&dpo|w6z!Wz<|rFW2nF9woBWWA<0}M*}bmh@jZAlB-ywO%if}>HDANZsuRjox}wc6?GnIA@+P)4wSf| z=8mWI@8<3ojMkj|8hw!6?d)1&!OuRbQ~#U|ospX!{;gt|P>X;ZT6uIRwZ zFsJgz)1XB0zPEw_V2FN&l0GkiUGv69r^uC4NWWOfxA(;+D!fI0kKW}-USe0e~Zb9JL9a!o?S> zF>h;B5u?$uQSnmOy<`L*kf7im2Bup%*i7! z#F3!x3!AXq;g3@)d=%R-JLii2!^R!`=(J;-50?>d&r0L{r;7NiKs5=wQjOhyUkU~> z4cyTtNOT@|RnV@2RRF(5q&9stPAf!6s6ECsVF;j;f{J=FLwN_O;VPOT*;>rX1olcu z3v>5Q_ce;!lgOf=pQABb+CqY?a<}%9?4#a{qA>!yo()x7;_|ONtln!Fq+$IjbP6Bw zng(Y5)VUMvn?f}Qt`<)s4M+r(gX5HgnaDW1xD}pgOx3y*F*d?+d_1SRFIPd|LMh3H zv9j2rSX61kVXoi9I;R&XJDw0|>6G^P0SFY~hZ)~=GR+5e}eR{_aFW$vQgR*ynm;A2R4qQx~K1d_+LZMzC458zpw&mQulw2P@@P@ z>i{UPf_CAAm6dgR0&1t5$+q?qPxd&p*aTYFl_nH&Ylmr$*puJ5U~^th`pyddsxGvh ztm5|t2}^#BoC8sE$sHOJwdrrJIgZ)Xfs89G?Xm@)zgs+;Ee39m*DKW=Z$c1WJQ(%} z7PE|jNj4LX6$`-f9|#vtBf5Tx`UU#>h6q+ULBJ?4)$x`h2Y|*o@{7Qj9xflIt3Kdd zxORFPt;t{77y+W6?N4qcMo>N3A5nu!wzcRt+l)dlw6z^rYBrso-I6cX=`0MarfJks zN3#5k!r*bd!1lNQ7qJH|4n~6$9I?5g!xud(*L>{a)U%BKp`0@n9AjwjT@UZw<;)Yr zfYT0>0E?vE@XhK~!u~y8BY-=z!*QuKJ8OO>mj<}81H|z4sMCS%FRIR9NxQRp<>K>n z9kkrEvTlg@pU;3S-dA%5U%J8_7oLc*#-G^|2OBeb5~ft$hkLsB&?e);nuXAnlXVbx zdDWT&LSz$`9tQw|{GP{R)$(ZKMtY^x_*38k22p2h!5*&qMZA4P%0yy&QO{>@Yso6= z>bXe3?3&Tah(;PS=t$rw2VWD9=CH1R6D$4o^tFlQ=|Mb)j?V?Uyhx{)J4~Re0x{%& zdN$jjL(|nu9BL5cOh~uTdJ)-eJ_WsoFQE1r=QGDyy#8zMM{g>+m5eP?;q_tI0PT1# zGLAR5?5hNR)V=~j{1vppMxVZlln^O&VdP~^Rhf1O7+8hc2mBwg>heO-{v)uzXB8B> z9_Wr&y8s4iTfe+xNe?}P@&EN1fLFQS$1 zoz<;ny4i^z3`K#b^nDr;t`4iLQKPJz@l8T(kMMP!1?6Befk!{tw^& z^kfL)I!1@1o=eQ}n~9DI{1rj}A2;Y}a|U@HH|rc!MmvL5jnxO>n~msfei?W)Vmt;~ z^=mfe1HXW0eBeR#fHek`v_#LfVBa@Bywg-l^fj#?c=4IK-xx>k8lK)Z2!ck`ONrB1 znMpYaSd^GQEu?HSSMt96nA^7tWZdfyKE-|pXmyED>>b{F(cTMzvP|&q(3}TW>~1+0 zI=ogqZjo8qX)oeMH=5nDdBUAel{Qh)GFGFNv%JMV)MjXV!uKNu5JB})jMVbhn2K|* z7%LEIZf9?NAd-miVvbKtcRcoGIb;o*viFKe!S?-fF$Q!UTk+|9hd~7pYsA=D8$>>O zrMNZ@DexEc6)WhkoIa_ze{o&P-&-&j)nZZs@!>foN!qvvV8cNOTw0L=dx@N*b(}PW zFCRAN9V(Jw?7-$G^h_Psy!6SYG#GiX-!lfbHP7lhs#gs6bw|k?JbSz&=(Q0r2I^My z_4D`N9YE43o_0|Z#y2wffa=|VG4(23q{G-5TJ6qCpfXU{ShZ@&gdoDP^FX(-$|Y9b zbh{%t{A4%eWFEU2k&fW>3_3;r&3Ut{EPl-!>L*bF#3*mFuYrpFoq=Z13RrhX<y>lk4ksdp8yhY;6R zBQ<)KjgN8;&gh&6of8@$uS; zRNoY>*Ay*!1k7HI&-uM?mVj>d}Vo8N7HI z-Xv$mZ#LT+#qm?;S3<~r_Nt5$lfIW%S5l!=O#&f5FPQBn1|`%Ucm$pg;tAbI-uPK` zBW$alX#bFHn%@*GnOezpA6vS>$q*P&aDnS}C{$EPs1fAw z_`R5e?ZFIzrnLTcC>A({fw~r4>{<;@T*tr{zqt4<<|4E;1!?V|b;hlKnmJP$^nVj0 zl5}FXUaVf@%VQYBVQa@>>*vyWe|Oj;1VC=$VS^8<$j_9b`*P3_ND!|;Z5RiWg5h9J zGJ#ayTXNnJCGRNv%cT~dgeXp4F+j#o98^v$9j{ZI2
th8&^CFdXuZFZkmt8N1o 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%0Di9jD;KQe3K-&QPF^go;AYjP>yH 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 z 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

-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�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 ({ - createWebview() { - editorDispatch('coderoad.open_webview') - }, - async newOrContinue() { - // verify that the user has an existing tutorial to continue - const hasExistingTutorial: boolean = await tutorialModel.hasExisting() - machine.send(hasExistingTutorial ? 'CONTINUE' : 'NEW') - }, - testRunnerSetup() { - const codingLanguage: G.EnumCodingLanguage = tutorialModel.config.codingLanguage - editorDispatch('coderoad.test_runner_setup', codingLanguage) - }, - initializeNewTutorial: () => { - console.log('initializeNewTutorial') - }, - tutorialContinue() { - console.log('tutorial continue') - }, - // tutorialContinue: assign({ - // // load initial data, progress & position - // data(): CR.TutorialData { - // console.log('ACTION: tutorialLoad.data') - // if (!currentTutorial) { - // throw new Error('No Tutorial loaded') - // } - // return currentTutorial.data - // }, - // progress(): CR.Progress { - // console.log('ACTION: tutorialLoad.progress') - // return currentProgress - // }, - // position(context: any): CR.Position { - // console.log('ACTION: tutorialLoad.position') - // if (!currentTutorial) { - // throw new Error('No Tutorial loaded') - // } - // const {data} = currentTutorial - // const position = calculatePosition({data, progress: currentProgress}) - - // console.log('position', position) - // return position - // }, - // }), - testStart() { - editorDispatch('coderoad.run_test') - }, - testPass(): void { - editorDispatch('coderoad.test_pass') - // git.gitSaveCommit(tutorialModel.position) - }, - testFail() { - editorDispatch('coderoad.test_fail') - }, - // @ts-ignore - progressUpdate() { - tutorialModel.updateProgress() - tutorialModel.nextPosition() - }, - - // assign({ - // progress: (): CR.Progress => { - - // console.log('progress update') - // const {progress, position, data} = context - // const nextProgress = progress - - // nextProgress.steps[position.stepId] = true - // const {stepList} = data.stages[position.stageId] - // const stageComplete = stepList[stepList.length - 1] === position.stepId - // if (stageComplete) { - // nextProgress.stages[position.stageId] = true - // const {stageList} = data.levels[position.levelId] - // const levelComplete = stageList[stageList.length - 1] === position.stageId - // if (levelComplete) { - // nextProgress.levels[position.levelId] = true - // const {levelList} = data.summary - // const tutorialComplete = levelList[levelList.length - 1] === position.levelId - // if (tutorialComplete) { - // nextProgress.complete = true - // } - // } - // } - // console.log('progress update', nextProgress) - // storage.setProgress(nextProgress) - // return nextProgress - // }, - // }), - // stepLoadNext: assign({ - // position: (context: any): CR.Position => { - // const {data, position} = context - // const {stepList} = data.stages[position.stageId] - // const currentStepIndex = stepList.indexOf(position.stepId) - - // const nextStepId = currentStepIndex < stepList.length ? stepList[currentStepIndex + 1] : position.stepId - - // const nextPosition = { - // ...context.position, - // stepId: nextStepId, - // } - - // return nextPosition - // }, - // }), - loadLevel(): void { - tutorialModel.triggerCurrent('LEVEL') - }, - stageLoadNext() { - console.log('stageLoadNext') - tutorialModel.nextPosition() - }, - loadStage(): void { - tutorialModel.triggerCurrent('STAGE') - }, - // @ts-ignore - // updatePosition: assign({ - // position: () => calculatePosition({ - // data: context.data, - // progress: context.progress, - // }), - // }), - stepLoadCommits(): void { - tutorialModel.triggerCurrent('STEP') - }, -}) +// import {machine} from '../../extension' +// import {cache} from '../../services/apollo' +// import {editorDispatch} from '../../utils/vscode' +// import * as CR from 'typings' +// import * as G from 'typings/graphql' +// import tutorialConfig from '../../services/apollo/queries/tutorialConfig' + + +export default {} + +// export default { +// createWebview() { +// editorDispatch('coderoad.open_webview') +// }, +// async newOrContinue() { +// // verify that the user has an existing tutorial to continue +// // const hasExistingTutorial: boolean = await tutorialModel.hasExisting() +// // machine.send(hasExistingTutorial ? 'CONTINUE' : 'NEW') +// }, +// testRunnerSetup() { +// const result = cache.readQuery({query: tutorialConfig}) +// console.log('result', result) +// // const codingLanguage: G.EnumCodingLanguage = result.data.codingLanguage +// // editorDispatch('coderoad.test_runner_setup', codingLanguage) +// }, +// initializeNewTutorial: () => { +// console.log('initializeNewTutorial') +// }, +// tutorialContinue() { +// console.log('tutorial continue') +// }, +// testStart() { +// editorDispatch('coderoad.run_test') +// }, +// testPass(): void { +// editorDispatch('coderoad.test_pass') +// // git.gitSaveCommit(tutorialModel.position) +// }, +// testFail() { +// editorDispatch('coderoad.test_fail') +// }, +// // @ts-ignore +// progressUpdate() { +// // tutorialModel.updateProgress() +// // tutorialModel.nextPosition() +// }, +// loadLevel(): void { +// // tutorialModel.triggerCurrent('LEVEL') +// }, +// stageLoadNext() { +// console.log('stageLoadNext') +// // tutorialModel.nextPosition() +// }, +// loadStage(): void { +// // tutorialModel.triggerCurrent('STAGE') +// }, +// stepLoadCommits(): void { +// // tutorialModel.triggerCurrent('STEP') +// }, +// } diff --git a/web-app/src/state/guards/index.ts b/web-app/src/state/guards/index.ts index fc2d8eb1..024b3cd2 100644 --- a/web-app/src/state/guards/index.ts +++ b/web-app/src/state/guards/index.ts @@ -1,41 +1,43 @@ -import * as CR from 'typings' -import {TutorialModel} from '../../services/tutorial' +// import * as CR from 'typings' +// import {TutorialModel} from '../../services/tutorial' -// TODO: refactor into a single calculation -export default (tutorialModel: TutorialModel) => ({ - hasNextStep: (): boolean => { +export default {} - const nextPosition: CR.Position = tutorialModel.nextPosition() +// // TODO: refactor into a single calculation +// export default (tutorialModel: TutorialModel) => ({ +// hasNextStep: (): boolean => { - const sameStage = nextPosition.stageId === tutorialModel.position.stageId - const sameStep = nextPosition.stepId === tutorialModel.position.stepId +// const nextPosition: CR.Position = tutorialModel.nextPosition() - const hasNext: boolean = sameStage && sameStep +// const sameStage = nextPosition.stageId === tutorialModel.position.stageId +// const sameStep = nextPosition.stepId === tutorialModel.position.stepId - console.log('GUARD: hasNextStep', hasNext) - return hasNext - }, - hasNextStage: (): boolean => { - const nextPosition: CR.Position = tutorialModel.nextPosition() +// const hasNext: boolean = sameStage && sameStep - const sameLevel = nextPosition.levelId === tutorialModel.position.levelId - const sameStage = nextPosition.stageId === tutorialModel.position.stageId +// console.log('GUARD: hasNextStep', hasNext) +// return hasNext +// }, +// hasNextStage: (): boolean => { +// const nextPosition: CR.Position = tutorialModel.nextPosition() - const hasNext: boolean = sameLevel && sameStage +// const sameLevel = nextPosition.levelId === tutorialModel.position.levelId +// const sameStage = nextPosition.stageId === tutorialModel.position.stageId - console.log('GUARD: hasNextStage', hasNext) - return hasNext - }, - hasNextLevel: (): boolean => { - const nextPosition: CR.Position = tutorialModel.nextPosition() +// const hasNext: boolean = sameLevel && sameStage - const sameLevel = nextPosition.levelId === tutorialModel.position.levelId +// console.log('GUARD: hasNextStage', hasNext) +// return hasNext +// }, +// hasNextLevel: (): boolean => { +// const nextPosition: CR.Position = tutorialModel.nextPosition() - const hasNext: boolean = sameLevel +// const sameLevel = nextPosition.levelId === tutorialModel.position.levelId - // TODO: ensure this accounts for end - console.log('GUARD: hasNextLevel', hasNext) - return hasNext - }, -}) +// const hasNext: boolean = sameLevel + +// // TODO: ensure this accounts for end +// console.log('GUARD: hasNextLevel', hasNext) +// return hasNext +// }, +// }) diff --git a/web-app/src/state/index.ts b/web-app/src/state/index.ts index b4277c50..9a9d3f54 100644 --- a/web-app/src/state/index.ts +++ b/web-app/src/state/index.ts @@ -1,7 +1,6 @@ import {interpret, Interpreter} from 'xstate' -import {TutorialModel} from '../services/tutorial' import * as CR from 'typings' -import createMachine from './machine' +import machine from './machine' import stateToString from './utils/stateToString' // machine interpreter @@ -15,14 +14,12 @@ class StateMachine { } private service: Interpreter<{}, CR.MachineStateSchema, CR.MachineEvent> - constructor(tutorialModel: TutorialModel, editorDispatch: CR.EditorDispatch) { - const machine = createMachine(tutorialModel, editorDispatch) - + constructor() { // format state as a string and send it to the client this.syncState = (state: any): void => { const stateValue: string = stateToString(state.value) console.log(`STATE: ${stateValue}`) - editorDispatch('coderoad.send_state', {state: stateValue}) + // editorDispatch('coderoad.send_state', {state: stateValue}) } // callback on all state changes @@ -54,4 +51,4 @@ class StateMachine { } -export default StateMachine +export default new StateMachine() diff --git a/web-app/src/state/machine.ts b/web-app/src/state/machine.ts index 7afcb33a..4b447857 100644 --- a/web-app/src/state/machine.ts +++ b/web-app/src/state/machine.ts @@ -1,172 +1,170 @@ import {Machine} from 'xstate' import * as CR from 'typings' -import {TutorialModel} from '../services/tutorial' -import createActions from './actions' -import createGuards from './guards' +import actions from './actions' +import guards from './guards' -export const machine = (tutorialModel: TutorialModel, editorDispatch: CR.EditorDispatch) => - Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( - { - id: 'root', - initial: 'Start', - states: { - Start: { - onEntry: ['createWebview'], - initial: 'Initial', - states: { - Initial: { - on: { - WEBVIEW_INITIALIZED: 'Startup', - }, +export const machine = Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( + { + id: 'root', + initial: 'Start', + states: { + Start: { + onEntry: ['createWebview'], + initial: 'Initial', + states: { + Initial: { + on: { + WEBVIEW_INITIALIZED: 'Startup', }, - Startup: { - onEntry: ['newOrContinue'], - on: { - CONTINUE: 'ContinueTutorial', - NEW: 'NewTutorial', - }, + }, + Startup: { + onEntry: ['newOrContinue'], + on: { + CONTINUE: 'ContinueTutorial', + NEW: 'NewTutorial', }, - NewTutorial: { - initial: 'SelectTutorial', - states: { - SelectTutorial: { - on: { - TUTORIAL_START: 'InitializeTutorial', - }, + }, + NewTutorial: { + initial: 'SelectTutorial', + states: { + SelectTutorial: { + on: { + TUTORIAL_START: 'InitializeTutorial', }, - InitializeTutorial: { - on: { - TUTORIAL_LOADED: '#tutorial', - }, + }, + InitializeTutorial: { + on: { + TUTORIAL_LOADED: '#tutorial', }, }, }, - ContinueTutorial: { - onEntry: ['tutorialContinue'], - on: { - TUTORIAL_START: '#tutorial-load-next', - }, + }, + ContinueTutorial: { + onEntry: ['tutorialContinue'], + on: { + TUTORIAL_START: '#tutorial-load-next', }, }, }, - Tutorial: { - id: 'tutorial', - initial: 'Initialize', - onEntry: ['testRunnerSetup'], - on: { - WEBVIEW_INITIALIZED: '#tutorial-load-next' + }, + Tutorial: { + id: 'tutorial', + initial: 'Initialize', + onEntry: ['testRunnerSetup'], + on: { + WEBVIEW_INITIALIZED: '#tutorial-load-next' + }, + states: { + Initialize: { + onEntry: ['initializeNewTutorial'], + after: { + 0: 'Summary', + }, }, - states: { - Initialize: { - onEntry: ['initializeNewTutorial'], - after: { - 0: 'Summary', + LoadNext: { + id: 'tutorial-load-next', + after: { + 0: [{ + target: 'Stage', + cond: 'hasNextStep', }, - }, - LoadNext: { - id: 'tutorial-load-next', - after: { - 0: [{ - target: 'Stage', - cond: 'hasNextStep', - }, - { - target: 'Stage', - cond: 'hasNextStage', - }, - { - target: 'Level', - cond: 'hasNextLevel', - }, - { - target: '#completed-tutorial', - }, - ], + { + target: 'Stage', + cond: 'hasNextStage', + }, + { + target: 'Level', + cond: 'hasNextLevel', }, + { + target: '#completed-tutorial', + }, + ], }, + }, - Summary: { - on: { - NEXT: 'Level', - }, + Summary: { + on: { + NEXT: 'Level', }, - Level: { - onEntry: ['loadLevel'], - on: { - NEXT: 'Stage', - BACK: 'Summary', - }, + }, + Level: { + onEntry: ['loadLevel'], + on: { + NEXT: 'Stage', + BACK: 'Summary', }, - Stage: { - onEntry: ['loadStage', 'stepLoadCommits'], - initial: 'Normal', - states: { - Normal: { - on: { - TEST_RUN: 'TestRunning', - STEP_SOLUTION_LOAD: { - actions: ['callSolution'], - }, - }, - }, - TestRunning: { - onEntry: ['testStart'], - on: { - TEST_PASS: 'TestPass', - TEST_FAIL: 'TestFail', + }, + Stage: { + onEntry: ['loadStage', 'stepLoadCommits'], + initial: 'Normal', + states: { + Normal: { + on: { + TEST_RUN: 'TestRunning', + STEP_SOLUTION_LOAD: { + actions: ['callSolution'], }, }, - TestPass: { - onEntry: ['testPass', 'progressUpdate'], - onExit: ['stepLoadNext'], - after: { - 1000: 'StepNext', - }, + }, + TestRunning: { + onEntry: ['testStart'], + on: { + TEST_PASS: 'TestPass', + TEST_FAIL: 'TestFail', }, - TestFail: { - onEntry: ['testFail'], - after: { - 0: 'Normal', - }, + }, + TestPass: { + onEntry: ['testPass', 'progressUpdate'], + onExit: ['stepLoadNext'], + after: { + 1000: 'StepNext', }, - StepNext: { - after: { - 0: [ - { - target: 'Normal', - cond: 'hasNextStep', - actions: ['stepLoadCommits'], - }, - { - target: 'StageComplete', - }, - ], - }, + }, + TestFail: { + onEntry: ['testFail'], + after: { + 0: 'Normal', }, - StageComplete: { - on: { - STAGE_NEXT: { - target: '#tutorial-load-next', - actions: ['updatePosition'], + }, + StepNext: { + after: { + 0: [ + { + target: 'Normal', + cond: 'hasNextStep', + actions: ['stepLoadCommits'], + }, + { + target: 'StageComplete', }, + ], + }, + }, + StageComplete: { + on: { + STAGE_NEXT: { + target: '#tutorial-load-next', + actions: ['updatePosition'], }, }, }, }, - Completed: { - id: 'completed-tutorial', - type: 'final', - }, + }, + Completed: { + id: 'completed-tutorial', + type: 'final', }, }, }, }, - { - actions: createActions(tutorialModel, editorDispatch), - guards: createGuards(tutorialModel), - activities: {}, - }, - ) + }, + { + actions, + guards, + activities: {}, + }, +) export default machine diff --git a/web-app/src/state/utils/stateToString.ts b/web-app/src/state/utils/stateToString.ts index 5f690a6e..109357c9 100644 --- a/web-app/src/state/utils/stateToString.ts +++ b/web-app/src/state/utils/stateToString.ts @@ -3,6 +3,7 @@ const stateToString = (state: string | object, str: string = ''): string => { const keys = Object.keys(state) if (keys && keys.length) { const key = keys[0] + // @ts-ignore return stateToString(state[key], str.length ? `${str}.${key}` : key) } return str diff --git a/web-app/src/utils/vscode.ts b/web-app/src/utils/vscode.ts index 87b82c1c..8aa8083d 100644 --- a/web-app/src/utils/vscode.ts +++ b/web-app/src/utils/vscode.ts @@ -3,14 +3,17 @@ import {Action} from 'typings' declare var acquireVsCodeApi: any // @ts-ignore -window.acquireVsCodeApi = () => ({ - postMessage(event: string) { - console.log('postMessage', event) - } -}) +if (!window.acquireVsCodeApi) { + // @ts-ignore + window.acquireVsCodeApi = () => ({ + postMessage(event: string) { + console.log('postMessage', event) + } + }) +} const vscode = acquireVsCodeApi() -export function send(event: string | Action) { +export function editorDispatch(event: string | Action) { return vscode.postMessage(event) } From 0b9ba417ec45acead28a95a3acd28b6ae1eec728 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 1 Sep 2019 20:27:30 -0700 Subject: [PATCH 067/117] cleanup new router --- web-app/package-lock.json | 10 ++++ web-app/package.json | 4 +- web-app/src/Routes.tsx | 3 ++ web-app/src/components/Router/index.tsx | 23 +++++--- .../src/{ => services}/state/actions/index.ts | 3 -- .../src/{ => services}/state/guards/index.ts | 0 web-app/src/{ => services}/state/machine.ts | 1 - .../state/utils/stateToString.test.ts | 0 .../state/utils/stateToString.ts | 0 web-app/src/state/index.ts | 54 ------------------- 10 files changed, 32 insertions(+), 66 deletions(-) rename web-app/src/{ => services}/state/actions/index.ts (95%) rename web-app/src/{ => services}/state/guards/index.ts (100%) rename web-app/src/{ => services}/state/machine.ts (98%) rename web-app/src/{ => services}/state/utils/stateToString.test.ts (100%) rename web-app/src/{ => services}/state/utils/stateToString.ts (100%) delete mode 100644 web-app/src/state/index.ts diff --git a/web-app/package-lock.json b/web-app/package-lock.json index 99c5a12c..fb520232 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -3134,6 +3134,11 @@ "tslib": "^1.9.3" } }, + "@xstate/react": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@xstate/react/-/react-0.7.1.tgz", + "integrity": "sha512-6LKbMCWPtLfKL7Ph8E781qoKmypSPGS5e7e+LkTK/nhRpFcj6n3MfCl96mNWsdYMr7tb8ISQDZcxI+Ou0BpurQ==" + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -18817,6 +18822,11 @@ "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==" }, + "xstate": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/xstate/-/xstate-4.6.7.tgz", + "integrity": "sha512-mqgtH6BXOgjOHVDxZPyW/h6QUC5kfEggh5IN8uOitjzrdCScE/a/cwcRvgcH8CGAXYReDNvasOKD0aFBWAZ1fg==" + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", diff --git a/web-app/package.json b/web-app/package.json index 655455ed..a79c4673 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -28,6 +28,7 @@ "dependencies": { "@alifd/next": "^1.17.7", "@apollo/react-hooks": "^3.0.1", + "@xstate/react": "^0.7.1", "apollo-boost": "^0.4.4", "graphql": "^14.4.2", "markdown-it": "^9.1.0", @@ -37,7 +38,8 @@ "react": "^16.9.0", "react-dom": "^16.9.0", "react-scripts": "^3.1.1", - "typescript": "^3.5.3" + "typescript": "^3.5.3", + "xstate": "^4.6.7" }, "devDependencies": { "@babel/core": "^7.5.4", diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index cc1ab96b..bb7d55b6 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -46,6 +46,9 @@ const Routes = ({ state }: Props) => { return (

+ +
Initial
+
diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index 21a3a53e..c648ffb6 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -1,4 +1,6 @@ import * as React from 'react' +import { useMachine } from '@xstate/react' +import machine from '../../services/state/machine' import Route from './Route' interface Props { @@ -6,19 +8,26 @@ interface Props { children: any } -const stateMatch = (state: string, path: string) => { - return !!(new RegExp(`^${state}`).exec(path)) -} +// const stateMatch = (state: string, path: string) => { +// return !!(new RegExp(`^${state}`).exec(path)) +// } // router finds first state match of -const Router = ({ state, children }: Props) => { +const Router = ({ children }: Props) => { + const [current, send] = useMachine(machine) + const childArray = React.Children.toArray(children) for (const child of childArray) { - if (stateMatch(state, child.props.path)) { - return child.props.children + if (current.matches(child.props.path)) { + if (child.props.send) { + return React.cloneElement(child.props.children, { send }) + } else { + return child.props.children + } + } } - console.warn(`No Route matches for ${JSON.stringify(state)}`) + console.warn(`No Route matches for ${JSON.stringify(current)}`) return null } diff --git a/web-app/src/state/actions/index.ts b/web-app/src/services/state/actions/index.ts similarity index 95% rename from web-app/src/state/actions/index.ts rename to web-app/src/services/state/actions/index.ts index f08ef270..27f4fbc5 100644 --- a/web-app/src/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -9,9 +9,6 @@ export default {} // export default { -// createWebview() { -// editorDispatch('coderoad.open_webview') -// }, // async newOrContinue() { // // verify that the user has an existing tutorial to continue // // const hasExistingTutorial: boolean = await tutorialModel.hasExisting() diff --git a/web-app/src/state/guards/index.ts b/web-app/src/services/state/guards/index.ts similarity index 100% rename from web-app/src/state/guards/index.ts rename to web-app/src/services/state/guards/index.ts diff --git a/web-app/src/state/machine.ts b/web-app/src/services/state/machine.ts similarity index 98% rename from web-app/src/state/machine.ts rename to web-app/src/services/state/machine.ts index 4b447857..e12593df 100644 --- a/web-app/src/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -10,7 +10,6 @@ export const machine = Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( initial: 'Start', states: { Start: { - onEntry: ['createWebview'], initial: 'Initial', states: { Initial: { diff --git a/web-app/src/state/utils/stateToString.test.ts b/web-app/src/services/state/utils/stateToString.test.ts similarity index 100% rename from web-app/src/state/utils/stateToString.test.ts rename to web-app/src/services/state/utils/stateToString.test.ts diff --git a/web-app/src/state/utils/stateToString.ts b/web-app/src/services/state/utils/stateToString.ts similarity index 100% rename from web-app/src/state/utils/stateToString.ts rename to web-app/src/services/state/utils/stateToString.ts diff --git a/web-app/src/state/index.ts b/web-app/src/state/index.ts deleted file mode 100644 index 9a9d3f54..00000000 --- a/web-app/src/state/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import {interpret, Interpreter} from 'xstate' -import * as CR from 'typings' -import machine from './machine' -import stateToString from './utils/stateToString' - -// machine interpreter -// https://xstate.js.org/docs/guides/interpretation.html - -class StateMachine { - private machineOptions = { - devTools: true, - deferEvents: true, - execute: true, - } - private service: Interpreter<{}, CR.MachineStateSchema, CR.MachineEvent> - - constructor() { - // format state as a string and send it to the client - this.syncState = (state: any): void => { - const stateValue: string = stateToString(state.value) - console.log(`STATE: ${stateValue}`) - // editorDispatch('coderoad.send_state', {state: stateValue}) - } - - // callback on all state changes - this.service = interpret(machine, this.machineOptions) - // logging - .onTransition(state => { - if (state.changed) { - this.syncState(state) - } - }) - } - public activate() { - // initialize - this.service.start() - } - public deactivate() { - this.service.stop() - } - public refresh() { - console.log('service refresh') - console.log(this.service.state) - this.syncState(this.service.state) - } - public send(action: string | CR.Action) { - this.service.send(action) - } - // @ts-ignore - private syncState(state: any): void - -} - -export default new StateMachine() From 358cc198a7b19e1fcf5da4d0d9f85b46e65eb962 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 1 Sep 2019 20:28:11 -0700 Subject: [PATCH 068/117] remove unused --- .../state/utils/stateToString.test.ts | 28 ------------------- .../src/services/state/utils/stateToString.ts | 16 ----------- 2 files changed, 44 deletions(-) delete mode 100644 web-app/src/services/state/utils/stateToString.test.ts delete mode 100644 web-app/src/services/state/utils/stateToString.ts diff --git a/web-app/src/services/state/utils/stateToString.test.ts b/web-app/src/services/state/utils/stateToString.test.ts deleted file mode 100644 index 1190678b..00000000 --- a/web-app/src/services/state/utils/stateToString.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -// -// Note: This example test is leveraging the Mocha test framework. -// Please refer to their documentation on https://mochajs.org/ for help. -// - -// The module 'assert' provides assertion methods from node -import stateToString from './stateToString' - -// You can import and use all API from the 'vscode' module -// as well as import your extension to test it -// import * as vscode from 'vscode' -// import * as myExtension from '../extension' - -// Defines a Mocha test suite to group tests of similar kind together -describe('StateToString', () => { - - test('no levels deep', () => { - expect(stateToString('first')).toBe('first') - }) - // Defines a Mocha unit test - test('one level deep', () => { - expect(stateToString({first: 'second'})).toBe('first.second') - }) - - test('two levels deep', () => { - expect(stateToString({first: {second: 'third'}})).toBe('first.second.third') - }) -}) diff --git a/web-app/src/services/state/utils/stateToString.ts b/web-app/src/services/state/utils/stateToString.ts deleted file mode 100644 index 109357c9..00000000 --- a/web-app/src/services/state/utils/stateToString.ts +++ /dev/null @@ -1,16 +0,0 @@ -const stateToString = (state: string | object, str: string = ''): string => { - if (typeof state === 'object') { - const keys = Object.keys(state) - if (keys && keys.length) { - const key = keys[0] - // @ts-ignore - return stateToString(state[key], str.length ? `${str}.${key}` : key) - } - return str - } else if (typeof state === 'string') { - return str.length ? `${str}.${state}` : state - } - return '' -} - -export default stateToString From df5ff8390b13fc8482fe64ea9d730a31a53c52ae Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 1 Sep 2019 20:29:29 -0700 Subject: [PATCH 069/117] cleanup utils/services --- web-app/src/Routes.tsx | 2 +- web-app/src/containers/Continue/index.tsx | 2 +- web-app/src/containers/New/index.tsx | 2 +- web-app/src/services/state/actions/index.ts | 2 +- web-app/src/{utils/vscode.ts => services/vscode/index.ts} | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename web-app/src/{utils/vscode.ts => services/vscode/index.ts} (100%) diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index bb7d55b6..04c142bb 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { editorDispatch } from './utils/vscode' +import { editorDispatch } from './services/vscode' import Router from './components/Router' import LoadingPage from './containers/LoadingPage' diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index 923c2f98..d86cdf7b 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -4,7 +4,7 @@ import { Button, Card } from '@alifd/next' import * as T from 'typings/graphql' import currentTutorial from '../../services/current' -// import { editorDispatch } from '../../utils/vscode' +// import { editorDispatch } from '../../services/vscode' import LoadingPage from '../LoadingPage' import queryTutorial from './queryTutorial' import ErrorView from '../../components/Error' diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 2c0e6a70..4dcb3879 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -4,7 +4,7 @@ import * as T from 'typings/graphql' import * as CR from 'typings' import queryTutorials from './queryTutorials' -import { editorDispatch } from '../../utils/vscode' +import { editorDispatch } from '../../services/vscode' import LoadingPage from '../LoadingPage' import ErrorView from '../../components/Error' import TutorialList from './TutorialList' diff --git a/web-app/src/services/state/actions/index.ts b/web-app/src/services/state/actions/index.ts index 27f4fbc5..5390db49 100644 --- a/web-app/src/services/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -1,6 +1,6 @@ // import {machine} from '../../extension' // import {cache} from '../../services/apollo' -// import {editorDispatch} from '../../utils/vscode' +// import {editorDispatch} from '../../services/vscode' // import * as CR from 'typings' // import * as G from 'typings/graphql' // import tutorialConfig from '../../services/apollo/queries/tutorialConfig' diff --git a/web-app/src/utils/vscode.ts b/web-app/src/services/vscode/index.ts similarity index 100% rename from web-app/src/utils/vscode.ts rename to web-app/src/services/vscode/index.ts From 073a7424170230f306296ebcffa17551770ab802 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 1 Sep 2019 20:58:41 -0700 Subject: [PATCH 070/117] refactor debugger --- typings/index.d.ts | 1 - web-app/src/App.tsx | 28 ++--------------- web-app/src/Routes.tsx | 11 ++----- web-app/src/components/Debugger/index.tsx | 12 ++++--- web-app/src/components/Router/index.tsx | 31 +++++++++++++------ .../src/components/Router/stateToString.ts | 16 ++++++++++ web-app/src/services/state/actions/index.ts | 12 ++++++- web-app/src/services/state/machine.ts | 7 +---- 8 files changed, 61 insertions(+), 57 deletions(-) create mode 100644 web-app/src/components/Router/stateToString.ts diff --git a/typings/index.d.ts b/typings/index.d.ts index 861a5c32..95dda7d5 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -125,7 +125,6 @@ export interface MachineStateSchema { states: { Start: { states: { - Initial: {} Startup: {} NewTutorial: { states: { diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index f816e842..c603daa6 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -4,7 +4,6 @@ import * as CR from 'typings' import client from './services/apollo' import currentTutorial from './services/current' -import Debugger from './components/Debugger' import Routes from './Routes' interface ReceivedEvent { @@ -12,14 +11,6 @@ interface ReceivedEvent { } const App = () => { - const initialState = 'Start.Initial' - - // set state machine state - const [state, setState] = React.useState(initialState) - const [debuggerInfo, setDebuggerInfo] = React.useState({ - progress: { levels: {}, stages: {}, steps: {}, complete: false}, - position: { levelId: '', stageId: '', stepId: ''}, - }) // event bus listener React.useEffect(() => { @@ -28,17 +19,13 @@ const App = () => { const message = event.data // messages from core - if (message.type === 'SET_STATE') { - // SET_STATE - set state machine state - setState(message.payload.state) - - } else if (message.type === 'SET_DATA') { + if (message.type === 'SET_DATA') { // SET_DATA - set state machine context console.log('SET_DATA updated') const { progress, position } = message.payload if (process.env.REACT_APP_DEBUG) { console.log(`Position: ${position.levelId}/${position.stageId}/${position.stepId}`) - setDebuggerInfo({ progress, position }) + // setDebuggerInfo({ progress, position }) } console.log('set currentTutorial') currentTutorial.set({ position, progress }) @@ -53,18 +40,9 @@ const App = () => { } }, []) - // trigger progress when webview loaded - // React.useEffect(() => { - // editorDispatch('WEBVIEW_LOADED') - // }, []) - - // TODO: refactor cond to user and accept first route as if/else if return ( -
- {process.env.REACT_APP_DEBUG && } - -
+
) } diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 04c142bb..a48f6393 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -12,10 +12,6 @@ import CompletedPage from './containers/Tutorial/CompletedPage' const { Route } = Router -interface Props { - state: any -} - const styles = { page: { margin: 0, @@ -23,7 +19,7 @@ const styles = { }, } -const Routes = ({ state }: Props) => { +const Routes = () => { const [dimensions, setDimensions] = React.useState({ width: window.innerWidth - 20, height: window.innerHeight - 20, @@ -45,10 +41,7 @@ const Routes = ({ state }: Props) => { return (
- - -
Initial
-
+ diff --git a/web-app/src/components/Debugger/index.tsx b/web-app/src/components/Debugger/index.tsx index 268909f9..bf3f7357 100644 --- a/web-app/src/components/Debugger/index.tsx +++ b/web-app/src/components/Debugger/index.tsx @@ -3,15 +3,17 @@ import * as CR from 'typings' interface Props { state: string - position: CR.Position - progress: CR.Progress + // position: CR.Position + // progress: CR.Progress + children: React.ReactElement } -const Debugger = ({ state, position, progress }: Props) => ( +const Debugger = ({ state, children }: Props) => (

state: {state}

-

position: {JSON.stringify(position)}

-

progress: {JSON.stringify(progress)}

+ {/*

position: {JSON.stringify(position)}

+

progress: {JSON.stringify(progress)}

*/} + {children}
) diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index c648ffb6..673da736 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -1,33 +1,44 @@ import * as React from 'react' import { useMachine } from '@xstate/react' import machine from '../../services/state/machine' +import Debugger from '../Debugger' import Route from './Route' +import stateToString from './stateToString' interface Props { - state: string children: any } -// const stateMatch = (state: string, path: string) => { -// return !!(new RegExp(`^${state}`).exec(path)) -// } +{/* {process.env.REACT_APP_DEBUG && } */} + +const wrapDebugger = (element: React.ReactElement, state: any) => { + if (process.env.REACT_APP_DEBUG) { + return ( + + {element} + + ) + } + return element +} // router finds first state match of const Router = ({ children }: Props) => { - const [current, send] = useMachine(machine) + const [state, send] = useMachine(machine) const childArray = React.Children.toArray(children) for (const child of childArray) { - if (current.matches(child.props.path)) { + if (state.matches(child.props.path)) { + let element if (child.props.send) { - return React.cloneElement(child.props.children, { send }) + element = React.cloneElement(child.props.children, { send }) } else { - return child.props.children + element = child.props.children } - + return wrapDebugger(element, state) } } - console.warn(`No Route matches for ${JSON.stringify(current)}`) + console.warn(`No Route matches for ${JSON.stringify(state)}`) return null } diff --git a/web-app/src/components/Router/stateToString.ts b/web-app/src/components/Router/stateToString.ts new file mode 100644 index 00000000..705fb492 --- /dev/null +++ b/web-app/src/components/Router/stateToString.ts @@ -0,0 +1,16 @@ +const stateToString = (state: string | object, str: string = ''): string => { + if (typeof state === 'object') { + const keys = Object.keys(state) + if (keys && keys.length) { + const key = keys[0] + // @ts-ignore + return stateToString(state[key], str.length ? `${str}.${key}` : key) + } + return str + } else if (typeof state === 'string') { + return str.length ? `${str}.${state}` : state + } + return '' +} + +export default stateToString \ No newline at end of file diff --git a/web-app/src/services/state/actions/index.ts b/web-app/src/services/state/actions/index.ts index 5390db49..b2c2ebd9 100644 --- a/web-app/src/services/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -1,3 +1,4 @@ +import {send} from 'xstate' // import {machine} from '../../extension' // import {cache} from '../../services/apollo' // import {editorDispatch} from '../../services/vscode' @@ -6,7 +7,16 @@ // import tutorialConfig from '../../services/apollo/queries/tutorialConfig' -export default {} +export default { + async newOrContinue() { + console.log('new or continue') + // verify that the user has an existing tutorial to continue + + // TODO: verify continue or new + const hasExistingTutorial: boolean = false + send(hasExistingTutorial ? 'CONTINUE' : 'NEW') + }, +} // export default { // async newOrContinue() { diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index e12593df..6e1b38f0 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -10,13 +10,8 @@ export const machine = Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( initial: 'Start', states: { Start: { - initial: 'Initial', + initial: 'Startup', states: { - Initial: { - on: { - WEBVIEW_INITIALIZED: 'Startup', - }, - }, Startup: { onEntry: ['newOrContinue'], on: { From e71bb6f4c05b596033a43c14f6635b350023f259 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 1 Sep 2019 21:01:12 -0700 Subject: [PATCH 071/117] update deps --- web-app/package-lock.json | 24 +++++++++++------------ web-app/package.json | 8 ++++---- web-app/src/components/Debugger/index.tsx | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/web-app/package-lock.json b/web-app/package-lock.json index fb520232..df5d8208 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@alifd/next": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.17.7.tgz", - "integrity": "sha512-6JEtZ5VzYj5E6eHHS4uiTAsX/jlHA3/j0oVQBek73okdwU6RQ4330eYwcbwuUpPnIK3rvztbWW5jPsYLWbEdvw==", + "version": "1.17.8", + "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.17.8.tgz", + "integrity": "sha512-6vfiJyQOUGo/UCJt5KCWbkok7sp0Op3fifEt77VQsyf4xzPnJ/lIOCNJ2/uPX5rDrNvse23IIcgbwePjAQGvnw==", "requires": { "babel-runtime": "^6.26.0", "classnames": "^2.2.3", @@ -2810,9 +2810,9 @@ } }, "@types/node": { - "version": "12.7.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz", - "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==" + "version": "12.7.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.3.tgz", + "integrity": "sha512-3SiLAIBkDWDg6vFo0+5YJyHPWU9uwu40Qe+v+0MH8wRKYBimHvvAOyk3EzMrD/TrIlLYfXrqDqrg913PynrMJQ==" }, "@types/prop-types": { "version": "15.7.1", @@ -8792,9 +8792,9 @@ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, "graphql": { - "version": "14.4.2", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.4.2.tgz", - "integrity": "sha512-6uQadiRgnpnSS56hdZUSvFrVcQ6OF9y6wkxJfKquFtHlnl7+KSuWwSJsdwiK1vybm1HgcdbpGkCpvhvsVQ0UZQ==", + "version": "14.5.4", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.5.4.tgz", + "integrity": "sha512-dPLvHoxy5m9FrkqWczPPRnH0X80CyvRE6e7Fa5AWEqEAzg9LpxHvKh24po/482E6VWHigOkAmb4xCp6P9yT9gw==", "requires": { "iterall": "^1.2.2" } @@ -17709,9 +17709,9 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "typescript": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", - "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==" + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz", + "integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==" }, "typescript-eslint-parser": { "version": "22.0.0", diff --git a/web-app/package.json b/web-app/package.json index a79c4673..b629c38d 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -26,11 +26,11 @@ "extends": "react-app" }, "dependencies": { - "@alifd/next": "^1.17.7", + "@alifd/next": "^1.17.8", "@apollo/react-hooks": "^3.0.1", "@xstate/react": "^0.7.1", "apollo-boost": "^0.4.4", - "graphql": "^14.4.2", + "graphql": "^14.5.4", "markdown-it": "^9.1.0", "markdown-it-emoji": "^1.4.0", "markdown-it-prism": "^2.0.2", @@ -38,7 +38,7 @@ "react": "^16.9.0", "react-dom": "^16.9.0", "react-scripts": "^3.1.1", - "typescript": "^3.5.3", + "typescript": "^3.6.2", "xstate": "^4.6.7" }, "devDependencies": { @@ -51,7 +51,7 @@ "@types/highlight.js": "^9.12.3", "@types/jest": "^24.0.18", "@types/markdown-it": "0.0.8", - "@types/node": "^12.7.2", + "@types/node": "^12.7.3", "@types/react": "^16.9.2", "@types/react-dom": "^16.9.0", "@types/storybook__react": "^4.0.2", diff --git a/web-app/src/components/Debugger/index.tsx b/web-app/src/components/Debugger/index.tsx index bf3f7357..f3e1b32e 100644 --- a/web-app/src/components/Debugger/index.tsx +++ b/web-app/src/components/Debugger/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import * as CR from 'typings' +// import * as CR from 'typings' interface Props { state: string From 81c3f057ec1bc75cad0835302d545bede67e55e1 Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 2 Sep 2019 07:44:19 -0700 Subject: [PATCH 072/117] progress setting up client app --- web-app/src/Routes.tsx | 6 ++--- web-app/src/components/Router/Route.tsx | 2 +- web-app/src/components/Router/index.tsx | 16 ++++++------- web-app/src/containers/New/index.tsx | 18 ++++++++++---- web-app/src/services/state/actions/index.ts | 26 +++++++++++++++------ web-app/src/services/state/machine.ts | 1 + 6 files changed, 44 insertions(+), 25 deletions(-) diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index a48f6393..8f906cdf 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -44,13 +44,13 @@ const Routes = () => { + + + - - - diff --git a/web-app/src/components/Router/Route.tsx b/web-app/src/components/Router/Route.tsx index 7e80f066..33b1abe8 100644 --- a/web-app/src/components/Router/Route.tsx +++ b/web-app/src/components/Router/Route.tsx @@ -1,6 +1,6 @@ interface Props { children: any - path: string + path: string } const Route = ({ children }: Props) => children diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index 673da736..11fa1435 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -1,4 +1,5 @@ import * as React from 'react' +import * as CR from 'typings' import { useMachine } from '@xstate/react' import machine from '../../services/state/machine' import Debugger from '../Debugger' @@ -9,8 +10,6 @@ interface Props { children: any } -{/* {process.env.REACT_APP_DEBUG && } */} - const wrapDebugger = (element: React.ReactElement, state: any) => { if (process.env.REACT_APP_DEBUG) { return ( @@ -22,19 +21,18 @@ const wrapDebugger = (element: React.ReactElement, state: any) => { return element } +interface CloneElementProps { + send(action: CR.Action): void +} + // router finds first state match of -const Router = ({ children }: Props) => { +const Router = ({ children }: Props): React.ReactElement|null => { const [state, send] = useMachine(machine) const childArray = React.Children.toArray(children) for (const child of childArray) { if (state.matches(child.props.path)) { - let element - if (child.props.send) { - element = React.cloneElement(child.props.children, { send }) - } else { - element = child.props.children - } + const element = React.cloneElement(child.props.children, { send }) return wrapDebugger(element, state) } } diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 4dcb3879..6ade658a 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -4,7 +4,6 @@ import * as T from 'typings/graphql' import * as CR from 'typings' import queryTutorials from './queryTutorials' -import { editorDispatch } from '../../services/vscode' import LoadingPage from '../LoadingPage' import ErrorView from '../../components/Error' import TutorialList from './TutorialList' @@ -16,14 +15,19 @@ interface Props { export const NewPage = (props: Props) => (
-

Start a new Project

+

Start a New Tutorial

) const Loading = () => -const NewPageContainer = () => { +interface ContainerProps { + send?(action: CR.Action): void +} + +const NewPageContainer = (props: ContainerProps) => { + console.log('props', props) const { data, loading, error } = useQuery(queryTutorials) if (loading) { return @@ -31,11 +35,15 @@ const NewPageContainer = () => { if (error) { return - } + } + + // TODO: cleanup React.cloneElement props issue + const sendFallback = (action: CR.Action) => console.log('Cannot send') + const send = props.send || sendFallback return ( - + ) } diff --git a/web-app/src/services/state/actions/index.ts b/web-app/src/services/state/actions/index.ts index b2c2ebd9..98a0aab6 100644 --- a/web-app/src/services/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -8,14 +8,16 @@ import {send} from 'xstate' export default { - async newOrContinue() { + newOrContinue: send((context): 'NEW' | 'CONTINUE' => { console.log('new or continue') - // verify that the user has an existing tutorial to continue - // TODO: verify continue or new + // TODO: verify that the user has an existing tutorial to continue const hasExistingTutorial: boolean = false - send(hasExistingTutorial ? 'CONTINUE' : 'NEW') - }, + return hasExistingTutorial ? 'CONTINUE' : 'NEW' + }), + tutorialStart() { + console.log('start') + } } // export default { @@ -30,9 +32,19 @@ export default { // // const codingLanguage: G.EnumCodingLanguage = result.data.codingLanguage // // editorDispatch('coderoad.test_runner_setup', codingLanguage) // }, -// initializeNewTutorial: () => { -// console.log('initializeNewTutorial') +// initializeNewTutorial: assign({ +// position: (context: any): CR.Position => { +// const { tutorial } = context +// const levelId = data.summary.levelList[0] +// const stageId = data.levels[levelId].stageList[0] +// const stepId = data.stages[stageId].stepList[0] +// return { +// levelId, +// stageId, +// stepId, +// } // }, +// }) // tutorialContinue() { // console.log('tutorial continue') // }, diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 6e1b38f0..f75deb81 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -28,6 +28,7 @@ export const machine = Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( }, }, InitializeTutorial: { + onEntry: ['tutorialStart'], on: { TUTORIAL_LOADED: '#tutorial', }, From 2dcb5b4e2fcc823d48ed7b06812292577c1f974f Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 2 Sep 2019 08:07:59 -0700 Subject: [PATCH 073/117] cleanup senders --- web-app/src/App.tsx | 35 ++------------------ web-app/src/Routes.tsx | 12 ++++--- web-app/src/containers/New/index.tsx | 8 ++--- web-app/src/services/channel/index.ts | 42 ++++++++++++++++++++++++ web-app/src/services/channel/mock.ts | 9 +++++ web-app/src/services/channel/receiver.ts | 12 +++++++ web-app/src/services/vscode/index.ts | 19 ----------- 7 files changed, 74 insertions(+), 63 deletions(-) create mode 100644 web-app/src/services/channel/index.ts create mode 100644 web-app/src/services/channel/mock.ts create mode 100644 web-app/src/services/channel/receiver.ts delete mode 100644 web-app/src/services/vscode/index.ts diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index c603daa6..d8144d14 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -1,44 +1,13 @@ import * as React from 'react' import { ApolloProvider } from '@apollo/react-hooks' -import * as CR from 'typings' import client from './services/apollo' -import currentTutorial from './services/current' import Routes from './Routes' - -interface ReceivedEvent { - data: CR.Action -} +import messageBusReceiver from './services/channel/receiver' const App = () => { - // event bus listener - React.useEffect(() => { - // update state based on response from editor - const handleEvent = (event: ReceivedEvent): void => { - const message = event.data - // messages from core - - if (message.type === 'SET_DATA') { - // SET_DATA - set state machine context - console.log('SET_DATA updated') - const { progress, position } = message.payload - if (process.env.REACT_APP_DEBUG) { - console.log(`Position: ${position.levelId}/${position.stageId}/${position.stepId}`) - // setDebuggerInfo({ progress, position }) - } - console.log('set currentTutorial') - currentTutorial.set({ position, progress }) - - } - } - - const listener = 'message' - window.addEventListener(listener, handleEvent) - return () => { - window.removeEventListener(listener, handleEvent) - } - }, []) + React.useEffect(messageBusReceiver, []) return ( diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 8f906cdf..1dc8392e 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { editorDispatch } from './services/vscode' +// import { editorDispatch } from './services/vscode' import Router from './components/Router' import LoadingPage from './containers/LoadingPage' @@ -19,6 +19,8 @@ const styles = { }, } +const tempSend = (action: any) => console.log('sent') + const Routes = () => { const [dimensions, setDimensions] = React.useState({ width: window.innerWidth - 20, @@ -46,7 +48,7 @@ const Routes = () => {
- + @@ -61,13 +63,13 @@ const Routes = () => { - + - + - + diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 6ade658a..10aa8cf4 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -23,7 +23,7 @@ export const NewPage = (props: Props) => ( const Loading = () => interface ContainerProps { - send?(action: CR.Action): void + send(action: CR.Action): void } const NewPageContainer = (props: ContainerProps) => { @@ -36,14 +36,10 @@ const NewPageContainer = (props: ContainerProps) => { if (error) { return } - - // TODO: cleanup React.cloneElement props issue - const sendFallback = (action: CR.Action) => console.log('Cannot send') - const send = props.send || sendFallback return ( - + ) } diff --git a/web-app/src/services/channel/index.ts b/web-app/src/services/channel/index.ts new file mode 100644 index 00000000..a1c9d734 --- /dev/null +++ b/web-app/src/services/channel/index.ts @@ -0,0 +1,42 @@ +import {Action} from 'typings' + +declare var acquireVsCodeApi: any + +// @ts-ignore +if (!window.acquireVsCodeApi) { + require('./mock') +} + +const channel = acquireVsCodeApi() + + +// Send to Editor +export const send = (action: Action) => { + return channel.postMessage(action) +} + +interface ReceivedEvent { + data: Action +} + +// Receive from Editor +export const receive = (event: ReceivedEvent): void => { + + const message = event.data + console.log('message', message) + // messages from core + + // if (message.type === 'SET_DATA') { + // // SET_DATA - set state machine context + // console.log('SET_DATA updated') + // const {progress, position} = message.payload + // if (process.env.REACT_APP_DEBUG) { + // console.log(`Position: ${position.levelId}/${position.stageId}/${position.stepId}`) + // // setDebuggerInfo({ progress, position }) + // } + // console.log('set currentTutorial') + // // currentTutorial.set({position, progress}) + + // } +} + diff --git a/web-app/src/services/channel/mock.ts b/web-app/src/services/channel/mock.ts new file mode 100644 index 00000000..c44416b1 --- /dev/null +++ b/web-app/src/services/channel/mock.ts @@ -0,0 +1,9 @@ +import {receive} from './index' + +// mock vscode from client side development +// @ts-ignore +window.acquireVsCodeApi = () => ({ + postMessage(event: string) { + console.log('postMessage', event) + } +}) \ No newline at end of file diff --git a/web-app/src/services/channel/receiver.ts b/web-app/src/services/channel/receiver.ts new file mode 100644 index 00000000..55327bab --- /dev/null +++ b/web-app/src/services/channel/receiver.ts @@ -0,0 +1,12 @@ +import {receive} from './index' + +const messageBusReceiver = () => { + // update state based on response from editor + const listener = 'message' + window.addEventListener(listener, receive) + return () => { + window.removeEventListener(listener, receive) + } +} + +export default messageBusReceiver \ No newline at end of file diff --git a/web-app/src/services/vscode/index.ts b/web-app/src/services/vscode/index.ts deleted file mode 100644 index 8aa8083d..00000000 --- a/web-app/src/services/vscode/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {Action} from 'typings' - -declare var acquireVsCodeApi: any - -// @ts-ignore -if (!window.acquireVsCodeApi) { - // @ts-ignore - window.acquireVsCodeApi = () => ({ - postMessage(event: string) { - console.log('postMessage', event) - } - }) -} - -const vscode = acquireVsCodeApi() - -export function editorDispatch(event: string | Action) { - return vscode.postMessage(event) -} From 595e1818753e09b4e40241a0f75a4ffa293848a5 Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 2 Sep 2019 08:40:09 -0700 Subject: [PATCH 074/117] cleanup debugger wrapper --- web-app/src/App.tsx | 16 +++------ web-app/src/Routes.tsx | 36 +++++++++---------- .../components/Debugger/debuggerWrapper.tsx | 16 +++++++++ .../{Router => Debugger}/stateToString.ts | 0 web-app/src/components/Router/index.tsx | 25 ++++++------- web-app/src/containers/New/index.tsx | 1 - web-app/src/services/channel/index.ts | 20 +++++++++-- web-app/src/services/channel/mock.ts | 21 +++++++++-- web-app/src/services/state/actions/index.ts | 10 +++++- 9 files changed, 95 insertions(+), 50 deletions(-) create mode 100644 web-app/src/components/Debugger/debuggerWrapper.tsx rename web-app/src/components/{Router => Debugger}/stateToString.ts (100%) diff --git a/web-app/src/App.tsx b/web-app/src/App.tsx index d8144d14..159d2a8e 100644 --- a/web-app/src/App.tsx +++ b/web-app/src/App.tsx @@ -3,17 +3,11 @@ import { ApolloProvider } from '@apollo/react-hooks' import client from './services/apollo' import Routes from './Routes' -import messageBusReceiver from './services/channel/receiver' -const App = () => { - // event bus listener - React.useEffect(messageBusReceiver, []) - - return ( - - - - ) -} +const App = () => ( + + + +) export default App diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 1dc8392e..341023d5 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -22,27 +22,27 @@ const styles = { const tempSend = (action: any) => console.log('sent') const Routes = () => { - const [dimensions, setDimensions] = React.useState({ - width: window.innerWidth - 20, - height: window.innerHeight - 20, - }) + // const [dimensions, setDimensions] = React.useState({ + // width: window.innerWidth - 20, + // height: window.innerHeight - 20, + // }) - // solution for windows getting off size - // without adding multiple listeners - React.useEffect(() => { - const dimensionsInterval = setInterval(() => { - setDimensions({ - width: window.innerWidth - 20, - height: window.innerHeight - 20, - }) - }, 5000) - return () => { - clearInterval(dimensionsInterval) - } - }, []) + // // solution for windows getting off size + // // without adding multiple listeners + // React.useEffect(() => { + // const dimensionsInterval = setInterval(() => { + // setDimensions({ + // width: window.innerWidth - 20, + // height: window.innerHeight - 20, + // }) + // }, 5000) + // return () => { + // clearInterval(dimensionsInterval) + // } + // }, []) return ( -
+
diff --git a/web-app/src/components/Debugger/debuggerWrapper.tsx b/web-app/src/components/Debugger/debuggerWrapper.tsx new file mode 100644 index 00000000..42b658e9 --- /dev/null +++ b/web-app/src/components/Debugger/debuggerWrapper.tsx @@ -0,0 +1,16 @@ +import * as React from 'react' +import Debugger from './index' +import stateToString from './stateToString' + +const debuggerWrapper = (element: React.ReactElement, state: any) => { + if (process.env.REACT_APP_DEBUG) { + return ( + + {element} + + ) + } + return element +} + +export default debuggerWrapper diff --git a/web-app/src/components/Router/stateToString.ts b/web-app/src/components/Debugger/stateToString.ts similarity index 100% rename from web-app/src/components/Router/stateToString.ts rename to web-app/src/components/Debugger/stateToString.ts diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index 11fa1435..acd2b10b 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -2,38 +2,33 @@ import * as React from 'react' import * as CR from 'typings' import { useMachine } from '@xstate/react' import machine from '../../services/state/machine' -import Debugger from '../Debugger' + import Route from './Route' -import stateToString from './stateToString' +import debuggerWrapper from '../Debugger/debuggerWrapper' +import messageBusReceiver from '../../services/channel/receiver' interface Props { children: any } -const wrapDebugger = (element: React.ReactElement, state: any) => { - if (process.env.REACT_APP_DEBUG) { - return ( - - {element} - - ) - } - return element -} - interface CloneElementProps { send(action: CR.Action): void } // router finds first state match of const Router = ({ children }: Props): React.ReactElement|null => { - const [state, send] = useMachine(machine) + const [state, send] = useMachine(machine, { + logger: console.log.bind('XSTATE:') + }) + + // event bus listener + React.useEffect(messageBusReceiver, []) const childArray = React.Children.toArray(children) for (const child of childArray) { if (state.matches(child.props.path)) { const element = React.cloneElement(child.props.children, { send }) - return wrapDebugger(element, state) + return debuggerWrapper(element, state) } } console.warn(`No Route matches for ${JSON.stringify(state)}`) diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 10aa8cf4..1806dd03 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -27,7 +27,6 @@ interface ContainerProps { } const NewPageContainer = (props: ContainerProps) => { - console.log('props', props) const { data, loading, error } = useQuery(queryTutorials) if (loading) { return diff --git a/web-app/src/services/channel/index.ts b/web-app/src/services/channel/index.ts index a1c9d734..b10ad24f 100644 --- a/web-app/src/services/channel/index.ts +++ b/web-app/src/services/channel/index.ts @@ -1,9 +1,11 @@ import {Action} from 'typings' +import {send as stateMachineSend} from 'xstate' declare var acquireVsCodeApi: any // @ts-ignore if (!window.acquireVsCodeApi) { + // @ts-ignore require('./mock') } @@ -22,9 +24,23 @@ interface ReceivedEvent { // Receive from Editor export const receive = (event: ReceivedEvent): void => { - const message = event.data - console.log('message', message) + const action = event.data + + // @ts-ignore // ignore browser events from plugins + if (action.source) {return } + + console.log('receive action', action) // messages from core + switch (action.type) { + case 'TUTORIAL_LOADED': + // send action to state machine + stateMachineSend('TUTORIAL_LOADED') + console.log(stateMachineSend) + console.log('send action to state machine') + return + default: + console.warn(`Unknown received action ${action.type}`, action) + } // if (message.type === 'SET_DATA') { // // SET_DATA - set state machine context diff --git a/web-app/src/services/channel/mock.ts b/web-app/src/services/channel/mock.ts index c44416b1..9594316f 100644 --- a/web-app/src/services/channel/mock.ts +++ b/web-app/src/services/channel/mock.ts @@ -1,9 +1,26 @@ +import {Action} from 'typings' import {receive} from './index' +const createReceiveEvent = (action: Action) => ({ + data: action +}) + // mock vscode from client side development // @ts-ignore window.acquireVsCodeApi = () => ({ - postMessage(event: string) { - console.log('postMessage', event) + postMessage(action: Action) { + console.log('postMessage', action) + + switch (action.type) { + case 'TUTORIAL_START': + return setTimeout(() => { + const receiveAction: Action = { + type: 'TUTORIAL_LOADED' + } + receive(createReceiveEvent(receiveAction)) + }, 1000) + default: + console.warn(`${action.type} not found in post message mock`) + } } }) \ No newline at end of file diff --git a/web-app/src/services/state/actions/index.ts b/web-app/src/services/state/actions/index.ts index 98a0aab6..c151cf9b 100644 --- a/web-app/src/services/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -1,4 +1,5 @@ import {send} from 'xstate' +import * as channel from '../../channel' // import {machine} from '../../extension' // import {cache} from '../../services/apollo' // import {editorDispatch} from '../../services/vscode' @@ -16,7 +17,14 @@ export default { return hasExistingTutorial ? 'CONTINUE' : 'NEW' }), tutorialStart() { - console.log('start') + channel.send({ + type: 'TUTORIAL_START', + payload: { + tutorial: { + id: 'some-tutorial-id' + } + } + }) } } From e31c39bbe2dd99ca5aa2f2da571adbf861ef8b7d Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 2 Sep 2019 08:59:11 -0700 Subject: [PATCH 075/117] setup editor/machine channel --- web-app/src/components/Router/index.tsx | 3 + web-app/src/services/channel/index.ts | 105 +++++++++++--------- web-app/src/services/channel/mock.ts | 4 +- web-app/src/services/channel/receiver.ts | 6 +- web-app/src/services/state/actions/index.ts | 4 +- 5 files changed, 70 insertions(+), 52 deletions(-) diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index acd2b10b..6b223988 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -5,6 +5,7 @@ import machine from '../../services/state/machine' import Route from './Route' import debuggerWrapper from '../Debugger/debuggerWrapper' +import channel from '../../services/channel' import messageBusReceiver from '../../services/channel/receiver' interface Props { @@ -21,6 +22,8 @@ const Router = ({ children }: Props): React.ReactElement|null logger: console.log.bind('XSTATE:') }) + channel.setMachineSend(send) + // event bus listener React.useEffect(messageBusReceiver, []) diff --git a/web-app/src/services/channel/index.ts b/web-app/src/services/channel/index.ts index b10ad24f..a90536a9 100644 --- a/web-app/src/services/channel/index.ts +++ b/web-app/src/services/channel/index.ts @@ -1,58 +1,73 @@ import {Action} from 'typings' -import {send as stateMachineSend} from 'xstate' declare var acquireVsCodeApi: any -// @ts-ignore -if (!window.acquireVsCodeApi) { - // @ts-ignore - require('./mock') +interface ReceivedEvent { + data: Action } -const channel = acquireVsCodeApi() +class Channel { + constructor() { + // setup mock if browser only + // @ts-ignore + if (!window.acquireVsCodeApi) { + // @ts-ignore + require('./mock') + } + const editor = acquireVsCodeApi() + this.editorSend = editor.postMessage + } + public machineSend = (action: Action | string) => console.log('machine send') + public editorSend = (action: Action) => console.log('editor send') -// Send to Editor -export const send = (action: Action) => { - return channel.postMessage(action) -} + public setMachineSend(send: any) { + this.machineSend = send + } + public receive(event: ReceivedEvent) { + const action = event.data -interface ReceivedEvent { - data: Action -} + // @ts-ignore // ignore browser events from plugins + if (action.source) {return } -// Receive from Editor -export const receive = (event: ReceivedEvent): void => { - - const action = event.data - - // @ts-ignore // ignore browser events from plugins - if (action.source) {return } - - console.log('receive action', action) - // messages from core - switch (action.type) { - case 'TUTORIAL_LOADED': - // send action to state machine - stateMachineSend('TUTORIAL_LOADED') - console.log(stateMachineSend) - console.log('send action to state machine') - return - default: - console.warn(`Unknown received action ${action.type}`, action) + console.log('receive action', action) + // messages from core + switch (action.type) { + case 'TUTORIAL_LOADED': + // send action to state machine + this.machineSend('TUTORIAL_LOADED') + console.log('send action to state machine') + return + default: + console.warn(`Unknown received action ${action.type}`, action) + } } - - // if (message.type === 'SET_DATA') { - // // SET_DATA - set state machine context - // console.log('SET_DATA updated') - // const {progress, position} = message.payload - // if (process.env.REACT_APP_DEBUG) { - // console.log(`Position: ${position.levelId}/${position.stageId}/${position.stepId}`) - // // setDebuggerInfo({ progress, position }) - // } - // console.log('set currentTutorial') - // // currentTutorial.set({position, progress}) - - // } } +export default new Channel() + +// Send to Editor +// export const send = (action: Action) => { +// return +// } + + + +// // Receive from Editor +// export const receive = (event: ReceivedEvent): void => { + + +// // if (message.type === 'SET_DATA') { +// // // SET_DATA - set state machine context +// // console.log('SET_DATA updated') +// // const {progress, position} = message.payload +// // if (process.env.REACT_APP_DEBUG) { +// // console.log(`Position: ${position.levelId}/${position.stageId}/${position.stepId}`) +// // // setDebuggerInfo({ progress, position }) +// // } +// // console.log('set currentTutorial') +// // // currentTutorial.set({position, progress}) + +// // } +// } + diff --git a/web-app/src/services/channel/mock.ts b/web-app/src/services/channel/mock.ts index 9594316f..eb3ba84d 100644 --- a/web-app/src/services/channel/mock.ts +++ b/web-app/src/services/channel/mock.ts @@ -1,5 +1,5 @@ import {Action} from 'typings' -import {receive} from './index' +import channel from './index' const createReceiveEvent = (action: Action) => ({ data: action @@ -17,7 +17,7 @@ window.acquireVsCodeApi = () => ({ const receiveAction: Action = { type: 'TUTORIAL_LOADED' } - receive(createReceiveEvent(receiveAction)) + channel.receive(createReceiveEvent(receiveAction)) }, 1000) default: console.warn(`${action.type} not found in post message mock`) diff --git a/web-app/src/services/channel/receiver.ts b/web-app/src/services/channel/receiver.ts index 55327bab..b4abe3d0 100644 --- a/web-app/src/services/channel/receiver.ts +++ b/web-app/src/services/channel/receiver.ts @@ -1,11 +1,11 @@ -import {receive} from './index' +import channel from './index' const messageBusReceiver = () => { // update state based on response from editor const listener = 'message' - window.addEventListener(listener, receive) + window.addEventListener(listener, channel.receive) return () => { - window.removeEventListener(listener, receive) + window.removeEventListener(listener, channel.receive) } } diff --git a/web-app/src/services/state/actions/index.ts b/web-app/src/services/state/actions/index.ts index c151cf9b..9e1a56a6 100644 --- a/web-app/src/services/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -1,5 +1,5 @@ import {send} from 'xstate' -import * as channel from '../../channel' +import channel from '../../channel' // import {machine} from '../../extension' // import {cache} from '../../services/apollo' // import {editorDispatch} from '../../services/vscode' @@ -17,7 +17,7 @@ export default { return hasExistingTutorial ? 'CONTINUE' : 'NEW' }), tutorialStart() { - channel.send({ + channel.editorSend({ type: 'TUTORIAL_START', payload: { tutorial: { From ac42ad7b894fd9ef6edc7701ff8d4c029dedd2a1 Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 2 Sep 2019 10:43:56 -0700 Subject: [PATCH 076/117] init/set tutorial with progress --- typings/index.d.ts | 6 +++- web-app/package-lock.json | 28 ++++++++++++++--- web-app/package.json | 2 ++ web-app/src/Routes.tsx | 8 ++--- .../components/Debugger/debuggerWrapper.tsx | 2 +- web-app/src/components/Debugger/index.tsx | 15 +++++---- web-app/src/components/Router/index.tsx | 5 ++- .../src/containers/New/TutorialList/index.tsx | 13 ++------ web-app/src/containers/New/index.tsx | 5 ++- .../containers/Tutorial/LevelPage/index.tsx | 12 ++++--- .../Tutorial/LevelPage/queryLevel.ts | 2 +- .../containers/Tutorial/StagePage/index.tsx | 2 ++ .../containers/Tutorial/SummaryPage/index.tsx | 21 +++++++++---- .../Tutorial/SummaryPage/querySummary.ts | 31 ++++++++++++------- web-app/src/services/state/actions/context.ts | 29 +++++++++++++++++ web-app/src/services/state/actions/index.ts | 10 ++++-- web-app/src/services/state/machine.ts | 28 +++++++++++++---- 17 files changed, 157 insertions(+), 62 deletions(-) create mode 100644 web-app/src/services/state/actions/context.ts diff --git a/typings/index.d.ts b/typings/index.d.ts index 95dda7d5..65256314 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -114,7 +114,11 @@ export interface Action { meta?: any } -export interface MachineContext {} +export interface MachineContext { + tutorial: G.Tutorial | null, + position: CR.Position, + progress: CR.Progress, +} export interface MachineEvent { type: string diff --git a/web-app/package-lock.json b/web-app/package-lock.json index df5d8208..b7a2d2e5 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -2825,6 +2825,15 @@ "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==" }, + "@types/ramda": { + "version": "0.26.21", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.26.21.tgz", + "integrity": "sha512-zMYtIZMceA6BvH+or6LmewLBgojbXg5+FGCwjO8K+Z+d/ZWxILmhhASXkehW0PqJL+V0QbyDeeAHix0dvEKXfQ==", + "dev": true, + "requires": { + "ts-toolbelt": "^3.8.4" + } + }, "@types/react": { "version": "16.9.2", "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.2.tgz", @@ -8255,6 +8264,12 @@ "requires": { "graceful-fs": "^4.1.6" } + }, + "ramda": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz", + "integrity": "sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=", + "dev": true } } }, @@ -14067,10 +14082,9 @@ "dev": true }, "ramda": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz", - "integrity": "sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=", - "dev": true + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", + "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==" }, "randombytes": { "version": "2.1.0", @@ -17638,6 +17652,12 @@ "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.2.tgz", "integrity": "sha512-f5Knjh7XCyRIzoC/z1Su1yLLRrPrFCgtUAh/9fCSP6NKbATwpOL1+idQVXQokK9GRFURn/jYPGPfegIctwunoA==" }, + "ts-toolbelt": { + "version": "3.8.63", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-3.8.63.tgz", + "integrity": "sha512-OlsFC8uF1mpN2O7DlvSkgnXzOvubO790eFhTvZBFI+WLge2BYzkQk73Q3yF0R8usxhkqbemLomqRhCGWasoIKw==", + "dev": true + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", diff --git a/web-app/package.json b/web-app/package.json index b629c38d..c6b4b160 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -35,6 +35,7 @@ "markdown-it-emoji": "^1.4.0", "markdown-it-prism": "^2.0.2", "moment": "^2.24.0", + "ramda": "^0.26.1", "react": "^16.9.0", "react-dom": "^16.9.0", "react-scripts": "^3.1.1", @@ -52,6 +53,7 @@ "@types/jest": "^24.0.18", "@types/markdown-it": "0.0.8", "@types/node": "^12.7.3", + "@types/ramda": "^0.26.21", "@types/react": "^16.9.2", "@types/react-dom": "^16.9.0", "@types/storybook__react": "^4.0.2", diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 341023d5..6ebb19f1 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -1,6 +1,6 @@ import * as React from 'react' // import { editorDispatch } from './services/vscode' - +import * as CR from 'typings' import Router from './components/Router' import LoadingPage from './containers/LoadingPage' import ContinuePage from './containers/Continue' @@ -63,13 +63,13 @@ const Routes = () => { - + - + - + diff --git a/web-app/src/components/Debugger/debuggerWrapper.tsx b/web-app/src/components/Debugger/debuggerWrapper.tsx index 42b658e9..dbd9ed8d 100644 --- a/web-app/src/components/Debugger/debuggerWrapper.tsx +++ b/web-app/src/components/Debugger/debuggerWrapper.tsx @@ -5,7 +5,7 @@ import stateToString from './stateToString' const debuggerWrapper = (element: React.ReactElement, state: any) => { if (process.env.REACT_APP_DEBUG) { return ( - + {element} ) diff --git a/web-app/src/components/Debugger/index.tsx b/web-app/src/components/Debugger/index.tsx index f3e1b32e..d6442786 100644 --- a/web-app/src/components/Debugger/index.tsx +++ b/web-app/src/components/Debugger/index.tsx @@ -1,18 +1,21 @@ import * as React from 'react' -// import * as CR from 'typings' +import * as G from 'typings/graphql' +import * as CR from 'typings' interface Props { state: string - // position: CR.Position - // progress: CR.Progress + tutorial: G.Tutorial + position: CR.Position + progress: CR.Progress children: React.ReactElement } -const Debugger = ({ state, children }: Props) => ( +const Debugger = ({ state, children, position, progress, tutorial }: Props) => (

state: {state}

- {/*

position: {JSON.stringify(position)}

-

progress: {JSON.stringify(progress)}

*/} +

tutorial: {tutorial ? tutorial.id : 'none'}

+

position: {JSON.stringify(position)}

+

progress: {JSON.stringify(progress)}

{children}
) diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index 6b223988..5ff06a8c 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -13,6 +13,7 @@ interface Props { } interface CloneElementProps { + context: CR.MachineContext send(action: CR.Action): void } @@ -22,6 +23,8 @@ const Router = ({ children }: Props): React.ReactElement|null logger: console.log.bind('XSTATE:') }) + console.log('state', state) + channel.setMachineSend(send) // event bus listener @@ -30,7 +33,7 @@ const Router = ({ children }: Props): React.ReactElement|null const childArray = React.Children.toArray(children) for (const child of childArray) { if (state.matches(child.props.path)) { - const element = React.cloneElement(child.props.children, { send }) + const element = React.cloneElement(child.props.children, { send, context: state.context }) return debuggerWrapper(element, state) } } diff --git a/web-app/src/containers/New/TutorialList/index.tsx b/web-app/src/containers/New/TutorialList/index.tsx index 896aa365..bd85f14b 100644 --- a/web-app/src/containers/New/TutorialList/index.tsx +++ b/web-app/src/containers/New/TutorialList/index.tsx @@ -1,26 +1,19 @@ import * as React from 'react' -import currentTutorial from '../../../services/current' -import * as CR from 'typings' +import channel from '../../../services/channel' import * as T from 'typings/graphql' import TutorialItem from './TutorialItem' interface Props { tutorialList: T.Tutorial[] - onNew(Action: CR.Action): void } const TutorialList = (props: Props) => { const onSelect = (tutorial: T.Tutorial) => { - currentTutorial.set({ - tutorialId: tutorial.id, - version: tutorial.version.version, - }) - props.onNew({ + channel.machineSend({ type: 'TUTORIAL_START', payload: { - id: tutorial.id, - version: tutorial.version.version, + tutorial, } }) } diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 1806dd03..4e373269 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -10,13 +10,12 @@ import TutorialList from './TutorialList' interface Props { tutorialList: T.Tutorial[] - onNew(action: CR.Action): void } export const NewPage = (props: Props) => (

Start a New Tutorial

- +
) @@ -38,7 +37,7 @@ const NewPageContainer = (props: ContainerProps) => { return ( - + ) } diff --git a/web-app/src/containers/Tutorial/LevelPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx index 012dc8a9..3d9293f7 100644 --- a/web-app/src/containers/Tutorial/LevelPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/index.tsx @@ -1,5 +1,6 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' +import * as CR from 'typings' import * as G from 'typings/graphql' import currentTutorial from '../../../services/current' @@ -23,17 +24,18 @@ export const LevelSummaryPage = (props: LevelProps) => { } interface ContainerProps { - send(action: string): void + context: CR.MachineContext + send(action: string): void } const LevelSummaryPageContainer = (props: ContainerProps) => { - const { tutorialId, version, position, progress } = currentTutorial.get() - console.log('load level summary') + const { tutorial, position, progress } = props.context + const { loading, error, data } = useQuery(queryLevel, { variables: { - tutorialId, - version, + tutorialId: tutorial.id, + version: tutorial.version.version, levelId: position.levelId, }, }) diff --git a/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts b/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts index 70ce134a..5c1bd872 100644 --- a/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts +++ b/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts @@ -1,4 +1,4 @@ -import { gql } from 'apollo-boost' +import {gql} from 'apollo-boost' export default gql` query getLevel($tutorialId: ID!, $version: String, $levelId: ID!) { diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index f20dcdc3..3da96626 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -1,4 +1,5 @@ import * as React from 'react' +import * as CR from 'typings' import { useQuery } from '@apollo/react-hooks' import currentTutorial from '../../../services/current' @@ -7,6 +8,7 @@ import Stage from './Stage' import queryStage from './queryStage' interface PageProps { + context: CR.MachineContext, send(action: string): void } diff --git a/web-app/src/containers/Tutorial/SummaryPage/index.tsx b/web-app/src/containers/Tutorial/SummaryPage/index.tsx index c8fce580..4afbd973 100644 --- a/web-app/src/containers/Tutorial/SummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/SummaryPage/index.tsx @@ -1,20 +1,23 @@ import * as React from 'react' +import * as CR from 'typings' import { useQuery } from '@apollo/react-hooks' import querySummary from './querySummary' import Summary from './Summary' -import currentTutorial from '../../../services/current' import ErrorView from '../../../components/Error' interface PageProps { - send(action: string): void + context: CR.MachineContext + send(action: CR.Action): void } const SummaryPage = (props: PageProps) => { - const { tutorialId } = currentTutorial.get() + const { tutorial } = props.context const { loading, error, data } = useQuery(querySummary, { + fetchPolicy: 'network-only', // for debugging purposes variables: { - tutorialId, + tutorialId: tutorial.id, + version: tutorial.version.version, }, }) @@ -26,8 +29,14 @@ const SummaryPage = (props: PageProps) => { return } - const { title, text } = data.tutorial - const onNext = () => props.send('NEXT') + const onNext = () => props.send({ + type: 'LOAD_TUTORIAL', + payload: { + tutorial: data.tutorial, + } + }) + + const { title, text } = data.tutorial return } diff --git a/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts b/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts index 78dcf89a..ad876713 100644 --- a/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts +++ b/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts @@ -1,15 +1,24 @@ -import { gql } from 'apollo-boost' +import {gql} from 'apollo-boost' export default gql` query getSummary($tutorialId: ID!, $version: String) { - tutorial(id: $tutorialId) { - id - title - text - version(version: $version) { - version - coderoadVersion - } - } -} + tutorial(id: $tutorialId) { + id + title + text + version(version: $version) { + version + coderoadVersion + levels { + id + stages { + id + steps { + id + } + } + } + } + } + } ` diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts new file mode 100644 index 00000000..8d05f507 --- /dev/null +++ b/web-app/src/services/state/actions/context.ts @@ -0,0 +1,29 @@ +import {assign} from 'xstate' +import * as G from 'typings/graphql' +import * as CR from 'typings' + +export default { + setTutorial: assign({ + tutorial: (context: CR.MachineContext, event: CR.MachineEvent): any => { + return event.payload.tutorial + }, + }), + // @ts-ignore + initPosition: assign({ + position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { + if (!event.payload.tutorial) { + throw new Error('Invalid tutorial') + } + + const version: G.TutorialVersion = event.payload.tutorial.version + + const position: CR.Position = { + levelId: version.levels[0].id, + stageId: version.levels[0].stages[0].id, + stepId: version.levels[0].stages[0].steps[0].id, + } + + return position + }, + }) +} \ No newline at end of file diff --git a/web-app/src/services/state/actions/index.ts b/web-app/src/services/state/actions/index.ts index 9e1a56a6..52eea7f5 100644 --- a/web-app/src/services/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -3,10 +3,10 @@ import channel from '../../channel' // import {machine} from '../../extension' // import {cache} from '../../services/apollo' // import {editorDispatch} from '../../services/vscode' -// import * as CR from 'typings' +import * as CR from 'typings' // import * as G from 'typings/graphql' // import tutorialConfig from '../../services/apollo/queries/tutorialConfig' - +import contextActions from './context' export default { newOrContinue: send((context): 'NEW' | 'CONTINUE' => { @@ -25,7 +25,11 @@ export default { } } }) - } + }, + testRunnerSetup(context: CR.MachineContext) { + console.log('test runner setup', context) + }, + ...contextActions, } // export default { diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index f75deb81..123d072b 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -4,10 +4,20 @@ import * as CR from 'typings' import actions from './actions' import guards from './guards' -export const machine = Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( +export const machine = Machine( { id: 'root', initial: 'Start', + context: { + tutorial: null, + position: {levelId: '', stageId: '', stepId: ''}, + progress: { + levels: {}, + stages: {}, + steps: {}, + complete: false + } + }, states: { Start: { initial: 'Startup', @@ -24,7 +34,10 @@ export const machine = Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( states: { SelectTutorial: { on: { - TUTORIAL_START: 'InitializeTutorial', + TUTORIAL_START: { + target: 'InitializeTutorial', + actions: ['setTutorial'], + }, }, }, InitializeTutorial: { @@ -47,9 +60,9 @@ export const machine = Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( id: 'tutorial', initial: 'Initialize', onEntry: ['testRunnerSetup'], - on: { - WEBVIEW_INITIALIZED: '#tutorial-load-next' - }, + // on: { + // WEBVIEW_INITIALIZED: '#tutorial-load-next' + // }, states: { Initialize: { onEntry: ['initializeNewTutorial'], @@ -81,7 +94,10 @@ export const machine = Machine<{}, CR.MachineStateSchema, CR.MachineEvent>( Summary: { on: { - NEXT: 'Level', + LOAD_TUTORIAL: { + target: 'Level', + actions: ['initPosition', 'setTutorial'] + } }, }, Level: { From 74e20ee95f49ff3da8a3f8355ce31dd3b5ab2659 Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 2 Sep 2019 11:17:09 -0700 Subject: [PATCH 077/117] fix loading of levels/stages/steps --- web-app/src/components/Error/index.tsx | 4 ++-- .../containers/Tutorial/LevelPage/index.tsx | 8 ------- .../Tutorial/LevelPage/queryLevel.ts | 14 +++++++++-- .../containers/Tutorial/StagePage/index.tsx | 24 ++++++++++++------- .../Tutorial/StagePage/queryStage.ts | 22 ++++++++++++++--- .../Tutorial/SummaryPage/querySummary.ts | 24 +++++++++++++++++++ 6 files changed, 73 insertions(+), 23 deletions(-) diff --git a/web-app/src/components/Error/index.tsx b/web-app/src/components/Error/index.tsx index cffa3f08..b9c71bbf 100644 --- a/web-app/src/components/Error/index.tsx +++ b/web-app/src/components/Error/index.tsx @@ -21,8 +21,8 @@ const ErrorView = ({ error }: Props) => {

Error

{error.graphQLErrors && (
- {error.graphQLErrors.map(({ message, locations, path }: GraphQLError) => ( -
+ {error.graphQLErrors.map(({ message, locations, path }: GraphQLError, index: number) => ( +
[GraphQL error]: Message: {message}, Location: {locations}, Path: {path}
))} diff --git a/web-app/src/containers/Tutorial/LevelPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx index 3d9293f7..c4bf52e8 100644 --- a/web-app/src/containers/Tutorial/LevelPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/index.tsx @@ -3,7 +3,6 @@ import { useQuery } from '@apollo/react-hooks' import * as CR from 'typings' import * as G from 'typings/graphql' -import currentTutorial from '../../../services/current' import ErrorView from '../../../components/Error' import Level from './Level' import queryLevel from './queryLevel' @@ -29,7 +28,6 @@ interface ContainerProps { } const LevelSummaryPageContainer = (props: ContainerProps) => { - console.log('load level summary') const { tutorial, position, progress } = props.context const { loading, error, data } = useQuery(queryLevel, { @@ -39,9 +37,6 @@ const LevelSummaryPageContainer = (props: ContainerProps) => { levelId: position.levelId, }, }) - - console.log('load level data') - console.log(JSON.stringify(data)) if (loading) { return
Loading Levels...
@@ -63,9 +58,6 @@ const LevelSummaryPageContainer = (props: ContainerProps) => { } }) - console.log('check level') - console.log(JSON.stringify(level)) - return } diff --git a/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts b/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts index 5c1bd872..adb4a553 100644 --- a/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts +++ b/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts @@ -11,12 +11,22 @@ export default gql` id title text - status @client + setup { + id + commits + commands + files + } stages { id title text - status @client + setup { + id + commits + commands + files + } } } } diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index 3da96626..51634eac 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -1,8 +1,8 @@ import * as React from 'react' import * as CR from 'typings' +import * as G from 'typings/graphql' import { useQuery } from '@apollo/react-hooks' -import currentTutorial from '../../../services/current' import ErrorView from '../../../components/Error' import Stage from './Stage' import queryStage from './queryStage' @@ -13,12 +13,12 @@ interface PageProps { } const StageSummaryPageContainer = (props: PageProps) => { - const { tutorialId, version, position: { stageId } } = currentTutorial.get() + const { tutorial, position, progress } = props.context const { loading, error, data } = useQuery(queryStage, { variables: { - tutorialId, - version, - stageId, + tutorialId: tutorial.id, + version: tutorial.version.version, + stageId: position.stageId, }, }) if (loading) { @@ -29,9 +29,17 @@ const StageSummaryPageContainer = (props: PageProps) => { return } - console.log('data', data) - - const { stage } = data.tutorial.version + const { stage } = data.tutorial.version + + stage.steps.forEach((step: G.Step) => { + if (step.id === position.stepId) { + step.status = 'ACTIVE' + } else if (progress.steps[step.id]) { + step.status = 'COMPLETE' + } else { + step.status = 'INCOMPLETE' + } + }) const onContinue = (): void => { props.send('STAGE_NEXT') diff --git a/web-app/src/containers/Tutorial/StagePage/queryStage.ts b/web-app/src/containers/Tutorial/StagePage/queryStage.ts index 5b261720..9331bc64 100644 --- a/web-app/src/containers/Tutorial/StagePage/queryStage.ts +++ b/web-app/src/containers/Tutorial/StagePage/queryStage.ts @@ -1,4 +1,4 @@ -import { gql } from 'apollo-boost' +import {gql} from 'apollo-boost' export default gql` query getStage($tutorialId: ID!, $version: String, $stageId: ID!) { @@ -11,12 +11,28 @@ export default gql` id title text - status @client + setup { + id + commits + commands + files + } steps { id title text - status @client + setup { + id + commits + commands + files + } + solution { + id + commits + commands + files + } } } } diff --git a/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts b/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts index ad876713..eb2d7294 100644 --- a/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts +++ b/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts @@ -11,10 +11,34 @@ export default gql` coderoadVersion levels { id + setup { + id + commands + commits + files + } stages { id + setup { + id + commands + commits + files + } steps { id + setup { + id + commands + commits + files + } + solution { + id + commands + commits + files + } } } } From e0e28395870181655cd52d93375a4c006624a198 Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 2 Sep 2019 12:08:12 -0700 Subject: [PATCH 078/117] remove unused model --- web-app/src/Routes.tsx | 2 +- web-app/src/containers/Continue/index.tsx | 15 +++-- .../Tutorial/StagePage/Stage/index.tsx | 13 +++-- .../containers/Tutorial/StagePage/index.tsx | 26 +++++++-- web-app/src/services/current/index.ts | 57 ------------------- web-app/src/services/state/actions/context.ts | 24 ++++++++ web-app/src/services/state/actions/editor.ts | 21 +++++++ web-app/src/services/state/actions/index.ts | 16 +----- web-app/src/services/state/machine.ts | 5 +- 9 files changed, 88 insertions(+), 91 deletions(-) delete mode 100644 web-app/src/services/current/index.ts create mode 100644 web-app/src/services/state/actions/editor.ts diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 6ebb19f1..d679c242 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -54,7 +54,7 @@ const Routes = () => { - + diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index d86cdf7b..b804fd84 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -1,9 +1,9 @@ import * as React from 'react' import { useQuery } from '@apollo/react-hooks' import { Button, Card } from '@alifd/next' +import * as CR from 'typings' import * as T from 'typings/graphql' -import currentTutorial from '../../services/current' // import { editorDispatch } from '../../services/vscode' import LoadingPage from '../LoadingPage' import queryTutorial from './queryTutorial' @@ -29,13 +29,18 @@ export const ContinuePage = (props: Props) => ( const Loading = () => -const ContinuePageContainer = () => { +interface ContainerProps { + context: CR.MachineContext +} + +const ContinuePageContainer = ({ context }: ContainerProps) => { // TODO: load specific tutorialId - const { tutorialId, version } = currentTutorial.get() + const { tutorial } = context + // const { tutorialId, version } = currentTutorial.get() const { data, loading, error } = useQuery(queryTutorial, { variables: { - tutorialId, - version, + tutorialId: tutorial.id, + version: tutorial.version.version, }, }) diff --git a/web-app/src/containers/Tutorial/StagePage/Stage/index.tsx b/web-app/src/containers/Tutorial/StagePage/Stage/index.tsx index dd2a05cc..6c35f5ae 100644 --- a/web-app/src/containers/Tutorial/StagePage/Stage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/Stage/index.tsx @@ -24,10 +24,11 @@ const styles = { interface Props { stage: T.Stage - onContinue(): void + onContinue(): void + onSave(): void } -const Stage = ({ stage, onContinue }: Props) => { +const Stage = ({ stage, onContinue, onSave }: Props) => { if (!stage.steps) { throw new Error('No Stage steps found') } @@ -61,11 +62,15 @@ const Stage = ({ stage, onContinue }: Props) => {
- {stage.status === 'COMPLETE' && ( + {stage.status === 'COMPLETE' ? (
- )} + ) : ( +
+ +
+ )}
) } diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index 51634eac..8a4e66a5 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -9,7 +9,7 @@ import queryStage from './queryStage' interface PageProps { context: CR.MachineContext, - send(action: string): void + send(action: CR.Action): void } const StageSummaryPageContainer = (props: PageProps) => { @@ -31,6 +31,24 @@ const StageSummaryPageContainer = (props: PageProps) => { const { stage } = data.tutorial.version + const onContinue = (): void => { + props.send({ + type: 'STAGE_NEXT', + payload: { + stageId: position.stageId, + } + }) + } + + const onSave =(): void => { + props.send({ + type: 'TEST_RUNNING', + payload: { + stepId: position.stepId, + } + }) + } + stage.steps.forEach((step: G.Step) => { if (step.id === position.stepId) { step.status = 'ACTIVE' @@ -41,11 +59,7 @@ const StageSummaryPageContainer = (props: PageProps) => { } }) - const onContinue = (): void => { - props.send('STAGE_NEXT') - } - - return + return } export default StageSummaryPageContainer diff --git a/web-app/src/services/current/index.ts b/web-app/src/services/current/index.ts deleted file mode 100644 index 3d3f2cb9..00000000 --- a/web-app/src/services/current/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -// import * as React from 'react' -import * as CR from 'typings' - -// const CurrentContext = React.createContext({ -// tutorialId: '', -// version: '', -// position: {levelId: '', stageId: '', stepId: ''}, -// progress: { -// levels: {}, -// stages: {}, -// steps: {}, -// complete: false -// } -// }) - -interface CurrentTutorialParams { - tutorialId: string - version: string - position: CR.Position - progress: CR.Progress -} - -interface SetCurrentTutorialParams { - tutorialId?: string - version?: string - position?: CR.Position - progress?: CR.Progress -} - -class CurrentTutorial { - private tutorialId = '' - private version = '' - private position: CR.Position = {levelId: '', stageId: '', stepId: ''} - private progress: CR.Progress = {levels: {}, stages: {}, steps: {}, complete: false} - public set({tutorialId, version, position, progress}: SetCurrentTutorialParams) { - this.tutorialId = tutorialId || this.tutorialId - this.version = version || this.version - this.position = position || this.position - this.progress = progress || this.progress - } - public get(): CurrentTutorialParams { - return { - tutorialId: this.tutorialId, - version: this.version, - position: this.position, - progress: this.progress, - } - } - public clear() { - this.tutorialId = '' - this.version = '' - this.position = {levelId: '', stageId: '', stepId: ''} - this.progress = {levels: {}, stages: {}, steps: {}, complete: false} - } -} - -export default new CurrentTutorial() diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 8d05f507..9ec03ad6 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -25,5 +25,29 @@ export default { return position }, + }), + // @ts-ignore + testPass: assign({ + progress: (context: CR.MachineContext, event: CR.MachineEvent): CR.Progress => { + // update progress by tracking completed + const currentProgress: CR.Progress = context.progress + const stepId = event.payload.stepId + + currentProgress.steps[stepId] = true + + return currentProgress + }, + }), + // @ts-ignore + stepLoadNext: assign({ + position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { + const currentPosition: CR.Position = context.position + // merge in the updated position + // sent with the test to ensure consistency + return { + ...currentPosition, + ...event.payload.nextPosition, + } + }, }) } \ No newline at end of file diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts new file mode 100644 index 00000000..413f79fe --- /dev/null +++ b/web-app/src/services/state/actions/editor.ts @@ -0,0 +1,21 @@ +import * as CR from 'typings' +import channel from '../../channel' + +export default { + tutorialStart() { + channel.editorSend({ + type: 'TUTORIAL_START', + payload: { + tutorial: { + id: 'some-tutorial-id' + } + } + }) + }, + testRunnerSetup(context: CR.MachineContext) { + console.log('test runner setup', context) + }, + testStart() { + console.log('test start') + } +} \ No newline at end of file diff --git a/web-app/src/services/state/actions/index.ts b/web-app/src/services/state/actions/index.ts index 52eea7f5..50e55e0a 100644 --- a/web-app/src/services/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -1,11 +1,11 @@ import {send} from 'xstate' -import channel from '../../channel' // import {machine} from '../../extension' // import {cache} from '../../services/apollo' // import {editorDispatch} from '../../services/vscode' import * as CR from 'typings' // import * as G from 'typings/graphql' // import tutorialConfig from '../../services/apollo/queries/tutorialConfig' +import editorActions from './editor' import contextActions from './context' export default { @@ -16,19 +16,7 @@ export default { const hasExistingTutorial: boolean = false return hasExistingTutorial ? 'CONTINUE' : 'NEW' }), - tutorialStart() { - channel.editorSend({ - type: 'TUTORIAL_START', - payload: { - tutorial: { - id: 'some-tutorial-id' - } - } - }) - }, - testRunnerSetup(context: CR.MachineContext) { - console.log('test runner setup', context) - }, + ...editorActions, ...contextActions, } diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 123d072b..6ec9d0c2 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -60,9 +60,6 @@ export const machine = Machine Date: Mon, 2 Sep 2019 12:39:08 -0700 Subject: [PATCH 079/117] cleanup hasNext guards --- .../containers/Tutorial/LevelPage/index.tsx | 21 +----- .../Tutorial/LevelPage/queryLevel.ts | 35 ---------- .../containers/Tutorial/StagePage/index.tsx | 21 +----- web-app/src/services/channel/index.ts | 4 ++ web-app/src/services/channel/mock.ts | 8 +++ web-app/src/services/state/actions/context.ts | 6 +- web-app/src/services/state/actions/editor.ts | 9 ++- web-app/src/services/state/guards/index.ts | 69 ++++++++----------- web-app/src/services/state/machine.ts | 11 ++- 9 files changed, 63 insertions(+), 121 deletions(-) delete mode 100644 web-app/src/containers/Tutorial/LevelPage/queryLevel.ts diff --git a/web-app/src/containers/Tutorial/LevelPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx index c4bf52e8..fd19a934 100644 --- a/web-app/src/containers/Tutorial/LevelPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/index.tsx @@ -1,11 +1,8 @@ import * as React from 'react' -import { useQuery } from '@apollo/react-hooks' import * as CR from 'typings' import * as G from 'typings/graphql' -import ErrorView from '../../../components/Error' import Level from './Level' -import queryLevel from './queryLevel' interface LevelProps { level: G.Level @@ -30,23 +27,7 @@ interface ContainerProps { const LevelSummaryPageContainer = (props: ContainerProps) => { const { tutorial, position, progress } = props.context - const { loading, error, data } = useQuery(queryLevel, { - variables: { - tutorialId: tutorial.id, - version: tutorial.version.version, - levelId: position.levelId, - }, - }) - - if (loading) { - return
Loading Levels...
- } - - if (error) { - return - } - - const { level } = data.tutorial.version + const level: G.Level = tutorial.version.levels.find((l: G.Level) => l.id === position.levelId) level.stages.forEach((stage: G.Stage) => { if (stage.id === position.stageId) { diff --git a/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts b/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts deleted file mode 100644 index adb4a553..00000000 --- a/web-app/src/containers/Tutorial/LevelPage/queryLevel.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {gql} from 'apollo-boost' - -export default gql` - query getLevel($tutorialId: ID!, $version: String, $levelId: ID!) { - tutorial(id: $tutorialId) { - id - version(version: $version) { - version - coderoadVersion - level(levelId: $levelId) { - id - title - text - setup { - id - commits - commands - files - } - stages { - id - title - text - setup { - id - commits - commands - files - } - } - } - } - } -} -` diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index 8a4e66a5..9c118584 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -1,11 +1,8 @@ import * as React from 'react' import * as CR from 'typings' import * as G from 'typings/graphql' -import { useQuery } from '@apollo/react-hooks' -import ErrorView from '../../../components/Error' import Stage from './Stage' -import queryStage from './queryStage' interface PageProps { context: CR.MachineContext, @@ -14,22 +11,8 @@ interface PageProps { const StageSummaryPageContainer = (props: PageProps) => { const { tutorial, position, progress } = props.context - const { loading, error, data } = useQuery(queryStage, { - variables: { - tutorialId: tutorial.id, - version: tutorial.version.version, - stageId: position.stageId, - }, - }) - if (loading) { - return
Loading Stage...
- } - if (error) { - return - } - - const { stage } = data.tutorial.version + const stage: G.Stage = tutorial.version.levels.find((l: G.Level) => l.id === position.levelId).stages.find((s: G.Stage) => s.id === position.stageId) const onContinue = (): void => { props.send({ @@ -42,7 +25,7 @@ const StageSummaryPageContainer = (props: PageProps) => { const onSave =(): void => { props.send({ - type: 'TEST_RUNNING', + type: 'TEST_RUN', payload: { stepId: position.stepId, } diff --git a/web-app/src/services/channel/index.ts b/web-app/src/services/channel/index.ts index a90536a9..aa5f5160 100644 --- a/web-app/src/services/channel/index.ts +++ b/web-app/src/services/channel/index.ts @@ -38,6 +38,10 @@ class Channel { this.machineSend('TUTORIAL_LOADED') console.log('send action to state machine') return + case 'TEST_PASS': + this.machineSend(action) + console.log('test passed') + return default: console.warn(`Unknown received action ${action.type}`, action) } diff --git a/web-app/src/services/channel/mock.ts b/web-app/src/services/channel/mock.ts index eb3ba84d..a4604935 100644 --- a/web-app/src/services/channel/mock.ts +++ b/web-app/src/services/channel/mock.ts @@ -19,6 +19,14 @@ window.acquireVsCodeApi = () => ({ } channel.receive(createReceiveEvent(receiveAction)) }, 1000) + case 'TEST_RUN': + return setTimeout(() => { + const receiveAction: Action = { + type: 'TEST_PASS', + payload: action.payload, + } + channel.receive(createReceiveEvent(receiveAction)) + }) default: console.warn(`${action.type} not found in post message mock`) } diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 9ec03ad6..1888a5c9 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -27,10 +27,11 @@ export default { }, }), // @ts-ignore - testPass: assign({ + updateStepProgress: assign({ progress: (context: CR.MachineContext, event: CR.MachineEvent): CR.Progress => { // update progress by tracking completed const currentProgress: CR.Progress = context.progress + console.log('progress update', event.payload) const stepId = event.payload.stepId currentProgress.steps[stepId] = true @@ -44,9 +45,10 @@ export default { const currentPosition: CR.Position = context.position // merge in the updated position // sent with the test to ensure consistency + console.log('should calculate next step') + return { ...currentPosition, - ...event.payload.nextPosition, } }, }) diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index 413f79fe..5971976a 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -15,7 +15,14 @@ export default { testRunnerSetup(context: CR.MachineContext) { console.log('test runner setup', context) }, - testStart() { + testStart(context: CR.MachineContext, event: CR.MachineEvent) { console.log('test start') + const {stepId} = event.payload + channel.editorSend({ + type: 'TEST_RUN', + payload: { + stepId, + } + }) } } \ No newline at end of file diff --git a/web-app/src/services/state/guards/index.ts b/web-app/src/services/state/guards/index.ts index 024b3cd2..8b880a68 100644 --- a/web-app/src/services/state/guards/index.ts +++ b/web-app/src/services/state/guards/index.ts @@ -1,43 +1,30 @@ -// import * as CR from 'typings' -// import {TutorialModel} from '../../services/tutorial' - - -export default {} +import * as G from 'typings/graphql' +import * as CR from 'typings' // // TODO: refactor into a single calculation -// export default (tutorialModel: TutorialModel) => ({ -// hasNextStep: (): boolean => { - -// const nextPosition: CR.Position = tutorialModel.nextPosition() - -// const sameStage = nextPosition.stageId === tutorialModel.position.stageId -// const sameStep = nextPosition.stepId === tutorialModel.position.stepId - -// const hasNext: boolean = sameStage && sameStep - -// console.log('GUARD: hasNextStep', hasNext) -// return hasNext -// }, -// hasNextStage: (): boolean => { -// const nextPosition: CR.Position = tutorialModel.nextPosition() - -// const sameLevel = nextPosition.levelId === tutorialModel.position.levelId -// const sameStage = nextPosition.stageId === tutorialModel.position.stageId - -// const hasNext: boolean = sameLevel && sameStage - -// console.log('GUARD: hasNextStage', hasNext) -// return hasNext -// }, -// hasNextLevel: (): boolean => { -// const nextPosition: CR.Position = tutorialModel.nextPosition() - -// const sameLevel = nextPosition.levelId === tutorialModel.position.levelId - -// const hasNext: boolean = sameLevel - -// // TODO: ensure this accounts for end -// console.log('GUARD: hasNextLevel', hasNext) -// return hasNext -// }, -// }) +export default { + hasNextStep: (context: CR.MachineContext): boolean => { + const {tutorial, position} = context + // TODO: protect against errors + const steps: G.Step[] = tutorial.version.levels.find((l: G.Level) => l.id === position.levelId).stages.find((s: G.Stage) => s.id === position.stageId).steps + + // TODO: verify not -1 + return !(steps.indexOf(position.stepId) === steps.length - 1) + }, + hasNextStage: (context: CR.MachineContext): boolean => { + const {tutorial, position} = context + // TODO: protect against errors + const stages: G.Stage[] = tutorial.version.levels.find((l: G.Level) => l.id === position.levelId).stages + + // TODO: verify not -1 + return !(stages.indexOf(position.stageId) === stages.length - 1) + }, + hasNextLevel: (context: CR.MachineContext): boolean => { + const {tutorial, position} = context + // TODO: protect against errors + const levels: G.Level[] = tutorial.version.levels + + // TODO: verify not -1 + return !(levels.indexOf(position.levelId) === levels.length - 1) + }, +} diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 6ec9d0c2..0b663392 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -110,7 +110,10 @@ export const machine = Machine Date: Mon, 2 Sep 2019 12:57:36 -0700 Subject: [PATCH 080/117] fix up step progress --- .../containers/Tutorial/StagePage/index.tsx | 29 +++++++++++++++++-- web-app/src/services/state/actions/context.ts | 16 ++++++++-- web-app/src/services/state/guards/index.ts | 15 ++++++---- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index 9c118584..fa382bc0 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -12,7 +12,9 @@ interface PageProps { const StageSummaryPageContainer = (props: PageProps) => { const { tutorial, position, progress } = props.context - const stage: G.Stage = tutorial.version.levels.find((l: G.Level) => l.id === position.levelId).stages.find((s: G.Stage) => s.id === position.stageId) + const stage: G.Stage = tutorial.version + .levels.find((l: G.Level) => l.id === position.levelId) + .stages.find((s: G.Stage) => s.id === position.stageId) const onContinue = (): void => { props.send({ @@ -32,7 +34,7 @@ const StageSummaryPageContainer = (props: PageProps) => { }) } - stage.steps.forEach((step: G.Step) => { + stage.steps.map((step: G.Step) => { if (step.id === position.stepId) { step.status = 'ACTIVE' } else if (progress.steps[step.id]) { @@ -46,3 +48,26 @@ const StageSummaryPageContainer = (props: PageProps) => { } export default StageSummaryPageContainer + +/* + const formattedStage = { + ...stage, + steps: stage.steps.map((step: G.Step) => { + if (step.id === position.stepId) { + return { + ...step, + status: 'ACTIVE' + } + } else if (progress.steps[step.id]) { + return { + ...step, + status: 'COMPLETE' + } + } else { + return { + ...step, + status: 'INCOMPLETE' + } + } + }) + */ \ No newline at end of file diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 1888a5c9..9cb9ea26 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -42,13 +42,23 @@ export default { // @ts-ignore stepLoadNext: assign({ position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { - const currentPosition: CR.Position = context.position + const position: CR.Position = context.position // merge in the updated position // sent with the test to ensure consistency - console.log('should calculate next step') + const steps: G.Step[] = context.tutorial.version + .levels.find((l: G.Level) => l.id === position.levelId) + .stages.find((s: G.Stage) => s.id === position.stageId) + .steps + + const stepIndex = steps.findIndex((s: G.Step) => s.id === position.stepId) + console.log('step index', stepIndex) + const step: G.Step = steps[stepIndex + 1] + + console.log('step load next', step.id, position.stepId) return { - ...currentPosition, + ...position, + stepId: step.id } }, }) diff --git a/web-app/src/services/state/guards/index.ts b/web-app/src/services/state/guards/index.ts index 8b880a68..86763294 100644 --- a/web-app/src/services/state/guards/index.ts +++ b/web-app/src/services/state/guards/index.ts @@ -6,18 +6,23 @@ export default { hasNextStep: (context: CR.MachineContext): boolean => { const {tutorial, position} = context // TODO: protect against errors - const steps: G.Step[] = tutorial.version.levels.find((l: G.Level) => l.id === position.levelId).stages.find((s: G.Stage) => s.id === position.stageId).steps + const steps: G.Step[] = tutorial.version + .levels.find((l: G.Level) => l.id === position.levelId) + .stages.find((s: G.Stage) => s.id === position.stageId) + .steps // TODO: verify not -1 - return !(steps.indexOf(position.stepId) === steps.length - 1) + return !(steps.findIndex((s: G.Step) => s.id === position.stepId) === steps.length - 1) }, hasNextStage: (context: CR.MachineContext): boolean => { const {tutorial, position} = context // TODO: protect against errors - const stages: G.Stage[] = tutorial.version.levels.find((l: G.Level) => l.id === position.levelId).stages + const stages: G.Stage[] = tutorial.version + .levels.find((l: G.Level) => l.id === position.levelId) + .stages // TODO: verify not -1 - return !(stages.indexOf(position.stageId) === stages.length - 1) + return !(stages.findIndex((s: G.Stage) => s.id === position.stageId) === stages.length - 1) }, hasNextLevel: (context: CR.MachineContext): boolean => { const {tutorial, position} = context @@ -25,6 +30,6 @@ export default { const levels: G.Level[] = tutorial.version.levels // TODO: verify not -1 - return !(levels.indexOf(position.levelId) === levels.length - 1) + return !(levels.findIndex((l: G.Level) => l.id === position.levelId) === levels.length - 1) }, } From bb1490153e9b8c6c433f5b888ec3ab7f1347a933 Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 2 Sep 2019 13:46:21 -0700 Subject: [PATCH 081/117] fix stage complete --- .../src/containers/Tutorial/StagePage/index.tsx | 9 +++++---- web-app/src/services/state/actions/context.ts | 16 +++++++++++++++- web-app/src/services/state/actions/index.ts | 2 +- web-app/src/services/state/guards/index.ts | 4 +++- web-app/src/services/state/machine.ts | 1 + 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index fa382bc0..688bd4eb 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -34,15 +34,16 @@ const StageSummaryPageContainer = (props: PageProps) => { }) } - stage.steps.map((step: G.Step) => { - if (step.id === position.stepId) { - step.status = 'ACTIVE' - } else if (progress.steps[step.id]) { + stage.steps.forEach((step: G.Step) => { + if (progress.steps[step.id]) { step.status = 'COMPLETE' + } else if (step.id === position.stepId) { + step.status = 'ACTIVE' } else { step.status = 'INCOMPLETE' } }) + stage.status = progress.stages[position.stageId] ? 'COMPLETE' : 'ACTIVE' return } diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 9cb9ea26..1cc688d7 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -31,8 +31,8 @@ export default { progress: (context: CR.MachineContext, event: CR.MachineEvent): CR.Progress => { // update progress by tracking completed const currentProgress: CR.Progress = context.progress - console.log('progress update', event.payload) const stepId = event.payload.stepId + console.log('step progress update', stepId) currentProgress.steps[stepId] = true @@ -40,6 +40,20 @@ export default { }, }), // @ts-ignore + updateStageProgress: assign({ + progress: (context: CR.MachineContext, event: CR.MachineEvent): CR.Progress => { + // update progress by tracking completed + const {progress, position} = context + + const stageId: string = position.stageId + console.log('stage progress update', stageId) + + progress.stages[stageId] = true + + return progress + }, + }), + // @ts-ignore stepLoadNext: assign({ position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { const position: CR.Position = context.position diff --git a/web-app/src/services/state/actions/index.ts b/web-app/src/services/state/actions/index.ts index 50e55e0a..96816a3b 100644 --- a/web-app/src/services/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -2,7 +2,7 @@ import {send} from 'xstate' // import {machine} from '../../extension' // import {cache} from '../../services/apollo' // import {editorDispatch} from '../../services/vscode' -import * as CR from 'typings' +// import * as CR from 'typings' // import * as G from 'typings/graphql' // import tutorialConfig from '../../services/apollo/queries/tutorialConfig' import editorActions from './editor' diff --git a/web-app/src/services/state/guards/index.ts b/web-app/src/services/state/guards/index.ts index 86763294..66e87811 100644 --- a/web-app/src/services/state/guards/index.ts +++ b/web-app/src/services/state/guards/index.ts @@ -12,7 +12,9 @@ export default { .steps // TODO: verify not -1 - return !(steps.findIndex((s: G.Step) => s.id === position.stepId) === steps.length - 1) + const hasNextStep = !(steps.findIndex((s: G.Step) => s.id === position.stepId) === steps.length - 1) + console.log(hasNextStep, steps, position.stepId) + return hasNextStep }, hasNextStage: (context: CR.MachineContext): boolean => { const {tutorial, position} = context diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 0b663392..d4ef9456 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -151,6 +151,7 @@ export const machine = Machine Date: Mon, 2 Sep 2019 14:00:01 -0700 Subject: [PATCH 082/117] navigate through stages & levels --- web-app/src/services/state/actions/context.ts | 87 ++++++++++++++----- web-app/src/services/state/machine.ts | 9 +- 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 1cc688d7..da4d9f01 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -27,6 +27,70 @@ export default { }, }), // @ts-ignore + updateStepPosition: assign({ + position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { + const position: CR.Position = context.position + // merge in the updated position + // sent with the test to ensure consistency + const steps: G.Step[] = context.tutorial.version + .levels.find((l: G.Level) => l.id === position.levelId) + .stages.find((s: G.Stage) => s.id === position.stageId) + .steps + + const stepIndex = steps.findIndex((s: G.Step) => s.id === position.stepId) + const step: G.Step = steps[stepIndex + 1] + + console.log('step load next', step.id, position.stepId) + + return { + ...position, + stepId: step.id + } + }, + }), + // @ts-ignore + updateStagePosition: assign({ + position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { + const position: CR.Position = context.position + // merge in the updated position + // sent with the test to ensure consistency + const stages: G.Stage[] = context.tutorial.version + .levels.find((l: G.Level) => l.id === position.levelId) + .stages + + const stageIndex = stages.findIndex((s: G.Stage) => s.id === position.stageId) + const stage: G.Stage = stages[stageIndex + 1] + + console.log('stage load next', stage.id, position.stageId) + + return { + ...position, + stageId: stage.id, + stepId: stage.steps[0].id, + } + }, + }), + // @ts-ignore + updateLevelPosition: assign({ + position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { + const position: CR.Position = context.position + // merge in the updated position + // sent with the test to ensure consistency + const levels: G.Level[] = context.tutorial.version.levels + + const levelIndex = levels.findIndex((l: G.Level) => l.id === position.levelId) + const level: G.Level = levels[levelIndex + 1] + + console.log('level load next', level.id, position.levelId) + + return { + levelId: level.id, + stageId: level.stages[0].id, + stepId: level.stages[0].steps[0].id, + } + }, + }), + // @ts-ignore updateStepProgress: assign({ progress: (context: CR.MachineContext, event: CR.MachineEvent): CR.Progress => { // update progress by tracking completed @@ -53,27 +117,4 @@ export default { return progress }, }), - // @ts-ignore - stepLoadNext: assign({ - position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { - const position: CR.Position = context.position - // merge in the updated position - // sent with the test to ensure consistency - const steps: G.Step[] = context.tutorial.version - .levels.find((l: G.Level) => l.id === position.levelId) - .stages.find((s: G.Stage) => s.id === position.stageId) - .steps - - const stepIndex = steps.findIndex((s: G.Step) => s.id === position.stepId) - console.log('step index', stepIndex) - const step: G.Step = steps[stepIndex + 1] - - console.log('step load next', step.id, position.stepId) - - return { - ...position, - stepId: step.id - } - }, - }) } \ No newline at end of file diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index d4ef9456..b9cb6157 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -77,10 +77,12 @@ export const machine = Machine Date: Mon, 2 Sep 2019 14:13:25 -0700 Subject: [PATCH 083/117] complete new tutorial loop --- web-app/src/Routes.tsx | 2 +- .../src/containers/Tutorial/CompletedPage.tsx | 27 +++++++++++++++++-- .../Tutorial/LevelPage/Level/index.tsx | 10 +++---- .../containers/Tutorial/LevelPage/index.tsx | 5 +--- .../containers/Tutorial/StagePage/index.tsx | 2 +- web-app/src/services/state/machine.ts | 5 +++- 6 files changed, 35 insertions(+), 16 deletions(-) diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index d679c242..c276447e 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -72,7 +72,7 @@ const Routes = () => { - +
diff --git a/web-app/src/containers/Tutorial/CompletedPage.tsx b/web-app/src/containers/Tutorial/CompletedPage.tsx index 813290e3..742dc0ea 100644 --- a/web-app/src/containers/Tutorial/CompletedPage.tsx +++ b/web-app/src/containers/Tutorial/CompletedPage.tsx @@ -1,7 +1,30 @@ import * as React from 'react' +import { Button } from '@alifd/next' +import * as CR from 'typings' -const CompletedPage = () => { - return
Tutorial Complete
+const styles = { + options: { + padding: '0rem 1rem', + }, +} + +interface Props { + context: CR.MachineContext + send(action: CR.Action|string): void +} + +const CompletedPage = (props: Props) => { + const selectNewTutorial = () => { + props.send('SELECT_TUTORIAL') + } + return ( +
+

Tutorial Complete

+
+ +
+
+ ) } export default CompletedPage diff --git a/web-app/src/containers/Tutorial/LevelPage/Level/index.tsx b/web-app/src/containers/Tutorial/LevelPage/Level/index.tsx index cb6eefa5..785bc088 100644 --- a/web-app/src/containers/Tutorial/LevelPage/Level/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/Level/index.tsx @@ -1,4 +1,4 @@ -import { Button, Step } from '@alifd/next' +import { Step } from '@alifd/next' import * as React from 'react' import * as T from 'typings/graphql' @@ -26,10 +26,9 @@ const styles = { interface Props { level: T.Level onNext(): void - onBack(): void } -const Level = ({ level, onNext, onBack }: Props) => { +const Level = ({ level, onNext }: Props) => { if (!level || !level.stages) { throw new Error('No level stages found') } @@ -53,7 +52,7 @@ const Level = ({ level, onNext, onBack }: Props) => { /* empty */ } // note - must add click handler to title, content & step.item - // as all are separted components + // as all are separated components return ( { })}
-
- -
) } diff --git a/web-app/src/containers/Tutorial/LevelPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx index fd19a934..92110601 100644 --- a/web-app/src/containers/Tutorial/LevelPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/index.tsx @@ -13,10 +13,7 @@ export const LevelSummaryPage = (props: LevelProps) => { const onNext = (): void => { props.send('NEXT') } - const onBack = (): void => { - props.send('BACK') - } - return + return } interface ContainerProps { diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index 688bd4eb..5479632e 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -5,7 +5,7 @@ import * as G from 'typings/graphql' import Stage from './Stage' interface PageProps { - context: CR.MachineContext, + context: CR.MachineContext send(action: CR.Action): void } diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index b9cb6157..ac9b6c1a 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -30,6 +30,7 @@ export const machine = Machine Date: Mon, 2 Sep 2019 14:17:57 -0700 Subject: [PATCH 084/117] reset progress on exit --- web-app/src/services/state/actions/context.ts | 21 +++++++++++++++++++ web-app/src/services/state/machine.ts | 5 ++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index da4d9f01..669f399b 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -117,4 +117,25 @@ export default { return progress }, }), + // @ts-ignore + reset: assign({ + tutorial() { + return null + }, + progress(): CR.Progress { + return { + levels: {}, + stages: {}, + steps: {}, + complete: false + } + }, + position(): CR.Position { + return { + levelId: '', + stageId: '', + stepId: '' + } + } + }) } \ No newline at end of file diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index ac9b6c1a..baa14f4b 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -169,7 +169,10 @@ export const machine = Machine Date: Mon, 2 Sep 2019 14:33:34 -0700 Subject: [PATCH 085/117] fix up client tutorialConfig --- .../src/containers/Continue/queryTutorial.ts | 3 +- .../Tutorial/StagePage/queryStage.ts | 41 ------------------- .../Tutorial/SummaryPage/querySummary.ts | 5 +++ .../services/apollo/queries/tutorialConfig.ts | 13 ------ .../services/apollo/queries/tutorialRepo.ts | 16 -------- web-app/src/services/state/actions/editor.ts | 18 ++++++-- web-app/src/services/state/machine.ts | 3 +- 7 files changed, 23 insertions(+), 76 deletions(-) delete mode 100644 web-app/src/containers/Tutorial/StagePage/queryStage.ts delete mode 100644 web-app/src/services/apollo/queries/tutorialConfig.ts delete mode 100644 web-app/src/services/apollo/queries/tutorialRepo.ts diff --git a/web-app/src/containers/Continue/queryTutorial.ts b/web-app/src/containers/Continue/queryTutorial.ts index 43739ed9..ef4042b7 100644 --- a/web-app/src/containers/Continue/queryTutorial.ts +++ b/web-app/src/containers/Continue/queryTutorial.ts @@ -1,4 +1,4 @@ -import { gql } from 'apollo-boost' +import {gql} from 'apollo-boost' export default gql` query getTutorial($tutorialId: ID!, $version: String) { @@ -12,6 +12,7 @@ export default gql` } createdAt codingLanguage + testRunner repo { uri branch diff --git a/web-app/src/containers/Tutorial/StagePage/queryStage.ts b/web-app/src/containers/Tutorial/StagePage/queryStage.ts deleted file mode 100644 index 9331bc64..00000000 --- a/web-app/src/containers/Tutorial/StagePage/queryStage.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {gql} from 'apollo-boost' - -export default gql` - query getStage($tutorialId: ID!, $version: String, $stageId: ID!) { - tutorial(id: $tutorialId) { - id - version(version: $version) { - version - coderoadVersion - stage(stageId: $stageId) { - id - title - text - setup { - id - commits - commands - files - } - steps { - id - title - text - setup { - id - commits - commands - files - } - solution { - id - commits - commands - files - } - } - } - } - } -} -` diff --git a/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts b/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts index eb2d7294..9228ebd4 100644 --- a/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts +++ b/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts @@ -6,6 +6,11 @@ export default gql` id title text + codingLanguage + testRunner + repo { + uri + } version(version: $version) { version coderoadVersion diff --git a/web-app/src/services/apollo/queries/tutorialConfig.ts b/web-app/src/services/apollo/queries/tutorialConfig.ts deleted file mode 100644 index 23ce4ba6..00000000 --- a/web-app/src/services/apollo/queries/tutorialConfig.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {gql} from 'apollo-boost' - -const getTutorialConfig = gql` - query getTutorialConfig($tutorialId: ID!) { - tutorial(id: $tutorialId) { - id - testRunner - codingLanguage - } - } -` - -export default getTutorialConfig \ No newline at end of file diff --git a/web-app/src/services/apollo/queries/tutorialRepo.ts b/web-app/src/services/apollo/queries/tutorialRepo.ts deleted file mode 100644 index 3c8dfd6c..00000000 --- a/web-app/src/services/apollo/queries/tutorialRepo.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {gql} from 'apollo-boost' - -const getTutorialRepo = gql` - query getTutorialRepo($tutorialId: ID!) { - tutorial(id: $tutorialId) { - id - repo { - uri - name - branch - } - } - } -` - -export default getTutorialRepo \ No newline at end of file diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index 5971976a..5f8672cd 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -3,6 +3,7 @@ import channel from '../../channel' export default { tutorialStart() { + console.log('EDITOR: TUTORIAL_START') channel.editorSend({ type: 'TUTORIAL_START', payload: { @@ -12,11 +13,22 @@ export default { } }) }, - testRunnerSetup(context: CR.MachineContext) { - console.log('test runner setup', context) + tutorialConfig(context: CR.MachineContext) { + // setup test runner and git + const {tutorial} = context + const payload = { + codingLanguage: tutorial.codingLanguage, + testRunner: tutorial.testRunner, + repo: tutorial.repo, + } + console.log('EDITOR: TUTORIAL_CONFIG') + channel.editorSend({ + type: 'TUTORIAL_CONFIG', + payload, + }) }, testStart(context: CR.MachineContext, event: CR.MachineEvent) { - console.log('test start') + console.log('EDITOR: TEST_RUN') const {stepId} = event.payload channel.editorSend({ type: 'TEST_RUN', diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index baa14f4b..10345a04 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -60,7 +60,6 @@ export const machine = Machine Date: Mon, 2 Sep 2019 14:57:51 -0700 Subject: [PATCH 086/117] setup local storage of tutorial,progress,position --- src/editor/storage.ts | 22 ------ src/services/storage.ts | 78 ------------------- web-app/src/services/state/actions/context.ts | 38 +++++++-- web-app/src/services/state/actions/storage.ts | 27 +++++++ 4 files changed, 59 insertions(+), 106 deletions(-) delete mode 100644 src/editor/storage.ts delete mode 100644 src/services/storage.ts create mode 100644 web-app/src/services/state/actions/storage.ts diff --git a/src/editor/storage.ts b/src/editor/storage.ts deleted file mode 100644 index b63c8562..00000000 --- a/src/editor/storage.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as vscode from 'vscode' - -class EditorStorage { - private storage: vscode.Memento - constructor() { - this.storage = {} as vscode.Memento - } - public init = (storage: vscode.Memento): void => { - console.log('setStorage workspace') - this.storage = storage - } - public get = (key: string): T | undefined => { - console.log(`called get ${key}`) - return this.storage.get(key) - } - public update = (key: string, value: string | object): Thenable => { - console.log(`called update on ${key}`) - return this.storage.update(key, value) - } -} - -export default new EditorStorage() diff --git a/src/services/storage.ts b/src/services/storage.ts deleted file mode 100644 index 61eaeddd..00000000 --- a/src/services/storage.ts +++ /dev/null @@ -1,78 +0,0 @@ -import * as CR from 'typings' -import * as G from 'typings/graphql' -import storage from '../editor/storage' - -// TUTORIAL -const STORE_TUTORIAL = 'coderoad:tutorial' - -export async function getTutorial(): Promise { - return storage.get(STORE_TUTORIAL) -} - -export async function setTutorial(tutorial: G.Tutorial): Promise { - await storage.update(STORE_TUTORIAL, tutorial) -} - -// POSITION -const STORE_POSITION = 'coderoad:position' - -const defaultPosition = {levelId: '', stageId: '', stepId: ''} - -export async function getPosition(): Promise { - const position: CR.Position | undefined = storage.get(STORE_POSITION) - return position || defaultPosition -} - -export async function setPosition(position: CR.Position): Promise { - await storage.update(STORE_POSITION, position) -} - -// PROGRESS -const STORE_PROGRESS = 'coderoad:progress' - -const defaultProgress = {levels: {}, stages: {}, steps: {}, hints: {}, complete: false} - -export async function getProgress(): Promise { - const progress: CR.Progress | undefined = await storage.get(STORE_PROGRESS) - return progress || defaultProgress -} - -export async function resetProgress(): Promise { - await storage.update(STORE_PROGRESS, defaultProgress) -} - -interface ProgressUpdate { - levels?: { - [levelId: string]: boolean - } - stages?: { - [stageid: string]: boolean - } - steps?: { - [stepId: string]: boolean - } -} - -export async function setProgress(record: ProgressUpdate): Promise { - const progress = await getProgress() - if (record.levels) { - progress.levels = { - ...progress.levels, - ...record.levels, - } - } - if (record.stages) { - progress.stages = { - ...progress.stages, - ...record.stages, - } - } - if (record.steps) { - progress.steps = { - ...progress.steps, - ...record.steps, - } - } - - await storage.update(STORE_PROGRESS, progress) -} diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 669f399b..03588bb7 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -1,11 +1,14 @@ import {assign} from 'xstate' import * as G from 'typings/graphql' import * as CR from 'typings' +import * as storage from './storage' export default { setTutorial: assign({ tutorial: (context: CR.MachineContext, event: CR.MachineEvent): any => { - return event.payload.tutorial + const {tutorial} = event.payload + storage.tutorial.set(tutorial) + return tutorial }, }), // @ts-ignore @@ -23,6 +26,8 @@ export default { stepId: version.levels[0].stages[0].steps[0].id, } + storage.position.set(position) + return position }, }), @@ -42,10 +47,14 @@ export default { console.log('step load next', step.id, position.stepId) - return { + const nextPosition: CR.Position = { ...position, stepId: step.id } + + storage.position.set(nextPosition) + + return nextPosition }, }), // @ts-ignore @@ -63,11 +72,15 @@ export default { console.log('stage load next', stage.id, position.stageId) - return { + const nextPosition: CR.Position = { ...position, stageId: stage.id, stepId: stage.steps[0].id, } + + storage.position.set(nextPosition) + + return nextPosition }, }), // @ts-ignore @@ -83,11 +96,15 @@ export default { console.log('level load next', level.id, position.levelId) - return { + const nextPosition: CR.Position = { levelId: level.id, stageId: level.stages[0].id, stepId: level.stages[0].steps[0].id, } + + storage.position.set(nextPosition) + + return nextPosition }, }), // @ts-ignore @@ -100,6 +117,8 @@ export default { currentProgress.steps[stepId] = true + storage.progress.set(currentProgress) + return currentProgress }, }), @@ -114,28 +133,35 @@ export default { progress.stages[stageId] = true + storage.progress.set(progress) + return progress }, }), // @ts-ignore reset: assign({ tutorial() { + storage.tutorial.set(null) return null }, progress(): CR.Progress { - return { + const progress: CR.Progress = { levels: {}, stages: {}, steps: {}, complete: false } + storage.progress.set(progress) + return progress }, position(): CR.Position { - return { + const position: CR.Position = { levelId: '', stageId: '', stepId: '' } + storage.position.set(position) + return position } }) } \ No newline at end of file diff --git a/web-app/src/services/state/actions/storage.ts b/web-app/src/services/state/actions/storage.ts new file mode 100644 index 00000000..863846fc --- /dev/null +++ b/web-app/src/services/state/actions/storage.ts @@ -0,0 +1,27 @@ +import * as CR from 'typings' +import * as G from 'typings/graphql' + +// localStorage + +class Storage { + private key: string + private storage = localStorage + constructor(key: string) { + this.key = key + } + public get = (key: string): T | null => { + const value = this.storage.getItem(this.key) + if (value) { + return JSON.parse(value) + } + return null + } + public set = (value: T): void => { + const stringValue = JSON.stringify(value) + this.storage.setItem(this.key, stringValue) + } +} + +export const tutorial = new Storage('coderoad:tutorial') +export const position = new Storage('coderoad:position') +export const progress = new Storage('coderoad:progress') From beafa327e94aac7bef0122f7e73de760719794c6 Mon Sep 17 00:00:00 2001 From: shmck Date: Mon, 2 Sep 2019 16:47:25 -0700 Subject: [PATCH 087/117] load all tutorial --- web-app/src/containers/Continue/index.tsx | 25 +--------------- .../src/containers/Continue/queryTutorial.ts | 29 ------------------- .../containers/Tutorial/StagePage/index.tsx | 2 ++ .../containers/Tutorial/SummaryPage/index.tsx | 4 +-- .../{querySummary.ts => queryTutorial.ts} | 8 ++++- web-app/src/services/state/guards/index.ts | 8 ++--- 6 files changed, 15 insertions(+), 61 deletions(-) delete mode 100644 web-app/src/containers/Continue/queryTutorial.ts rename web-app/src/containers/Tutorial/SummaryPage/{querySummary.ts => queryTutorial.ts} (83%) diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index b804fd84..52fbd73d 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -1,14 +1,8 @@ import * as React from 'react' -import { useQuery } from '@apollo/react-hooks' import { Button, Card } from '@alifd/next' import * as CR from 'typings' import * as T from 'typings/graphql' -// import { editorDispatch } from '../../services/vscode' -import LoadingPage from '../LoadingPage' -import queryTutorial from './queryTutorial' -import ErrorView from '../../components/Error' - interface Props { tutorial: T.Tutorial onContinue(): void @@ -27,8 +21,6 @@ export const ContinuePage = (props: Props) => (
) -const Loading = () => - interface ContainerProps { context: CR.MachineContext } @@ -36,25 +28,10 @@ interface ContainerProps { const ContinuePageContainer = ({ context }: ContainerProps) => { // TODO: load specific tutorialId const { tutorial } = context - // const { tutorialId, version } = currentTutorial.get() - const { data, loading, error } = useQuery(queryTutorial, { - variables: { - tutorialId: tutorial.id, - version: tutorial.version.version, - }, - }) - - if (loading) { - return - } - - if (error) { - return - } return ( { console.log('TUTORIAL_START') }} diff --git a/web-app/src/containers/Continue/queryTutorial.ts b/web-app/src/containers/Continue/queryTutorial.ts deleted file mode 100644 index ef4042b7..00000000 --- a/web-app/src/containers/Continue/queryTutorial.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {gql} from 'apollo-boost' - -export default gql` - query getTutorial($tutorialId: ID!, $version: String) { - tutorial(id: $tutorialId) { - id - title - text - createdBy { - id - name - } - createdAt - codingLanguage - testRunner - repo { - uri - branch - owner - name - } - version(version: $version) { - version - coderoadVersion - } - } -} - -` diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index 5479632e..fb477e46 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -45,6 +45,8 @@ const StageSummaryPageContainer = (props: PageProps) => { }) stage.status = progress.stages[position.stageId] ? 'COMPLETE' : 'ACTIVE' + console.log('stage.status', stage.status) + return } diff --git a/web-app/src/containers/Tutorial/SummaryPage/index.tsx b/web-app/src/containers/Tutorial/SummaryPage/index.tsx index 4afbd973..f4443f63 100644 --- a/web-app/src/containers/Tutorial/SummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/SummaryPage/index.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import * as CR from 'typings' import { useQuery } from '@apollo/react-hooks' -import querySummary from './querySummary' +import queryTutorial from './queryTutorial' import Summary from './Summary' import ErrorView from '../../../components/Error' @@ -13,7 +13,7 @@ interface PageProps { const SummaryPage = (props: PageProps) => { const { tutorial } = props.context - const { loading, error, data } = useQuery(querySummary, { + const { loading, error, data } = useQuery(queryTutorial, { fetchPolicy: 'network-only', // for debugging purposes variables: { tutorialId: tutorial.id, diff --git a/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts b/web-app/src/containers/Tutorial/SummaryPage/queryTutorial.ts similarity index 83% rename from web-app/src/containers/Tutorial/SummaryPage/querySummary.ts rename to web-app/src/containers/Tutorial/SummaryPage/queryTutorial.ts index 9228ebd4..fe4a27d1 100644 --- a/web-app/src/containers/Tutorial/SummaryPage/querySummary.ts +++ b/web-app/src/containers/Tutorial/SummaryPage/queryTutorial.ts @@ -1,7 +1,7 @@ import {gql} from 'apollo-boost' export default gql` - query getSummary($tutorialId: ID!, $version: String) { + query getTutorial($tutorialId: ID!, $version: String) { tutorial(id: $tutorialId) { id title @@ -16,6 +16,8 @@ export default gql` coderoadVersion levels { id + title + text setup { id commands @@ -24,6 +26,8 @@ export default gql` } stages { id + title + text setup { id commands @@ -32,6 +36,8 @@ export default gql` } steps { id + title + text setup { id commands diff --git a/web-app/src/services/state/guards/index.ts b/web-app/src/services/state/guards/index.ts index 66e87811..5462409a 100644 --- a/web-app/src/services/state/guards/index.ts +++ b/web-app/src/services/state/guards/index.ts @@ -12,9 +12,7 @@ export default { .steps // TODO: verify not -1 - const hasNextStep = !(steps.findIndex((s: G.Step) => s.id === position.stepId) === steps.length - 1) - console.log(hasNextStep, steps, position.stepId) - return hasNextStep + return !(steps[steps.length - 1].id === position.stepId) }, hasNextStage: (context: CR.MachineContext): boolean => { const {tutorial, position} = context @@ -24,7 +22,7 @@ export default { .stages // TODO: verify not -1 - return !(stages.findIndex((s: G.Stage) => s.id === position.stageId) === stages.length - 1) + return !(stages[stages.length - 1].id === position.stageId) }, hasNextLevel: (context: CR.MachineContext): boolean => { const {tutorial, position} = context @@ -32,6 +30,6 @@ export default { const levels: G.Level[] = tutorial.version.levels // TODO: verify not -1 - return !(levels.findIndex((l: G.Level) => l.id === position.levelId) === levels.length - 1) + return !(levels[levels.length - 1].id === position.levelId) }, } From 55661c9ed23067a7559154a0576a6d0c1f0874d9 Mon Sep 17 00:00:00 2001 From: shmck Date: Tue, 3 Sep 2019 22:25:25 -0700 Subject: [PATCH 088/117] remove xstate react --- web-app/package-lock.json | 18 +++++++++--------- web-app/package.json | 7 +++---- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/web-app/package-lock.json b/web-app/package-lock.json index b7a2d2e5..c81e3ac3 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@alifd/next": { - "version": "1.17.8", - "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.17.8.tgz", - "integrity": "sha512-6vfiJyQOUGo/UCJt5KCWbkok7sp0Op3fifEt77VQsyf4xzPnJ/lIOCNJ2/uPX5rDrNvse23IIcgbwePjAQGvnw==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.17.9.tgz", + "integrity": "sha512-FJPlEyyleZjXNH6bdLwicn6NLTXwc5DdUbP1dNcYQaIpR6pMknmt2bR/0aI+kqjBe1/xW6KROFnTCGiyap3VQA==", "requires": { "babel-runtime": "^6.26.0", "classnames": "^2.2.3", @@ -2810,9 +2810,9 @@ } }, "@types/node": { - "version": "12.7.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.3.tgz", - "integrity": "sha512-3SiLAIBkDWDg6vFo0+5YJyHPWU9uwu40Qe+v+0MH8wRKYBimHvvAOyk3EzMrD/TrIlLYfXrqDqrg913PynrMJQ==" + "version": "12.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.4.tgz", + "integrity": "sha512-W0+n1Y+gK/8G2P/piTkBBN38Qc5Q1ZSO6B5H3QmPCUewaiXOo2GCAWZ4ElZCcNhjJuBSUSLGFUJnmlCn5+nxOQ==" }, "@types/prop-types": { "version": "15.7.1", @@ -3963,9 +3963,9 @@ } }, "babel-plugin-import": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/babel-plugin-import/-/babel-plugin-import-1.12.0.tgz", - "integrity": "sha512-3Fo7sJ2Hm71y1VJS7eMA/E7J5+roKJmzwia5BxzUQREBs6CRylwtvQq8m39W8nplG4Y7rZwOCndh5MzRTSmHpA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/babel-plugin-import/-/babel-plugin-import-1.12.1.tgz", + "integrity": "sha512-3BwVJFEByTUyqZWOxizr/YwYcqqre2EebmgSUtXyToJbHzJv6rTxA0LApDntvwERlmIvcM6lUktUN0snMTjOsA==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", diff --git a/web-app/package.json b/web-app/package.json index c6b4b160..5e3744c7 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -26,9 +26,8 @@ "extends": "react-app" }, "dependencies": { - "@alifd/next": "^1.17.8", + "@alifd/next": "^1.17.9", "@apollo/react-hooks": "^3.0.1", - "@xstate/react": "^0.7.1", "apollo-boost": "^0.4.4", "graphql": "^14.5.4", "markdown-it": "^9.1.0", @@ -52,13 +51,13 @@ "@types/highlight.js": "^9.12.3", "@types/jest": "^24.0.18", "@types/markdown-it": "0.0.8", - "@types/node": "^12.7.3", + "@types/node": "^12.7.4", "@types/ramda": "^0.26.21", "@types/react": "^16.9.2", "@types/react-dom": "^16.9.0", "@types/storybook__react": "^4.0.2", "babel-loader": "^8.0.6", - "babel-plugin-import": "^1.12.0", + "babel-plugin-import": "^1.12.1", "node-sass": "^4.12.0", "sass-loader": "^7.3.1", "typescript-eslint-parser": "^22.0.0" From ed19795344b907258c144743ac0e012c4e03305a Mon Sep 17 00:00:00 2001 From: shmck Date: Tue, 3 Sep 2019 22:25:57 -0700 Subject: [PATCH 089/117] cleanup machine --- web-app/src/components/Router/index.tsx | 13 +++++-- web-app/src/services/state/actions/editor.ts | 11 +++++- web-app/src/services/state/machine.ts | 39 +++++++------------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index 5ff06a8c..72a270b2 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -1,12 +1,15 @@ import * as React from 'react' import * as CR from 'typings' -import { useMachine } from '@xstate/react' +import { useMachine } from '../../services/xstate-react' import machine from '../../services/state/machine' import Route from './Route' import debuggerWrapper from '../Debugger/debuggerWrapper' import channel from '../../services/channel' import messageBusReceiver from '../../services/channel/receiver' +import actions from '../../services/state/actions' +import guards from '../../services/state/guards' + interface Props { children: any @@ -20,11 +23,13 @@ interface CloneElementProps { // router finds first state match of const Router = ({ children }: Props): React.ReactElement|null => { const [state, send] = useMachine(machine, { - logger: console.log.bind('XSTATE:') + actions, + guards, + interpreterOptions: { + logger: console.log.bind('XSTATE:') + } }) - console.log('state', state) - channel.setMachineSend(send) // event bus listener diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index 5f8672cd..9642bdea 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -36,5 +36,14 @@ export default { stepId, } }) - } + }, + loadLevel(): void { + // load step actions + }, + loadStage(): void { + // load step actions + }, + loadStep(): void { + // load step actions + }, } \ No newline at end of file diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 10345a04..8a9c8145 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -1,9 +1,6 @@ import {Machine} from 'xstate' import * as CR from 'typings' -import actions from './actions' -import guards from './guards' - export const machine = Machine( { id: 'root', @@ -69,26 +66,22 @@ export const machine = Machine Date: Tue, 3 Sep 2019 22:26:17 -0700 Subject: [PATCH 090/117] fix save/continue routing, improve "loadNext" --- .../containers/Tutorial/StagePage/index.tsx | 25 --- web-app/src/services/state/actions/context.ts | 87 ++++++++++- web-app/src/services/state/actions/index.ts | 4 +- web-app/src/services/state/guards/index.ts | 13 +- web-app/src/services/xstate-react/index.ts | 145 ++++++++++++++++++ 5 files changed, 239 insertions(+), 35 deletions(-) create mode 100644 web-app/src/services/xstate-react/index.ts diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index fb477e46..3d2da298 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -45,32 +45,7 @@ const StageSummaryPageContainer = (props: PageProps) => { }) stage.status = progress.stages[position.stageId] ? 'COMPLETE' : 'ACTIVE' - console.log('stage.status', stage.status) - return } export default StageSummaryPageContainer - -/* - const formattedStage = { - ...stage, - steps: stage.steps.map((step: G.Step) => { - if (step.id === position.stepId) { - return { - ...step, - status: 'ACTIVE' - } - } else if (progress.steps[step.id]) { - return { - ...step, - status: 'COMPLETE' - } - } else { - return { - ...step, - status: 'INCOMPLETE' - } - } - }) - */ \ No newline at end of file diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 03588bb7..a61cd65f 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -1,4 +1,4 @@ -import {assign} from 'xstate' +import {assign, send} from 'xstate' import * as G from 'typings/graphql' import * as CR from 'typings' import * as storage from './storage' @@ -42,10 +42,15 @@ export default { .stages.find((s: G.Stage) => s.id === position.stageId) .steps + + // final step but not completed + if (steps[steps.length - 1].id === position.stepId) { + return position + } + const stepIndex = steps.findIndex((s: G.Step) => s.id === position.stepId) - const step: G.Step = steps[stepIndex + 1] - console.log('step load next', step.id, position.stepId) + const step: G.Step = steps[stepIndex + 1] const nextPosition: CR.Position = { ...position, @@ -139,6 +144,82 @@ export default { }, }), // @ts-ignore + updatePosition: assign({ + position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Progress => { + console.log('updatePosition event', event) + const {position} = event.payload + return position + } + }), + loadNext: send((context: CR.MachineContext): CR.Action => { + const {tutorial, position, progress} = context + + // has next step? + const levels: G.Level[] = tutorial.version.levels + const level: G.Level | undefined = levels.find((l: G.Level) => l.id === position.levelId) + if (!level) { + throw new Error('No Level found') + } + const stages: G.Stage[] = level.stages + const stage: G.Stage | undefined = stages.find((s: G.Stage) => s.id === position.stageId) + if (!stage) { + throw new Error('No Stage found') + } + const steps: G.Step[] = stage.steps + + const stepIndex = steps.findIndex((s: G.Step) => s.id === position.stepId) + const stepComplete = progress.steps[position.stepId] + const finalStep = (stepIndex > -1 && stepIndex === steps.length - 1) + const hasNextStep = (!finalStep && !stepComplete) + + + // NEXT STEP + if (hasNextStep) { + const nextPosition = {...position, stepId: steps[stepIndex + 1].id} + return {type: 'NEXT_STEP', payload: {position: nextPosition}} + } + + // has next stage? + + const stageIndex = stages.findIndex((s: G.Stage) => s.id === position.stageId) + const stageComplete = progress.stages[position.stageId] + const finalStage = (stageIndex > -1 && stageIndex === stages.length - 1) + const hasNextStage = (!finalStage) + + // NEXT STAGE + if (hasNextStage) { + const nextStage = stages[stageIndex + 1] + const nextPosition = { + levelId: position.levelId, + stageId: nextStage.id, + stepId: nextStage.steps[0].id, + } + return {type: 'NEXT_STAGE', payload: {position: nextPosition}} + } + + // has next level? + + const levelIndex = levels.findIndex((l: G.Level) => l.id === position.levelId) + const levelComplete = progress.levels[position.levelId] + const finalLevel = (levelIndex > -1 && levelIndex === levels.length - 1) + const hasNextLevel = (!finalLevel) + + // NEXT LEVEL + if (hasNextLevel) { + const nextLevel = levels[levelIndex + 1] + const nextStage = nextLevel.stages[0] + const nextPosition = { + levelId: nextLevel.id, + stageId: nextStage.id, + stepId: nextStage.steps[0].id, + } + return {type: 'NEXT_LEVEL', payload: {position: nextPosition}} + } + + // COMPLETED + return {type: 'COMPLETED'} + }), + // @ts-ignore reset: assign({ tutorial() { storage.tutorial.set(null) diff --git a/web-app/src/services/state/actions/index.ts b/web-app/src/services/state/actions/index.ts index 96816a3b..179f1252 100644 --- a/web-app/src/services/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -63,9 +63,7 @@ export default { // // tutorialModel.updateProgress() // // tutorialModel.nextPosition() // }, -// loadLevel(): void { -// // tutorialModel.triggerCurrent('LEVEL') -// }, + // stageLoadNext() { // console.log('stageLoadNext') // // tutorialModel.nextPosition() diff --git a/web-app/src/services/state/guards/index.ts b/web-app/src/services/state/guards/index.ts index 5462409a..ed6b1776 100644 --- a/web-app/src/services/state/guards/index.ts +++ b/web-app/src/services/state/guards/index.ts @@ -4,7 +4,7 @@ import * as CR from 'typings' // // TODO: refactor into a single calculation export default { hasNextStep: (context: CR.MachineContext): boolean => { - const {tutorial, position} = context + const {tutorial, position, progress} = context // TODO: protect against errors const steps: G.Step[] = tutorial.version .levels.find((l: G.Level) => l.id === position.levelId) @@ -12,17 +12,22 @@ export default { .steps // TODO: verify not -1 - return !(steps[steps.length - 1].id === position.stepId) + const finalStep = steps[steps.length - 1].id === position.stepId + const stepComplete = progress.steps[position.stepId] + // not final step, or final step but not complete + return !finalStep || !stepComplete }, hasNextStage: (context: CR.MachineContext): boolean => { - const {tutorial, position} = context + const {tutorial, position, progress} = context // TODO: protect against errors const stages: G.Stage[] = tutorial.version .levels.find((l: G.Level) => l.id === position.levelId) .stages // TODO: verify not -1 - return !(stages[stages.length - 1].id === position.stageId) + const finalStage = stages[stages.length - 1].id === position.stageId + const stageComplete = progress.stages[position.stageId] + return !finalStage || !stageComplete }, hasNextLevel: (context: CR.MachineContext): boolean => { const {tutorial, position} = context diff --git a/web-app/src/services/xstate-react/index.ts b/web-app/src/services/xstate-react/index.ts new file mode 100644 index 00000000..c0970bae --- /dev/null +++ b/web-app/src/services/xstate-react/index.ts @@ -0,0 +1,145 @@ +import {useState, useRef, useEffect} from 'react' +import { + interpret, + EventObject, + StateMachine, + State, + Interpreter, + InterpreterOptions, + MachineOptions +} from 'xstate' + +interface UseMachineOptions { + /** + * If provided, will be merged with machine's context. + */ + context?: Partial + /** + * If `true`, service will start immediately (before mount). + */ + immediate: boolean +} + +const defaultOptions = { + immediate: false +} + +export function useMachine( + machine: StateMachine, + options: Partial & + Partial> & + Partial> = defaultOptions +): [ + State, + Interpreter['send'], + Interpreter + ] { + const { + context, + guards, + actions, + activities, + services, + delays, + immediate, + ...interpreterOptions + } = options + + const machineConfig = { + context, + guards, + actions, + activities, + services, + delays + } + + // Reference the machine + const machineRef = useRef | null>(null) + + // Create the machine only once + // See https://reactjs.org/docs/hooks-faq.html#how-to-create-expensive-objects-lazily + if (machineRef.current === null) { + machineRef.current = machine.withConfig(machineConfig, { + ...machine.context, + ...context + } as TContext) + } + + // Reference the service + const serviceRef = useRef | null>(null) + + // Create the service only once + if (serviceRef.current === null) { + serviceRef.current = interpret( + machineRef.current, + interpreterOptions + ).onTransition(state => { + // Update the current machine state when a transition occurs + if (state.changed) { + setCurrent(state) + } + }) + } + + const service = serviceRef.current + + // Make sure actions are kept updated when they change. + // This mutation assignment is safe because the service instance is only used + // in one place -- this hook's caller. + useEffect(() => { + Object.assign(service.machine.options.actions, actions) + }, [actions]) + + // Start service immediately (before mount) if specified in options + if (immediate) { + service.start() + } + + // Keep track of the current machine state + const [current, setCurrent] = useState(service.initialState) + + useEffect(() => { + // Start the service when the component mounts. + // Note: the service will start only if it hasn't started already. + service.start() + + return () => { + // Stop the service when the component unmounts + service.stop() + } + }, []) + + return [current, service.send, service] +} + +export function useService( + service: Interpreter +): [ + State, + Interpreter['send'], + Interpreter + ] { + const [current, setCurrent] = useState(service.state) + + useEffect(() => { + // Set to current service state as there is a possibility + // of a transition occurring between the initial useState() + // initialization and useEffect() commit. + setCurrent(service.state) + + const listener = (state: State) => { + if (state.changed) { + setCurrent(state) + } + } + + service.onTransition(listener) + + return () => { + service.off(listener) + } + }, [service]) + + return [current, service.send, service] +} From 0b645af7654ec997a79d1775bbef6bdff4212bca Mon Sep 17 00:00:00 2001 From: shmck Date: Tue, 3 Sep 2019 22:29:02 -0700 Subject: [PATCH 091/117] cleanup loadNext completed --- web-app/src/services/state/actions/context.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index a61cd65f..f35a90c2 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -182,7 +182,6 @@ export default { // has next stage? const stageIndex = stages.findIndex((s: G.Stage) => s.id === position.stageId) - const stageComplete = progress.stages[position.stageId] const finalStage = (stageIndex > -1 && stageIndex === stages.length - 1) const hasNextStage = (!finalStage) @@ -200,7 +199,6 @@ export default { // has next level? const levelIndex = levels.findIndex((l: G.Level) => l.id === position.levelId) - const levelComplete = progress.levels[position.levelId] const finalLevel = (levelIndex > -1 && levelIndex === levels.length - 1) const hasNextLevel = (!finalLevel) From 95f6f73ca4aaa031b7937827d49532af7997009f Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 4 Sep 2019 07:56:17 -0700 Subject: [PATCH 092/117] update sass loader to 8 --- web-app/package-lock.json | 49 ++++++++++++++++++++++++++------------- web-app/package.json | 2 +- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/web-app/package-lock.json b/web-app/package-lock.json index c81e3ac3..aadae583 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -3143,11 +3143,6 @@ "tslib": "^1.9.3" } }, - "@xstate/react": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@xstate/react/-/react-0.7.1.tgz", - "integrity": "sha512-6LKbMCWPtLfKL7Ph8E781qoKmypSPGS5e7e+LkTK/nhRpFcj6n3MfCl96mNWsdYMr7tb8ISQDZcxI+Ou0BpurQ==" - }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -16200,18 +16195,36 @@ } }, "sass-loader": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.3.1.tgz", - "integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.0.tgz", + "integrity": "sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w==", "dev": true, "requires": { "clone-deep": "^4.0.1", - "loader-utils": "^1.0.1", - "neo-async": "^2.5.0", - "pify": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.1.0", "semver": "^6.3.0" }, "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, "clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -16229,11 +16242,15 @@ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true + "schema-utils": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.2.0.tgz", + "integrity": "sha512-5EwsCNhfFTZvUreQhx/4vVQpJ/lnCAkgoIHLhSpp4ZirE+4hzFvdJi0FMub6hxbFVBJYSpeVVmon+2e7uEGRrA==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } }, "semver": { "version": "6.3.0", diff --git a/web-app/package.json b/web-app/package.json index 5e3744c7..600b29e3 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -59,7 +59,7 @@ "babel-loader": "^8.0.6", "babel-plugin-import": "^1.12.1", "node-sass": "^4.12.0", - "sass-loader": "^7.3.1", + "sass-loader": "^8.0.0", "typescript-eslint-parser": "^22.0.0" } } From 923ea3759d902213121769f715c94af6b1c2a1ae Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 4 Sep 2019 21:06:54 -0700 Subject: [PATCH 093/117] replace stepNext guards with actions --- web-app/src/components/Router/index.tsx | 2 -- web-app/src/services/state/actions/index.ts | 36 +++++++++++++++++-- web-app/src/services/state/guards/index.ts | 40 --------------------- web-app/src/services/state/machine.ts | 24 ++++++------- 4 files changed, 44 insertions(+), 58 deletions(-) delete mode 100644 web-app/src/services/state/guards/index.ts diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index 72a270b2..0258470c 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -8,7 +8,6 @@ import debuggerWrapper from '../Debugger/debuggerWrapper' import channel from '../../services/channel' import messageBusReceiver from '../../services/channel/receiver' import actions from '../../services/state/actions' -import guards from '../../services/state/guards' interface Props { @@ -24,7 +23,6 @@ interface CloneElementProps { const Router = ({ children }: Props): React.ReactElement|null => { const [state, send] = useMachine(machine, { actions, - guards, interpreterOptions: { logger: console.log.bind('XSTATE:') } diff --git a/web-app/src/services/state/actions/index.ts b/web-app/src/services/state/actions/index.ts index 179f1252..12f39ab1 100644 --- a/web-app/src/services/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -2,20 +2,50 @@ import {send} from 'xstate' // import {machine} from '../../extension' // import {cache} from '../../services/apollo' // import {editorDispatch} from '../../services/vscode' -// import * as CR from 'typings' -// import * as G from 'typings/graphql' +import * as CR from 'typings' +import * as G from 'typings/graphql' // import tutorialConfig from '../../services/apollo/queries/tutorialConfig' import editorActions from './editor' import contextActions from './context' export default { - newOrContinue: send((context): 'NEW' | 'CONTINUE' => { + newOrContinue: send((context: CR.MachineContext): 'NEW' | 'CONTINUE' => { console.log('new or continue') // TODO: verify that the user has an existing tutorial to continue const hasExistingTutorial: boolean = false return hasExistingTutorial ? 'CONTINUE' : 'NEW' }), + stepNext: send((context: CR.MachineContext): CR.Action => { + const {tutorial, position, progress} = context + // TODO: protect against errors + const steps: G.Step[] = tutorial.version + .levels.find((l: G.Level) => l.id === position.levelId) + .stages.find((s: G.Stage) => s.id === position.stageId) + .steps + + // TODO: verify not -1 + const stepIndex = steps.findIndex((s: G.Step) => s.id === position.stepId) + const finalStep = stepIndex === steps.length - 1 + const stepComplete = progress.steps[position.stepId] + // not final step, or final step but not complete + const hasNextStep = !finalStep || !stepComplete + + if (hasNextStep) { + const nextStep = steps[stepIndex + 1] + return { + type: 'LOAD_NEXT_STEP', + payload: { + step: nextStep + } + } + } else { + return { + type: 'STAGE_COMPLETE' + } + } + + }), ...editorActions, ...contextActions, } diff --git a/web-app/src/services/state/guards/index.ts b/web-app/src/services/state/guards/index.ts deleted file mode 100644 index ed6b1776..00000000 --- a/web-app/src/services/state/guards/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as G from 'typings/graphql' -import * as CR from 'typings' - -// // TODO: refactor into a single calculation -export default { - hasNextStep: (context: CR.MachineContext): boolean => { - const {tutorial, position, progress} = context - // TODO: protect against errors - const steps: G.Step[] = tutorial.version - .levels.find((l: G.Level) => l.id === position.levelId) - .stages.find((s: G.Stage) => s.id === position.stageId) - .steps - - // TODO: verify not -1 - const finalStep = steps[steps.length - 1].id === position.stepId - const stepComplete = progress.steps[position.stepId] - // not final step, or final step but not complete - return !finalStep || !stepComplete - }, - hasNextStage: (context: CR.MachineContext): boolean => { - const {tutorial, position, progress} = context - // TODO: protect against errors - const stages: G.Stage[] = tutorial.version - .levels.find((l: G.Level) => l.id === position.levelId) - .stages - - // TODO: verify not -1 - const finalStage = stages[stages.length - 1].id === position.stageId - const stageComplete = progress.stages[position.stageId] - return !finalStage || !stageComplete - }, - hasNextLevel: (context: CR.MachineContext): boolean => { - const {tutorial, position} = context - // TODO: protect against errors - const levels: G.Level[] = tutorial.version.levels - - // TODO: verify not -1 - return !(levels[levels.length - 1].id === position.levelId) - }, -} diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 8a9c8145..1b49347f 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -138,19 +138,17 @@ export const machine = Machine Date: Wed, 4 Sep 2019 21:28:11 -0700 Subject: [PATCH 094/117] create api actions --- web-app/src/services/channel/index.ts | 4 +- web-app/src/services/channel/mock.ts | 2 +- web-app/src/services/state/actions/api.ts | 3 + web-app/src/services/state/actions/context.ts | 29 +++++ web-app/src/services/state/actions/editor.ts | 7 ++ web-app/src/services/state/actions/index.ts | 102 +----------------- web-app/src/services/state/machine.ts | 2 +- web-app/src/services/xstate-react/index.ts | 4 +- 8 files changed, 48 insertions(+), 105 deletions(-) create mode 100644 web-app/src/services/state/actions/api.ts diff --git a/web-app/src/services/channel/index.ts b/web-app/src/services/channel/index.ts index aa5f5160..b837ef72 100644 --- a/web-app/src/services/channel/index.ts +++ b/web-app/src/services/channel/index.ts @@ -43,7 +43,9 @@ class Channel { console.log('test passed') return default: - console.warn(`Unknown received action ${action.type}`, action) + if (action.type) { + console.warn(`Unknown received action ${action.type}`, action) + } } } } diff --git a/web-app/src/services/channel/mock.ts b/web-app/src/services/channel/mock.ts index a4604935..6d373f02 100644 --- a/web-app/src/services/channel/mock.ts +++ b/web-app/src/services/channel/mock.ts @@ -26,7 +26,7 @@ window.acquireVsCodeApi = () => ({ payload: action.payload, } channel.receive(createReceiveEvent(receiveAction)) - }) + }, 1000) default: console.warn(`${action.type} not found in post message mock`) } diff --git a/web-app/src/services/state/actions/api.ts b/web-app/src/services/state/actions/api.ts new file mode 100644 index 00000000..5c933b16 --- /dev/null +++ b/web-app/src/services/state/actions/api.ts @@ -0,0 +1,3 @@ +export default { + +} \ No newline at end of file diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index f35a90c2..ac3476f8 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -217,6 +217,35 @@ export default { // COMPLETED return {type: 'COMPLETED'} }), + stepNext: send((context: CR.MachineContext): CR.Action => { + const {tutorial, position, progress} = context + // TODO: protect against errors + const steps: G.Step[] = tutorial.version + .levels.find((l: G.Level) => l.id === position.levelId) + .stages.find((s: G.Stage) => s.id === position.stageId) + .steps + + // TODO: verify not -1 + const stepIndex = steps.findIndex((s: G.Step) => s.id === position.stepId) + const finalStep = stepIndex === steps.length - 1 + const stepComplete = progress.steps[position.stepId] + // not final step, or final step but not complete + const hasNextStep = !finalStep || !stepComplete + + if (hasNextStep) { + const nextStep = steps[stepIndex + 1] + return { + type: 'LOAD_NEXT_STEP', + payload: { + step: nextStep + } + } + } else { + return { + type: 'STAGE_COMPLETE' + } + } + }), // @ts-ignore reset: assign({ tutorial() { diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index 9642bdea..8fb7147f 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -1,7 +1,14 @@ +import {send} from 'xstate' import * as CR from 'typings' import channel from '../../channel' export default { + newOrContinue: send((context: CR.MachineContext): 'NEW' | 'CONTINUE' => { + console.log('new or continue') + // TODO: verify that the user has an existing tutorial to continue + const hasExistingTutorial: boolean = false + return hasExistingTutorial ? 'CONTINUE' : 'NEW' + }), tutorialStart() { console.log('EDITOR: TUTORIAL_START') channel.editorSend({ diff --git a/web-app/src/services/state/actions/index.ts b/web-app/src/services/state/actions/index.ts index 12f39ab1..0af5449f 100644 --- a/web-app/src/services/state/actions/index.ts +++ b/web-app/src/services/state/actions/index.ts @@ -1,107 +1,9 @@ -import {send} from 'xstate' -// import {machine} from '../../extension' -// import {cache} from '../../services/apollo' -// import {editorDispatch} from '../../services/vscode' -import * as CR from 'typings' -import * as G from 'typings/graphql' -// import tutorialConfig from '../../services/apollo/queries/tutorialConfig' import editorActions from './editor' import contextActions from './context' +import apiActions from './api' export default { - newOrContinue: send((context: CR.MachineContext): 'NEW' | 'CONTINUE' => { - console.log('new or continue') - - // TODO: verify that the user has an existing tutorial to continue - const hasExistingTutorial: boolean = false - return hasExistingTutorial ? 'CONTINUE' : 'NEW' - }), - stepNext: send((context: CR.MachineContext): CR.Action => { - const {tutorial, position, progress} = context - // TODO: protect against errors - const steps: G.Step[] = tutorial.version - .levels.find((l: G.Level) => l.id === position.levelId) - .stages.find((s: G.Stage) => s.id === position.stageId) - .steps - - // TODO: verify not -1 - const stepIndex = steps.findIndex((s: G.Step) => s.id === position.stepId) - const finalStep = stepIndex === steps.length - 1 - const stepComplete = progress.steps[position.stepId] - // not final step, or final step but not complete - const hasNextStep = !finalStep || !stepComplete - - if (hasNextStep) { - const nextStep = steps[stepIndex + 1] - return { - type: 'LOAD_NEXT_STEP', - payload: { - step: nextStep - } - } - } else { - return { - type: 'STAGE_COMPLETE' - } - } - - }), ...editorActions, ...contextActions, + ...apiActions, } - -// export default { -// async newOrContinue() { -// // verify that the user has an existing tutorial to continue -// // const hasExistingTutorial: boolean = await tutorialModel.hasExisting() -// // machine.send(hasExistingTutorial ? 'CONTINUE' : 'NEW') -// }, -// testRunnerSetup() { -// const result = cache.readQuery({query: tutorialConfig}) -// console.log('result', result) -// // const codingLanguage: G.EnumCodingLanguage = result.data.codingLanguage -// // editorDispatch('coderoad.test_runner_setup', codingLanguage) -// }, -// initializeNewTutorial: assign({ -// position: (context: any): CR.Position => { -// const { tutorial } = context -// const levelId = data.summary.levelList[0] -// const stageId = data.levels[levelId].stageList[0] -// const stepId = data.stages[stageId].stepList[0] -// return { -// levelId, -// stageId, -// stepId, -// } -// }, -// }) -// tutorialContinue() { -// console.log('tutorial continue') -// }, -// testStart() { -// editorDispatch('coderoad.run_test') -// }, -// testPass(): void { -// editorDispatch('coderoad.test_pass') -// // git.gitSaveCommit(tutorialModel.position) -// }, -// testFail() { -// editorDispatch('coderoad.test_fail') -// }, -// // @ts-ignore -// progressUpdate() { -// // tutorialModel.updateProgress() -// // tutorialModel.nextPosition() -// }, - -// stageLoadNext() { -// console.log('stageLoadNext') -// // tutorialModel.nextPosition() -// }, -// loadStage(): void { -// // tutorialModel.triggerCurrent('STAGE') -// }, -// stepLoadCommits(): void { -// // tutorialModel.triggerCurrent('STEP') -// }, -// } diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 1b49347f..bfb175e5 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -59,7 +59,6 @@ export const machine = Machine( // in one place -- this hook's caller. useEffect(() => { Object.assign(service.machine.options.actions, actions) - }, [actions]) + }, [service.machine.options.actions, actions]) // Start service immediately (before mount) if specified in options if (immediate) { @@ -108,7 +108,7 @@ export function useMachine( // Stop the service when the component unmounts service.stop() } - }, []) + }, [service]) return [current, service.send, service] } From 81fb9289d1db56e9d317547e03982e4fdf305178 Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 4 Sep 2019 22:13:24 -0700 Subject: [PATCH 095/117] invoke newOrContinue --- typings/index.d.ts | 1 + web-app/src/services/state/actions/api.ts | 6 ++++- web-app/src/services/state/actions/context.ts | 7 +++++- web-app/src/services/state/actions/editor.ts | 7 ------ web-app/src/services/state/actions/invoke.ts | 25 +++++++++++++++++++ web-app/src/services/state/machine.ts | 15 +++++++---- .../services/state/{actions => }/storage.ts | 4 +-- 7 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 web-app/src/services/state/actions/invoke.ts rename web-app/src/services/state/{actions => }/storage.ts (86%) diff --git a/typings/index.d.ts b/typings/index.d.ts index 65256314..130453b4 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -123,6 +123,7 @@ export interface MachineContext { export interface MachineEvent { type: string payload?: any + data?: any } export interface MachineStateSchema { diff --git a/web-app/src/services/state/actions/api.ts b/web-app/src/services/state/actions/api.ts index 5c933b16..9b2486cd 100644 --- a/web-app/src/services/state/actions/api.ts +++ b/web-app/src/services/state/actions/api.ts @@ -1,3 +1,7 @@ -export default { +import * as CR from 'typings' +export default { + userTutorialComplete(context: CR.MachineContext) { + console.log('should update user tutorial as complete') + } } \ No newline at end of file diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index ac3476f8..25842742 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -1,7 +1,7 @@ import {assign, send} from 'xstate' import * as G from 'typings/graphql' import * as CR from 'typings' -import * as storage from './storage' +import * as storage from '../storage' export default { setTutorial: assign({ @@ -11,6 +11,11 @@ export default { return tutorial }, }), + continueTutorial: assign({ + tutorial: (context: CR.MachineContext, event: CR.MachineEvent) => event.data.payload.tutorial, + progress: (context: CR.MachineContext, event: CR.MachineEvent) => event.data.payload.progress, + position: (context: CR.MachineContext, event: CR.MachineEvent) => event.data.payload.position, + }), // @ts-ignore initPosition: assign({ position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index 8fb7147f..9642bdea 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -1,14 +1,7 @@ -import {send} from 'xstate' import * as CR from 'typings' import channel from '../../channel' export default { - newOrContinue: send((context: CR.MachineContext): 'NEW' | 'CONTINUE' => { - console.log('new or continue') - // TODO: verify that the user has an existing tutorial to continue - const hasExistingTutorial: boolean = false - return hasExistingTutorial ? 'CONTINUE' : 'NEW' - }), tutorialStart() { console.log('EDITOR: TUTORIAL_START') channel.editorSend({ diff --git a/web-app/src/services/state/actions/invoke.ts b/web-app/src/services/state/actions/invoke.ts new file mode 100644 index 00000000..7734061e --- /dev/null +++ b/web-app/src/services/state/actions/invoke.ts @@ -0,0 +1,25 @@ +import * as storage from '../storage' +import * as CR from 'typings' + +export const newOrContinue = async (context: CR.MachineContext) => { + const [tutorial, position, progress] = await Promise.all([ + storage.tutorial.get(), + storage.position.get(), + storage.progress.get() + ]) + + const hasExistingTutorial = (tutorial && tutorial.id && progress && !progress.complete) + if (hasExistingTutorial) { + // TODO: calculate position based on progress + return { + type: 'CONTINUE', + payload: { + tutorial, + position, + progress + } + } + } + // New tutorial + return Promise.reject() +} \ No newline at end of file diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index bfb175e5..e76f8d0f 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -1,5 +1,6 @@ import {Machine} from 'xstate' import * as CR from 'typings' +import * as invoke from './actions/invoke' export const machine = Machine( { @@ -20,10 +21,14 @@ export const machine = Machine { constructor(key: string) { this.key = key } - public get = (key: string): T | null => { - const value = this.storage.getItem(this.key) + public get = async (): Promise => { + const value = await this.storage.getItem(this.key) if (value) { return JSON.parse(value) } From ff9e572718acfde24f9d569787d8723665e871b1 Mon Sep 17 00:00:00 2001 From: shmck Date: Wed, 4 Sep 2019 23:17:24 -0700 Subject: [PATCH 096/117] continue from same point --- web-app/src/Routes.tsx | 40 +++++++------- web-app/src/containers/Continue/index.tsx | 18 +++---- web-app/src/services/channel/index.ts | 1 - web-app/src/services/state/actions/invoke.ts | 56 +++++++++++++++----- web-app/src/services/state/machine.ts | 4 +- 5 files changed, 70 insertions(+), 49 deletions(-) diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index c276447e..3944adcc 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -47,34 +47,34 @@ const Routes = () => { - - + + - + - + - - - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + +
) } diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index 52fbd73d..19ace120 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -22,21 +22,15 @@ export const ContinuePage = (props: Props) => ( ) interface ContainerProps { - context: CR.MachineContext + context: CR.MachineContext + send(action: CR.Action | string): void } -const ContinuePageContainer = ({ context }: ContainerProps) => { - // TODO: load specific tutorialId - const { tutorial } = context +const ContinuePageContainer = ({ context, send }: ContainerProps) => { + // TODO: load specific tutorialId + const { tutorial } = context - return ( - { - console.log('TUTORIAL_START') - }} - /> - ) + return send('TUTORIAL_START')} /> } export default ContinuePageContainer diff --git a/web-app/src/services/channel/index.ts b/web-app/src/services/channel/index.ts index b837ef72..9409e1ac 100644 --- a/web-app/src/services/channel/index.ts +++ b/web-app/src/services/channel/index.ts @@ -30,7 +30,6 @@ class Channel { // @ts-ignore // ignore browser events from plugins if (action.source) {return } - console.log('receive action', action) // messages from core switch (action.type) { case 'TUTORIAL_LOADED': diff --git a/web-app/src/services/state/actions/invoke.ts b/web-app/src/services/state/actions/invoke.ts index 7734061e..e04d53a7 100644 --- a/web-app/src/services/state/actions/invoke.ts +++ b/web-app/src/services/state/actions/invoke.ts @@ -1,25 +1,53 @@ import * as storage from '../storage' import * as CR from 'typings' +import * as G from 'typings/graphql' export const newOrContinue = async (context: CR.MachineContext) => { - const [tutorial, position, progress] = await Promise.all([ + const [tutorial, progress] = await Promise.all([ storage.tutorial.get(), - storage.position.get(), storage.progress.get() ]) - const hasExistingTutorial = (tutorial && tutorial.id && progress && !progress.complete) - if (hasExistingTutorial) { - // TODO: calculate position based on progress - return { - type: 'CONTINUE', - payload: { - tutorial, - position, - progress - } + const hasExistingTutorial: boolean = (!!tutorial && !!progress && !progress.complete && !!tutorial.id) + + if (!hasExistingTutorial) { + return Promise.reject() + } + + // Calculate position based on progress + + // @ts-ignore + const level = tutorial.version.levels.find((l: G.Level) => !progress.levels[l.id]) + if (!level) { + // tutorial complete + return Promise.reject() + } + + // @ts-ignore + const stage = level.stages.find((s: G.Stage) => !progress.stages[s.id]) + if (!stage) { + // something went wrong + return Promise.reject() + } + + // @ts-ignore + const step = stage.steps.find((s: G.Step) => !progress.steps[s.id]) + if (!step) { + return Promise.reject() + } + + const position = { + levelId: level.id, + stageId: stage.id, + stepId: step.id, + } + + return { + type: 'CONTINUE', + payload: { + tutorial, + position, + progress } } - // New tutorial - return Promise.reject() } \ No newline at end of file diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index e76f8d0f..5d68a009 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -52,9 +52,8 @@ export const machine = Machine Date: Sat, 7 Sep 2019 13:13:06 -0700 Subject: [PATCH 097/117] update deps --- web-app/package-lock.json | 26 +++++++++++++------------- web-app/package.json | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/web-app/package-lock.json b/web-app/package-lock.json index aadae583..52c54b94 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@alifd/next": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.17.9.tgz", - "integrity": "sha512-FJPlEyyleZjXNH6bdLwicn6NLTXwc5DdUbP1dNcYQaIpR6pMknmt2bR/0aI+kqjBe1/xW6KROFnTCGiyap3VQA==", + "version": "1.17.10", + "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.17.10.tgz", + "integrity": "sha512-+8mTQ8YUHAIB62B4EK9v5TMxPepBO/6uvto/RyWS9Yr42wHxCKW5L3ZWF04H4n9AAdvDUFap+pKrnMDBYweCxg==", "requires": { "babel-runtime": "^6.26.0", "classnames": "^2.2.3", @@ -26,9 +26,9 @@ } }, "@apollo/react-common": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@apollo/react-common/-/react-common-3.0.1.tgz", - "integrity": "sha512-7SC4qqPFo/41AhaQKCRovIshKkm4JLEGXyRHi+NPsaNJyk2J/HrWREnlHVqoPzYeIyq33f1L6j/NAkKn1NOnnQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@apollo/react-common/-/react-common-3.1.0.tgz", + "integrity": "sha512-X8IfSZyvV8oHPJ46163Am4e81Kjl4BbojpYaYEpQtpGFHIA7cZ+MvuG4M6OJNh+SZArTfnwcPvJaCtkY8n3apA==", "requires": { "ts-invariant": "^0.4.4", "tslib": "^1.10.0" @@ -42,11 +42,11 @@ } }, "@apollo/react-hooks": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@apollo/react-hooks/-/react-hooks-3.0.1.tgz", - "integrity": "sha512-Boai/T+2z3m23Gy82m1pB+FOlrhkBJ//EIYa3pqX9sUsvgRWMKC+3NxpeHEUYqsf0qzFiM1dO4Pn9OxCFstM8g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@apollo/react-hooks/-/react-hooks-3.1.0.tgz", + "integrity": "sha512-tbVIAQMemeM6FaMFA7JCV+7hfJzPJSl/r7QAaFc5i8fWmdXZPYzZCeFOI7DdsWyAoLQS+RY14mDH9Ufacaulnw==", "requires": { - "@apollo/react-common": "^3.0.1", + "@apollo/react-common": "^3.1.0", "@wry/equality": "^0.1.9", "ts-invariant": "^0.4.4", "tslib": "^1.10.0" @@ -11426,9 +11426,9 @@ "integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=" }, "markdown-it-prism": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/markdown-it-prism/-/markdown-it-prism-2.0.2.tgz", - "integrity": "sha512-tBRK+L36D2m4NauUr9teyFYJXBtw6XtuCdCJJWeNabSBwKlgI3oil4TfHHWd0bunwSf8zkmXEZkJzDVgVkfp+g==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/markdown-it-prism/-/markdown-it-prism-2.0.3.tgz", + "integrity": "sha512-ygl74S7LnJMzmMclxRPzuWgd251r+u6ROmED1sPY42UZweRMbmrJqZo2WXTN3PeMHJPZPXiCsWBsyOxUPyiRGQ==", "requires": { "prismjs": "^1.16.0" } diff --git a/web-app/package.json b/web-app/package.json index 600b29e3..ddb51c46 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -26,13 +26,13 @@ "extends": "react-app" }, "dependencies": { - "@alifd/next": "^1.17.9", - "@apollo/react-hooks": "^3.0.1", + "@alifd/next": "^1.17.10", + "@apollo/react-hooks": "^3.1.0", "apollo-boost": "^0.4.4", "graphql": "^14.5.4", "markdown-it": "^9.1.0", "markdown-it-emoji": "^1.4.0", - "markdown-it-prism": "^2.0.2", + "markdown-it-prism": "^2.0.3", "moment": "^2.24.0", "ramda": "^0.26.1", "react": "^16.9.0", From adb575b8a306b0c3abdc9bb5c2272b898f1a9b44 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 7 Sep 2019 13:37:59 -0700 Subject: [PATCH 098/117] prepare cleanup editor unused --- src/editor/ReactWebView.ts | 6 - src/editor/commands/index.ts | 4 - src/editor/commands/loadSolution.ts | 10 +- src/editor/commands/runTest.ts | 3 +- src/editor/index.ts | 2 - src/editor/workspace.ts | 60 ++++----- src/environment.ts | 11 -- src/services/git/errorMessages.ts | 13 +- src/services/tutorial/index.ts | 117 +----------------- web-app/src/services/state/actions/context.ts | 7 -- web-app/src/services/state/actions/editor.ts | 13 +- web-app/src/services/state/machine.ts | 1 - 12 files changed, 48 insertions(+), 199 deletions(-) delete mode 100644 src/environment.ts diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index b5f246bf..e08fc181 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -38,13 +38,7 @@ class ReactWebView { const onReceive = (action: string | CR.Action) => { const actionType: string = typeof action === 'string' ? action : action.type switch (actionType) { - case 'WEBVIEW_LOADED': - // await loading of webview in React before proceeding with loaded state - this.loaded = true - break case 'TUTORIAL_START': - console.log('TUTORIAL_START called') - console.log(action) if (typeof action === 'string' || !action.payload || !action.payload.id) { throw new Error('No tutorial id on tutorial start action') } diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index 88b74652..a348937a 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -3,7 +3,6 @@ import * as CR from 'typings' import * as G from 'typings/graphql' import * as vscode from 'vscode' import ReactWebView from '../ReactWebView' -import storage from '../storage' import runTest from './runTest' import {isEmptyWorkspace} from '../workspace' @@ -52,9 +51,6 @@ export const createCommands = ({vscodeExt}: CreateCommandProps) => { webviewState = 'RESTARTING' } - // ini - storage.init(vscodeExt.workspaceState) - // activate machine webview = new ReactWebView(vscodeExt.extensionPath) if (webviewState === 'INITIALIZING') { diff --git a/src/editor/commands/loadSolution.ts b/src/editor/commands/loadSolution.ts index 24e8b939..8c3aad2c 100644 --- a/src/editor/commands/loadSolution.ts +++ b/src/editor/commands/loadSolution.ts @@ -4,10 +4,12 @@ import {TutorialModel} from '../../services/tutorial' import {gitLoadCommits, gitClear} from '../../services/git' export default async function loadSolution(dispatch: CR.EditorDispatch, tutorialModel: TutorialModel): Promise { - const step: G.Step = tutorialModel.step() - const solution = step.solution + // TODO: should load same as commits - await gitClear() - await gitLoadCommits(solution, dispatch) + // const step: G.Step = tutorialModel.step() + // const solution = step.solution + + // await gitClear() + // await gitLoadCommits(solution, dispatch) } diff --git a/src/editor/commands/runTest.ts b/src/editor/commands/runTest.ts index bcc0dbb0..4a468775 100644 --- a/src/editor/commands/runTest.ts +++ b/src/editor/commands/runTest.ts @@ -1,6 +1,5 @@ import * as vscode from 'vscode' import {exec} from '../../services/node' -import * as storage from '../../services/storage' // ensure only latest run_test action is taken let currentId = 0 @@ -51,7 +50,7 @@ export default async function runTest({onSuccess, onFail}: Props): Promise try { // capture position early on test start // in case position changes - const [position, {stdout}] = await Promise.all([storage.getPosition(), exec(commandLine)]) + const {stdout} = await exec(commandLine) if (shouldExitEarly(processId)) { // exit early return diff --git a/src/editor/index.ts b/src/editor/index.ts index a86fe53f..52beddc9 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -31,8 +31,6 @@ class Editor { for (const disposable of this.vscodeExt.subscriptions) { disposable.dispose() } - // shut down state machine - console.log('deactivate machine') } // execute vscode command diff --git a/src/editor/workspace.ts b/src/editor/workspace.ts index e1ecd1cd..b7b7f044 100644 --- a/src/editor/workspace.ts +++ b/src/editor/workspace.ts @@ -1,43 +1,43 @@ import * as fs from 'fs' import * as path from 'path' import * as vscode from 'vscode' -import { exec, exists } from '../services/node' +import {exec, exists} from '../services/node' export async function isEmptyWorkspace(): Promise { - const { stdout, stderr } = await exec('ls') - if (stderr) { - throw new Error('Error validating if project is empty') - } - return !stdout.length + const {stdout, stderr} = await exec('ls') + if (stderr) { + throw new Error('Error validating if project is empty') + } + return !stdout.length } // // TODO: workspace change listener export async function openReadme(): Promise { - const { stderr } = await exec('ls') - if (stderr) { - throw new Error('Error looking for initial file') - } + const {stderr} = await exec('ls') + if (stderr) { + throw new Error('Error looking for initial file') + } - const file = 'README.md' - const filePath = path.join(vscode.workspace.rootPath || '', file) - console.log('filePath', filePath) - const hasReadme = await exists(file) + const file = 'README.md' + const filePath = path.join(vscode.workspace.rootPath || '', file) + console.log('filePath', filePath) + const hasReadme = await exists(file) - if (!hasReadme) { - // add readme if none exists - try { - const content = '# Welcome to CodeRoad!' - fs.writeFileSync(filePath, content, 'utf8') - } catch (error) { - throw new Error('Error writing READM.md') - } - } + if (!hasReadme) { + // add readme if none exists + try { + const content = '# Welcome to CodeRoad!' + fs.writeFileSync(filePath, content, 'utf8') + } catch (error) { + throw new Error('Error writing README.md') + } + } - try { - const openPath = vscode.Uri.parse(filePath) - const doc = await vscode.workspace.openTextDocument(openPath) - await vscode.window.showTextDocument(doc) - } catch (error) { - throw new Error('Error opening README doc') - } + try { + const openPath = vscode.Uri.parse(filePath) + const doc = await vscode.workspace.openTextDocument(openPath) + await vscode.window.showTextDocument(doc) + } catch (error) { + throw new Error('Error opening README doc') + } } diff --git a/src/environment.ts b/src/environment.ts deleted file mode 100644 index 2e6886ab..00000000 --- a/src/environment.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as path from 'path' -import * as dotenv from 'dotenv' - -dotenv.config({ - path: path.join(__dirname, '../.env') -}) - -export const api = { - url: process.env.API_URL || '', - token: process.env.API_AUTH_TOKEN || '', // dev only -} \ No newline at end of file diff --git a/src/services/git/errorMessages.ts b/src/services/git/errorMessages.ts index 3b3a7e0e..4de72216 100644 --- a/src/services/git/errorMessages.ts +++ b/src/services/git/errorMessages.ts @@ -1,13 +1,14 @@ interface ErrorMessageFilter { - [lang: string]: { - [key: string]: string - } + [lang: string]: { + [key: string]: string + } } +// likely should be loaded on startup const errorMessages: ErrorMessageFilter = { - js: { - 'node-gyp': 'Error running npm setup command' - } + js: { + 'node-gyp': 'Error running npm setup command' + } } export default errorMessages \ No newline at end of file diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index a05a2ef3..86d59541 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -1,8 +1,6 @@ import * as G from 'typings/graphql' import * as CR from 'typings' import * as git from '../../services/git' -import {machine} from '../../extension' -import * as storage from '../storage' interface TutorialConfig { codingLanguage: G.EnumCodingLanguage @@ -16,10 +14,7 @@ export interface TutorialModel { position: CR.Position progress: CR.Progress launch(tutorial: G.Tutorial): void - updateProgress(): void - nextPosition(): CR.Position hasExisting(): Promise - syncClient(): void triggerCurrent(stepActions: G.StepActions): void } @@ -29,7 +24,6 @@ class Tutorial implements TutorialModel { public version: G.TutorialVersion public position: CR.Position public progress: CR.Progress - public syncClient: () => void public openFile: (file: string) => void constructor(editorDispatch: CR.EditorDispatch) { @@ -40,11 +34,6 @@ class Tutorial implements TutorialModel { this.version = {} as G.TutorialVersion this.position = {} as CR.Position this.progress = {} as CR.Progress - this.syncClient = () => editorDispatch('coderoad.send_data', { - tutorial: {id: this.version.tutorialId}, - progress: this.progress, - position: this.position, - }) this.openFile = (file: string) => editorDispatch('coderoad.open_file', file) } public launch = async (tutorial: G.Tutorial) => { @@ -71,42 +60,11 @@ class Tutorial implements TutorialModel { this.version = tutorial.version console.log('version', this.version) - // set initial position - this.position = { - levelId: this.version.levels[0].id, - stageId: this.version.levels[0].stages[0].id, - stepId: this.version.levels[0].stages[0].steps[0].id, - } - // set empty initial progress - this.progress = { - levels: {}, - stages: {}, - steps: {}, - complete: false, - } - - // setup git, git remote - - - await this.syncClient() - - // set tutorial, position, progress locally - // TODO: base position off of progress - Promise.all([ - storage.setTutorial(tutorial), - storage.setPosition(this.position), - storage.setProgress(this.progress) - ]) - - console.log('tutorial loaded') - machine.send('TUTORIAL_LOADED') } public async hasExisting(): Promise { - const [tutorial, progress] = await Promise.all([ - storage.getTutorial(), - storage.getProgress(), - ]) + // instead should configure git if does not exist + // and update git to current position // verify git is setup with a coderoad remote const [hasGit, hasGitRemote] = await Promise.all([ @@ -115,82 +73,13 @@ class Tutorial implements TutorialModel { ]) // TODO: may need to clean up git remote if no existing tutorial - const canContinue = !!(tutorial && progress && hasGit && hasGitRemote) + const canContinue = !!(hasGit && hasGitRemote) return canContinue } public triggerCurrent = (stepActions: G.StepActions) => { git.gitLoadCommits(stepActions, this.openFile) } - public updateProgress = () => { - const {levelId, stageId, stepId} = this.position - this.progress.levels[levelId] = true - this.progress.stages[stageId] = true - this.progress.steps[stepId] = true - - this.syncClient() - } - public nextPosition = (): CR.Position => { - const {levelId, stageId, stepId} = this.position - // TODO: calculate and return next position - - // is next step - const stage: G.Stage | null = this.stage(stageId) - if (!stage) { - throw new Error('Stage not found') - } - const {steps} = stage - const indexOfStep = steps.findIndex((s: G.Step): boolean => s.id === stepId) - if (indexOfStep === -1) { - throw new Error('Step not found') - } - if (indexOfStep < steps.length - 1) { - - return { - levelId, - stageId, - stepId: steps[indexOfStep + 1].id - } - } - - // is next stage - const level: G.Level | null = this.level(levelId) - if (!level) { - throw new Error('Level not found') - } - const {stages} = level - const indexOfStage = stages.findIndex((s: G.Stage): boolean => s.id === stageId) - if (indexOfStage === -1) { - throw new Error('Stage not found') - } - if (indexOfStage < stages.length - 1) { - // next stage - const nextStage = stages[indexOfStage + 1] - return { - levelId, - stageId: nextStage.id, - stepId: nextStage.steps[0].id - } - } - - // is next level - const levels = this.version.levels - const indexOfLevel = levels.findIndex((l: G.Level): boolean => l.id === levelId) - if (indexOfLevel === -1) { - throw new Error('Level not found') - } - if (indexOfLevel < levels.length - 1) { - const nextLevel = levels[indexOfLevel + 1] - const nextStage = nextLevel.stages[0] - return { - levelId: nextLevel.id, - stageId: nextStage.id, - stepId: nextStage.steps[0].id, - } - } - - throw new Error('Could not calculate next position') - } } export default Tutorial \ No newline at end of file diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 25842742..fd93cfbc 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -80,8 +80,6 @@ export default { const stageIndex = stages.findIndex((s: G.Stage) => s.id === position.stageId) const stage: G.Stage = stages[stageIndex + 1] - console.log('stage load next', stage.id, position.stageId) - const nextPosition: CR.Position = { ...position, stageId: stage.id, @@ -104,8 +102,6 @@ export default { const levelIndex = levels.findIndex((l: G.Level) => l.id === position.levelId) const level: G.Level = levels[levelIndex + 1] - console.log('level load next', level.id, position.levelId) - const nextPosition: CR.Position = { levelId: level.id, stageId: level.stages[0].id, @@ -123,7 +119,6 @@ export default { // update progress by tracking completed const currentProgress: CR.Progress = context.progress const stepId = event.payload.stepId - console.log('step progress update', stepId) currentProgress.steps[stepId] = true @@ -139,7 +134,6 @@ export default { const {progress, position} = context const stageId: string = position.stageId - console.log('stage progress update', stageId) progress.stages[stageId] = true @@ -151,7 +145,6 @@ export default { // @ts-ignore updatePosition: assign({ position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Progress => { - console.log('updatePosition event', event) const {position} = event.payload return position } diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index 9642bdea..ad902d44 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -2,17 +2,6 @@ import * as CR from 'typings' import channel from '../../channel' export default { - tutorialStart() { - console.log('EDITOR: TUTORIAL_START') - channel.editorSend({ - type: 'TUTORIAL_START', - payload: { - tutorial: { - id: 'some-tutorial-id' - } - } - }) - }, tutorialConfig(context: CR.MachineContext) { // setup test runner and git const {tutorial} = context @@ -21,7 +10,7 @@ export default { testRunner: tutorial.testRunner, repo: tutorial.repo, } - console.log('EDITOR: TUTORIAL_CONFIG') + console.log('EDITOR: TUTORIAL_CONFIG', payload) channel.editorSend({ type: 'TUTORIAL_CONFIG', payload, diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 5d68a009..1b4a8254 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -44,7 +44,6 @@ export const machine = Machine Date: Sat, 7 Sep 2019 16:40:02 -0700 Subject: [PATCH 099/117] clean up typings preventing build --- src/editor/commands/index.ts | 20 ++--- src/editor/index.ts | 2 +- src/services/tutorial/index.ts | 2 +- typings/index.d.ts | 5 +- web-app/src/components/Router/index.tsx | 25 +++--- web-app/src/containers/Continue/index.tsx | 5 +- .../containers/Tutorial/LevelPage/index.tsx | 40 ++++++---- .../containers/Tutorial/StagePage/index.tsx | 80 +++++++++++-------- .../containers/Tutorial/SummaryPage/index.tsx | 31 ++++--- web-app/src/services/channel/index.ts | 6 ++ web-app/src/services/state/actions/context.ts | 35 ++++++-- web-app/src/services/state/actions/editor.ts | 3 + web-app/src/services/state/machine.ts | 11 ++- 13 files changed, 164 insertions(+), 101 deletions(-) diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index a348937a..1000423e 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -117,16 +117,16 @@ export const createCommands = ({vscodeExt}: CreateCommandProps) => { // machine.send(action) }, [COMMANDS.RUN_TEST]: () => { - // runTest({ - // onSuccess: () => machine.send('TEST_PASS'), - // onFail: () => machine.send('TEST_FAIL'), - // }) - }, - [COMMANDS.TEST_PASS]: () => { - vscode.window.showInformationMessage('PASS') - }, - [COMMANDS.TEST_FAIL]: () => { - vscode.window.showWarningMessage('FAIL') + runTest({ + onSuccess: () => { + console.log('TEST_PASS') + vscode.window.showInformationMessage('PASS') + }, + onFail: () => { + console.log('TEST_FAIL') + vscode.window.showWarningMessage('FAIL') + } + }) }, } } diff --git a/src/editor/index.ts b/src/editor/index.ts index 52beddc9..f238f2df 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode' -import {setWorkspaceRoot} from './services/node' +import {setWorkspaceRoot} from '../services/node' import {createCommands} from './commands' class Editor { diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index 86d59541..4220ccf5 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -38,7 +38,7 @@ class Tutorial implements TutorialModel { } public launch = async (tutorial: G.Tutorial) => { console.log('launch tutorial') - machine.send('TUTORIAL_START') + // machine.send('TUTORIAL_START') console.log('tutorial', tutorial) diff --git a/typings/index.d.ts b/typings/index.d.ts index 130453b4..a133cf4e 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1,5 +1,6 @@ import {send} from 'xstate' import TutorialModel from '../src/services/tutorial' +import * as G from './graphql' export interface TutorialLevel { stageList: string[] @@ -116,8 +117,8 @@ export interface Action { export interface MachineContext { tutorial: G.Tutorial | null, - position: CR.Position, - progress: CR.Progress, + position: Position, + progress: Progress, } export interface MachineEvent { diff --git a/web-app/src/components/Router/index.tsx b/web-app/src/components/Router/index.tsx index 0258470c..41fadf36 100644 --- a/web-app/src/components/Router/index.tsx +++ b/web-app/src/components/Router/index.tsx @@ -7,36 +7,33 @@ import Route from './Route' import debuggerWrapper from '../Debugger/debuggerWrapper' import channel from '../../services/channel' import messageBusReceiver from '../../services/channel/receiver' -import actions from '../../services/state/actions' - interface Props { children: any } interface CloneElementProps { - context: CR.MachineContext - send(action: CR.Action): void + context: CR.MachineContext + send(action: CR.Action): void } // router finds first state match of -const Router = ({ children }: Props): React.ReactElement|null => { - const [state, send] = useMachine(machine, { - actions, - interpreterOptions: { - logger: console.log.bind('XSTATE:') - } - }) +const Router = ({ children }: Props): React.ReactElement | null => { + const [state, send] = useMachine(machine, { + interpreterOptions: { + logger: console.log.bind('XSTATE:'), + }, + }) - channel.setMachineSend(send) + channel.setMachineSend(send) - // event bus listener + // event bus listener React.useEffect(messageBusReceiver, []) const childArray = React.Children.toArray(children) for (const child of childArray) { if (state.matches(child.props.path)) { - const element = React.cloneElement(child.props.children, { send, context: state.context }) + const element = React.cloneElement(child.props.children, { send, context: state.context }) return debuggerWrapper(element, state) } } diff --git a/web-app/src/containers/Continue/index.tsx b/web-app/src/containers/Continue/index.tsx index 19ace120..a01ea5c7 100644 --- a/web-app/src/containers/Continue/index.tsx +++ b/web-app/src/containers/Continue/index.tsx @@ -27,9 +27,12 @@ interface ContainerProps { } const ContinuePageContainer = ({ context, send }: ContainerProps) => { - // TODO: load specific tutorialId const { tutorial } = context + if (!tutorial) { + throw new Error('Tutorial not found') + } + return send('TUTORIAL_START')} /> } diff --git a/web-app/src/containers/Tutorial/LevelPage/index.tsx b/web-app/src/containers/Tutorial/LevelPage/index.tsx index 92110601..aa4ba130 100644 --- a/web-app/src/containers/Tutorial/LevelPage/index.tsx +++ b/web-app/src/containers/Tutorial/LevelPage/index.tsx @@ -13,28 +13,36 @@ export const LevelSummaryPage = (props: LevelProps) => { const onNext = (): void => { props.send('NEXT') } - return + return } interface ContainerProps { - context: CR.MachineContext - send(action: string): void + context: CR.MachineContext + send(action: string): void } const LevelSummaryPageContainer = (props: ContainerProps) => { - const { tutorial, position, progress } = props.context - - const level: G.Level = tutorial.version.levels.find((l: G.Level) => l.id === position.levelId) - - level.stages.forEach((stage: G.Stage) => { - if (stage.id === position.stageId) { - stage.status = 'ACTIVE' - } else if (progress.stages[stage.id]) { - stage.status = 'COMPLETE' - } else { - stage.status = 'INCOMPLETE' - } - }) + const { tutorial, position, progress } = props.context + + if (!tutorial) { + throw new Error('Tutorial not found in LevelSummaryPageContainer') + } + + const level: G.Level | undefined = tutorial.version.levels.find((l: G.Level) => l.id === position.levelId) + + if (!level) { + throw new Error('Level not found in LevelSummaryPageContainer') + } + + level.stages.forEach((stage: G.Stage) => { + if (stage.id === position.stageId) { + stage.status = 'ACTIVE' + } else if (progress.stages[stage.id]) { + stage.status = 'COMPLETE' + } else { + stage.status = 'INCOMPLETE' + } + }) return } diff --git a/web-app/src/containers/Tutorial/StagePage/index.tsx b/web-app/src/containers/Tutorial/StagePage/index.tsx index 3d2da298..d677ebe6 100644 --- a/web-app/src/containers/Tutorial/StagePage/index.tsx +++ b/web-app/src/containers/Tutorial/StagePage/index.tsx @@ -5,47 +5,59 @@ import * as G from 'typings/graphql' import Stage from './Stage' interface PageProps { - context: CR.MachineContext + context: CR.MachineContext send(action: CR.Action): void } const StageSummaryPageContainer = (props: PageProps) => { - const { tutorial, position, progress } = props.context + const { tutorial, position, progress } = props.context + + if (!tutorial) { + throw new Error('Tutorial not found in StageSummaryPageContainer') + } + + const level: G.Level | undefined = tutorial.version.levels.find((l: G.Level) => l.id === position.levelId) + + if (!level) { + throw new Error('Level not found in StageSummaryPageContainer') + } + + const stage: G.Stage | undefined = level.stages.find((s: G.Stage) => s.id === position.stageId) + + if (!stage) { + throw new Error('Stage not found in StageSummaryPageContainer') + } - const stage: G.Stage = tutorial.version - .levels.find((l: G.Level) => l.id === position.levelId) - .stages.find((s: G.Stage) => s.id === position.stageId) - const onContinue = (): void => { props.send({ - type: 'STAGE_NEXT', - payload: { - stageId: position.stageId, - } - }) - } - - const onSave =(): void => { - props.send({ - type: 'TEST_RUN', - payload: { - stepId: position.stepId, - } - }) - } - - stage.steps.forEach((step: G.Step) => { - if (progress.steps[step.id]) { - step.status = 'COMPLETE' - } else if (step.id === position.stepId) { - step.status = 'ACTIVE' - } else { - step.status = 'INCOMPLETE' - } - }) - stage.status = progress.stages[position.stageId] ? 'COMPLETE' : 'ACTIVE' - - return + type: 'STAGE_NEXT', + payload: { + stageId: position.stageId, + }, + }) + } + + const onSave = (): void => { + props.send({ + type: 'TEST_RUN', + payload: { + stepId: position.stepId, + }, + }) + } + + stage.steps.forEach((step: G.Step) => { + if (progress.steps[step.id]) { + step.status = 'COMPLETE' + } else if (step.id === position.stepId) { + step.status = 'ACTIVE' + } else { + step.status = 'INCOMPLETE' + } + }) + stage.status = progress.stages[position.stageId] ? 'COMPLETE' : 'ACTIVE' + + return } export default StageSummaryPageContainer diff --git a/web-app/src/containers/Tutorial/SummaryPage/index.tsx b/web-app/src/containers/Tutorial/SummaryPage/index.tsx index f4443f63..19eea612 100644 --- a/web-app/src/containers/Tutorial/SummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/SummaryPage/index.tsx @@ -7,17 +7,21 @@ import Summary from './Summary' import ErrorView from '../../../components/Error' interface PageProps { - context: CR.MachineContext - send(action: CR.Action): void + context: CR.MachineContext + send(action: CR.Action): void } const SummaryPage = (props: PageProps) => { - const { tutorial } = props.context + const { tutorial } = props.context + + if (!tutorial) { + throw new Error('Tutorial not found in summary page') + } const { loading, error, data } = useQuery(queryTutorial, { - fetchPolicy: 'network-only', // for debugging purposes + fetchPolicy: 'network-only', // for debugging purposes variables: { - tutorialId: tutorial.id, - version: tutorial.version.version, + tutorialId: tutorial.id, + version: tutorial.version.version, }, }) @@ -29,14 +33,15 @@ const SummaryPage = (props: PageProps) => { return } - const onNext = () => props.send({ - type: 'LOAD_TUTORIAL', - payload: { - tutorial: data.tutorial, - } - }) + const onNext = () => + props.send({ + type: 'LOAD_TUTORIAL', + payload: { + tutorial: data.tutorial, + }, + }) - const { title, text } = data.tutorial + const { title, text } = data.tutorial return } diff --git a/web-app/src/services/channel/index.ts b/web-app/src/services/channel/index.ts index 9409e1ac..f9f2e3c1 100644 --- a/web-app/src/services/channel/index.ts +++ b/web-app/src/services/channel/index.ts @@ -41,6 +41,12 @@ class Channel { this.machineSend(action) console.log('test passed') return + case 'TEST_FAIL': + this.machineSend(action) + return + case 'ACTIONS_LOADED': + console.log('ACTIONS_LOADED') + return default: if (action.type) { console.warn(`Unknown received action ${action.type}`, action) diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index fd93cfbc..019cebd5 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -39,9 +39,14 @@ export default { // @ts-ignore updateStepPosition: assign({ position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { - const position: CR.Position = context.position + const {tutorial, position} = context + + if (!tutorial) { + throw new Error('Tutorial not found when updating step position') + } // merge in the updated position // sent with the test to ensure consistency + // @ts-ignore const steps: G.Step[] = context.tutorial.version .levels.find((l: G.Level) => l.id === position.levelId) .stages.find((s: G.Stage) => s.id === position.stageId) @@ -70,10 +75,15 @@ export default { // @ts-ignore updateStagePosition: assign({ position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { - const position: CR.Position = context.position + const {tutorial, position} = context + + if (!tutorial) { + throw new Error('Tutorial not found when updating stage position') + } // merge in the updated position // sent with the test to ensure consistency - const stages: G.Stage[] = context.tutorial.version + // @ts-ignore + const stages: G.Stage[] = tutorial.version .levels.find((l: G.Level) => l.id === position.levelId) .stages @@ -94,10 +104,14 @@ export default { // @ts-ignore updateLevelPosition: assign({ position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { - const position: CR.Position = context.position + const {tutorial, position} = context + + if (!tutorial) { + throw new Error('Tutorial not found when updating level position') + } // merge in the updated position // sent with the test to ensure consistency - const levels: G.Level[] = context.tutorial.version.levels + const levels: G.Level[] = tutorial.version.levels const levelIndex = levels.findIndex((l: G.Level) => l.id === position.levelId) const level: G.Level = levels[levelIndex + 1] @@ -152,6 +166,10 @@ export default { loadNext: send((context: CR.MachineContext): CR.Action => { const {tutorial, position, progress} = context + if (!tutorial) { + throw new Error('No tutorial found for loading next step') + } + // has next step? const levels: G.Level[] = tutorial.version.levels const level: G.Level | undefined = levels.find((l: G.Level) => l.id === position.levelId) @@ -217,7 +235,13 @@ export default { }), stepNext: send((context: CR.MachineContext): CR.Action => { const {tutorial, position, progress} = context + + if (!tutorial || !tutorial.version) { + throw new Error('No tutorial found when loading next step') + } + // TODO: protect against errors + // @ts-ignore const steps: G.Step[] = tutorial.version .levels.find((l: G.Level) => l.id === position.levelId) .stages.find((s: G.Stage) => s.id === position.stageId) @@ -244,7 +268,6 @@ export default { } } }), - // @ts-ignore reset: assign({ tutorial() { storage.tutorial.set(null) diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index ad902d44..f91cb10e 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -5,6 +5,9 @@ export default { tutorialConfig(context: CR.MachineContext) { // setup test runner and git const {tutorial} = context + if (!tutorial) { + throw new Error('Invalid tutorial for tutorial config') + } const payload = { codingLanguage: tutorial.codingLanguage, testRunner: tutorial.testRunner, diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 1b4a8254..2177bfa4 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -1,7 +1,13 @@ -import {Machine} from 'xstate' +import {Machine, MachineOptions} from 'xstate' import * as CR from 'typings' +import actions from './actions' import * as invoke from './actions/invoke' +const options: MachineOptions = { + // @ts-ignore + actions +} + export const machine = Machine( { id: 'root', @@ -173,7 +179,6 @@ export const machine = Machine Date: Sat, 7 Sep 2019 18:37:50 -0700 Subject: [PATCH 100/117] setup programmatic jest test runner --- jest.config.js | 7 -- package-lock.json | 178 +++++++++++++++++++++---------- package.json | 11 +- src/test/extension.test.ts | 21 ---- src/test/index.ts | 23 ---- src/test/runTest.ts | 24 +++++ src/test/suite/extension.test.ts | 14 +++ src/test/suite/index.ts | 23 ++++ 8 files changed, 190 insertions(+), 111 deletions(-) delete mode 100644 jest.config.js delete mode 100644 src/test/extension.test.ts delete mode 100644 src/test/index.ts create mode 100644 src/test/runTest.ts create mode 100644 src/test/suite/extension.test.ts create mode 100644 src/test/suite/index.ts diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index 44342108..00000000 --- a/jest.config.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - roots: ['/src'], - transform: { - '^.+\\.tsx?$': 'ts-jest', - }, - testPathIgnorePatterns: ['node_modules', 'src/test'], -} diff --git a/package-lock.json b/package-lock.json index 1286d646..756fad7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,18 +14,18 @@ } }, "@babel/core": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.5.5.tgz", - "integrity": "sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.0.tgz", + "integrity": "sha512-FuRhDRtsd6IptKpHXAa+4WPZYY2ZzgowkbLBecEDDSje1X/apG7jQM33or3NdOmjXBKWGOg4JmSiRfUfuTtHXw==", "dev": true, "requires": { "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.5.5", - "@babel/helpers": "^7.5.5", - "@babel/parser": "^7.5.5", - "@babel/template": "^7.4.4", - "@babel/traverse": "^7.5.5", - "@babel/types": "^7.5.5", + "@babel/generator": "^7.6.0", + "@babel/helpers": "^7.6.0", + "@babel/parser": "^7.6.0", + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.0", + "@babel/types": "^7.6.0", "convert-source-map": "^1.1.0", "debug": "^4.1.0", "json5": "^2.1.0", @@ -59,12 +59,12 @@ } }, "@babel/generator": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.5.tgz", - "integrity": "sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.0.tgz", + "integrity": "sha512-Ms8Mo7YBdMMn1BYuNtKuP/z0TgEIhbcyB8HVR6PPNYp4P61lMsABiS4A3VG1qznjXVCf3r+fVHhm4efTYVsySA==", "dev": true, "requires": { - "@babel/types": "^7.5.5", + "@babel/types": "^7.6.0", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0", @@ -115,14 +115,14 @@ } }, "@babel/helpers": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.5.5.tgz", - "integrity": "sha512-nRq2BUhxZFnfEn/ciJuhklHvFOqjJUD5wpx+1bxUF2axL9C+v4DE/dmp5sT2dKnpOs4orZWzpAZqlCy8QqE/7g==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.0.tgz", + "integrity": "sha512-W9kao7OBleOjfXtFGgArGRX6eCP0UEcA2ZWEWNkJdRZnHhW4eEbeswbG3EwaRsnQUAEGWYgMq1HsIXuNNNy2eQ==", "dev": true, "requires": { - "@babel/template": "^7.4.4", - "@babel/traverse": "^7.5.5", - "@babel/types": "^7.5.5" + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.0", + "@babel/types": "^7.6.0" } }, "@babel/highlight": { @@ -137,9 +137,9 @@ } }, "@babel/parser": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz", - "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.0.tgz", + "integrity": "sha512-+o2q111WEx4srBs7L9eJmcwi655eD8sXniLqMB93TBK9GrNzGrxDWSjiqz2hLU0Ha8MTXFIP0yd9fNdP+m43ZQ==", "dev": true }, "@babel/plugin-syntax-object-rest-spread": { @@ -152,28 +152,28 @@ } }, "@babel/template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", - "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", + "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.4.4", - "@babel/types": "^7.4.4" + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" } }, "@babel/traverse": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.5.tgz", - "integrity": "sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.0.tgz", + "integrity": "sha512-93t52SaOBgml/xY74lsmt7xOR4ufYvhb5c5qiM6lu4J/dWGMAfAh6eKw4PjLes6DI6nQgearoxnFJk60YchpvQ==", "dev": true, "requires": { "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.5.5", + "@babel/generator": "^7.6.0", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.5.5", - "@babel/types": "^7.5.5", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" @@ -197,9 +197,9 @@ } }, "@babel/types": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", - "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.1.tgz", + "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", "dev": true, "requires": { "esutils": "^2.0.2", @@ -411,9 +411,9 @@ } }, "@types/babel__core": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.2.tgz", - "integrity": "sha512-cfCCrFmiGY/yq0NuKNxIQvZFy9kY/1immpSpTngOnyIbD4+eJOG5mxphhHDv3CHL9GltO4GcKr54kGBg3RNdbg==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", + "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -460,6 +460,23 @@ "@types/node": "*" } }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, "@types/graphql": { "version": "14.5.0", "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-14.5.0.tgz", @@ -509,10 +526,16 @@ "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", "dev": true }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, "@types/node": { - "version": "12.7.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.3.tgz", - "integrity": "sha512-3SiLAIBkDWDg6vFo0+5YJyHPWU9uwu40Qe+v+0MH8wRKYBimHvvAOyk3EzMrD/TrIlLYfXrqDqrg913PynrMJQ==", + "version": "12.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.4.tgz", + "integrity": "sha512-W0+n1Y+gK/8G2P/piTkBBN38Qc5Q1ZSO6B5H3QmPCUewaiXOo2GCAWZ4ElZCcNhjJuBSUSLGFUJnmlCn5+nxOQ==", "dev": true }, "@types/stack-utils": { @@ -531,9 +554,9 @@ } }, "@types/yargs-parser": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.0.0.tgz", - "integrity": "sha512-wBlsw+8n21e6eTd4yVv8YD/E3xq0O6nNnJIquutAsFGE7EyMKz7W6RNT6BRu1SmdgmlCZ9tb0X+j+D6HGr8pZw==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", + "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", "dev": true }, "abab": { @@ -1360,17 +1383,21 @@ } }, "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.1.tgz", + "integrity": "sha512-cp/Tb1oA/rh2X7vqeSOvM+TSo3UkJLX70eNihgVEvnzwAgikjkTFr/QVgRCaxjm0knCNQzNoxxxcw2zO2LJdZA==", "dev": true, "requires": { "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", "has": "^1.0.3", + "has-symbols": "^1.0.0", "is-callable": "^1.1.4", "is-regex": "^1.0.4", - "object-keys": "^1.0.12" + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.0.0", + "string.prototype.trimright": "^2.0.0" } }, "es-to-primitive": { @@ -2355,9 +2382,9 @@ "dev": true }, "handlebars": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", - "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.2.0.tgz", + "integrity": "sha512-Kb4xn5Qh1cxAKvQnzNWZ512DhABzyFNmsaJf3OAkWNa4NkaqWcNI8Tao8Tasi0/F4JD9oyG0YxuFyvyR57d+Gw==", "dev": true, "requires": { "neo-async": "^2.6.0", @@ -3978,6 +4005,12 @@ } } }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "dev": true + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -4888,6 +4921,26 @@ "strip-ansi": "^4.0.0" } }, + "string.prototype.trimleft": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.0.0.tgz", + "integrity": "sha1-aLaqjhYsaoDnbjqKDC50cYbicf8=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.0.2" + } + }, + "string.prototype.trimright": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.0.0.tgz", + "integrity": "sha1-q0pW2AKgH75yk+EehPJNyBZGYd0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.0.2" + } + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -5292,15 +5345,28 @@ "source-map-support": "^0.5.0", "url-parse": "^1.4.4", "vscode-test": "^0.4.1" + }, + "dependencies": { + "vscode-test": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-0.4.3.tgz", + "integrity": "sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==", + "requires": { + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1" + } + } } }, "vscode-test": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-0.4.3.tgz", - "integrity": "sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.2.0.tgz", + "integrity": "sha512-aowqgc8gZe0eflzVUXsBjBrlsJ8eC35kfgfSEeHu9PKA1vQKm/3rVK43TlbxGue8hKtZBElNAJ5QuYklR/vLJA==", + "dev": true, "requires": { "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.1" + "https-proxy-agent": "^2.2.1", + "rimraf": "^2.6.3" } }, "w3c-hr-time": { diff --git a/package.json b/package.json index 1f78d872..ac57a8da 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "postinstall": "node ./node_modules/vscode/bin/install", "machine": "node ./out/state/index.js", "storybook": "cd web-app && npm run storybook", - "test:ext": "npm run build && node ./node_modules/vscode/bin/test", + "test:ext": "node ./build/test/runTest.js", "test": "jest", "vscode:prepublish": "npm run build", "watch": "tsc -watch -p ./" @@ -39,16 +39,19 @@ }, "devDependencies": { "@types/dotenv": "^6.1.1", + "@types/glob": "^7.1.1", "@types/graphql": "^14.5.0", "@types/jest": "^24.0.18", - "@types/node": "^12.7.3", + "@types/node": "^12.7.4", "concurrently": "^4.1.2", - "jest": "24.8.0", + "glob": "^7.1.4", + "jest": "^24.8.0", "prettier": "^1.18.2", "ts-jest": "^24.0.2", "tslint": "^5.19.0", "tslint-config-prettier": "^1.18.0", - "typescript": "^3.6.2" + "typescript": "^3.6.2", + "vscode-test": "^1.2.0" }, "engines": { "vscode": "^1.34.0" diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts deleted file mode 100644 index 193dd793..00000000 --- a/src/test/extension.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -// -// Note: This example test is leveraging the Mocha test framework. -// Please refer to their documentation on https://mochajs.org/ for help. -// - -// The module 'assert' provides assertion methods from node -// import * as assert from 'assert' - -// You can import and use all API from the 'vscode' module -// as well as import your extension to test it -// import * as vscode from 'vscode' -// import * as myExtension from '../extension' - -// Defines a Mocha test suite to group tests of similar kind together -// suite('Extension Tests', function() { -// // Defines a Mocha unit test -// test('Something 1', function() { -// assert.equal(-1, [1, 2, 3].indexOf(5)) -// assert.equal(-1, [1, 2, 3].indexOf(0)) -// }) -// }) diff --git a/src/test/index.ts b/src/test/index.ts deleted file mode 100644 index 5ebcde50..00000000 --- a/src/test/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -// -// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING -// -// This file is providing the test runner to use when running extension tests. -// By default the test runner in use is Mocha based. -// -// You can provide your own test runner if you want to override it by exporting -// a function run(testsRoot: string, clb: (error: Error, failures?: number) => void): void -// that the extension host can call to run the tests. The test runner is expected to use console.log -// to report the results back to the caller. When the tests are finished, return -// a possible error to the callback or null if none. - -import * as testRunner from 'vscode/lib/testrunner' - -// You can directly control Mocha options by configuring the test runner below -// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options -// for more info -testRunner.configure({ - ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) - useColors: true, // colored output from test results -}) - -module.exports = testRunner diff --git a/src/test/runTest.ts b/src/test/runTest.ts new file mode 100644 index 00000000..3e08b985 --- /dev/null +++ b/src/test/runTest.ts @@ -0,0 +1,24 @@ +import * as path from 'path' + +import {runTests} from 'vscode-test' + +async function main() { + console.log('__dirname', __dirname) + // The folder containing the Extension Manifest package.json + // Passed to `--extensionDevelopmentPath` + const extensionDevelopmentPath: string = path.resolve(__dirname, '../../') + + // The path to the extension test script + // Passed to --extensionTestsPath + const extensionTestsPath: string = path.resolve(__dirname, './suite/index') + + // Download VS Code, unzip it and run the integration test + await runTests({extensionDevelopmentPath, extensionTestsPath}) + .catch((err: Error) => { + console.error('Failed to run tests') + console.error(err) + process.exit(1) + }) +} + +main() \ No newline at end of file diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts new file mode 100644 index 00000000..533116ca --- /dev/null +++ b/src/test/suite/extension.test.ts @@ -0,0 +1,14 @@ + +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +// import * as vscode from 'vscode' +// import * as myExtension from '../../extension' + +console.log('running extension.test.js') + +describe('Extension tests', () => { + test('Some test', () => { + console.log('some test ran!') + expect(2).toBe(2) + }) +}) \ No newline at end of file diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts new file mode 100644 index 00000000..77cb4ea2 --- /dev/null +++ b/src/test/suite/index.ts @@ -0,0 +1,23 @@ +import * as path from 'path' +// import * as glob from 'glob' +import * as jest from 'jest' + +export async function run(): Promise { + + const testDir = __dirname + + const config = { + bail: false, + // rootDir: testDir, + browser: false, + json: false, + useStderr: true, + } + // @ts-ignore + const result = await jest.runCLI(config, [testDir]) + .catch((failure: any) => { + console.error(failure) + }) + + console.log('--- JEST OUTPUT ---\n\n', JSON.stringify(result.results, null, 2)) +} \ No newline at end of file From a9730d04325d489234162badf28b72811bb5951d Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 7 Sep 2019 18:43:26 -0700 Subject: [PATCH 101/117] disable extensions during tests --- src/test/runTest.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/runTest.ts b/src/test/runTest.ts index 3e08b985..22c78819 100644 --- a/src/test/runTest.ts +++ b/src/test/runTest.ts @@ -12,8 +12,14 @@ async function main() { // Passed to --extensionTestsPath const extensionTestsPath: string = path.resolve(__dirname, './suite/index') + const config = { + extensionDevelopmentPath, + extensionTestsPath, + launchArgs: ['--disable-extensions'] // turn off other extensions + } + // Download VS Code, unzip it and run the integration test - await runTests({extensionDevelopmentPath, extensionTestsPath}) + await runTests(config) .catch((err: Error) => { console.error('Failed to run tests') console.error(err) From 12c72c25acb07735d549703863bb52680b3ccb49 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 7 Sep 2019 18:55:01 -0700 Subject: [PATCH 102/117] cleanup test return response --- src/test/runTest.ts | 3 ++- src/test/suite/extension.test.ts | 3 --- src/test/suite/index.ts | 14 +++++++++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/test/runTest.ts b/src/test/runTest.ts index 22c78819..9f6cb22a 100644 --- a/src/test/runTest.ts +++ b/src/test/runTest.ts @@ -21,10 +21,11 @@ async function main() { // Download VS Code, unzip it and run the integration test await runTests(config) .catch((err: Error) => { - console.error('Failed to run tests') console.error(err) process.exit(1) }) + + process.exit(0) } main() \ No newline at end of file diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 533116ca..1f0f84d2 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -4,11 +4,8 @@ // import * as vscode from 'vscode' // import * as myExtension from '../../extension' -console.log('running extension.test.js') - describe('Extension tests', () => { test('Some test', () => { - console.log('some test ran!') expect(2).toBe(2) }) }) \ No newline at end of file diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index 77cb4ea2..bfc6ebf3 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -8,16 +8,24 @@ export async function run(): Promise { const config = { bail: false, - // rootDir: testDir, + rootDir: testDir, browser: false, json: false, useStderr: true, } // @ts-ignore - const result = await jest.runCLI(config, [testDir]) + const {results} = await jest.runCLI(config, [testDir]) .catch((failure: any) => { console.error(failure) }) - console.log('--- JEST OUTPUT ---\n\n', JSON.stringify(result.results, null, 2)) + if (results.numFailedTests > 0) { + const failedTests = results.testResults.filter((t: any) => t.numFailingTests || t.numPendingTests) + + failedTests.forEach(console.log) + throw new Error(' Test(s) failed') + } + + console.log('--- JEST OUTPUT ---\n\n', JSON.stringify(results, null, 2)) + console.log(`${results.numPassedTests} test(s) passed!`) } \ No newline at end of file From d17c65a4cf962462e0ce2b8ada876e92caf9314f Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 7 Sep 2019 19:38:36 -0700 Subject: [PATCH 103/117] revert back to mocha (jest not working correctly) --- package-lock.json | 4645 ++++-------------------------- package.json | 7 +- src/test/suite/extension.test.ts | 22 +- src/test/suite/index.ts | 54 +- 4 files changed, 574 insertions(+), 4154 deletions(-) diff --git a/package-lock.json b/package-lock.json index 756fad7f..98bf3039 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,118 +13,6 @@ "@babel/highlight": "^7.0.0" } }, - "@babel/core": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.0.tgz", - "integrity": "sha512-FuRhDRtsd6IptKpHXAa+4WPZYY2ZzgowkbLBecEDDSje1X/apG7jQM33or3NdOmjXBKWGOg4JmSiRfUfuTtHXw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.0", - "@babel/helpers": "^7.6.0", - "@babel/parser": "^7.6.0", - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.0", - "@babel/types": "^7.6.0", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.0.tgz", - "integrity": "sha512-Ms8Mo7YBdMMn1BYuNtKuP/z0TgEIhbcyB8HVR6PPNYp4P61lMsABiS4A3VG1qznjXVCf3r+fVHhm4efTYVsySA==", - "dev": true, - "requires": { - "@babel/types": "^7.6.0", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", - "dev": true - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helpers": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.0.tgz", - "integrity": "sha512-W9kao7OBleOjfXtFGgArGRX6eCP0UEcA2ZWEWNkJdRZnHhW4eEbeswbG3EwaRsnQUAEGWYgMq1HsIXuNNNy2eQ==", - "dev": true, - "requires": { - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.0", - "@babel/types": "^7.6.0" - } - }, "@babel/highlight": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", @@ -136,321 +24,12 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.0.tgz", - "integrity": "sha512-+o2q111WEx4srBs7L9eJmcwi655eD8sXniLqMB93TBK9GrNzGrxDWSjiqz2hLU0Ha8MTXFIP0yd9fNdP+m43ZQ==", + "@types/assert": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.4.3.tgz", + "integrity": "sha512-491hfOvNr0+BGOHT2m36xJ+LK68IuOshvxV0VIrKOnzBDL11WlDa3PwO+drTYkwCdfzJRN9REcDPZVVcrx1ucw==", "dev": true }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", - "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/template": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", - "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.0" - } - }, - "@babel/traverse": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.0.tgz", - "integrity": "sha512-93t52SaOBgml/xY74lsmt7xOR4ufYvhb5c5qiM6lu4J/dWGMAfAh6eKw4PjLes6DI6nQgearoxnFJk60YchpvQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.0", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.1.tgz", - "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "@cnakazawa/watch": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", - "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "dev": true, - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/core": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", - "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/reporters": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-changed-files": "^24.9.0", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-resolve-dependencies": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "jest-watcher": "^24.9.0", - "micromatch": "^3.1.10", - "p-each-series": "^1.0.0", - "realpath-native": "^1.1.0", - "rimraf": "^2.5.4", - "slash": "^2.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "@jest/environment": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", - "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", - "dev": true, - "requires": { - "@jest/fake-timers": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/reporters": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", - "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.2", - "istanbul-lib-instrument": "^3.0.1", - "istanbul-lib-report": "^2.0.4", - "istanbul-lib-source-maps": "^3.0.1", - "istanbul-reports": "^2.2.6", - "jest-haste-map": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "node-notifier": "^5.4.2", - "slash": "^2.0.0", - "source-map": "^0.6.0", - "string-length": "^2.0.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, - "@jest/test-sequencer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", - "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0" - } - }, - "@jest/transform": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", - "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^24.9.0", - "babel-plugin-istanbul": "^5.1.0", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.15", - "jest-haste-map": "^24.9.0", - "jest-regex-util": "^24.9.0", - "jest-util": "^24.9.0", - "micromatch": "^3.1.10", - "pirates": "^4.0.1", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "2.4.1" - } - }, - "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@types/babel__core": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", - "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.0.2.tgz", - "integrity": "sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", - "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", - "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, "@types/dotenv": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz", @@ -486,115 +65,23 @@ "graphql": "*" } }, - "@types/istanbul-lib-coverage": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", - "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", - "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", - "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "24.0.18", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.18.tgz", - "integrity": "sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ==", - "dev": true, - "requires": { - "@types/jest-diff": "*" - } - }, - "@types/jest-diff": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz", - "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", - "dev": true - }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", "dev": true }, + "@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==" + }, "@types/node": { "version": "12.7.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.4.tgz", "integrity": "sha512-W0+n1Y+gK/8G2P/piTkBBN38Qc5Q1ZSO6B5H3QmPCUewaiXOo2GCAWZ4ElZCcNhjJuBSUSLGFUJnmlCn5+nxOQ==", "dev": true }, - "@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", - "dev": true - }, - "@types/yargs": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.2.tgz", - "integrity": "sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", - "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", - "dev": true - }, - "abab": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.1.tgz", - "integrity": "sha512-1zSbbCuoIjafKZ3mblY5ikvAb0ODUbqBnFuUb7f6uLeQhhGJ0vEV4ntmtxKLT2WgXCO94E07BjunsIw1jOMPZw==", - "dev": true - }, - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - }, - "acorn-globals": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.3.tgz", - "integrity": "sha512-vkR40VwS2SYO98AIeFvzWWh+xyc2qi9s7OoXSFEGIP/rOJKzjnhykaZJNnHdoq4BL2gGxI5EZOU16z896EYnOQ==", - "dev": true, - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - }, - "dependencies": { - "acorn": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", - "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", - "dev": true - } - } - }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", - "dev": true - }, "agent-base": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", @@ -614,10 +101,10 @@ "uri-js": "^4.2.2" } }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", "dev": true }, "ansi-regex": { @@ -635,16 +122,6 @@ "color-convert": "^1.9.0" } }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -654,36 +131,6 @@ "sprintf-js": "~1.0.2" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -692,40 +139,28 @@ "safer-buffer": "~2.1.0" } }, + "assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "dev": true, + "requires": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "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==", - "dev": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -736,118 +171,17 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, - "babel-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", - "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", - "dev": true, - "requires": { - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/babel__core": "^7.1.0", - "babel-plugin-istanbul": "^5.1.0", - "babel-preset-jest": "^24.9.0", - "chalk": "^2.4.2", - "slash": "^2.0.0" - } + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "babel-plugin-istanbul": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", - "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", - "dev": true, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.3.0", - "test-exclude": "^5.2.3" - } - }, - "babel-plugin-jest-hoist": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", - "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", - "dev": true, - "requires": { - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", - "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", - "dev": true, - "requires": { - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.9.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" + "tweetnacl": "^0.14.3" } }, "brace-expansion": { @@ -859,81 +193,11 @@ "concat-map": "0.0.1" } }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "browser-process-hrtime": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", - "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", - "dev": true - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "dev": true, - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz", - "integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -945,44 +209,12 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -999,35 +231,6 @@ "supports-color": "^5.3.0" } }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -1039,28 +242,12 @@ "wrap-ansi": "^2.0.0" } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -1089,12 +276,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1134,29 +315,6 @@ } } }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -1184,21 +342,6 @@ "which": "^1.2.9" } }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", - "dev": true, - "requires": { - "cssom": "0.3.x" - } - }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -1207,30 +350,6 @@ "assert-plus": "^1.0.0" } }, - "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" - }, - "dependencies": { - "whatwg-url": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", - "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, "date-fns": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", @@ -1251,18 +370,6 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -1272,78 +379,16 @@ "object-keys": "^1.0.12" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", - "dev": true - }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", - "dev": true - }, - "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, - "requires": { - "webidl-conversions": "^4.0.2" - } - }, "dotenv": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz", @@ -1411,6 +456,12 @@ "is-symbol": "^1.0.2" } }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "dev": true + }, "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -1429,51 +480,18 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, - "escodegen": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", - "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", - "dev": true, - "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true - } - } - }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "exec-sh": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", - "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", - "dev": true - }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -1489,229 +507,52 @@ "strip-eof": "^1.0.0" } }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" - } - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "locate-path": "^3.0.0" } }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", "dev": true, "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "is-buffer": "~2.0.3" }, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fb-watchman": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", - "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", - "dev": true, - "requires": { - "bser": "^2.0.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "dev": true } } }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -1727,595 +568,32 @@ "mime-types": "^2.1.12" } }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "requires": { "pump": "^3.0.0" } }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -2333,1135 +611,219 @@ "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", - "dev": true - }, - "graphql": { - "version": "14.5.4", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.5.4.tgz", - "integrity": "sha512-dPLvHoxy5m9FrkqWczPPRnH0X80CyvRE6e7Fa5AWEqEAzg9LpxHvKh24po/482E6VWHigOkAmb4xCp6P9yT9gw==", - "requires": { - "iterall": "^1.2.2" - } - }, - "graphql-request": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-1.8.2.tgz", - "integrity": "sha512-dDX2M+VMsxXFCmUX0Vo0TopIZIX4ggzOtiCsThgtrKR4niiaagsGTDIHj3fsOMFETpa064vzovI+4YV4QnMbcg==", - "requires": { - "cross-fetch": "2.2.2" - } - }, - "graphql-tag": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", - "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==" - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true - }, - "handlebars": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.2.0.tgz", - "integrity": "sha512-Kb4xn5Qh1cxAKvQnzNWZ512DhABzyFNmsaJf3OAkWNa4NkaqWcNI8Tao8Tasi0/F4JD9oyG0YxuFyvyR57d+Gw==", - "dev": true, - "requires": { - "neo-async": "^2.6.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" - }, - "hosted-git-info": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", - "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, - "http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", - "requires": { - "agent-base": "4", - "debug": "3.1.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-proxy-agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", - "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "dev": true, - "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", - "dev": true, - "requires": { - "handlebars": "^4.1.2" - } - }, - "iterall": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", - "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" - }, - "jest": { - "version": "24.8.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-24.8.0.tgz", - "integrity": "sha512-o0HM90RKFRNWmAWvlyV8i5jGZ97pFwkeVoGvPW1EtLTgJc2+jcuqcbbqcSZLE/3f2S5pt0y2ZBETuhpWNl1Reg==", - "dev": true, - "requires": { - "import-local": "^2.0.0", - "jest-cli": "^24.8.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 - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "jest-cli": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", - "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", - "dev": true, - "requires": { - "@jest/core": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "import-local": "^2.0.0", - "is-ci": "^2.0.0", - "jest-config": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "prompts": "^2.0.1", - "realpath-native": "^1.1.0", - "yargs": "^13.3.0" - } - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "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" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, - "jest-changed-files": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", - "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", - "dev": true, + "graphql": { + "version": "14.5.4", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.5.4.tgz", + "integrity": "sha512-dPLvHoxy5m9FrkqWczPPRnH0X80CyvRE6e7Fa5AWEqEAzg9LpxHvKh24po/482E6VWHigOkAmb4xCp6P9yT9gw==", "requires": { - "@jest/types": "^24.9.0", - "execa": "^1.0.0", - "throat": "^4.0.0" + "iterall": "^1.2.2" } }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", - "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", - "dev": true, + "graphql-request": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-1.8.2.tgz", + "integrity": "sha512-dDX2M+VMsxXFCmUX0Vo0TopIZIX4ggzOtiCsThgtrKR4niiaagsGTDIHj3fsOMFETpa064vzovI+4YV4QnMbcg==", "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^24.9.0", - "@jest/types": "^24.9.0", - "babel-jest": "^24.9.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^24.9.0", - "jest-environment-node": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "micromatch": "^3.1.10", - "pretty-format": "^24.9.0", - "realpath-native": "^1.1.0" + "cross-fetch": "2.2.2" } }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } + "graphql-tag": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", + "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==" }, - "jest-docblock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", - "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", - "dev": true, - "requires": { - "detect-newline": "^2.1.0" - } + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" }, - "jest-each": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", - "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0" - } + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, - "jest-environment-jsdom": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", - "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", - "dev": true, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0", - "jsdom": "^11.5.1" + "ajv": "^6.5.5", + "har-schema": "^2.0.0" } }, - "jest-environment-node": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", - "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0" + "function-bind": "^1.1.1" } }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" - } + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true }, - "jest-jasmine2": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", - "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "co": "^4.6.0", - "expect": "^24.9.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0", - "throat": "^4.0.0" - } + "hosted-git-info": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", + "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", + "dev": true }, - "jest-leak-detector": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", - "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", - "dev": true, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", "requires": { - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + "agent-base": "4", + "debug": "3.1.0" } }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", - "dev": true, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "dev": true, + "https-proxy-agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", + "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" + "agent-base": "^4.3.0", + "debug": "^3.1.0" } }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "dev": true, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "@jest/types": "^24.9.0" + "once": "^1.3.0", + "wrappy": "1" } }, - "jest-pnp-resolver": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", - "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", "dev": true }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" - } + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true }, - "jest-resolve-dependencies": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", - "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-snapshot": "^24.9.0" - } + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true }, - "jest-runner": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", - "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.4.2", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-docblock": "^24.3.0", - "jest-haste-map": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-leak-detector": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "source-map-support": "^0.5.6", - "throat": "^4.0.0" - } + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true }, - "jest-runtime": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", - "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/source-map": "^24.3.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "strip-bom": "^3.0.0", - "yargs": "^13.3.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 - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "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" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } + "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 }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", + "is-generator-function": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", + "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==", "dev": true }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", + "is-nan": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.2.1.tgz", + "integrity": "sha1-n69ltvttskt/XAYoR16nH5iEAeI=", "dev": true, "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "define-properties": "^1.1.1" } }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" + "has": "^1.0.1" } }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" - } + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true }, - "jest-watcher": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", - "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", "dev": true, "requires": { - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "jest-util": "^24.9.0", - "string-length": "^2.0.0" + "has-symbols": "^1.0.0" } }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "dev": true, - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "iterall": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", + "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" }, "js-tokens": { "version": "4.0.0", @@ -3484,46 +846,6 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, - "jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.1", - "escodegen": "^1.9.1", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", - "xml-name-validator": "^3.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -3545,23 +867,6 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, - "json5": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", - "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -3573,18 +878,6 @@ "verror": "1.10.0" } }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, "lcid": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", @@ -3594,40 +887,6 @@ "invert-kv": "^2.0.0" } }, - "left-pad": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -3644,52 +903,13 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", - "dev": true - }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "dev": true, "requires": { - "tmpl": "1.0.x" + "chalk": "^2.0.1" } }, "map-age-cleaner": { @@ -3701,21 +921,6 @@ "p-defer": "^1.0.0" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, "mem": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", @@ -3727,33 +932,6 @@ "p-is-promise": "^2.0.0" } }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, "mime-db": { "version": "1.40.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", @@ -3786,27 +964,6 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -3816,27 +973,62 @@ } }, "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz", + "integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==", + "dev": true, "requires": { + "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", + "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", - "glob": "7.1.2", + "find-up": "3.0.0", + "glob": "7.1.3", "growl": "1.10.5", - "he": "1.1.1", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", - "supports-color": "5.4.0" + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.2.2", + "yargs-parser": "13.0.0", + "yargs-unparser": "1.5.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 + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3845,6 +1037,76 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "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" + } + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", + "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.0.0" + } + }, + "yargs-parser": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", + "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } }, @@ -3853,80 +1115,27 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true - }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-environment-flags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", + "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, "node-fetch": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-notifier": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", - "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", - "dev": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" - } - }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -3939,15 +1148,6 @@ "validate-npm-package-license": "^3.0.1" } }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -3963,67 +1163,51 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, - "nwsapi": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", - "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==", - "dev": true - }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "object-inspect": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", "dev": true }, + "object-is": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", + "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", + "dev": true + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", "dev": true, "requires": { - "isobject": "^3.0.0" + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" } }, "object.getownpropertydescriptors": { @@ -4036,53 +1220,12 @@ "es-abstract": "^1.5.1" } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - }, - "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } + "wrappy": "1" } }, "os-locale": { @@ -4102,15 +1245,6 @@ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, - "p-each-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", - "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", - "dev": true, - "requires": { - "p-reduce": "^1.0.0" - } - }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -4141,12 +1275,6 @@ "p-limit": "^2.0.0" } }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", - "dev": true - }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -4163,18 +1291,6 @@ "json-parse-better-errors": "^1.0.1" } }, - "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -4198,15 +1314,6 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -4218,78 +1325,12 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, "prettier": { "version": "1.18.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", "dev": true }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - }, - "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 - } - } - }, - "prompts": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", - "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.3" - } - }, "psl": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.3.0.tgz", @@ -4320,12 +1361,6 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" }, - "react-is": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz", - "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", - "dev": true - }, "read-pkg": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", @@ -4337,66 +1372,6 @@ "pify": "^3.0.0" } }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - }, - "dependencies": { - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - } - } - }, - "realpath-native": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", - "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", - "dev": true, - "requires": { - "util.promisify": "^1.0.0" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -4424,26 +1399,6 @@ "uuid": "^3.3.2" } }, - "request-promise-core": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", - "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", - "dev": true, - "requires": { - "lodash": "^4.17.11" - } - }, - "request-promise-native": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", - "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", - "dev": true, - "requires": { - "request-promise-core": "1.1.2", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -4470,33 +1425,6 @@ "path-parse": "^1.0.6" } }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -4506,284 +1434,62 @@ "glob": "^7.1.3" } }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, - "rxjs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", - "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "sisteransi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", - "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "rxjs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", "dev": true, "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "tslib": "^1.9.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "shebang-regex": "^1.0.0" } }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, "source-map-support": { "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", @@ -4793,12 +1499,6 @@ "source-map": "^0.6.0" } }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, "spawn-command": { "version": "0.0.2-1", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", @@ -4837,15 +1537,6 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -4868,49 +1559,6 @@ "tweetnacl": "~0.14.0" } }, - "stack-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, - "string-length": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", - "dev": true, - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" - } - }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -4950,18 +1598,18 @@ "ansi-regex": "^3.0.0" } }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", @@ -4970,92 +1618,6 @@ "has-flag": "^3.0.0" } }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "dev": true, - "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - }, - "dependencies": { - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - } - } - }, - "throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", - "dev": true - }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -5072,61 +1634,12 @@ } } }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, "tree-kill": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", "dev": true }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, - "ts-jest": { - "version": "24.0.2", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-24.0.2.tgz", - "integrity": "sha512-h6ZCZiA1EQgjczxq+uGLXQlNgeg02WWJBbeT8j6nyIBRQdglqbvzDoHahTEIiS6Eor6x8mK6PfZ7brQ9Q6tzHw==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "buffer-from": "1.x", - "fast-json-stable-stringify": "2.x", - "json5": "2.x", - "make-error": "1.x", - "mkdirp": "0.x", - "resolve": "1.x", - "semver": "^5.5", - "yargs-parser": "10.x" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - } - } - }, "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", @@ -5182,93 +1695,12 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, "typescript": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz", "integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==", "dev": true }, - "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", - "dev": true, - "optional": true, - "requires": { - "commander": "~2.20.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true, - "optional": true - } - } - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -5277,12 +1709,6 @@ "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, "url-parse": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", @@ -5292,20 +1718,17 @@ "requires-port": "^1.0.0" } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "util": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.1.tgz", + "integrity": "sha512-MREAtYOp+GTt9/+kwf00IYoHZyjM8VU4aVrkzUlejyqaIjd2GztVl5V9hGXKlvBKE3gENn/FMfHE5v6hElXGcQ==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "object.entries": "^1.1.0", + "safe-buffer": "^5.1.2" } }, "uuid": { @@ -5347,6 +1770,44 @@ "vscode-test": "^0.4.1" }, "dependencies": { + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "vscode-test": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-0.4.3.tgz", @@ -5369,61 +1830,11 @@ "rimraf": "^2.6.3" } }, - "w3c-hr-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", - "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", - "dev": true, - "requires": { - "browser-process-hrtime": "^0.1.2" - } - }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "requires": { - "makeerror": "1.0.x" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, "whatwg-fetch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -5439,11 +1850,14 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } }, "wrap-ansi": { "version": "2.1.0", @@ -5497,32 +1911,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, "xstate": { "version": "4.6.7", "resolved": "https://registry.npmjs.org/xstate/-/xstate-4.6.7.tgz", @@ -5563,6 +1951,17 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "yargs-unparser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", + "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.11", + "yargs": "^12.0.5" + } } } } diff --git a/package.json b/package.json index ac57a8da..c6836e03 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "watch": "tsc -watch -p ./" }, "dependencies": { + "@types/mocha": "^5.2.7", "dotenv": "^8.1.0", "graphql": "^14.5.4", "graphql-request": "^1.8.2", @@ -38,16 +39,16 @@ "xstate": "^4.6.7" }, "devDependencies": { + "@types/assert": "^1.4.3", "@types/dotenv": "^6.1.1", "@types/glob": "^7.1.1", "@types/graphql": "^14.5.0", - "@types/jest": "^24.0.18", "@types/node": "^12.7.4", + "assert": "^2.0.0", "concurrently": "^4.1.2", "glob": "^7.1.4", - "jest": "^24.8.0", + "mocha": "^6.2.0", "prettier": "^1.18.2", - "ts-jest": "^24.0.2", "tslint": "^5.19.0", "tslint-config-prettier": "^1.18.0", "typescript": "^3.6.2", diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 1f0f84d2..f40bee78 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -1,11 +1,25 @@ // You can import and use all API from the 'vscode' module // as well as import your extension to test it -// import * as vscode from 'vscode' +import * as vscode from 'vscode' +import {before, after} from 'mocha' +import * as assert from 'assert' // import * as myExtension from '../../extension' -describe('Extension tests', () => { - test('Some test', () => { - expect(2).toBe(2) +suite('Extension tests', () => { + before(() => { + vscode.window.showInformationMessage('Start all tests.') + }) + + test('Loads App', async () => { + await vscode.commands.executeCommand('coderoad.start') + await setTimeout(() => Promise.resolve(), 5000) + // const webview = vscode.window.activeTextEditor + // console.log(webview) + assert.equal(2, 2) + }) + + after(() => { + console.log('done') }) }) \ No newline at end of file diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index bfc6ebf3..35a9b96e 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -1,31 +1,37 @@ import * as path from 'path' -// import * as glob from 'glob' -import * as jest from 'jest' +import * as Mocha from 'mocha' +import * as glob from 'glob' -export async function run(): Promise { +export function run(): Promise { + // Create the mocha test + const mocha = new Mocha({ + ui: 'tdd', + }) + mocha.useColors(true) - const testDir = __dirname + const testsRoot = path.resolve(__dirname, '..') - const config = { - bail: false, - rootDir: testDir, - browser: false, - json: false, - useStderr: true, - } - // @ts-ignore - const {results} = await jest.runCLI(config, [testDir]) - .catch((failure: any) => { - console.error(failure) - }) - - if (results.numFailedTests > 0) { - const failedTests = results.testResults.filter((t: any) => t.numFailingTests || t.numPendingTests) + return new Promise((c, e) => { + glob('**/**.test.js', {cwd: testsRoot}, (err, files) => { + if (err) { + return e(err) + } - failedTests.forEach(console.log) - throw new Error(' Test(s) failed') - } + // Add files to the test suite + files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))) - console.log('--- JEST OUTPUT ---\n\n', JSON.stringify(results, null, 2)) - console.log(`${results.numPassedTests} test(s) passed!`) + try { + // Run the mocha test + mocha.run(failures => { + if (failures > 0) { + e(new Error(`${failures} tests failed.`)) + } else { + c() + } + }) + } catch (err) { + e(err) + } + }) + }) } \ No newline at end of file From 4e94b71090da8283a992469eb601947dc1642558 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 7 Sep 2019 20:06:16 -0700 Subject: [PATCH 104/117] resolve failing webview issue --- src/editor/ReactWebView.ts | 19 +++---------------- src/editor/commands/index.ts | 23 ++++++++++------------- web-app/src/index.tsx | 2 +- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index e08fc181..62ddf21e 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -78,7 +78,7 @@ class ReactWebView { // TODO: prevent window from moving to the left when no windows remain on rights } - public createOrShow(column: number, callback?: () => void): void { + public createOrShow(column: number): void { // If we already have a panel, show it. // Otherwise, create a new panel. if (this.panel && this.panel.webview) { @@ -86,17 +86,6 @@ class ReactWebView { } else { this.panel = this.createWebviewPanel(column) } - if (callback) { - // listen for when webview is loaded - // unfortunately there is no easy way of doing this - const webPanelListener = setInterval(() => { - if (this.loaded) { - // callback tells editor the webview has loaded - setTimeout(callback) - clearInterval(webPanelListener) - } - }, 200) - } } public async postMessage(action: CR.Action): Promise { @@ -143,7 +132,7 @@ class ReactWebView { const styles = [ 'main.css', // get style chunk - // Object.keys(manifest.files).find(f => f.match(/^static\/css\/.+\.css$/)) || '' + Object.keys(manifest.files).find(f => f.match(/^static\/css\/.+\.css$/)) || '' ].map(style => getSrc(style)) // map over scripts @@ -161,7 +150,6 @@ class ReactWebView { src: script.manifest ? getSrc(script.manifest) : script.file })) - const indexHtml = ` @@ -173,14 +161,13 @@ class ReactWebView { ${styles.map(styleUri => ``).join('\n')} - -
Loading...
+
Loading...
${scripts.map(s => ``).join('\n')} ` diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index 1000423e..6bb083d7 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -37,6 +37,7 @@ export const createCommands = ({vscodeExt}: CreateCommandProps) => { return { // initialize [COMMANDS.START]: async () => { + console.log('start') await isEmptyWorkspace() @@ -53,24 +54,13 @@ export const createCommands = ({vscodeExt}: CreateCommandProps) => { // activate machine webview = new ReactWebView(vscodeExt.extensionPath) - if (webviewState === 'INITIALIZING') { - // machine.activate() - } else if (webviewState === 'RESTARTING') { - setTimeout(() => { - // timeout hack to make data update on new windows - // @ts-ignore - machine.refresh() - }, 1000) - } }, // open React webview [COMMANDS.OPEN_WEBVIEW]: (column: number = vscode.ViewColumn.Two) => { + console.log('open webview') // setup 1x1 horizontal layout resetLayout() - const callback = () => { - // machine.send('WEBVIEW_INITIALIZED') - } - webview.createOrShow(column, callback) + webview.createOrShow(column) }, [COMMANDS.TEST_RUNNER_SETUP]: async (codingLanguage: G.EnumCodingLanguage) => { @@ -90,6 +80,13 @@ export const createCommands = ({vscodeExt}: CreateCommandProps) => { [COMMANDS.OPEN_FILE]: async (relativeFilePath: string) => { console.log(`OPEN_FILE ${JSON.stringify(relativeFilePath)}`) try { + // TODO: reenable after testing + // const workspaceRoots: vscode.WorkspaceFolder[] | undefined = vscode.workspace.workspaceFolders + // if (!workspaceRoots || !workspaceRoots.length) { + // throw new Error('No workspace root path') + // } + // const rootWorkspace: vscode.WorkspaceFolder = workspaceRoots[0] + // const absoluteFilePath = join(rootWorkspace.uri.path, relativeFilePath) const workspaceRoot = vscode.workspace.rootPath if (!workspaceRoot) { throw new Error('No workspace root path') diff --git a/web-app/src/index.tsx b/web-app/src/index.tsx index 6a448537..c2315d7f 100644 --- a/web-app/src/index.tsx +++ b/web-app/src/index.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import * as React from 'react' import ReactDOM from 'react-dom' import App from './App' From 0bfc65a7ee13083797f217a49d765a7db0a3d616 Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 7 Sep 2019 20:21:28 -0700 Subject: [PATCH 105/117] temp fix issue with local storage not working in vscode --- src/editor/ReactWebView.ts | 5 +++-- web-app/src/services/state/storage.ts | 11 ++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index 62ddf21e..1b340c4e 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -156,12 +156,13 @@ class ReactWebView { + React App - + ${styles.map(styleUri => ``).join('\n')} - + diff --git a/web-app/src/services/state/storage.ts b/web-app/src/services/state/storage.ts index 2a4be716..18fdb438 100644 --- a/web-app/src/services/state/storage.ts +++ b/web-app/src/services/state/storage.ts @@ -5,7 +5,16 @@ import * as G from 'typings/graphql' class Storage { private key: string - private storage = localStorage + // TODO: replace somehow with localStorage + // window.localStorage not working inside of vscode + private storage = { + getItem(key: string) { + return null + }, + setItem(key: string, value: string) { + return + } + } constructor(key: string) { this.key = key } From f971eb0a5b5fb708272d7887a26dce964ad8a68b Mon Sep 17 00:00:00 2001 From: shmck Date: Sat, 7 Sep 2019 21:57:38 -0700 Subject: [PATCH 106/117] simplify selectTutorial routes --- typings/index.d.ts | 7 +------ web-app/src/Routes.tsx | 5 +---- web-app/src/services/state/machine.ts | 24 +++++++----------------- 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index a133cf4e..204a4f5d 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -132,12 +132,7 @@ export interface MachineStateSchema { Start: { states: { Startup: {} - NewTutorial: { - states: { - SelectTutorial: {} - InitializeTutorial: {} - } - } + SelectTutorial: {} ContinueTutorial: {} } } diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 3944adcc..11e765da 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -47,12 +47,9 @@ const Routes = () => { - + - - - diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 2177bfa4..49c3dc36 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -34,31 +34,21 @@ export const machine = Machine Date: Sun, 8 Sep 2019 11:17:51 -0700 Subject: [PATCH 107/117] add level/stage/step selectors --- web-app/package-lock.json | 5 +++ web-app/package.json | 1 + web-app/src/services/selectors/index.ts | 44 +++++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 web-app/src/services/selectors/index.ts diff --git a/web-app/package-lock.json b/web-app/package-lock.json index 52c54b94..661381c4 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -15764,6 +15764,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "reselect": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", + "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" + }, "resize-observer-polyfill": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", diff --git a/web-app/package.json b/web-app/package.json index ddb51c46..9f38977d 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -38,6 +38,7 @@ "react": "^16.9.0", "react-dom": "^16.9.0", "react-scripts": "^3.1.1", + "reselect": "^4.0.0", "typescript": "^3.6.2", "xstate": "^4.6.7" }, diff --git a/web-app/src/services/selectors/index.ts b/web-app/src/services/selectors/index.ts new file mode 100644 index 00000000..ed30eb0d --- /dev/null +++ b/web-app/src/services/selectors/index.ts @@ -0,0 +1,44 @@ +import {MachineContext} from 'typings' +import * as G from 'typings/graphql' +import {createSelector} from 'reselect' + +export const currentLevel = ({tutorial, position}: MachineContext): G.Level => { + if (!tutorial) { + throw new Error('Tutorial not found when selecting level') + } + // merge in the updated position + // sent with the test to ensure consistency + const levels: G.Level[] = tutorial.version.levels + + const level: G.Level | undefined = levels.find((l: G.Level) => l.id === position.levelId) + + if (!level) { + throw new Error('Level not found when selecting level') + } + return level +} + +export const currentStage = (context: MachineContext): G.Stage => createSelector( + currentLevel, + (level: G.Level): G.Stage => { + const stages: G.Stage[] = level.stages + const stage: G.Stage | undefined = stages.find((s: G.Stage) => s.id === context.position.stageId) + if (!stage) { + throw new Error('No Stage found') + } + return stage + } +)(context) + +export const currentStep = (context: MachineContext): G.Step => createSelector( + currentStage, + (stage: G.Stage): G.Step => { + const steps: G.Step[] = stage.steps + const step: G.Step | undefined = steps.find((s: G.Step) => s.id === context.position.stepId) + if (!step) { + throw new Error('No Step found') + } + return step + } +)(context) + From 87d8246f1aedf639e628a572072536034e789a39 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 8 Sep 2019 11:18:09 -0700 Subject: [PATCH 108/117] leverage selectors for stepActions --- web-app/src/services/state/actions/editor.ts | 36 ++++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index f91cb10e..79cf3d3e 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -1,8 +1,9 @@ import * as CR from 'typings' +import * as selectors from '../../selectors' import channel from '../../channel' export default { - tutorialConfig(context: CR.MachineContext) { + initializeTutorial(context: CR.MachineContext) { // setup test runner and git const {tutorial} = context if (!tutorial) { @@ -29,13 +30,34 @@ export default { } }) }, - loadLevel(): void { - // load step actions + loadLevel(context: CR.MachineContext): void { + const level = selectors.currentLevel(context) + if (level.setup) { + // load step actions + channel.editorSend({ + type: 'STEP_ACTIONS', + payload: level.setup, + }) + } }, - loadStage(): void { - // load step actions + loadStage(context: CR.MachineContext): void { + const stage = selectors.currentStage(context) + if (stage.setup) { + // load step actions + channel.editorSend({ + type: 'STEP_ACTIONS', + payload: stage.setup, + }) + } }, - loadStep(): void { - // load step actions + loadStep(context: CR.MachineContext): void { + const step = selectors.currentStep(context) + if (step.setup) { + // load step actions + channel.editorSend({ + type: 'STEP_ACTIONS', + payload: step.setup, + }) + } }, } \ No newline at end of file From aa1a2a5fa023982dec52578ef3d536c118298604 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 8 Sep 2019 11:18:17 -0700 Subject: [PATCH 109/117] cleanup react webview channel --- src/editor/Channel.ts | 42 +++++++++++++++++++++++++++ src/editor/ReactWebView.ts | 37 ++++++----------------- src/editor/commands/index.ts | 15 ---------- web-app/src/services/state/machine.ts | 6 ++-- 4 files changed, 53 insertions(+), 47 deletions(-) create mode 100644 src/editor/Channel.ts diff --git a/src/editor/Channel.ts b/src/editor/Channel.ts new file mode 100644 index 00000000..c3e0898d --- /dev/null +++ b/src/editor/Channel.ts @@ -0,0 +1,42 @@ +import * as CR from 'typings' +import * as vscode from 'vscode' + +interface Channel { + receive(action: CR.Action): void + send(action: CR.Action): void +} + +class Channel implements Channel { + private postMessage: (action: CR.Action) => Thenable + constructor(webview: vscode.Webview) { + this.postMessage = webview.postMessage + } + + // receive from webview + public receive(action: CR.Action) { + const actionType: string = typeof action === 'string' ? action : action.type + console.log('RECEIVED', actionType) + switch (actionType) { + case 'TEST_RUN': + return + case 'TUTORIAL_CONFIG': + return + case 'STEP_ACTIONS': + return + // add other cases + default: + return + } + } + // send to webview + public async send(action: CR.Action) { + const success = await this.postMessage(action) + if (!success) { + throw new Error(`Message post failure: ${JSON.stringify(action)}`) + } + } + +} + +export default Channel + diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index 1b340c4e..3733418e 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -1,7 +1,6 @@ import * as path from 'path' -import * as CR from 'typings' import * as vscode from 'vscode' -import {tutorialModel} from '../extension' +import Channel, * as channel from './channel' const getNonce = (): string => { let text = '' @@ -17,9 +16,12 @@ const getNonce = (): string => { class ReactWebView { // @ts-ignore public loaded: boolean + + public send: Channel['send'] private panel: vscode.WebviewPanel private extensionPath: string private disposables: vscode.Disposable[] = [] + private channel: Channel public constructor(extensionPath: string) { this.extensionPath = extensionPath @@ -34,24 +36,12 @@ class ReactWebView { // This happens when the user closes the panel or when the panel is closed programatically this.panel.onDidDispose(this.dispose, this, this.disposables) + this.channel = new Channel(this.panel.webview) // Handle messages from the webview - const onReceive = (action: string | CR.Action) => { - const actionType: string = typeof action === 'string' ? action : action.type - switch (actionType) { - case 'TUTORIAL_START': - if (typeof action === 'string' || !action.payload || !action.payload.id) { - throw new Error('No tutorial id on tutorial start action') - } - tutorialModel.launch(action.payload.id) - break - // add other cases - default: - // send to state machine - console.log('onReceive', action) - vscode.commands.executeCommand('coderoad.receive_machine_action', action) - } - } - this.panel.webview.onDidReceiveMessage(onReceive, null, this.disposables) + const receive = this.channel.receive + this.panel.webview.onDidReceiveMessage(receive, null, this.disposables) + this.send = this.channel.send + // update panel on changes const updateWindows = () => { @@ -88,15 +78,6 @@ class ReactWebView { } } - public async postMessage(action: CR.Action): Promise { - // Send a message to the webview webview. - // You can send any JSON serializable data. - const success = await this.panel.webview.postMessage(action) - if (!success) { - throw new Error(`Message post failure: ${JSON.stringify(action)}`) - } - } - private async dispose(): Promise { // Clean up our resources this.loaded = false diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts index 6bb083d7..04b1719f 100644 --- a/src/editor/commands/index.ts +++ b/src/editor/commands/index.ts @@ -10,9 +10,6 @@ const COMMANDS = { START: 'coderoad.start', TEST_RUNNER_SETUP: 'coderoad.test_runner_setup', OPEN_WEBVIEW: 'coderoad.open_webview', - SEND_STATE: 'coderoad.send_state', - SEND_DATA: 'coderoad.send_data', - RECEIVE_MACHINE_ACTION: 'coderoad.receive_machine_action', OPEN_FILE: 'coderoad.open_file', RUN_TEST: 'coderoad.run_test', TEST_PASS: 'coderoad.test_pass', @@ -101,18 +98,6 @@ export const createCommands = ({vscodeExt}: CreateCommandProps) => { console.log(`Failed to open file ${relativeFilePath}`, error) } }, - // send messages to webview - [COMMANDS.SEND_STATE]: (payload: {data: any; state: any}) => { - webview.postMessage({type: 'SET_STATE', payload}) - }, - [COMMANDS.SEND_DATA]: (payload: {data: any}) => { - webview.postMessage({type: 'SET_DATA', payload}) - }, - [COMMANDS.RECEIVE_MACHINE_ACTION]: (action: string | CR.Action) => { - // send received actions from web-app into state machine - console.log('receive action', action) - // machine.send(action) - }, [COMMANDS.RUN_TEST]: () => { runTest({ onSuccess: () => { diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 49c3dc36..580ae4af 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -58,6 +58,7 @@ export const machine = Machine Date: Sun, 8 Sep 2019 11:39:09 -0700 Subject: [PATCH 110/117] refactor tutorial selectors --- web-app/src/services/selectors/index.ts | 38 +++++++--- web-app/src/services/state/actions/context.ts | 76 +++++-------------- 2 files changed, 47 insertions(+), 67 deletions(-) diff --git a/web-app/src/services/selectors/index.ts b/web-app/src/services/selectors/index.ts index ed30eb0d..e653d7c6 100644 --- a/web-app/src/services/selectors/index.ts +++ b/web-app/src/services/selectors/index.ts @@ -2,21 +2,36 @@ import {MachineContext} from 'typings' import * as G from 'typings/graphql' import {createSelector} from 'reselect' -export const currentLevel = ({tutorial, position}: MachineContext): G.Level => { +export const currentTutorial = ({tutorial}: MachineContext): G.Tutorial => { if (!tutorial) { - throw new Error('Tutorial not found when selecting level') + throw new Error('Tutorial not found') } - // merge in the updated position - // sent with the test to ensure consistency - const levels: G.Level[] = tutorial.version.levels + return tutorial +} - const level: G.Level | undefined = levels.find((l: G.Level) => l.id === position.levelId) +export const currentVersion = createSelector( + currentTutorial, + (tutorial: G.Tutorial) => { + if (!tutorial.version) { + throw new Error('Tutorial version not found') + } + return tutorial.version + }) - if (!level) { - throw new Error('Level not found when selecting level') - } - return level -} +export const currentLevel = (context: MachineContext): G.Level => createSelector( + currentVersion, + (version: G.TutorialVersion): G.Level => { + // merge in the updated position + // sent with the test to ensure consistency + const levels: G.Level[] = version.levels + + const level: G.Level | undefined = levels.find((l: G.Level) => l.id === context.position.levelId) + + if (!level) { + throw new Error('Level not found when selecting level') + } + return level + })(context) export const currentStage = (context: MachineContext): G.Stage => createSelector( currentLevel, @@ -41,4 +56,3 @@ export const currentStep = (context: MachineContext): G.Step => createSelector( return step } )(context) - diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 019cebd5..c9fc93e4 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -2,6 +2,7 @@ import {assign, send} from 'xstate' import * as G from 'typings/graphql' import * as CR from 'typings' import * as storage from '../storage' +import * as selectors from '../../selectors' export default { setTutorial: assign({ @@ -39,19 +40,11 @@ export default { // @ts-ignore updateStepPosition: assign({ position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { - const {tutorial, position} = context - - if (!tutorial) { - throw new Error('Tutorial not found when updating step position') - } + const {position} = context // merge in the updated position // sent with the test to ensure consistency - // @ts-ignore - const steps: G.Step[] = context.tutorial.version - .levels.find((l: G.Level) => l.id === position.levelId) - .stages.find((s: G.Stage) => s.id === position.stageId) - .steps - + const stage: G.Stage = selectors.currentStage(context) + const steps: G.Step[] = stage.steps // final step but not completed if (steps[steps.length - 1].id === position.stepId) { @@ -74,18 +67,11 @@ export default { }), // @ts-ignore updateStagePosition: assign({ - position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { - const {tutorial, position} = context + position: (context: CR.MachineContext): CR.Position => { + const {position} = context - if (!tutorial) { - throw new Error('Tutorial not found when updating stage position') - } - // merge in the updated position - // sent with the test to ensure consistency - // @ts-ignore - const stages: G.Stage[] = tutorial.version - .levels.find((l: G.Level) => l.id === position.levelId) - .stages + const level: G.Level = selectors.currentLevel(context) + const stages: G.Stage[] = level.stages const stageIndex = stages.findIndex((s: G.Stage) => s.id === position.stageId) const stage: G.Stage = stages[stageIndex + 1] @@ -103,15 +89,12 @@ export default { }), // @ts-ignore updateLevelPosition: assign({ - position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { - const {tutorial, position} = context - - if (!tutorial) { - throw new Error('Tutorial not found when updating level position') - } + position: (context: CR.MachineContext): CR.Position => { + const {position} = context + const version = selectors.currentVersion(context) // merge in the updated position // sent with the test to ensure consistency - const levels: G.Level[] = tutorial.version.levels + const levels: G.Level[] = version.levels const levelIndex = levels.findIndex((l: G.Level) => l.id === position.levelId) const level: G.Level = levels[levelIndex + 1] @@ -164,23 +147,12 @@ export default { } }), loadNext: send((context: CR.MachineContext): CR.Action => { - const {tutorial, position, progress} = context + const {position, progress} = context - if (!tutorial) { - throw new Error('No tutorial found for loading next step') - } + const version = selectors.currentVersion(context) + const level = selectors.currentLevel(context) + const stage = selectors.currentStage(context) - // has next step? - const levels: G.Level[] = tutorial.version.levels - const level: G.Level | undefined = levels.find((l: G.Level) => l.id === position.levelId) - if (!level) { - throw new Error('No Level found') - } - const stages: G.Stage[] = level.stages - const stage: G.Stage | undefined = stages.find((s: G.Stage) => s.id === position.stageId) - if (!stage) { - throw new Error('No Stage found') - } const steps: G.Step[] = stage.steps const stepIndex = steps.findIndex((s: G.Step) => s.id === position.stepId) @@ -197,6 +169,7 @@ export default { // has next stage? + const {stages} = level const stageIndex = stages.findIndex((s: G.Stage) => s.id === position.stageId) const finalStage = (stageIndex > -1 && stageIndex === stages.length - 1) const hasNextStage = (!finalStage) @@ -214,6 +187,7 @@ export default { // has next level? + const {levels} = version const levelIndex = levels.findIndex((l: G.Level) => l.id === position.levelId) const finalLevel = (levelIndex > -1 && levelIndex === levels.length - 1) const hasNextLevel = (!finalLevel) @@ -234,19 +208,11 @@ export default { return {type: 'COMPLETED'} }), stepNext: send((context: CR.MachineContext): CR.Action => { - const {tutorial, position, progress} = context - - if (!tutorial || !tutorial.version) { - throw new Error('No tutorial found when loading next step') - } + const {position, progress} = context - // TODO: protect against errors - // @ts-ignore - const steps: G.Step[] = tutorial.version - .levels.find((l: G.Level) => l.id === position.levelId) - .stages.find((s: G.Stage) => s.id === position.stageId) - .steps + const stage: G.Stage = selectors.currentStage(context) + const {steps} = stage // TODO: verify not -1 const stepIndex = steps.findIndex((s: G.Step) => s.id === position.stepId) const finalStep = stepIndex === steps.length - 1 From a1f8922f70cb0145673e1e1ebc1e87fff5647fc9 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 8 Sep 2019 13:09:41 -0700 Subject: [PATCH 111/117] refactor selectors --- web-app/src/services/selectors/index.ts | 60 +------------------ web-app/src/services/selectors/position.ts | 16 +++++ web-app/src/services/selectors/tutorial.ts | 58 ++++++++++++++++++ web-app/src/services/state/actions/context.ts | 14 +---- 4 files changed, 77 insertions(+), 71 deletions(-) create mode 100644 web-app/src/services/selectors/position.ts create mode 100644 web-app/src/services/selectors/tutorial.ts diff --git a/web-app/src/services/selectors/index.ts b/web-app/src/services/selectors/index.ts index e653d7c6..1c74440d 100644 --- a/web-app/src/services/selectors/index.ts +++ b/web-app/src/services/selectors/index.ts @@ -1,58 +1,2 @@ -import {MachineContext} from 'typings' -import * as G from 'typings/graphql' -import {createSelector} from 'reselect' - -export const currentTutorial = ({tutorial}: MachineContext): G.Tutorial => { - if (!tutorial) { - throw new Error('Tutorial not found') - } - return tutorial -} - -export const currentVersion = createSelector( - currentTutorial, - (tutorial: G.Tutorial) => { - if (!tutorial.version) { - throw new Error('Tutorial version not found') - } - return tutorial.version - }) - -export const currentLevel = (context: MachineContext): G.Level => createSelector( - currentVersion, - (version: G.TutorialVersion): G.Level => { - // merge in the updated position - // sent with the test to ensure consistency - const levels: G.Level[] = version.levels - - const level: G.Level | undefined = levels.find((l: G.Level) => l.id === context.position.levelId) - - if (!level) { - throw new Error('Level not found when selecting level') - } - return level - })(context) - -export const currentStage = (context: MachineContext): G.Stage => createSelector( - currentLevel, - (level: G.Level): G.Stage => { - const stages: G.Stage[] = level.stages - const stage: G.Stage | undefined = stages.find((s: G.Stage) => s.id === context.position.stageId) - if (!stage) { - throw new Error('No Stage found') - } - return stage - } -)(context) - -export const currentStep = (context: MachineContext): G.Step => createSelector( - currentStage, - (stage: G.Stage): G.Step => { - const steps: G.Step[] = stage.steps - const step: G.Step | undefined = steps.find((s: G.Step) => s.id === context.position.stepId) - if (!step) { - throw new Error('No Step found') - } - return step - } -)(context) +export * from './tutorial' +export * from './position' \ No newline at end of file diff --git a/web-app/src/services/selectors/position.ts b/web-app/src/services/selectors/position.ts new file mode 100644 index 00000000..ee803743 --- /dev/null +++ b/web-app/src/services/selectors/position.ts @@ -0,0 +1,16 @@ +import {createSelector} from 'reselect' +import * as G from 'typings/graphql' +import * as CR from 'typings' +import * as tutorial from './tutorial' + +export const initialPosition = createSelector( + tutorial.currentVersion, + (version: G.TutorialVersion) => { + const position: CR.Position = { + levelId: version.levels[0].id, + stageId: version.levels[0].stages[0].id, + stepId: version.levels[0].stages[0].steps[0].id, + } + return position + } +) diff --git a/web-app/src/services/selectors/tutorial.ts b/web-app/src/services/selectors/tutorial.ts new file mode 100644 index 00000000..e653d7c6 --- /dev/null +++ b/web-app/src/services/selectors/tutorial.ts @@ -0,0 +1,58 @@ +import {MachineContext} from 'typings' +import * as G from 'typings/graphql' +import {createSelector} from 'reselect' + +export const currentTutorial = ({tutorial}: MachineContext): G.Tutorial => { + if (!tutorial) { + throw new Error('Tutorial not found') + } + return tutorial +} + +export const currentVersion = createSelector( + currentTutorial, + (tutorial: G.Tutorial) => { + if (!tutorial.version) { + throw new Error('Tutorial version not found') + } + return tutorial.version + }) + +export const currentLevel = (context: MachineContext): G.Level => createSelector( + currentVersion, + (version: G.TutorialVersion): G.Level => { + // merge in the updated position + // sent with the test to ensure consistency + const levels: G.Level[] = version.levels + + const level: G.Level | undefined = levels.find((l: G.Level) => l.id === context.position.levelId) + + if (!level) { + throw new Error('Level not found when selecting level') + } + return level + })(context) + +export const currentStage = (context: MachineContext): G.Stage => createSelector( + currentLevel, + (level: G.Level): G.Stage => { + const stages: G.Stage[] = level.stages + const stage: G.Stage | undefined = stages.find((s: G.Stage) => s.id === context.position.stageId) + if (!stage) { + throw new Error('No Stage found') + } + return stage + } +)(context) + +export const currentStep = (context: MachineContext): G.Step => createSelector( + currentStage, + (stage: G.Stage): G.Step => { + const steps: G.Step[] = stage.steps + const step: G.Step | undefined = steps.find((s: G.Step) => s.id === context.position.stepId) + if (!step) { + throw new Error('No Step found') + } + return step + } +)(context) diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index c9fc93e4..4eca2a24 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -20,20 +20,8 @@ export default { // @ts-ignore initPosition: assign({ position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { - if (!event.payload.tutorial) { - throw new Error('Invalid tutorial') - } - - const version: G.TutorialVersion = event.payload.tutorial.version - - const position: CR.Position = { - levelId: version.levels[0].id, - stageId: version.levels[0].stages[0].id, - stepId: version.levels[0].stages[0].steps[0].id, - } - + const position: CR.Position = selectors.initialPosition(event.payload) storage.position.set(position) - return position }, }), From 33eb7ff310056f8ecf635393622101eb266b89df Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 8 Sep 2019 13:12:47 -0700 Subject: [PATCH 112/117] setup default selectors --- web-app/src/services/selectors/index.ts | 3 ++- web-app/src/services/selectors/position.ts | 6 ++++++ web-app/src/services/selectors/progress.ts | 6 ++++++ web-app/src/services/state/actions/context.ts | 13 ++----------- 4 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 web-app/src/services/selectors/progress.ts diff --git a/web-app/src/services/selectors/index.ts b/web-app/src/services/selectors/index.ts index 1c74440d..315726a6 100644 --- a/web-app/src/services/selectors/index.ts +++ b/web-app/src/services/selectors/index.ts @@ -1,2 +1,3 @@ export * from './tutorial' -export * from './position' \ No newline at end of file +export * from './position' +export * from './progress' \ No newline at end of file diff --git a/web-app/src/services/selectors/position.ts b/web-app/src/services/selectors/position.ts index ee803743..ec7b0061 100644 --- a/web-app/src/services/selectors/position.ts +++ b/web-app/src/services/selectors/position.ts @@ -3,6 +3,12 @@ import * as G from 'typings/graphql' import * as CR from 'typings' import * as tutorial from './tutorial' +export const defaultPosition = () => ({ + levelId: '', + stageId: '', + stepId: '' +}) + export const initialPosition = createSelector( tutorial.currentVersion, (version: G.TutorialVersion) => { diff --git a/web-app/src/services/selectors/progress.ts b/web-app/src/services/selectors/progress.ts new file mode 100644 index 00000000..649272f5 --- /dev/null +++ b/web-app/src/services/selectors/progress.ts @@ -0,0 +1,6 @@ +export const defaultProgress = () => ({ + levels: {}, + stages: {}, + steps: {}, + complete: false +}) \ No newline at end of file diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 4eca2a24..1ebf8668 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -228,21 +228,12 @@ export default { return null }, progress(): CR.Progress { - const progress: CR.Progress = { - levels: {}, - stages: {}, - steps: {}, - complete: false - } + const progress: CR.Progress = selectors.defaultProgress() storage.progress.set(progress) return progress }, position(): CR.Position { - const position: CR.Position = { - levelId: '', - stageId: '', - stepId: '' - } + const position: CR.Position = selectors.defaultPosition() storage.position.set(position) return position } From cfbf955eefcca9cc02e69dd46b693787d219228d Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 8 Sep 2019 13:42:46 -0700 Subject: [PATCH 113/117] fix loading of tutorial config on client --- web-app/src/containers/New/index.tsx | 8 +++--- .../containers/Tutorial/SummaryPage/index.tsx | 2 +- .../apollo/queries/tutorial.ts} | 0 .../apollo/queries/tutorials.ts} | 0 web-app/src/services/state/actions/editor.ts | 4 +-- web-app/src/services/state/actions/invoke.ts | 28 +++++++++++++++++++ web-app/src/services/state/machine.ts | 13 ++++++--- 7 files changed, 44 insertions(+), 11 deletions(-) rename web-app/src/{containers/Tutorial/SummaryPage/queryTutorial.ts => services/apollo/queries/tutorial.ts} (100%) rename web-app/src/{containers/New/queryTutorials.ts => services/apollo/queries/tutorials.ts} (100%) diff --git a/web-app/src/containers/New/index.tsx b/web-app/src/containers/New/index.tsx index 4e373269..0086f950 100644 --- a/web-app/src/containers/New/index.tsx +++ b/web-app/src/containers/New/index.tsx @@ -3,7 +3,7 @@ import { useQuery } from '@apollo/react-hooks' import * as T from 'typings/graphql' import * as CR from 'typings' -import queryTutorials from './queryTutorials' +import queryTutorials from '../../services/apollo/queries/tutorials' import LoadingPage from '../LoadingPage' import ErrorView from '../../components/Error' import TutorialList from './TutorialList' @@ -22,7 +22,7 @@ export const NewPage = (props: Props) => ( const Loading = () => interface ContainerProps { - send(action: CR.Action): void + send(action: CR.Action): void } const NewPageContainer = (props: ContainerProps) => { @@ -33,11 +33,11 @@ const NewPageContainer = (props: ContainerProps) => { if (error) { return - } + } return ( - + ) } diff --git a/web-app/src/containers/Tutorial/SummaryPage/index.tsx b/web-app/src/containers/Tutorial/SummaryPage/index.tsx index 19eea612..95d17989 100644 --- a/web-app/src/containers/Tutorial/SummaryPage/index.tsx +++ b/web-app/src/containers/Tutorial/SummaryPage/index.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import * as CR from 'typings' import { useQuery } from '@apollo/react-hooks' -import queryTutorial from './queryTutorial' +import queryTutorial from '../../../services/apollo/queries/tutorial' import Summary from './Summary' import ErrorView from '../../../components/Error' diff --git a/web-app/src/containers/Tutorial/SummaryPage/queryTutorial.ts b/web-app/src/services/apollo/queries/tutorial.ts similarity index 100% rename from web-app/src/containers/Tutorial/SummaryPage/queryTutorial.ts rename to web-app/src/services/apollo/queries/tutorial.ts diff --git a/web-app/src/containers/New/queryTutorials.ts b/web-app/src/services/apollo/queries/tutorials.ts similarity index 100% rename from web-app/src/containers/New/queryTutorials.ts rename to web-app/src/services/apollo/queries/tutorials.ts diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index 79cf3d3e..324b4518 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -3,9 +3,9 @@ import * as selectors from '../../selectors' import channel from '../../channel' export default { - initializeTutorial(context: CR.MachineContext) { + initializeTutorial(context: CR.MachineContext, event: CR.MachineEvent) { // setup test runner and git - const {tutorial} = context + const {tutorial} = event.data.payload if (!tutorial) { throw new Error('Invalid tutorial for tutorial config') } diff --git a/web-app/src/services/state/actions/invoke.ts b/web-app/src/services/state/actions/invoke.ts index e04d53a7..9ffe965b 100644 --- a/web-app/src/services/state/actions/invoke.ts +++ b/web-app/src/services/state/actions/invoke.ts @@ -1,6 +1,8 @@ import * as storage from '../storage' import * as CR from 'typings' import * as G from 'typings/graphql' +import client from '../../apollo' +import tutorialQuery from '../../apollo/queries/tutorial' export const newOrContinue = async (context: CR.MachineContext) => { const [tutorial, progress] = await Promise.all([ @@ -50,4 +52,30 @@ export const newOrContinue = async (context: CR.MachineContext) => { progress } } +} + +export const loadTutorial = async (context: CR.MachineContext) => { + if (!context.tutorial) { + throw new Error('Tutorial not available to load') + } + + const result = await client.query({ + query: tutorialQuery, + variables: { + tutorialId: context.tutorial.id, + version: context.tutorial.version.version, + } + }) + .catch((error: Error) => { + return Promise.reject(`Failed to load tutorial config ${error.message}`) + }) + if (!result || !result.data) { + return Promise.reject('No tutorial returned from tutorial config query') + } + + const {data} = result + return { + type: 'TUTORIAL_LOADED', + payload: data + } } \ No newline at end of file diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 580ae4af..96a2f07e 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -58,9 +58,14 @@ export const machine = Machine Date: Sun, 8 Sep 2019 16:15:27 -0700 Subject: [PATCH 114/117] setup tutorialConfig --- src/{editor => }/Channel.ts | 22 +++- src/{editor/commands => actions}/runTest.ts | 2 +- src/actions/setupActions.ts | 69 +++++++++++ src/actions/solutionActions.ts | 17 +++ src/actions/tutorialConfig.ts | 24 ++++ src/editor/ReactWebView.ts | 4 +- src/editor/commands.ts | 69 +++++++++++ src/editor/commands/index.ts | 114 ------------------- src/editor/commands/loadSolution.ts | 15 --- src/editor/index.ts | 6 - src/extension.ts | 6 +- src/services/git/errorMessages.ts | 14 --- src/services/git/index.ts | 65 +++-------- src/services/tutorial/index.ts | 10 +- web-app/src/services/state/actions/editor.ts | 6 +- 15 files changed, 224 insertions(+), 219 deletions(-) rename src/{editor => }/Channel.ts (54%) rename src/{editor/commands => actions}/runTest.ts (98%) create mode 100644 src/actions/setupActions.ts create mode 100644 src/actions/solutionActions.ts create mode 100644 src/actions/tutorialConfig.ts create mode 100644 src/editor/commands.ts delete mode 100644 src/editor/commands/index.ts delete mode 100644 src/editor/commands/loadSolution.ts delete mode 100644 src/services/git/errorMessages.ts diff --git a/src/editor/Channel.ts b/src/Channel.ts similarity index 54% rename from src/editor/Channel.ts rename to src/Channel.ts index c3e0898d..39fa3299 100644 --- a/src/editor/Channel.ts +++ b/src/Channel.ts @@ -1,9 +1,13 @@ import * as CR from 'typings' import * as vscode from 'vscode' +import tutorialConfig from './actions/tutorialConfig' +import setupActions from './actions/setupActions' +import solutionActions from './actions/solutionActions' + interface Channel { receive(action: CR.Action): void - send(action: CR.Action): void + send(action: CR.Action): Promise } class Channel implements Channel { @@ -13,23 +17,29 @@ class Channel implements Channel { } // receive from webview - public receive(action: CR.Action) { + public receive = (action: CR.Action) => { const actionType: string = typeof action === 'string' ? action : action.type - console.log('RECEIVED', actionType) + console.log('RECEIVED:', actionType) switch (actionType) { case 'TEST_RUN': + vscode.commands.executeCommand('coderoad.run_test') return case 'TUTORIAL_CONFIG': + tutorialConfig(action.payload) + return + case 'SETUP_ACTIONS': + setupActions(action.payload) return - case 'STEP_ACTIONS': + case 'SOLUTION_ACTIONS': + solutionActions(action.payload) return - // add other cases default: + console.log(`No match for action type: ${actionType}`) return } } // send to webview - public async send(action: CR.Action) { + public send = async (action: CR.Action) => { const success = await this.postMessage(action) if (!success) { throw new Error(`Message post failure: ${JSON.stringify(action)}`) diff --git a/src/editor/commands/runTest.ts b/src/actions/runTest.ts similarity index 98% rename from src/editor/commands/runTest.ts rename to src/actions/runTest.ts index 4a468775..8948718a 100644 --- a/src/editor/commands/runTest.ts +++ b/src/actions/runTest.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode' -import {exec} from '../../services/node' +import {exec} from '../services/node' // ensure only latest run_test action is taken let currentId = 0 diff --git a/src/actions/setupActions.ts b/src/actions/setupActions.ts new file mode 100644 index 00000000..508c8f8b --- /dev/null +++ b/src/actions/setupActions.ts @@ -0,0 +1,69 @@ +import * as G from 'typings/graphql' +import {join} from 'path' +import * as vscode from 'vscode' +import * as git from '../services/git' +import {exec} from '../services/node' + +interface ErrorMessageFilter { + [lang: string]: { + [key: string]: string + } +} + +// TODO: should be loaded on startup based on language +const errorMessageFilter: ErrorMessageFilter = { + js: { + 'node-gyp': 'Error running npm setup command' + } +} + +const setupActions = async ({commands, commits, files}: G.StepActions): Promise => { + // run commits + for (const commit of commits) { + await git.loadCommit(commit) + } + + // run command + for (const command of commands) { + const {stdout, stderr} = await exec(command) + if (stderr) { + console.error(stderr) + // language specific error messages from running commands + for (const message of Object.keys(errorMessageFilter.js)) { + if (stderr.match(message)) { + // ignored error + throw new Error('Error running setup command') + } + } + } + console.log(`run command: ${command}`, stdout) + } + + // open files + for (const filePath of files) { + console.log(`OPEN_FILE ${filePath}`) + try { + // TODO: re-enable after testing + // const workspaceRoots: vscode.WorkspaceFolder[] | undefined = vscode.workspace.workspaceFolders + // if (!workspaceRoots || !workspaceRoots.length) { + // throw new Error('No workspace root path') + // } + // const rootWorkspace: vscode.WorkspaceFolder = workspaceRoots[0] + // const absoluteFilePath = join(rootWorkspace.uri.path, relativeFilePath) + const workspaceRoot = vscode.workspace.rootPath + if (!workspaceRoot) { + throw new Error('No workspace root path') + } + const absoluteFilePath = join(workspaceRoot, filePath) + const doc = await vscode.workspace.openTextDocument(absoluteFilePath) + await vscode.window.showTextDocument(doc, vscode.ViewColumn.One) + // there are times when initialization leave the panel behind any files opened + // ensure the panel is redrawn on the right side first + // webview.createOrShow(vscode.ViewColumn.Two) + } catch (error) { + console.log(`Failed to open file ${filePath}`, error) + } + } +} + +export default setupActions \ No newline at end of file diff --git a/src/actions/solutionActions.ts b/src/actions/solutionActions.ts new file mode 100644 index 00000000..43393eb0 --- /dev/null +++ b/src/actions/solutionActions.ts @@ -0,0 +1,17 @@ +// import * as CR from 'typings' +import * as G from 'typings/graphql' +// import {TutorialModel} from '../services/tutorial' +// import {gitLoadCommits, gitClear} from '../services/git' + +const solutionActions = async (stepActions: G.StepActions): Promise => { + // TODO: should load same as commits + + // const step: G.Step = tutorialModel.step() + // const solution = step.solution + + // await gitClear() + // await gitLoadCommits(solution, dispatch) + +} + +export default solutionActions diff --git a/src/actions/tutorialConfig.ts b/src/actions/tutorialConfig.ts new file mode 100644 index 00000000..bd0c0889 --- /dev/null +++ b/src/actions/tutorialConfig.ts @@ -0,0 +1,24 @@ +import * as G from 'typings/graphql' +import * as vscode from 'vscode' +import * as git from '../services/git' + +const tutorialConfig = async (tutorial: G.Tutorial) => { + + // setup git, add remote + await git.initIfNotExists() + await git.setupRemote(tutorial.repo.uri) + + // TODO: allow multiple coding languages in a tutorial + + // setup onSave hook + // console.log(`languageIds: ${languageIds.join(', ')}`) + vscode.workspace.onDidSaveTextDocument((document: vscode.TextDocument) => { + if (document.uri.scheme === 'file' && tutorial.codingLanguage === document.languageId) { + // do work + // TODO: resolve issue if client unaware or out of sync with running test + vscode.commands.executeCommand('coderoad.run_test') + } + }) +} + +export default tutorialConfig \ No newline at end of file diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index 3733418e..e7884567 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -1,6 +1,6 @@ import * as path from 'path' import * as vscode from 'vscode' -import Channel, * as channel from './channel' +import Channel from '../Channel' const getNonce = (): string => { let text = '' @@ -33,7 +33,7 @@ class ReactWebView { this.panel.webview.html = this.getHtmlForWebview() // Listen for when the panel is disposed - // This happens when the user closes the panel or when the panel is closed programatically + // This happens when the user closes the panel or when the panel is closed programmatically this.panel.onDidDispose(this.dispose, this, this.disposables) this.channel = new Channel(this.panel.webview) diff --git a/src/editor/commands.ts b/src/editor/commands.ts new file mode 100644 index 00000000..609b9565 --- /dev/null +++ b/src/editor/commands.ts @@ -0,0 +1,69 @@ +import * as vscode from 'vscode' +import ReactWebView from './ReactWebView' +import runTest from '../actions/runTest' +import {isEmptyWorkspace} from './workspace' + +const COMMANDS = { + START: 'coderoad.start', + OPEN_WEBVIEW: 'coderoad.open_webview', + RUN_TEST: 'coderoad.run_test', +} + +interface CreateCommandProps { + vscodeExt: vscode.ExtensionContext +} + +const resetLayout = () => { + vscode.commands.executeCommand('vscode.setEditorLayout', { + orientation: 0, + groups: [{groups: [{}], size: 0.6}, {groups: [{}], size: 0.4}], + }) +} + +export const createCommands = ({vscodeExt}: CreateCommandProps) => { + // React panel webview + let webview: any + + return { + // initialize + [COMMANDS.START]: async () => { + console.log('start') + + // TODO: replace with a prompt to open a workspace + await isEmptyWorkspace() + + let webviewState: 'INITIALIZING' | 'RESTARTING' + if (!webview) { + webviewState = 'INITIALIZING' + } else if (webview.loaded) { + // already loaded + vscode.window.showInformationMessage('CodeRoad already open') + return + } else { + webviewState = 'RESTARTING' + } + + // activate machine + webview = new ReactWebView(vscodeExt.extensionPath) + }, + // open React webview + [COMMANDS.OPEN_WEBVIEW]: (column: number = vscode.ViewColumn.Two) => { + console.log('open webview') + // setup 1x1 horizontal layout + resetLayout() + webview.createOrShow(column) + }, + [COMMANDS.RUN_TEST]: () => { + runTest({ + onSuccess: () => { + console.log('TEST_PASS') + vscode.window.showInformationMessage('PASS') + }, + onFail: () => { + console.log('TEST_FAIL') + vscode.window.showWarningMessage('FAIL') + } + }) + }, + } +} diff --git a/src/editor/commands/index.ts b/src/editor/commands/index.ts deleted file mode 100644 index 04b1719f..00000000 --- a/src/editor/commands/index.ts +++ /dev/null @@ -1,114 +0,0 @@ -import {join} from 'path' -import * as CR from 'typings' -import * as G from 'typings/graphql' -import * as vscode from 'vscode' -import ReactWebView from '../ReactWebView' -import runTest from './runTest' -import {isEmptyWorkspace} from '../workspace' - -const COMMANDS = { - START: 'coderoad.start', - TEST_RUNNER_SETUP: 'coderoad.test_runner_setup', - OPEN_WEBVIEW: 'coderoad.open_webview', - OPEN_FILE: 'coderoad.open_file', - RUN_TEST: 'coderoad.run_test', - TEST_PASS: 'coderoad.test_pass', - TEST_FAIL: 'coderoad.test_fail', -} - -interface CreateCommandProps { - vscodeExt: vscode.ExtensionContext -} - -const resetLayout = () => { - vscode.commands.executeCommand('vscode.setEditorLayout', { - orientation: 0, - groups: [{groups: [{}], size: 0.6}, {groups: [{}], size: 0.4}], - }) -} - -export const createCommands = ({vscodeExt}: CreateCommandProps) => { - // React panel webview - let webview: any - - return { - // initialize - [COMMANDS.START]: async () => { - console.log('start') - - await isEmptyWorkspace() - - let webviewState: 'INITIALIZING' | 'RESTARTING' - if (!webview) { - webviewState = 'INITIALIZING' - } else if (webview.loaded) { - // already loaded - vscode.window.showInformationMessage('CodeRoad already open') - return - } else { - webviewState = 'RESTARTING' - } - - // activate machine - webview = new ReactWebView(vscodeExt.extensionPath) - }, - // open React webview - [COMMANDS.OPEN_WEBVIEW]: (column: number = vscode.ViewColumn.Two) => { - console.log('open webview') - // setup 1x1 horizontal layout - resetLayout() - webview.createOrShow(column) - }, - [COMMANDS.TEST_RUNNER_SETUP]: async (codingLanguage: G.EnumCodingLanguage) => { - - // TODO: allow multiple coding languages in a tutorial - - // setup onSave hook - // console.log(`languageIds: ${languageIds.join(', ')}`) - vscode.workspace.onDidSaveTextDocument((document: vscode.TextDocument) => { - console.log('save document', document) - if (document.uri.scheme === 'file' && codingLanguage === document.languageId) { - // do work - // machine.send('TEST_RUN') - } - }) - }, - // open a file - [COMMANDS.OPEN_FILE]: async (relativeFilePath: string) => { - console.log(`OPEN_FILE ${JSON.stringify(relativeFilePath)}`) - try { - // TODO: reenable after testing - // const workspaceRoots: vscode.WorkspaceFolder[] | undefined = vscode.workspace.workspaceFolders - // if (!workspaceRoots || !workspaceRoots.length) { - // throw new Error('No workspace root path') - // } - // const rootWorkspace: vscode.WorkspaceFolder = workspaceRoots[0] - // const absoluteFilePath = join(rootWorkspace.uri.path, relativeFilePath) - const workspaceRoot = vscode.workspace.rootPath - if (!workspaceRoot) { - throw new Error('No workspace root path') - } - const absoluteFilePath = join(workspaceRoot, relativeFilePath) - const doc = await vscode.workspace.openTextDocument(absoluteFilePath) - await vscode.window.showTextDocument(doc, vscode.ViewColumn.One) - // there are times when initialization leave the panel behind any files opened - // ensure the panel is redrawn on the right side first - webview.createOrShow(vscode.ViewColumn.Two) - } catch (error) { - console.log(`Failed to open file ${relativeFilePath}`, error) - } - }, - [COMMANDS.RUN_TEST]: () => { - runTest({ - onSuccess: () => { - console.log('TEST_PASS') - vscode.window.showInformationMessage('PASS') - }, - onFail: () => { - console.log('TEST_FAIL') - vscode.window.showWarningMessage('FAIL') - } - }) - }, - } -} diff --git a/src/editor/commands/loadSolution.ts b/src/editor/commands/loadSolution.ts deleted file mode 100644 index 8c3aad2c..00000000 --- a/src/editor/commands/loadSolution.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as CR from 'typings' -import * as G from 'typings/graphql' -import {TutorialModel} from '../../services/tutorial' -import {gitLoadCommits, gitClear} from '../../services/git' - -export default async function loadSolution(dispatch: CR.EditorDispatch, tutorialModel: TutorialModel): Promise { - // TODO: should load same as commits - - // const step: G.Step = tutorialModel.step() - // const solution = step.solution - - // await gitClear() - // await gitLoadCommits(solution, dispatch) - -} diff --git a/src/editor/index.ts b/src/editor/index.ts index f238f2df..ae0b9513 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -8,7 +8,6 @@ class Editor { private vscodeExt: vscode.ExtensionContext constructor() { - // set workspace root for node executions const {workspace} = vscode const {rootPath} = workspace @@ -33,11 +32,6 @@ class Editor { } } - // execute vscode command - public dispatch = (type: string, payload?: any) => { - vscode.commands.executeCommand(type, payload) - } - private activateCommands = (): void => { const commands = createCommands({ vscodeExt: this.vscodeExt, diff --git a/src/extension.ts b/src/extension.ts index 8ec80193..1c3e3b87 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,8 +1,8 @@ -import * as vscode from 'vscode' -import Tutorial, {TutorialModel} from './services/tutorial' +// import * as vscode from 'vscode' +// import Tutorial, {TutorialModel} from './services/tutorial' import Editor from './editor' -export const tutorialModel: TutorialModel = new Tutorial(vscode.commands.executeCommand) +// export const tutorialModel: TutorialModel = new Tutorial(vscode.commands.executeCommand) // vscode editor export const editor = new Editor() diff --git a/src/services/git/errorMessages.ts b/src/services/git/errorMessages.ts deleted file mode 100644 index 4de72216..00000000 --- a/src/services/git/errorMessages.ts +++ /dev/null @@ -1,14 +0,0 @@ -interface ErrorMessageFilter { - [lang: string]: { - [key: string]: string - } -} - -// likely should be loaded on startup -const errorMessages: ErrorMessageFilter = { - js: { - 'node-gyp': 'Error running npm setup command' - } -} - -export default errorMessages \ No newline at end of file diff --git a/src/services/git/index.ts b/src/services/git/index.ts index 8166024b..52a8cf1c 100644 --- a/src/services/git/index.ts +++ b/src/services/git/index.ts @@ -1,7 +1,6 @@ -import * as G from 'typings/graphql' import * as CR from 'typings' import {exec, exists} from '../node' -import errorMessages from './errorMessages' + const gitOrigin = 'coderoad' @@ -39,42 +38,8 @@ const cherryPickCommit = async (commit: string, count = 0): Promise => { SINGLE git cherry-pick %COMMIT% if fails, will stash all and retry */ -export async function gitLoadCommits(actions: G.StepActions, openFile: (file: string) => void): Promise { - const {commits, commands, files} = actions - - console.log(`load commits: ${commits.join(', ')}`) - console.log(`commands: ${commands.join(', ')}`) - console.log(`files ${files.join(', s')}`) - - for (const commit of commits) { - // pull a commit from tutorial repo - console.log(`try cherry-pick ${commit}`) - await cherryPickCommit(commit) - } - - if (commands) { - // TODO: run shell as task - for (const command of commands) { - const {stdout, stderr} = await exec(command) - if (stderr) { - console.error(stderr) - // language specific error messages from running commands - for (const message of Object.keys(errorMessages.js)) { - if (stderr.match(message)) { - // ignored error - throw new Error('Error running setup command') - } - } - } - console.log(`run command: ${command}`, stdout) - } - } - - if (files) { - for (const filePath of files) { - openFile(filePath) - } - } +export function loadCommit(commit: string): Promise { + return cherryPickCommit(commit) } /* @@ -82,7 +47,7 @@ export async function gitLoadCommits(actions: G.StepActions, openFile: (file: st git commit -am '${level}/${stage}/${step} complete' */ -export async function gitSaveCommit(position: CR.Position): Promise { +export async function saveCommit(position: CR.Position): Promise { const {levelId, stageId, stepId} = position const {stdout, stderr} = await exec(`git commit -am 'completed ${levelId}/${stageId}/${stepId}'`) if (stderr) { @@ -92,7 +57,7 @@ export async function gitSaveCommit(position: CR.Position): Promise { console.log('save with commit & continue stdout', stdout) } -export async function gitClear(): Promise { +export async function clear(): Promise { try { // commit progress to git const {stderr} = await exec('git reset HEAD --hard && git clean -fd') @@ -106,7 +71,7 @@ export async function gitClear(): Promise { throw new Error('Error cleaning up current unsaved work') } -export async function gitVersion(): Promise { +export async function version(): Promise { const {stdout, stderr} = await exec('git --version') if (!stderr) { const match = stdout.match(/^git version (\d+\.)?(\d+\.)?(\*|\d+)/) @@ -119,15 +84,15 @@ export async function gitVersion(): Promise { throw new Error('Git not installed. Please install Git') } -async function gitInit(): Promise { +async function init(): Promise { const {stderr} = await exec('git init') if (stderr) { throw new Error('Error initializing Gits') } } -export async function gitInitIfNotExists(): Promise { - const hasGit = await gitVersion() +export async function initIfNotExists(): Promise { + const hasGit = await version() if (!hasGit) { throw new Error('Git must be installed') @@ -135,11 +100,11 @@ export async function gitInitIfNotExists(): Promise { const hasGitInit = exists('.git') if (!hasGitInit) { - await gitInit() + await init() } } -export async function gitAddRemote(repo: string): Promise { +export async function addRemote(repo: string): Promise { const {stderr} = await exec(`git remote add ${gitOrigin} ${repo} && git fetch ${gitOrigin}`) if (stderr) { const alreadyExists = stderr.match(`${gitOrigin} already exists.`) @@ -153,7 +118,7 @@ export async function gitAddRemote(repo: string): Promise { } } -export async function gitCheckRemoteExists(): Promise { +export async function checkRemoteExists(): Promise { try { const {stdout, stderr} = await exec('git remote -v') if (stderr) { @@ -167,12 +132,12 @@ export async function gitCheckRemoteExists(): Promise { } } -export async function gitSetupRemote(repo: string): Promise { +export async function setupRemote(repo: string): Promise { // check coderoad remote not taken - const hasRemote = await gitCheckRemoteExists() + const hasRemote = await checkRemoteExists() // git remote add coderoad tutorial // git fetch coderoad if (!hasRemote) { - await gitAddRemote(repo) + await addRemote(repo) } } diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts index 4220ccf5..34519b56 100644 --- a/src/services/tutorial/index.ts +++ b/src/services/tutorial/index.ts @@ -48,8 +48,8 @@ class Tutorial implements TutorialModel { throw new Error('Tutorial repo uri not found') } - await git.gitInitIfNotExists() - await git.gitSetupRemote(this.repo.uri) + await git.initIfNotExists() + await git.setupRemote(this.repo.uri) this.config = { codingLanguage: tutorial.codingLanguage, @@ -68,8 +68,8 @@ class Tutorial implements TutorialModel { // verify git is setup with a coderoad remote const [hasGit, hasGitRemote] = await Promise.all([ - git.gitVersion(), - git.gitCheckRemoteExists(), + git.version(), + git.checkRemoteExists(), ]) // TODO: may need to clean up git remote if no existing tutorial @@ -78,7 +78,7 @@ class Tutorial implements TutorialModel { return canContinue } public triggerCurrent = (stepActions: G.StepActions) => { - git.gitLoadCommits(stepActions, this.openFile) + // git.loadCommits(stepActions, this.openFile) } } diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index 324b4518..25e44e0a 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -35,7 +35,7 @@ export default { if (level.setup) { // load step actions channel.editorSend({ - type: 'STEP_ACTIONS', + type: 'SETUP_ACTIONS', payload: level.setup, }) } @@ -45,7 +45,7 @@ export default { if (stage.setup) { // load step actions channel.editorSend({ - type: 'STEP_ACTIONS', + type: 'SETUP_ACTIONS', payload: stage.setup, }) } @@ -55,7 +55,7 @@ export default { if (step.setup) { // load step actions channel.editorSend({ - type: 'STEP_ACTIONS', + type: 'SETUP_ACTIONS', payload: step.setup, }) } From a0f7bced8fb5eeb8c8ee1571e38df6a8879322dd Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 8 Sep 2019 16:50:38 -0700 Subject: [PATCH 115/117] cleanup stepAction loading --- src/Channel.ts | 2 ++ src/actions/runTest.ts | 6 ++-- src/actions/setupActions.ts | 4 +-- src/editor/index.ts | 5 +-- src/editor/workspace.ts | 8 ++--- src/services/git/index.ts | 20 ++++++------ src/services/node/index.ts | 33 +++++++++++--------- web-app/src/services/state/actions/editor.ts | 7 +++-- web-app/src/services/state/machine.ts | 2 +- 9 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/Channel.ts b/src/Channel.ts index 39fa3299..3e5764ee 100644 --- a/src/Channel.ts +++ b/src/Channel.ts @@ -28,9 +28,11 @@ class Channel implements Channel { tutorialConfig(action.payload) return case 'SETUP_ACTIONS': + console.log(action.payload) setupActions(action.payload) return case 'SOLUTION_ACTIONS': + console.log(action.payload) solutionActions(action.payload) return default: diff --git a/src/actions/runTest.ts b/src/actions/runTest.ts index 8948718a..6e4007da 100644 --- a/src/actions/runTest.ts +++ b/src/actions/runTest.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode' -import {exec} from '../services/node' +import node from '../services/node' // ensure only latest run_test action is taken let currentId = 0 @@ -50,7 +50,7 @@ export default async function runTest({onSuccess, onFail}: Props): Promise try { // capture position early on test start // in case position changes - const {stdout} = await exec(commandLine) + const {stdout} = await node.exec(commandLine) if (shouldExitEarly(processId)) { // exit early return @@ -98,7 +98,7 @@ export default async function runTest({onSuccess, onFail}: Props): Promise console.error('SOMETHING WENT WRONG WITH A PASSING TEST') } // test runner failed - const channel = getOutputChannel(outputChannelName) + channel = getOutputChannel(outputChannelName) if (stdout) { const lines = stdout.split(/\r{0,1}\n/) diff --git a/src/actions/setupActions.ts b/src/actions/setupActions.ts index 508c8f8b..7268df2c 100644 --- a/src/actions/setupActions.ts +++ b/src/actions/setupActions.ts @@ -2,7 +2,7 @@ import * as G from 'typings/graphql' import {join} from 'path' import * as vscode from 'vscode' import * as git from '../services/git' -import {exec} from '../services/node' +import node from '../services/node' interface ErrorMessageFilter { [lang: string]: { @@ -25,7 +25,7 @@ const setupActions = async ({commands, commits, files}: G.StepActions): Promise< // run command for (const command of commands) { - const {stdout, stderr} = await exec(command) + const {stdout, stderr} = await node.exec(command) if (stderr) { console.error(stderr) // language specific error messages from running commands diff --git a/src/editor/index.ts b/src/editor/index.ts index ae0b9513..02ec35e9 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -1,5 +1,4 @@ import * as vscode from 'vscode' -import {setWorkspaceRoot} from '../services/node' import {createCommands} from './commands' class Editor { @@ -9,12 +8,10 @@ class Editor { constructor() { // set workspace root for node executions - const {workspace} = vscode - const {rootPath} = workspace + const rootPath = vscode.workspace.rootPath if (!rootPath) { throw new Error('Requires a workspace. Please open a folder') } - setWorkspaceRoot(rootPath) } public activate = (vscodeExt: vscode.ExtensionContext): void => { console.log('ACTIVATE!') diff --git a/src/editor/workspace.ts b/src/editor/workspace.ts index b7b7f044..60264d06 100644 --- a/src/editor/workspace.ts +++ b/src/editor/workspace.ts @@ -1,10 +1,10 @@ import * as fs from 'fs' import * as path from 'path' import * as vscode from 'vscode' -import {exec, exists} from '../services/node' +import node from '../services/node' export async function isEmptyWorkspace(): Promise { - const {stdout, stderr} = await exec('ls') + const {stdout, stderr} = await node.exec('ls') if (stderr) { throw new Error('Error validating if project is empty') } @@ -13,7 +13,7 @@ export async function isEmptyWorkspace(): Promise { // // TODO: workspace change listener export async function openReadme(): Promise { - const {stderr} = await exec('ls') + const {stderr} = await node.exec('ls') if (stderr) { throw new Error('Error looking for initial file') } @@ -21,7 +21,7 @@ export async function openReadme(): Promise { const file = 'README.md' const filePath = path.join(vscode.workspace.rootPath || '', file) console.log('filePath', filePath) - const hasReadme = await exists(file) + const hasReadme = await node.exists(file) if (!hasReadme) { // add readme if none exists diff --git a/src/services/git/index.ts b/src/services/git/index.ts index 52a8cf1c..99724487 100644 --- a/src/services/git/index.ts +++ b/src/services/git/index.ts @@ -1,5 +1,5 @@ import * as CR from 'typings' -import {exec, exists} from '../node' +import node from '../node' const gitOrigin = 'coderoad' @@ -7,7 +7,7 @@ const gitOrigin = 'coderoad' const stashAllFiles = async () => { console.log('stashAllFiles') // stash files including untracked (eg. newly created file) - const {stdout, stderr} = await exec(`git stash --include-untracked`) + const {stdout, stderr} = await node.exec(`git stash --include-untracked`) if (stderr) { console.error(stderr) throw new Error('Error stashing files') @@ -20,7 +20,7 @@ const cherryPickCommit = async (commit: string, count = 0): Promise => { return } try { - const {stdout} = await exec(`git cherry-pick ${commit}`) + const {stdout} = await node.exec(`git cherry-pick ${commit}`) if (!stdout) { throw new Error('No cherry-pick output') } @@ -49,7 +49,7 @@ export function loadCommit(commit: string): Promise { export async function saveCommit(position: CR.Position): Promise { const {levelId, stageId, stepId} = position - const {stdout, stderr} = await exec(`git commit -am 'completed ${levelId}/${stageId}/${stepId}'`) + const {stdout, stderr} = await node.exec(`git commit -am 'completed ${levelId}/${stageId}/${stepId}'`) if (stderr) { console.error(stderr) throw new Error('Error saving progress to Git') @@ -60,7 +60,7 @@ export async function saveCommit(position: CR.Position): Promise { export async function clear(): Promise { try { // commit progress to git - const {stderr} = await exec('git reset HEAD --hard && git clean -fd') + const {stderr} = await node.exec('git reset HEAD --hard && git clean -fd') if (!stderr) { return } @@ -72,7 +72,7 @@ export async function clear(): Promise { } export async function version(): Promise { - const {stdout, stderr} = await exec('git --version') + const {stdout, stderr} = await node.exec('git --version') if (!stderr) { const match = stdout.match(/^git version (\d+\.)?(\d+\.)?(\*|\d+)/) if (match) { @@ -85,7 +85,7 @@ export async function version(): Promise { } async function init(): Promise { - const {stderr} = await exec('git init') + const {stderr} = await node.exec('git init') if (stderr) { throw new Error('Error initializing Gits') } @@ -98,14 +98,14 @@ export async function initIfNotExists(): Promise { throw new Error('Git must be installed') } - const hasGitInit = exists('.git') + const hasGitInit = node.exists('.git') if (!hasGitInit) { await init() } } export async function addRemote(repo: string): Promise { - const {stderr} = await exec(`git remote add ${gitOrigin} ${repo} && git fetch ${gitOrigin}`) + const {stderr} = await node.exec(`git remote add ${gitOrigin} ${repo} && git fetch ${gitOrigin}`) if (stderr) { const alreadyExists = stderr.match(`${gitOrigin} already exists.`) const successfulNewBranch = stderr.match('new branch') @@ -120,7 +120,7 @@ export async function addRemote(repo: string): Promise { export async function checkRemoteExists(): Promise { try { - const {stdout, stderr} = await exec('git remote -v') + const {stdout, stderr} = await node.exec('git remote -v') if (stderr) { return false } diff --git a/src/services/node/index.ts b/src/services/node/index.ts index 81e97d49..d6b583a0 100644 --- a/src/services/node/index.ts +++ b/src/services/node/index.ts @@ -1,26 +1,29 @@ import * as fs from 'fs' -import { join } from 'path' -import { exec as cpExec } from 'child_process' -import { promisify } from 'util' +import {join} from 'path' +import {exec as cpExec} from 'child_process' +import {promisify} from 'util' +import * as vscode from 'vscode' const asyncExec = promisify(cpExec) -let workspaceRoot: string +class Node { + private workspaceRoot: string + constructor() { + this.workspaceRoot = vscode.workspace.rootPath || '' + if (!this.workspaceRoot.length) { + throw new Error('Invalid workspaceRoot') + } + console.log(`workspaceRoot: ${this.workspaceRoot}`) + } + public exec = (cmd: string): Promise<{stdout: string; stderr: string}> => asyncExec(cmd, { + cwd: this.workspaceRoot, + }) -// set workspace root -// other function will use this to target the correct cwd -export function setWorkspaceRoot(rootPath: string): void { - workspaceRoot = rootPath + public exists = (...paths: string[]): boolean => fs.existsSync(join(this.workspaceRoot, ...paths)) } -export const exec = (cmd: string): Promise<{ stdout: string; stderr: string }> => - asyncExec(cmd, { - cwd: workspaceRoot, - }) +export default new Node() -// note: fs.exists is deprecated -// collect all paths together -export const exists = (...paths: string[]): boolean => fs.existsSync(join(workspaceRoot, ...paths)) // export async function clear(): Promise { // // remove all files including ignored diff --git a/web-app/src/services/state/actions/editor.ts b/web-app/src/services/state/actions/editor.ts index 25e44e0a..14d5133a 100644 --- a/web-app/src/services/state/actions/editor.ts +++ b/web-app/src/services/state/actions/editor.ts @@ -1,3 +1,4 @@ +import * as G from 'typings/graphql' import * as CR from 'typings' import * as selectors from '../../selectors' import channel from '../../channel' @@ -31,7 +32,7 @@ export default { }) }, loadLevel(context: CR.MachineContext): void { - const level = selectors.currentLevel(context) + const level: G.Level = selectors.currentLevel(context) if (level.setup) { // load step actions channel.editorSend({ @@ -41,7 +42,7 @@ export default { } }, loadStage(context: CR.MachineContext): void { - const stage = selectors.currentStage(context) + const stage: G.Stage = selectors.currentStage(context) if (stage.setup) { // load step actions channel.editorSend({ @@ -51,7 +52,7 @@ export default { } }, loadStep(context: CR.MachineContext): void { - const step = selectors.currentStep(context) + const step: G.Step = selectors.currentStep(context) if (step.setup) { // load step actions channel.editorSend({ diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index 96a2f07e..dfb22618 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -105,7 +105,7 @@ export const machine = Machine Date: Sun, 8 Sep 2019 16:56:16 -0700 Subject: [PATCH 116/117] refactor out workspace dimensions --- web-app/src/Routes.tsx | 32 +++------------------- web-app/src/components/Workspace/index.tsx | 30 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 28 deletions(-) create mode 100644 web-app/src/components/Workspace/index.tsx diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 11e765da..44b802c8 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -1,6 +1,8 @@ import * as React from 'react' // import { editorDispatch } from './services/vscode' import * as CR from 'typings' +import Workspace from './components/Workspace' + import Router from './components/Router' import LoadingPage from './containers/LoadingPage' import ContinuePage from './containers/Continue' @@ -12,37 +14,11 @@ import CompletedPage from './containers/Tutorial/CompletedPage' const { Route } = Router -const styles = { - page: { - margin: 0, - backgroundColor: 'white', - }, -} - const tempSend = (action: any) => console.log('sent') const Routes = () => { - // const [dimensions, setDimensions] = React.useState({ - // width: window.innerWidth - 20, - // height: window.innerHeight - 20, - // }) - - // // solution for windows getting off size - // // without adding multiple listeners - // React.useEffect(() => { - // const dimensionsInterval = setInterval(() => { - // setDimensions({ - // width: window.innerWidth - 20, - // height: window.innerHeight - 20, - // }) - // }, 5000) - // return () => { - // clearInterval(dimensionsInterval) - // } - // }, []) - return ( -
+ @@ -72,7 +48,7 @@ const Routes = () => { -
+ ) } diff --git a/web-app/src/components/Workspace/index.tsx b/web-app/src/components/Workspace/index.tsx new file mode 100644 index 00000000..ef2381b0 --- /dev/null +++ b/web-app/src/components/Workspace/index.tsx @@ -0,0 +1,30 @@ +import * as React from 'react' + +interface Props { + children: React.ReactElement +} + +const resize = () => ({ + width: window.innerWidth - 20, + height: window.innerHeight - 20, +}) + +const Workspace = ({ children }: Props) => { + const [dimensions, setDimensions] = React.useState(resize()) + + // solution for windows getting off size + React.useEffect(() => { + setDimensions(resize()) + }, [window.innerHeight, window.innerHeight]) + + const styles = { + page: { + margin: 0, + backgroundColor: 'white', + }, + } + + return
{children}
+} + +export default Workspace From 17e412efc91e92ec9d5ed368d5ceea3516ba55bc Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 8 Sep 2019 18:38:18 -0700 Subject: [PATCH 117/117] working version --- src/Channel.ts | 4 +- src/actions/runTest.ts | 7 +- src/actions/tutorialConfig.ts | 2 + src/editor/ReactWebView.ts | 5 +- src/editor/commands.ts | 26 +++--- src/extension.ts | 4 - src/services/tutorial/index.ts | 85 ------------------- typings/index.d.ts | 1 - web-app/src/Routes.tsx | 1 - web-app/src/services/channel/index.ts | 41 +++------ web-app/src/services/state/actions/context.ts | 9 +- web-app/src/services/state/machine.ts | 1 - 12 files changed, 48 insertions(+), 138 deletions(-) delete mode 100644 src/services/tutorial/index.ts diff --git a/src/Channel.ts b/src/Channel.ts index 3e5764ee..ec60e2f9 100644 --- a/src/Channel.ts +++ b/src/Channel.ts @@ -12,8 +12,8 @@ interface Channel { class Channel implements Channel { private postMessage: (action: CR.Action) => Thenable - constructor(webview: vscode.Webview) { - this.postMessage = webview.postMessage + constructor(postMessage: (action: CR.Action) => Thenable) { + this.postMessage = postMessage } // receive from webview diff --git a/src/actions/runTest.ts b/src/actions/runTest.ts index 6e4007da..d01e5cf2 100644 --- a/src/actions/runTest.ts +++ b/src/actions/runTest.ts @@ -22,12 +22,15 @@ const getOutputChannel = (name: string): vscode.OutputChannel => { interface Props { onSuccess(): void onFail(): void + onRun(): void } -export default async function runTest({onSuccess, onFail}: Props): Promise { +async function runTest({onSuccess, onFail, onRun}: Props): Promise { // increment process id const processId = ++currentId + onRun() + const outputChannelName = 'Test Output' // TODO: validate test directory from package.json exists @@ -139,3 +142,5 @@ export default async function runTest({onSuccess, onFail}: Props): Promise // } } } + +export default runTest \ No newline at end of file diff --git a/src/actions/tutorialConfig.ts b/src/actions/tutorialConfig.ts index bd0c0889..285c9b46 100644 --- a/src/actions/tutorialConfig.ts +++ b/src/actions/tutorialConfig.ts @@ -19,6 +19,8 @@ const tutorialConfig = async (tutorial: G.Tutorial) => { vscode.commands.executeCommand('coderoad.run_test') } }) + + console.log('configured') } export default tutorialConfig \ No newline at end of file diff --git a/src/editor/ReactWebView.ts b/src/editor/ReactWebView.ts index e7884567..d8d8354d 100644 --- a/src/editor/ReactWebView.ts +++ b/src/editor/ReactWebView.ts @@ -1,3 +1,4 @@ +import {Action} from 'typings' import * as path from 'path' import * as vscode from 'vscode' import Channel from '../Channel' @@ -36,7 +37,9 @@ class ReactWebView { // This happens when the user closes the panel or when the panel is closed programmatically this.panel.onDidDispose(this.dispose, this, this.disposables) - this.channel = new Channel(this.panel.webview) + this.channel = new Channel((action: Action): Thenable => { + return this.panel.webview.postMessage(action) + }) // Handle messages from the webview const receive = this.channel.receive this.panel.webview.onDidReceiveMessage(receive, null, this.disposables) diff --git a/src/editor/commands.ts b/src/editor/commands.ts index 609b9565..c186e831 100644 --- a/src/editor/commands.ts +++ b/src/editor/commands.ts @@ -13,13 +13,6 @@ interface CreateCommandProps { vscodeExt: vscode.ExtensionContext } -const resetLayout = () => { - vscode.commands.executeCommand('vscode.setEditorLayout', { - orientation: 0, - groups: [{groups: [{}], size: 0.6}, {groups: [{}], size: 0.4}], - }) -} - export const createCommands = ({vscodeExt}: CreateCommandProps) => { // React panel webview let webview: any @@ -50,18 +43,31 @@ export const createCommands = ({vscodeExt}: CreateCommandProps) => { [COMMANDS.OPEN_WEBVIEW]: (column: number = vscode.ViewColumn.Two) => { console.log('open webview') // setup 1x1 horizontal layout - resetLayout() + + // reset layout + vscode.commands.executeCommand('vscode.setEditorLayout', { + orientation: 0, + groups: [{groups: [{}], size: 0.6}, {groups: [{}], size: 0.4}], + }) + webview.createOrShow(column) }, [COMMANDS.RUN_TEST]: () => { + console.log('run test webview', Object.keys(webview)) runTest({ onSuccess: () => { - console.log('TEST_PASS') + console.log('COMMAND TEST_PASS') + webview.send({type: 'TEST_PASS'}) vscode.window.showInformationMessage('PASS') }, onFail: () => { - console.log('TEST_FAIL') + console.log('COMMAND TEST_FAIL') + webview.send({type: 'TEST_FAIL'}) vscode.window.showWarningMessage('FAIL') + }, + onRun: () => { + console.log('COMMAND TEST_RUN') + webview.send({type: 'TEST_RUN'}) } }) }, diff --git a/src/extension.ts b/src/extension.ts index 1c3e3b87..a12e7e2d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,9 +1,5 @@ -// import * as vscode from 'vscode' -// import Tutorial, {TutorialModel} from './services/tutorial' import Editor from './editor' -// export const tutorialModel: TutorialModel = new Tutorial(vscode.commands.executeCommand) - // vscode editor export const editor = new Editor() diff --git a/src/services/tutorial/index.ts b/src/services/tutorial/index.ts deleted file mode 100644 index 34519b56..00000000 --- a/src/services/tutorial/index.ts +++ /dev/null @@ -1,85 +0,0 @@ -import * as G from 'typings/graphql' -import * as CR from 'typings' -import * as git from '../../services/git' - -interface TutorialConfig { - codingLanguage: G.EnumCodingLanguage - testRunner: G.EnumTestRunner -} - -export interface TutorialModel { - repo: G.TutorialRepo - config: TutorialConfig - version: G.TutorialVersion - position: CR.Position - progress: CR.Progress - launch(tutorial: G.Tutorial): void - hasExisting(): Promise - triggerCurrent(stepActions: G.StepActions): void -} - -class Tutorial implements TutorialModel { - public repo: G.TutorialRepo - public config: TutorialConfig - public version: G.TutorialVersion - public position: CR.Position - public progress: CR.Progress - public openFile: (file: string) => void - - constructor(editorDispatch: CR.EditorDispatch) { - // initialize types, will be assigned when tutorial is selected - - this.repo = {} as G.TutorialRepo - this.config = {} as TutorialConfig - this.version = {} as G.TutorialVersion - this.position = {} as CR.Position - this.progress = {} as CR.Progress - this.openFile = (file: string) => editorDispatch('coderoad.open_file', file) - } - public launch = async (tutorial: G.Tutorial) => { - console.log('launch tutorial') - // machine.send('TUTORIAL_START') - - console.log('tutorial', tutorial) - - this.repo = tutorial.repo - - if (!this.repo || !this.repo.uri) { - throw new Error('Tutorial repo uri not found') - } - - await git.initIfNotExists() - await git.setupRemote(this.repo.uri) - - this.config = { - codingLanguage: tutorial.codingLanguage, - testRunner: tutorial.testRunner, - } - - // version containing level data - this.version = tutorial.version - console.log('version', this.version) - - } - - public async hasExisting(): Promise { - // instead should configure git if does not exist - // and update git to current position - - // verify git is setup with a coderoad remote - const [hasGit, hasGitRemote] = await Promise.all([ - git.version(), - git.checkRemoteExists(), - ]) - // TODO: may need to clean up git remote if no existing tutorial - - const canContinue = !!(hasGit && hasGitRemote) - - return canContinue - } - public triggerCurrent = (stepActions: G.StepActions) => { - // git.loadCommits(stepActions, this.openFile) - } -} - -export default Tutorial \ No newline at end of file diff --git a/typings/index.d.ts b/typings/index.d.ts index 204a4f5d..f90eb917 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1,5 +1,4 @@ import {send} from 'xstate' -import TutorialModel from '../src/services/tutorial' import * as G from './graphql' export interface TutorialLevel { diff --git a/web-app/src/Routes.tsx b/web-app/src/Routes.tsx index 44b802c8..f9aa1882 100644 --- a/web-app/src/Routes.tsx +++ b/web-app/src/Routes.tsx @@ -1,5 +1,4 @@ import * as React from 'react' -// import { editorDispatch } from './services/vscode' import * as CR from 'typings' import Workspace from './components/Workspace' diff --git a/web-app/src/services/channel/index.ts b/web-app/src/services/channel/index.ts index f9f2e3c1..3b5895d7 100644 --- a/web-app/src/services/channel/index.ts +++ b/web-app/src/services/channel/index.ts @@ -18,18 +18,19 @@ class Channel { const editor = acquireVsCodeApi() this.editorSend = editor.postMessage } - public machineSend = (action: Action | string) => console.log('machine send') - public editorSend = (action: Action) => console.log('editor send') + public machineSend = (action: Action | string) => { /* */} + public editorSend = (action: Action) => { /* */} - public setMachineSend(send: any) { + public setMachineSend = (send: any) => { this.machineSend = send } - public receive(event: ReceivedEvent) { + public receive = (event: ReceivedEvent) => { + console.log('CLIENT RECEIVE') const action = event.data // @ts-ignore // ignore browser events from plugins if (action.source) {return } - + console.log(`CLIENT RECEIVE: ${action.type}`, action) // messages from core switch (action.type) { case 'TUTORIAL_LOADED': @@ -38,12 +39,16 @@ class Channel { console.log('send action to state machine') return case 'TEST_PASS': + // { type: 'TEST_PASS', payload: { stepId: string }} this.machineSend(action) console.log('test passed') return case 'TEST_FAIL': this.machineSend(action) return + case 'TEST_RUN': + console.log('TEST_RUN') + return case 'ACTIONS_LOADED': console.log('ACTIONS_LOADED') return @@ -56,29 +61,3 @@ class Channel { } export default new Channel() - -// Send to Editor -// export const send = (action: Action) => { -// return -// } - - - -// // Receive from Editor -// export const receive = (event: ReceivedEvent): void => { - - -// // if (message.type === 'SET_DATA') { -// // // SET_DATA - set state machine context -// // console.log('SET_DATA updated') -// // const {progress, position} = message.payload -// // if (process.env.REACT_APP_DEBUG) { -// // console.log(`Position: ${position.levelId}/${position.stageId}/${position.stepId}`) -// // // setDebuggerInfo({ progress, position }) -// // } -// // console.log('set currentTutorial') -// // // currentTutorial.set({position, progress}) - -// // } -// } - diff --git a/web-app/src/services/state/actions/context.ts b/web-app/src/services/state/actions/context.ts index 1ebf8668..012abd53 100644 --- a/web-app/src/services/state/actions/context.ts +++ b/web-app/src/services/state/actions/context.ts @@ -28,6 +28,9 @@ export default { // @ts-ignore updateStepPosition: assign({ position: (context: CR.MachineContext, event: CR.MachineEvent): CR.Position => { + + // TODO: calculate from progress + const {position} = context // merge in the updated position // sent with the test to ensure consistency @@ -101,9 +104,13 @@ export default { // @ts-ignore updateStepProgress: assign({ progress: (context: CR.MachineContext, event: CR.MachineEvent): CR.Progress => { + // update progress by tracking completed const currentProgress: CR.Progress = context.progress - const stepId = event.payload.stepId + + // TODO: should use event id, to verify not multiple successes jumping one + // const stepId = event.payload.stepId + const {stepId} = context.position currentProgress.steps[stepId] = true diff --git a/web-app/src/services/state/machine.ts b/web-app/src/services/state/machine.ts index dfb22618..190c091d 100644 --- a/web-app/src/services/state/machine.ts +++ b/web-app/src/services/state/machine.ts @@ -121,7 +121,6 @@ export const machine = Machine