From e2d572f3c693c7251b72853fce383294b9c0d036 Mon Sep 17 00:00:00 2001 From: Josh Smeaton Date: Thu, 29 Mar 2018 16:10:45 +1100 Subject: [PATCH 1/2] Began adding black formatter --- package.json | 18 +++++++++++- src/client/common/types.ts | 5 +++- src/client/formatters/blackFormatter.ts | 37 +++++++++++++++++++++++++ src/client/formatters/types.ts | 2 +- src/client/providers/formatProvider.ts | 5 +++- src/client/telemetry/types.ts | 2 +- 6 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 src/client/formatters/blackFormatter.ts diff --git a/package.json b/package.json index 26d728dd09ba..d9251804d8d1 100644 --- a/package.json +++ b/package.json @@ -1515,7 +1515,8 @@ "enum": [ "autopep8", "yapf", - "none" + "none", + "black" ], "scope": "resource" }, @@ -1531,6 +1532,12 @@ "description": "Path to yapf, you can use a custom version of yapf by modifying this setting to include the full path.", "scope": "resource" }, + "python.formatting.blackPath": { + "type": "string", + "default": "black", + "description": "Path to black, you can use a custom version of black by modifying this setting to include the full path.", + "scope": "resource" + }, "python.formatting.autopep8Args": { "type": "array", "description": "Arguments passed in. Each argument is a separate item in the array.", @@ -1549,6 +1556,15 @@ }, "scope": "resource" }, + "python.formatting.blackArgs": { + "type": "array", + "description": "Arguments passed in. Each argument is a separate item in the array.", + "default": [], + "items": { + "type": "string" + }, + "scope": "resource" + }, "python.autoComplete.preloadModules": { "type": "array", "items": { diff --git a/src/client/common/types.ts b/src/client/common/types.ts index f64617178288..b81fbe593a17 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -62,7 +62,8 @@ export enum Product { unittest = 12, ctags = 13, rope = 14, - isort = 15 + isort = 15, + black = 16 } export enum ModuleNamePurpose { @@ -193,6 +194,8 @@ export interface IFormattingSettings { readonly autopep8Args: string[]; yapfPath: string; readonly yapfArgs: string[]; + blackPath: string; + readonly blackArgs: string[]; } export interface IAutoCompeteSettings { readonly addBrackets: boolean; diff --git a/src/client/formatters/blackFormatter.ts b/src/client/formatters/blackFormatter.ts new file mode 100644 index 000000000000..a2a159f701d4 --- /dev/null +++ b/src/client/formatters/blackFormatter.ts @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +import * as vscode from 'vscode'; +import { StopWatch } from '../common/stopWatch'; +import { IConfigurationService, Product } from '../common/types'; +import { IServiceContainer } from '../ioc/types'; +import { sendTelemetryWhenDone } from '../telemetry'; +import { FORMAT } from '../telemetry/constants'; +import { BaseFormatter } from './baseFormatter'; + +export class BlackFormatter extends BaseFormatter { + constructor(serviceContainer: IServiceContainer) { + super('black', Product.black, serviceContainer); + } + + public formatDocument(document: vscode.TextDocument, options: vscode.FormattingOptions, token: vscode.CancellationToken, range?: vscode.Range): Thenable { + const stopWatch = new StopWatch(); + const settings = this.serviceContainer.get(IConfigurationService).getSettings(document.uri); + const hasCustomArgs = Array.isArray(settings.formatting.blackArgs) && settings.formatting.blackArgs.length > 0; + const formatSelection = false; // range ? !range.isEmpty : false; + + const args = []; + // if (formatSelection) { + // // tslint:disable-next-line:no-non-null-assertion + // args.push(...['--lines', `${range!.start.line + 1}-${range!.end.line + 1}`]); + // } + // Yapf starts looking for config file starting from the file path. + const fallbarFolder = this.getWorkspaceUri(document).fsPath; + const cwd = this.getDocumentPath(document, fallbarFolder); + const promise = super.provideDocumentFormattingEdits(document, options, token, args, cwd); + sendTelemetryWhenDone(FORMAT, promise, stopWatch, { tool: 'black', hasCustomArgs, formatSelection }); + return promise; + } +} diff --git a/src/client/formatters/types.ts b/src/client/formatters/types.ts index d21ace78bb4f..e49ee9bc4f0e 100644 --- a/src/client/formatters/types.ts +++ b/src/client/formatters/types.ts @@ -6,7 +6,7 @@ import { ExecutionInfo, IFormattingSettings, Product } from '../common/types'; export const IFormatterHelper = Symbol('IFormatterHelper'); -export type FormatterId = 'autopep8' | 'yapf'; +export type FormatterId = 'autopep8' | 'yapf' | 'black'; export type FormatterSettingsPropertyNames = { argsName: keyof IFormattingSettings; diff --git a/src/client/providers/formatProvider.ts b/src/client/providers/formatProvider.ts index cabab87018e8..911be345575d 100644 --- a/src/client/providers/formatProvider.ts +++ b/src/client/providers/formatProvider.ts @@ -8,6 +8,7 @@ import { IConfigurationService } from '../common/types'; import { IServiceContainer } from '../ioc/types'; import { AutoPep8Formatter } from './../formatters/autoPep8Formatter'; import { BaseFormatter } from './../formatters/baseFormatter'; +import { BlackFormatter } from './../formatters/blackFormatter'; import { DummyFormatter } from './../formatters/dummyFormatter'; import { YapfFormatter } from './../formatters/yapfFormatter'; @@ -27,16 +28,18 @@ export class PythonFormattingEditProvider implements vscode.DocumentFormattingEd public constructor(context: vscode.ExtensionContext, serviceContainer: IServiceContainer) { const yapfFormatter = new YapfFormatter(serviceContainer); const autoPep8 = new AutoPep8Formatter(serviceContainer); + const blackFormatter = new BlackFormatter(serviceContainer); const dummy = new DummyFormatter(serviceContainer); this.formatters.set(yapfFormatter.Id, yapfFormatter); this.formatters.set(autoPep8.Id, autoPep8); + this.formatters.set(blackFormatter.Id, blackFormatter); this.formatters.set(dummy.Id, dummy); this.commands = serviceContainer.get(ICommandManager); this.workspace = serviceContainer.get(IWorkspaceService); this.documentManager = serviceContainer.get(IDocumentManager); this.config = serviceContainer.get(IConfigurationService); - this.disposables.push(this.documentManager.onDidSaveTextDocument(async document => await this.onSaveDocument(document))); + this.disposables.push(this.documentManager.onDidSaveTextDocument(async document => this.onSaveDocument(document))); } public dispose() { diff --git a/src/client/telemetry/types.ts b/src/client/telemetry/types.ts index dcb355155f45..aad06d6b79e1 100644 --- a/src/client/telemetry/types.ts +++ b/src/client/telemetry/types.ts @@ -7,7 +7,7 @@ export type EditorLoadTelemetry = { condaVersion: string; }; export type FormatTelemetry = { - tool: 'autopep8' | 'yapf'; + tool: 'autopep8' | 'yapf' | 'black'; hasCustomArgs: boolean; formatSelection: boolean; }; From ae2a693966f1b8de8fad5ec3a4c38f1063820282 Mon Sep 17 00:00:00 2001 From: Josh Smeaton Date: Sat, 7 Apr 2018 22:22:36 +1000 Subject: [PATCH 2/2] Black is working now --- requirements.txt | 1 + src/client/common/configSettings.ts | 4 +- .../common/installer/productInstaller.ts | 2 + src/client/common/installer/productNames.ts | 1 + src/client/formatters/baseFormatter.ts | 2 +- src/client/formatters/blackFormatter.ts | 9 +- src/client/formatters/helper.ts | 1 + yarn.lock | 87 ++++++++++++++++++- 8 files changed, 98 insertions(+), 9 deletions(-) diff --git a/requirements.txt b/requirements.txt index 439a8d6999b7..b63dcd211a78 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ autopep8 yapf +black pylint pep8 prospector diff --git a/src/client/common/configSettings.ts b/src/client/common/configSettings.ts index b88b82ce65bf..7af45967304c 100644 --- a/src/client/common/configSettings.ts +++ b/src/client/common/configSettings.ts @@ -213,10 +213,12 @@ export class PythonSettings extends EventEmitter implements IPythonSettings { this.formatting = this.formatting ? this.formatting : { autopep8Args: [], autopep8Path: 'autopep8', provider: 'autopep8', - yapfArgs: [], yapfPath: 'yapf' + yapfArgs: [], yapfPath: 'yapf', + blackArgs: [], blackPath: 'black' }; this.formatting.autopep8Path = getAbsolutePath(systemVariables.resolveAny(this.formatting.autopep8Path), workspaceRoot); this.formatting.yapfPath = getAbsolutePath(systemVariables.resolveAny(this.formatting.yapfPath), workspaceRoot); + this.formatting.blackPath = getAbsolutePath(systemVariables.resolveAny(this.formatting.blackPath), workspaceRoot); // tslint:disable-next-line:no-backbone-get-set-outside-model no-non-null-assertion const autoCompleteSettings = systemVariables.resolveAny(pythonSettings.get('autoComplete'))!; diff --git a/src/client/common/installer/productInstaller.ts b/src/client/common/installer/productInstaller.ts index 15610472ad80..7b5e5e6c3e0d 100644 --- a/src/client/common/installer/productInstaller.ts +++ b/src/client/common/installer/productInstaller.ts @@ -128,6 +128,7 @@ class FormatterInstaller extends BaseInstaller { const productName = ProductNames.get(product)!; const installThis = `Install ${productName}`; + // TODO(Josh): Wat const alternateFormatter = product === Product.autopep8 ? 'yapf' : 'autopep8'; const useOtherFormatter = `Use '${alternateFormatter}' formatter`; const item = await this.appShell.showErrorMessage(`Formatter ${productName} is not installed.`, installThis, useOtherFormatter); @@ -231,6 +232,7 @@ export class ProductInstaller implements IInstaller { this.ProductTypes.set(Product.unittest, ProductType.TestFramework); this.ProductTypes.set(Product.autopep8, ProductType.Formatter); this.ProductTypes.set(Product.yapf, ProductType.Formatter); + this.ProductTypes.set(Product.black, ProductType.Formatter); this.ProductTypes.set(Product.rope, ProductType.RefactoringLibrary); } diff --git a/src/client/common/installer/productNames.ts b/src/client/common/installer/productNames.ts index 9371f540c778..4bdb79277a58 100644 --- a/src/client/common/installer/productNames.ts +++ b/src/client/common/installer/productNames.ts @@ -16,4 +16,5 @@ ProductNames.set(Product.pydocstyle, 'pydocstyle'); ProductNames.set(Product.pylint, 'pylint'); ProductNames.set(Product.pytest, 'pytest'); ProductNames.set(Product.yapf, 'yapf'); +ProductNames.set(Product.black, 'black'); ProductNames.set(Product.rope, 'rope'); diff --git a/src/client/formatters/baseFormatter.ts b/src/client/formatters/baseFormatter.ts index 9e91b00a5a19..fb981c028fb5 100644 --- a/src/client/formatters/baseFormatter.ts +++ b/src/client/formatters/baseFormatter.ts @@ -59,7 +59,7 @@ export abstract class BaseFormatter { const executionInfo = this.helper.getExecutionInfo(this.product, args, document.uri); executionInfo.args.push(tempFile); const pythonToolsExecutionService = this.serviceContainer.get(IPythonToolExecutionService); - const promise = pythonToolsExecutionService.exec(executionInfo, { cwd, throwOnStdErr: true, token }, document.uri) + const promise = pythonToolsExecutionService.exec(executionInfo, { cwd, throwOnStdErr: false, token }, document.uri) .then(output => output.stdout) .then(data => { if (this.checkCancellation(document.fileName, tempFile, token)) { diff --git a/src/client/formatters/blackFormatter.ts b/src/client/formatters/blackFormatter.ts index a2a159f701d4..fb83b3f4132b 100644 --- a/src/client/formatters/blackFormatter.ts +++ b/src/client/formatters/blackFormatter.ts @@ -22,16 +22,17 @@ export class BlackFormatter extends BaseFormatter { const hasCustomArgs = Array.isArray(settings.formatting.blackArgs) && settings.formatting.blackArgs.length > 0; const formatSelection = false; // range ? !range.isEmpty : false; - const args = []; + const args = ['--diff']; // if (formatSelection) { + // black does not support partial formatting, throw an error? // // tslint:disable-next-line:no-non-null-assertion // args.push(...['--lines', `${range!.start.line + 1}-${range!.end.line + 1}`]); // } // Yapf starts looking for config file starting from the file path. - const fallbarFolder = this.getWorkspaceUri(document).fsPath; - const cwd = this.getDocumentPath(document, fallbarFolder); + const fallbackFolder = this.getWorkspaceUri(document).fsPath; + const cwd = this.getDocumentPath(document, fallbackFolder); const promise = super.provideDocumentFormattingEdits(document, options, token, args, cwd); - sendTelemetryWhenDone(FORMAT, promise, stopWatch, { tool: 'black', hasCustomArgs, formatSelection }); + //sendTelemetryWhenDone(FORMAT, promise, stopWatch, { tool: 'black', hasCustomArgs, formatSelection }); return promise; } } diff --git a/src/client/formatters/helper.ts b/src/client/formatters/helper.ts index b491c40baaa2..d12d58343ea8 100644 --- a/src/client/formatters/helper.ts +++ b/src/client/formatters/helper.ts @@ -16,6 +16,7 @@ export class FormatterHelper implements IFormatterHelper { switch (formatter) { case Product.autopep8: return 'autopep8'; case Product.yapf: return 'yapf'; + case Product.black: return 'black'; default: { throw new Error(`Unrecognized Formatter '${formatter}'`); } diff --git a/yarn.lock b/yarn.lock index 7027a7bdcfbc..ab6f8e5cb7b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -470,6 +470,13 @@ binary-extensions@^1.0.0: version "1.11.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" +"binary@>= 0.3.0 < 1": + version "0.3.0" + resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" + dependencies: + buffers "~0.1.1" + chainsaw "~0.1.0" + block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" @@ -550,6 +557,10 @@ buffer-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" +buffers@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" + builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -619,6 +630,12 @@ chai@^4.1.2: pathval "^1.0.0" type-detect "^4.0.0" +chainsaw@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" + dependencies: + traverse ">=0.3.0 <0.4" + chalk@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" @@ -1472,6 +1489,15 @@ fstream-ignore@^1.0.5: inherits "2" minimatch "^3.0.0" +"fstream@>= 0.1.30 < 1": + version "0.1.31" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-0.1.31.tgz#7337f058fbbbbefa8c9f561a28cab0849202c988" + dependencies: + graceful-fs "~3.0.2" + inherits "~2.0.0" + mkdirp "0.5" + rimraf "2" + fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: version "1.0.11" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" @@ -1695,7 +1721,7 @@ graceful-fs@4.X, graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, gr version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -graceful-fs@^3.0.0: +graceful-fs@^3.0.0, graceful-fs@~3.0.2: version "3.0.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" dependencies: @@ -2915,6 +2941,13 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +"match-stream@>= 0.0.2 < 1": + version "0.0.2" + resolved "https://registry.yarnpkg.com/match-stream/-/match-stream-0.0.2.tgz#99eb050093b34dffade421b9ac0b410a9cfa17cf" + dependencies: + buffers "~0.1.1" + readable-stream "~1.0.0" + md5.js@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" @@ -3052,7 +3085,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: +mkdirp@0.5, mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -3367,6 +3400,10 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +"over@>= 0.0.5 < 1": + version "0.0.5" + resolved "https://registry.yarnpkg.com/over/-/over-0.0.5.tgz#f29852e70fd7e25f360e013a8ec44c82aedb5708" + p-map@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" @@ -3547,6 +3584,15 @@ pseudomap@^1.0.1, pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" +"pullstream@>= 0.4.1 < 1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/pullstream/-/pullstream-0.4.1.tgz#d6fb3bf5aed697e831150eb1002c25a3f8ae1314" + dependencies: + over ">= 0.0.5 < 1" + readable-stream "~1.0.31" + setimmediate ">= 1.0.2 < 2" + slice-stream ">= 1.0.0 < 2" + pump@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" @@ -3625,7 +3671,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -"readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.17: +"readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.0, readable-stream@~1.0.17, readable-stream@~1.0.31: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: @@ -3763,6 +3809,12 @@ replace-ext@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" +request-progress@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" + dependencies: + throttleit "^1.0.0" + request@2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" @@ -3986,6 +4038,10 @@ set-value@^2.0.0: is-plain-object "^2.0.3" split-string "^3.0.1" +"setimmediate@>= 1.0.1 < 2", "setimmediate@>= 1.0.2 < 2": + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + shortid@^2.2.8: version "2.2.8" resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.8.tgz#033b117d6a2e975804f6f0969dbe7d3d0b355131" @@ -4014,6 +4070,12 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" +"slice-stream@>= 1.0.0 < 2": + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-stream/-/slice-stream-1.0.0.tgz#5b33bd66f013b1a7f86460b03d463dec39ad3ea0" + dependencies: + readable-stream "~1.0.31" + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -4341,6 +4403,10 @@ text-encoding@^0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19" +throttleit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + through2-filter@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec" @@ -4450,6 +4516,10 @@ tough-cookie@~2.3.0, tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" +"traverse@>=0.3.0 <0.4": + version "0.3.9" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" + tree-kill@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36" @@ -4620,6 +4690,17 @@ untildify@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.2.tgz#7f1f302055b3fea0f3e81dc78eb36766cb65e3f1" +unzip@^0.1.11: + version "0.1.11" + resolved "https://registry.yarnpkg.com/unzip/-/unzip-0.1.11.tgz#89749c63b058d7d90d619f86b98aa1535d3b97f0" + dependencies: + binary ">= 0.3.0 < 1" + fstream ">= 0.1.30 < 1" + match-stream ">= 0.0.2 < 1" + pullstream ">= 0.4.1 < 1" + readable-stream "~1.0.31" + setimmediate ">= 1.0.1 < 2" + upath@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.4.tgz#ee2321ba0a786c50973db043a50b7bcba822361d"