From b0856fdbc296013c3be5468b410c8ee1e2cd85ba Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 8 May 2019 13:06:07 -0700 Subject: [PATCH] init --- .gitignore | 82 +++++ .npmignore | 2 + LICENSE | 21 ++ package-lock.json | 692 +++++++++++++++++++++++++++++++++++++++ package.json | 55 ++++ readme.md | 23 ++ src/index.ts | 35 ++ src/master.ts | 45 +++ src/progress-reporter.ts | 64 ++++ src/protocol.ts | 79 +++++ src/worker-pool.ts | 63 ++++ src/worker.ts | 83 +++++ tsconfig.json | 17 + tslint.json | 7 + 14 files changed, 1268 insertions(+) create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 LICENSE create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 readme.md create mode 100644 src/index.ts create mode 100644 src/master.ts create mode 100644 src/progress-reporter.ts create mode 100644 src/protocol.ts create mode 100644 src/worker-pool.ts create mode 100644 src/worker.ts create mode 100644 tsconfig.json create mode 100644 tslint.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57f5061 --- /dev/null +++ b/.gitignore @@ -0,0 +1,82 @@ + +# Created by https://www.gitignore.io/api/node + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless + + +# End of https://www.gitignore.io/api/node + +/dist diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..7e7a454 --- /dev/null +++ b/.npmignore @@ -0,0 +1,2 @@ +/* +!/dist diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5ae193c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f93625d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,692 @@ +{ + "name": "@mixer/parallel-prettier", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha1-BuKrGb21NThVWaq7W6WXKUgoAPg=", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha1-9xDDjI1Fjm3ZogGvtjf8t4HOmeQ=", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/@types/events/-/events-3.0.0.tgz", + "integrity": "sha1-KGLz9Yqaf3w+eNefEw3U1xwlwqc=", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-qlmhxuP7xCHgfM0xqUTDDrpSFXU=", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/glob-stream": { + "version": "6.1.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/@types/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-ft6KM+WRQFNPjYrfuKye37MYl7w=", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha1-PcoOPzOyAPx9ETnAzZbBJoyt/Z0=", + "dev": true + }, + "@types/node": { + "version": "12.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/@types/node/-/node-12.0.0.tgz", + "integrity": "sha1-0RgTucD/iqyinwTLwSgX9MfWVuU=", + "dev": true + }, + "@types/prettier": { + "version": "1.16.3", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/@types/prettier/-/prettier-1.16.3.tgz", + "integrity": "sha1-FBvfTcuqwG/Ss/BeIz/yO2aGb58=", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-spinners": { + "version": "2.1.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/cli-spinners/-/cli-spinners-2.1.0.tgz", + "integrity": "sha1-IsNLTVH1cyQIhbIB79pOTsn/88c=" + }, + "clone": { + "version": "1.0.4", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "commander": { + "version": "2.20.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/commander/-/commander-2.20.0.tgz", + "integrity": "sha1-1YuytcHuj4ew00ACfp6U4iLFpCI=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "requires": { + "clone": "^1.0.2" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/diff/-/diff-3.5.0.tgz", + "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk=", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", + "requires": { + "once": "^1.4.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "extend": { + "version": "3.0.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/extend/-/extend-3.0.2.tgz", + "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.4", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/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" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "requires": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=", + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=" + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=", + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha1-r/FRswv9+o5J4F2iLnQV6d+jeEc=", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=", + "requires": { + "chalk": "^2.0.1" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "ora": { + "version": "3.4.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/ora/-/ora-3.4.0.tgz", + "integrity": "sha1-vwdSSRBZo+8+1MhQl1Md6f280xg=", + "requires": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + } + }, + "ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "requires": { + "readable-stream": "^2.0.1" + } + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=", + "dev": true + }, + "prettier": { + "version": "1.17.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/prettier/-/prettier-1.17.0.tgz", + "integrity": "sha1-U7MDZ27tIswUqfDOwJtHezAmwAg=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" + }, + "pump": { + "version": "2.0.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/pump/-/pump-2.0.1.tgz", + "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4=", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", + "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" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "resolve": { + "version": "1.10.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/resolve/-/resolve-1.10.1.tgz", + "integrity": "sha1-ZkhCrJYHlbvnWCIc3M2mH7ZLXxg=", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "rxjs": { + "version": "6.5.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/rxjs/-/rxjs-6.5.1.tgz", + "integrity": "sha1-96AFqThjYZIbhSTzj1TL+A5dCPQ=", + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" + }, + "semver": { + "version": "5.7.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/semver/-/semver-5.7.0.tgz", + "integrity": "sha1-eQp89v6lRZuslhELKbYEEtyP+Ws=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "requires": { + "has-flag": "^3.0.0" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/through2/-/through2-2.0.5.tgz", + "integrity": "sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0=", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "through2-filter": { + "version": "3.0.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha1-cA54bfI2fCyIzYqlvkz5weeDElQ=", + "requires": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "requires": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + } + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha1-1+TdeSRdhUKMTX5IIqeZF5VMooY=" + }, + "tslint": { + "version": "5.16.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/tslint/-/tslint-5.16.0.tgz", + "integrity": "sha1-rmH5xamNKVuaT0VTsbHoMcGYTWc=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.13.0", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + } + }, + "tslint-config-prettier": { + "version": "1.18.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz", + "integrity": "sha1-dfFAvelH012PDSOODr+AnWRZLDc=", + "dev": true + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha1-MrSIUBRnrL7dS4VJhnOggSrKC5k=", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "typescript": { + "version": "3.4.5", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/typescript/-/typescript-3.4.5.tgz", + "integrity": "sha1-LSYY0Qu1ZlcrjXqtUYDYQlfXCpk=", + "dev": true + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, + "unique-stream": { + "version": "2.3.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha1-xl0RDppK35psWUiygFPZqNBMvqw=", + "requires": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "requires": { + "defaults": "^1.0.3" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://watchmixer.pkgs.visualstudio.com/_packaging/mixer/npm/registry/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..58da7dd --- /dev/null +++ b/package.json @@ -0,0 +1,55 @@ +{ + "name": "@mixer/parallel-prettier", + "version": "1.0.0", + "description": "Concurrent prettier runner", + "main": "./dist/index.js", + "bin": { + "pprettier": "./dist/index.js" + }, + "scripts": { + "prepare": "tsc", + "build": "tsc", + "fmt": "node dist/index --write \"src/**/*.ts\" && npm run test:lint -- --fix", + "test": "npm run test:lint && npm run test:fmt", + "test:lint": "tslint --project tsconfig.json \"src/**/*.ts\"", + "test:fmt": "node dist/index \"src/**/*.ts\" --check" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/mixer/parallel-prettier.git" + }, + "keywords": [ + "prettier", + "parallel", + "concurrent", + "mixer" + ], + "author": "Connor Peet ", + "license": "MIT", + "bugs": { + "url": "https://github.com/mixer/parallel-prettier/issues" + }, + "homepage": "https://github.com/mixer/parallel-prettier#readme", + "dependencies": { + "chalk": "^2.4.2", + "commander": "^2.20.0", + "glob-stream": "^6.1.0", + "ora": "^3.4.0", + "prettier": "^1.17.0", + "rxjs": "^6.5.1" + }, + "devDependencies": { + "@types/glob-stream": "^6.1.0", + "@types/node": "^12.0.0", + "@types/prettier": "^1.16.3", + "tslint": "^5.16.0", + "tslint-config-prettier": "^1.18.0", + "typescript": "^3.4.5" + }, + "prettier": { + "trailingComma": "all", + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2 + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..8d2ae9f --- /dev/null +++ b/readme.md @@ -0,0 +1,23 @@ +# @mixer/parallel-prettier + +A wrapper around [prettier]() that formats files in parallel to speed up large projects. + +``` +npm install -g @mixer/parallel-prettier +``` + +After installing the CLI, the `pprettier` command will be available to you. + +### Ad-hoc Performance + +``` +# 300 file project: + +prettier --write "src/**/*.{ts,tsx,json,scss}" 6.57s user 0.55s system 131% cpu 5.405 total +pprettier --write "src/**/*.{ts,tsx,json,scss}" 0.41s user 0.08s system 14% cpu 3.455 total + +# 1200 file project: + +prettier --write "src/**/*.{ts,tsx,json,scss}" 27.09s user 3.26s system 123% cpu 24.496 total +pprettier --write "src/**/*.{ts,tsx,json,scss}" 1.21s user 0.27s system 14% cpu 10.580 total +``` diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..7507ce1 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,35 @@ +#!/usr/bin/env node + +import * as cluster from 'cluster'; +import * as commander from 'commander'; +import { cpus } from 'os'; +import * as prettier from 'prettier'; + +const { version } = require('../package.json'); + +function startMaster() { + const program: any = commander + .option( + '--check, --list-different', + 'Whether to list unformatted files, instead of writing them out', + ) + .option('--write', 'Whether to write files to the output') + .option('--concurrency [value]', 'Maximum concurrency', cpus().length) + .option('--quiet, -q', 'If set, pprettier will not output progress') + .version(`@mixer/parallel-prettier version ${version} / prettier version ${prettier.version}`) + .parse(process.argv); + + require('./master').spawnWorkers({ + check: program.listDifferent, + concurrency: program.concurrency, + files: program.args, + quiet: program.quiet, + write: program.write, + }); +} + +if (module === require.main && cluster.isMaster) { + startMaster(); +} else if (cluster.isWorker) { + require('./worker').startWorker(); +} diff --git a/src/master.ts b/src/master.ts new file mode 100644 index 0000000..76c3d94 --- /dev/null +++ b/src/master.ts @@ -0,0 +1,45 @@ +import * as globStream from 'glob-stream'; +import { Observable } from 'rxjs'; +import { bufferCount, mergeMap } from 'rxjs/operators'; + +import { ProgressReporter } from './progress-reporter'; +import { IOptions } from './protocol'; +import { WorkerPool } from './worker-pool'; + +const bufferSize = 50; + +function runGlobs(files: string[]) { + return new Observable(subscriber => { + const stream = globStream(files); + stream.addListener('data', data => subscriber.next(data)); + stream.addListener('error', err => subscriber.error(err)); + stream.addListener('finish', () => subscriber.complete()); + stream.resume(); + }); +} + +export function spawnWorkers(options: IOptions) { + const pool = new WorkerPool(options); + const progress = new ProgressReporter(options.quiet, options.check); + + runGlobs(options.files) + .pipe( + bufferCount(bufferSize), + mergeMap(files => pool.format(files)), + ) + .subscribe( + result => progress.update(result), + err => { + throw err; + }, + () => { + progress.complete(); + + if (progress.reformatted && options.check) { + process.exit(1); + } else { + process.exit(0); + } + }, + ); +} diff --git a/src/progress-reporter.ts b/src/progress-reporter.ts new file mode 100644 index 0000000..69eaa82 --- /dev/null +++ b/src/progress-reporter.ts @@ -0,0 +1,64 @@ +import * as ora from 'ora'; +import { relative } from 'path'; +import { IFormatResults } from './protocol'; + +/** + * Handles reporting progress of the formatting to the console. + */ +export class ProgressReporter { + public total = 0; + public reformatted = 0; + private spinner?: ora.Ora; + + constructor(quiet: boolean, private readonly check: boolean) { + if (!quiet) { + this.spinner = ora('Starting...').start(); + } + } + + /** + * Increments the count of the total and reformatted files. + */ + public update(results: IFormatResults) { + this.total += results.files; + this.reformatted += results.formatted.length; + + if (results.formatted.length) { + if (this.spinner) { + this.spinner.stop(); + } + + for (const file of results.formatted) { + process.stdout.write(`${relative(file.base, file.path)}\r\n`); + } + + if (this.spinner) { + this.spinner.text = this.getMessage(); + this.spinner.start(); + } + } else if (this.spinner) { + this.spinner.text = this.getMessage(); + } + } + + /** + * Prints a completion message. + */ + public complete() { + if (!this.spinner) { + return; + } + + if (this.check && this.reformatted) { + this.spinner.fail(`${this.reformatted} files were not formatted`); + } else { + this.spinner.succeed(this.getMessage()); + } + } + + private getMessage() { + return this.check + ? `Checked ${this.total} files` + : `Reformatted ${this.reformatted} / ${this.total} files...`; + } +} diff --git a/src/protocol.ts b/src/protocol.ts new file mode 100644 index 0000000..e8b1984 --- /dev/null +++ b/src/protocol.ts @@ -0,0 +1,79 @@ +/** + * MessageType delimits the kind of message sent in the formatter IPC. + */ +export const enum MessageType { + WorkerInitialization, + WorkerFiles, + Formatted, + Complete, +} + +export const enum WorkerMode { + Write, + Print, + Assert, +} + +/** + * An InitializationMessage is sent from + * the master to queue work on its workers. + */ +export interface IInitializationMessage { + type: MessageType.WorkerInitialization; + mode: WorkerMode.Write; +} + +/** + * IFiles is sent to queue files to format on the worker. + */ +export interface IFilesMessage { + type: MessageType.WorkerFiles; + files: IDiscoveredFile[]; + id: number; +} + +/** + * MasterMessage is sent from the cluster master to its workers. + */ +export type MasterMessage = IInitializationMessage | IFilesMessage; + +/** + * Results returned from formatting files. + */ +export interface IFormatResults { + files: number; + formatted: IDiscoveredFile[]; +} + +/** + * Format message received from a worker. + */ +export interface IFormattedMessage extends IFormatResults { + type: MessageType.Formatted; + id: number; +} + +/** + * Discovered file item. + */ +export interface IDiscoveredFile { + cwd: string; + base: string; + path: string; +} + +/** + * Mesage is sent from the worker to the parent process. + */ +export type WorkerMessage = IFormattedMessage; + +/** + * Top-level options for the formatter. + */ +export interface IOptions { + check: boolean; + write: boolean; + concurrency: number; + quiet: boolean; + files: string[]; +} diff --git a/src/worker-pool.ts b/src/worker-pool.ts new file mode 100644 index 0000000..50a07cb --- /dev/null +++ b/src/worker-pool.ts @@ -0,0 +1,63 @@ +import * as cluster from 'cluster'; +import { fromEvent, Observable } from 'rxjs'; +import { filter, map, take, tap } from 'rxjs/operators'; +import { + IFormatResults, + IInitializationMessage, + IOptions, + MessageType, + WorkerMessage, + WorkerMode, +} from './protocol'; + +/** + * Pool of workers. + */ +export class WorkerPool { + private readonly workers: Array<{ worker: cluster.Worker; active: number }> = []; + private workIdCounter: number = 0; + + constructor(private readonly options: IOptions) {} + + /** + * Schedules the given files to be formatted. + */ + public format(files: string[]): Observable { + if (this.workers.length < this.options.concurrency) { + this.spawnWorker(); + } + + const target = this.workers[0]; + const id = this.workIdCounter++; + target.active++; + target.worker.send({ type: MessageType.WorkerFiles, files, id }); + this.sortWorkers(); + + return fromEvent<[WorkerMessage]>(target.worker, 'message').pipe( + map(([m]) => m), + filter(m => m.id === id), + take(1), + tap(() => { + target.active--; + this.sortWorkers(); + }), + ); + } + + private sortWorkers() { + this.workers.sort((a, b) => a.active - b.active); + } + + private spawnWorker() { + const worker = { worker: cluster.fork(), active: 0 }; + this.workers.unshift(worker); + worker.worker.send({ + mode: this.options.check + ? WorkerMode.Assert + : this.options.write + ? WorkerMode.Write + : WorkerMode.Print, + type: MessageType.WorkerInitialization, + } as IInitializationMessage); + } +} diff --git a/src/worker.ts b/src/worker.ts new file mode 100644 index 0000000..3e3ef63 --- /dev/null +++ b/src/worker.ts @@ -0,0 +1,83 @@ +import { readFile, writeFile } from 'fs'; +import * as prettier from 'prettier'; +import { combineLatest, Observable, of, Subject } from 'rxjs'; +import { last, mergeMap } from 'rxjs/operators'; +import { promisify } from 'util'; +import { + IFilesMessage, + IFormattedMessage, + IInitializationMessage, + MasterMessage, + MessageType, + WorkerMessage, + WorkerMode, +} from './protocol'; + +const readFileAsync = promisify(readFile); +const writeFileAsync = promisify(writeFile); + +/** + * Reads the files from the observable stream and, with the specified + * concurrency, formats them. Returns a stream of results to send back + * to the master. + */ +function runFormatting( + settings: IInitializationMessage, + files: IFilesMessage, +): Observable { + const output: IFormattedMessage = { + files: files.files.length, + formatted: [], + id: files.id, + type: MessageType.Formatted, + }; + + return of(...files.files).pipe( + mergeMap(async file => { + const contents = await readFileAsync(file.path, 'utf-8'); + const formatted = prettier.format(contents, { + ...(await prettier.resolveConfig(file.path)), + filepath: file.path, + }); + + if (formatted === contents) { + return output; + } + + if (settings.mode === WorkerMode.Write) { + await writeFileAsync(file.path, formatted); + } else if (settings.mode === WorkerMode.Print) { + process.stdout.write(formatted); + } + + output.formatted.push(file); + return output; + }), + last(), + ); +} + +export function startWorker() { + const settings = new Subject(); + const files = new Subject(); + + process.on('message', (data: MasterMessage) => { + switch (data.type) { + case MessageType.WorkerInitialization: + settings.next(data); + break; + case MessageType.WorkerFiles: + files.next(data); + break; + } + }); + + combineLatest(settings, files) + .pipe(mergeMap(([s, f]) => runFormatting(s, f))) + .subscribe( + message => process.send!(message), + err => { + throw err; + }, + ); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9e9f572 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "forceConsistentCasingInFileNames": true, + "sourceMap": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "strict": true, + "moduleResolution": "node", + "newLine": "LF", + "module": "commonjs", + "target": "es6", + "lib": ["es6", "es7"], + "outDir": "dist", + "types": ["node"] + } +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..4c33d6d --- /dev/null +++ b/tslint.json @@ -0,0 +1,7 @@ +{ + "$schema": "http://json.schemastore.org/tslint", + "extends": ["tslint:recommended", "tslint-config-prettier"], + "rules": { + "no-var-requires": false + } +}