diff --git a/.vscode/settings.json b/.vscode/settings.json index 7992cb51..b80cab66 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,5 +15,9 @@ "titleBar.activeBackground": "#000000", "titleBar.activeForeground": "#FFFFFF" }, - "cSpell.ignoreWords": ["camelcase"] + "cSpell.ignoreWords": ["camelcase"], + "files.exclude": { + ".vscode-test/**": true, + "*.vsix": true + } } diff --git a/package-lock.json b/package-lock.json index 5bfc2f91..57a6dd67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "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", @@ -40,6 +41,14 @@ "integrity": "sha512-491hfOvNr0+BGOHT2m36xJ+LK68IuOshvxV0VIrKOnzBDL11WlDa3PwO+drTYkwCdfzJRN9REcDPZVVcrx1ucw==", "dev": true }, + "@types/chokidar": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@types/chokidar/-/chokidar-2.1.3.tgz", + "integrity": "sha512-6qK3xoLLAhQVTucQGHTySwOVA1crHRXnJeLwqK6KIFkkKa2aoMFXh+WEi8PotxDtvN6MQJLyYN9ag9P6NLV81w==", + "requires": { + "chokidar": "*" + } + }, "@types/dotenv": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-8.2.0.tgz", @@ -75,12 +84,14 @@ "@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==" + "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": "*" } @@ -89,6 +100,7 @@ "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": "*" @@ -98,6 +110,7 @@ "version": "24.0.23", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.23.tgz", "integrity": "sha512-L7MBvwfNpe7yVPTXLn32df/EK+AMBFAFvZrRuArGs7npEWnlziUXK+5GMIUTI4NIuwok3XibsjXCs5HxviYXjg==", + "dev": true, "requires": { "jest-diff": "^24.3.0" } @@ -149,6 +162,7 @@ "version": "13.0.3", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", + "dev": true, "requires": { "@types/yargs-parser": "*" } @@ -156,7 +170,8 @@ "@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==" + "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", + "dev": true }, "@typescript-eslint/eslint-plugin": { "version": "2.7.0", @@ -333,10 +348,20 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "requires": { "color-convert": "^1.9.0" } }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -416,6 +441,11 @@ "tweetnacl": "^0.14.3" } }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -426,6 +456,14 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, "browser-process-hrtime": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", @@ -473,6 +511,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -485,6 +524,21 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -521,6 +575,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { "color-name": "1.1.3" } @@ -528,7 +583,8 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "combined-stream": { "version": "1.0.8", @@ -689,7 +745,8 @@ "diff-sequences": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==" + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "dev": true }, "doctrine": { "version": "3.0.0", @@ -800,7 +857,8 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "escodegen": { "version": "1.12.0", @@ -1065,6 +1123,14 @@ "flat-cache": "^2.0.1" } }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -1132,6 +1198,12 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -1191,7 +1263,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -1243,7 +1314,8 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "has-symbols": { "version": "1.0.0", @@ -1450,6 +1522,14 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-buffer": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", @@ -1471,8 +1551,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -1490,7 +1569,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -1504,6 +1582,11 @@ "define-properties": "^1.1.1" } }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -1560,6 +1643,7 @@ "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", @@ -1570,7 +1654,8 @@ "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==" + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true }, "js-tokens": { "version": "4.0.0", @@ -2028,6 +2113,11 @@ "validate-npm-package-license": "^3.0.1" } }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -2248,6 +2338,11 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "picomatch": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", + "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==" + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -2283,6 +2378,7 @@ "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", @@ -2293,7 +2389,8 @@ "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 } } }, @@ -2337,7 +2434,8 @@ "react-is": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", - "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==" + "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", + "dev": true }, "read-pkg": { "version": "4.0.1", @@ -2350,6 +2448,14 @@ "pify": "^3.0.0" } }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "requires": { + "picomatch": "^2.0.4" + } + }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", @@ -2695,6 +2801,7 @@ "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -2765,6 +2872,14 @@ "os-tmpdir": "~1.0.2" } }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, "tough-cookie": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", diff --git a/package.json b/package.json index bcefaa67..15c9eea5 100644 --- a/package.json +++ b/package.json @@ -31,13 +31,15 @@ "watch": "tsc -watch -p ./" }, "dependencies": { - "@types/jest": "^24.0.23", + "@types/chokidar": "^2.1.3", + "chokidar": "^3.3.0", "jsdom": "^15.2.1" }, "devDependencies": { "@types/assert": "^1.4.3", "@types/dotenv": "^8.2.0", "@types/glob": "^7.1.1", + "@types/jest": "^24.0.23", "@types/jsdom": "^12.2.4", "@types/node": "^12.12.8", "@typescript-eslint/eslint-plugin": "^2.7.0", diff --git a/src/actions/setupActions.ts b/src/actions/setupActions.ts index 760d6d7c..d918168a 100644 --- a/src/actions/setupActions.ts +++ b/src/actions/setupActions.ts @@ -1,136 +1,42 @@ import * as G from 'typings/graphql' -import { join } from 'path' import * as vscode from 'vscode' import * as git from '../services/git' import node from '../services/node' -// interface ErrorMessageFilter { -// [lang: string]: { -// [key: string]: string -// } -// } +import openFiles from './utils/openFiles' +import loadWatchers from './utils/loadWatchers' -// TODO: should be loaded on startup based on language -// const commandErrorMessageFilter: ErrorMessageFilter = { -// JAVASCRIPT: { -// 'node-gyp': 'Error running npm setup command' -// } -// } - -// TODO: pass command and command name down for filtering. Eg. JAVASCRIPT, 'npm install' const runCommands = async (commands: string[]) => { + if (!commands.length) { + return + } for (const command of commands) { const { stdout, stderr } = await node.exec(command) if (stderr) { console.error(stderr) - // language specific error messages from running commands - // const filteredMessages = Object.keys(commandErrorMessageFilter[language]) - // for (const message of filteredMessages) { - // if (stderr.match(message)) { - // // ignored error - // throw new Error('Error running setup command') - // } - // } } console.log(`run command: ${command}`, stdout) } } -// collect active file watchers (listeners) -const watchers: { [key: string]: vscode.FileSystemWatcher } = {} - -const disposeWatcher = (listener: string) => { - watchers[listener].dispose() - delete watchers[listener] -} - const setupActions = async (workspaceRoot: vscode.WorkspaceFolder, actions: G.StepActions): Promise => { - const { commands, commits, files, listeners } = actions - // run commits + const { commands, commits, files, watchers } = actions + + // 1. run commits if (commits) { for (const commit of commits) { await git.loadCommit(commit) } } - // run file watchers (listeners) - if (listeners) { - console.log('listeners') - for (const listener of listeners) { - if (!watchers[listener]) { - const rootUri = vscode.workspace.getWorkspaceFolder(workspaceRoot.uri) - const pattern = new vscode.RelativePattern(rootUri!, listener) // eslint-disable-line - console.log(pattern) - const listen = vscode.workspace.createFileSystemWatcher(pattern) - watchers[listener] = listen - watchers[listener].onDidChange(() => { - console.log('onDidChange') - // trigger save - vscode.commands.executeCommand('coderoad.run_test', null, () => { - // cleanup watcher on success - disposeWatcher(listener) - }) - }) - watchers[listener].onDidCreate(() => { - console.log('onDidCreate') - // trigger save - vscode.commands.executeCommand('coderoad.run_test', null, () => { - // cleanup watcher on success - disposeWatcher(listener) - }) - }) - watchers[listener].onDidDelete(() => { - console.log('onDidDelete') - // trigger save - vscode.commands.executeCommand('coderoad.run_test', null, () => { - // cleanup watcher on success - disposeWatcher(listener) - }) - }) - } - } - } else { - // remove all watchers - for (const listener of Object.keys(watchers)) { - disposeWatcher(listener) - } - } + // 2. open files + openFiles(files || []) - // run command - if (commands) { - await runCommands(commands) - } + // 3. start file watchers + loadWatchers(watchers || [], workspaceRoot.uri) - // open files - if (files) { - for (const filePath of files) { - try { - // TODO: figure out why this does not work - // try { - // const absoluteFilePath = join(workspaceRoot.uri.path, 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() - // } catch (error) { - // console.log(`Failed to open file ${filePath}`, error) - // } - const wr = vscode.workspace.rootPath - if (!wr) { - throw new Error('No workspace root path') - } - const absoluteFilePath = join(wr, 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 - vscode.commands.executeCommand('coderoad.open_webview') - } catch (error) { - console.log(`Failed to open file ${filePath}`, error) - } - } - } + // 4. run command + await runCommands(commands || []) } export default setupActions diff --git a/src/actions/tutorialConfig.ts b/src/actions/tutorialConfig.ts index c0040d70..8ffc0827 100644 --- a/src/actions/tutorialConfig.ts +++ b/src/actions/tutorialConfig.ts @@ -42,7 +42,7 @@ const tutorialConfig = async ({ config, alreadyConfigured }: TutorialConfigParam // setup onSave hook vscode.workspace.onDidSaveTextDocument((document: vscode.TextDocument) => { if (shouldRunTest(document)) { - vscode.commands.executeCommand('coderoad.run_test') + vscode.commands.executeCommand(COMMANDS.RUN_TEST) } }) } diff --git a/src/actions/utils/loadWatchers.ts b/src/actions/utils/loadWatchers.ts new file mode 100644 index 00000000..7504d5ef --- /dev/null +++ b/src/actions/utils/loadWatchers.ts @@ -0,0 +1,51 @@ +import * as vscode from 'vscode' +import * as chokidar from 'chokidar' +import { COMMANDS } from '../../editor/commands' + +// NOTE: vscode createFileWatcher doesn't seem to detect changes outside of vscode +// such as `npm install` of a package. Went with chokidar instead + +// collect active file watchers as an object keyed on pattern +const watcherObject: { [key: string]: chokidar.FSWatcher } = {} + +const disposeWatcher = (watcher: string) => { + watcherObject[watcher].close() + delete watcherObject[watcher] +} + +const loadWatchers = (watchers: string[], workspaceUri: vscode.Uri) => { + if (!watchers.length) { + // remove all watchers + for (const watcher of Object.keys(watcherObject)) { + disposeWatcher(watcher) + } + } + for (const watcher of watchers) { + if (!watcherObject[watcher]) { + // see how glob patterns are used in VSCode (not like a regex) + // https://code.visualstudio.com/api/references/vscode-api#GlobPattern + const rootUri = vscode.workspace.getWorkspaceFolder(workspaceUri) + if (!rootUri) { + return + } + + const fsWatcher: chokidar.FSWatcher = chokidar.watch(watcher, { + cwd: rootUri.uri.path, + interval: 1000, + }) + + fsWatcher.on('change', (path, event) => { + vscode.commands.executeCommand(COMMANDS.RUN_TEST, null, () => { + // cleanup watcher on success + disposeWatcher(watcher) + }) + }) + + // key fs watcher on name + // to easily add/remove multiple watchers + watcherObject[watcher] = fsWatcher + } + } +} + +export default loadWatchers diff --git a/src/actions/utils/openFiles.ts b/src/actions/utils/openFiles.ts new file mode 100644 index 00000000..011aa596 --- /dev/null +++ b/src/actions/utils/openFiles.ts @@ -0,0 +1,38 @@ +import { join } from 'path' +import * as vscode from 'vscode' +import { COMMANDS } from '../../editor/commands' + +const openFiles = async (files: string[]) => { + if (!files.length) { + return + } + for (const filePath of files) { + try { + // TODO: figure out why this does not work + // try { + // const absoluteFilePath = join(workspaceRoot.uri.path, 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() + // } catch (error) { + // console.log(`Failed to open file ${filePath}`, error) + // } + const wr = vscode.workspace.rootPath + if (!wr) { + throw new Error('No workspace root path') + } + const absoluteFilePath = join(wr, 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 + vscode.commands.executeCommand(COMMANDS.OPEN_WEBVIEW) + } catch (error) { + console.log(`Failed to open file ${filePath}`, error) + } + } +} + +export default openFiles diff --git a/src/channel/index.ts b/src/channel/index.ts index c4addb03..72dde390 100644 --- a/src/channel/index.ts +++ b/src/channel/index.ts @@ -7,6 +7,7 @@ import tutorialConfig from '../actions/tutorialConfig' import setupActions from '../actions/setupActions' import solutionActions from '../actions/solutionActions' import saveCommit from '../actions/saveCommit' +import { COMMANDS } from '../editor/commands' interface Channel { receive(action: CR.Action): Promise @@ -81,7 +82,7 @@ class Channel implements Channel { // configure test runner, language, git case 'EDITOR_TUTORIAL_CONFIG': const tutorialData: G.Tutorial = action.payload.tutorial - // setup tutorial config (save listener, test runner, etc) + // setup tutorial config (save watcher, test runner, etc) this.context.setTutorial(this.workspaceState, tutorialData) const data: G.TutorialData = tutorialData.version.data @@ -117,14 +118,14 @@ class Channel implements Channel { return // load step actions (git commits, commands, open files) case 'SETUP_ACTIONS': - vscode.commands.executeCommand('coderoad.set_current_step', action.payload) + vscode.commands.executeCommand(COMMANDS.SET_CURRENT_STEP, action.payload) setupActions(this.workspaceRoot, action.payload) return // load solution step actions (git commits, commands, open files) case 'SOLUTION_ACTIONS': await solutionActions(this.workspaceRoot, action.payload) // run test following solution to update position - vscode.commands.executeCommand('coderoad.run_test', action.payload) + vscode.commands.executeCommand(COMMANDS.RUN_TEST, action.payload) return default: diff --git a/typings/graphql.d.ts b/typings/graphql.d.ts index 5aaa51ae..9ae6adbf 100644 --- a/typings/graphql.d.ts +++ b/typings/graphql.d.ts @@ -148,7 +148,7 @@ export type StepActions = { commits: Array files?: Maybe> commands?: Maybe> - listeners?: Maybe> + watchers?: Maybe> } /** A tutorial for use in VSCode CodeRoad */ @@ -513,7 +513,7 @@ export type StepActionsResolvers< commits?: Resolver, ParentType, ContextType> files?: Resolver>, ParentType, ContextType> commands?: Resolver>, ParentType, ContextType> - listeners?: Resolver>, ParentType, ContextType> + watchers?: Resolver>, ParentType, ContextType> } export type TutorialResolvers< diff --git a/web-app/package-lock.json b/web-app/package-lock.json index f7ede962..1535cbc5 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -14,9 +14,9 @@ } }, "@alifd/next": { - "version": "1.18.15", - "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.18.15.tgz", - "integrity": "sha512-J0Qx11f4ixOGntNSlS1wXgQea5xkCrwCYYxR27C5GpoNC61VMkfklvnL8G8+mEhWoocYF2lzr9Ex7/DBoeM0YA==", + "version": "1.18.16", + "resolved": "https://registry.npmjs.org/@alifd/next/-/next-1.18.16.tgz", + "integrity": "sha512-19NoEQNpN/eMJ4G158r30Hq4Z/8UWSbSBeWA1NV4tvVeKM70qQwl0gs4vPAUFjkltNnLz+m6o2Ok7NVD5hOYpA==", "requires": { "@alifd/field": "~1.3.3", "@alifd/validate": "~1.1.4", @@ -2342,9 +2342,9 @@ } }, "@types/node": { - "version": "12.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.7.tgz", - "integrity": "sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w==" + "version": "12.12.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.8.tgz", + "integrity": "sha512-XLla8N+iyfjvsa0KKV+BP/iGSoTmwxsu5Ci5sM33z9TjohF72DEz95iNvD6pPmemvbQgxAv/909G73gUn8QR7w==" }, "@types/prismjs": { "version": "1.16.0", diff --git a/web-app/package.json b/web-app/package.json index dc8ffd90..a2fe8e39 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -1,76 +1,76 @@ { - "name": "coderoad-app", - "version": "0.1.0", - "private": true, - "scripts": { - "build": "react-scripts build", - "postbuild": "cp -R ./build/ ../build/", - "build-storybook": "build-storybook", - "start": "react-scripts start", - "storybook": "start-storybook -p 6006", - "test": "react-scripts test" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - }, - "eslintConfig": { - "extends": "react-app" - }, - "dependencies": { - "@alifd/next": "^1.18.15", - "@alifd/theme-4": "^0.2.0", - "@apollo/react-hooks": "^3.1.3", - "apollo-boost": "^0.4.4", - "graphql": "^14.5.8", - "markdown-it": "^10.0.0", - "markdown-it-emoji": "^1.4.0", - "markdown-it-prism": "^2.0.3", - "moment": "^2.24.0", - "prismjs": "^1.17.1", - "ramda": "^0.26.1", - "react": "^16.12.0", - "react-dom": "^16.12.0", - "reselect": "^4.0.0", - "typescript": "^3.7.2", - "xstate": "^4.6.7" - }, - "devDependencies": { - "@babel/core": "^7.5.4", - "@storybook/addon-actions": "^5.2.6", - "@storybook/addon-knobs": "^5.2.6", - "@storybook/addon-links": "^5.2.6", - "@storybook/addons": "^5.2.6", - "@storybook/react": "^5.2.6", - "@types/graphql": "^14.5.0", - "@types/highlight.js": "^9.12.3", - "@types/jest": "^24.0.23", - "@types/markdown-it": "0.0.9", - "@types/node": "^12.12.7", - "@types/prismjs": "^1.16.0", - "@types/ramda": "^0.26.34", - "@types/react": "^16.9.11", - "@types/react-dom": "^16.9.4", - "@types/storybook__react": "^4.0.2", - "@typescript-eslint/eslint-plugin": "^2.7.0", - "@typescript-eslint/parser": "^2.7.0", - "babel-loader": "8.0.5", - "babel-plugin-import": "^1.12.1", - "eslint": "^6.6.0", - "eslint-config-prettier": "^6.5.0", - "eslint-plugin-prettier": "^3.1.1", - "node-sass": "^4.13.0", - "prettier": "^1.19.1", - "react-scripts": "^3.2.0", - "sass-loader": "^8.0.0", - "typescript-eslint-parser": "^22.0.0" - } + "name": "coderoad-app", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "react-scripts build", + "postbuild": "cp -R ./build/ ../build/", + "build-storybook": "build-storybook", + "start": "react-scripts start", + "storybook": "start-storybook -p 6006", + "test": "react-scripts test" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "eslintConfig": { + "extends": "react-app" + }, + "dependencies": { + "@alifd/next": "^1.18.16", + "@alifd/theme-4": "^0.2.0", + "@apollo/react-hooks": "^3.1.3", + "apollo-boost": "^0.4.4", + "graphql": "^14.5.8", + "markdown-it": "^10.0.0", + "markdown-it-emoji": "^1.4.0", + "markdown-it-prism": "^2.0.3", + "moment": "^2.24.0", + "prismjs": "^1.17.1", + "ramda": "^0.26.1", + "react": "^16.12.0", + "react-dom": "^16.12.0", + "reselect": "^4.0.0", + "typescript": "^3.7.2", + "xstate": "^4.6.7" + }, + "devDependencies": { + "@babel/core": "^7.5.4", + "@storybook/addon-actions": "^5.2.6", + "@storybook/addon-knobs": "^5.2.6", + "@storybook/addon-links": "^5.2.6", + "@storybook/addons": "^5.2.6", + "@storybook/react": "^5.2.6", + "@types/graphql": "^14.5.0", + "@types/highlight.js": "^9.12.3", + "@types/jest": "^24.0.23", + "@types/markdown-it": "0.0.9", + "@types/node": "^12.12.8", + "@types/prismjs": "^1.16.0", + "@types/ramda": "^0.26.34", + "@types/react": "^16.9.11", + "@types/react-dom": "^16.9.4", + "@types/storybook__react": "^4.0.2", + "@typescript-eslint/eslint-plugin": "^2.7.0", + "@typescript-eslint/parser": "^2.7.0", + "babel-loader": "8.0.5", + "babel-plugin-import": "^1.12.1", + "eslint": "^6.6.0", + "eslint-config-prettier": "^6.5.0", + "eslint-plugin-prettier": "^3.1.1", + "node-sass": "^4.13.0", + "prettier": "^1.19.1", + "react-scripts": "^3.2.0", + "sass-loader": "^8.0.0", + "typescript-eslint-parser": "^22.0.0" + } } diff --git a/web-app/src/services/apollo/queries/tutorial.ts b/web-app/src/services/apollo/queries/tutorial.ts index 64d43efa..9abb2735 100644 --- a/web-app/src/services/apollo/queries/tutorial.ts +++ b/web-app/src/services/apollo/queries/tutorial.ts @@ -44,7 +44,7 @@ export default gql` commits commands files - listeners + watchers } solution { commits