diff --git a/.eslintrc b/.eslintrc index 75d90e364335..fe804c081f6a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -40,7 +40,16 @@ "no-useless-constructor": "off", "@typescript-eslint/no-useless-constructor": "error", "@typescript-eslint/no-var-requires": "off", + // Overriding formatting rules to let Prettier handle them + "comma-dangle": "off", + "function-paren-newline": "off", + "implicit-arrow-linebreak": "off", + "indent": "off", + "max-len": "off", + "object-curly-newline": ["error", {"ImportDeclaration": {"consistent": true}}], + "operator-linebreak": "off", // Other rules + "class-methods-use-this": ["error", {"exceptMethods": ["dispose"]}], "func-names": "off", "import/extensions": "off", "import/namespace": "off", @@ -52,24 +61,7 @@ } ], "import/prefer-default-export": "off", - "indent": [ - "error", - 4, - { - "SwitchCase": 1 - } - ], "linebreak-style": "off", - "max-len": [ - "warn", - { - "code": 120, - "ignorePattern": "^import\\s.+\\sfrom\\s.+;$", - "ignoreStrings": true, - "ignoreTemplateLiterals": true, - "ignoreUrls": true - } - ], "no-await-in-loop": "off", "no-confusing-arrow": [ "error", diff --git a/src/client/activation/jedi/languageServerProxy.ts b/src/client/activation/jedi/languageServerProxy.ts index dd5f2185976c..2915972ac2b9 100644 --- a/src/client/activation/jedi/languageServerProxy.ts +++ b/src/client/activation/jedi/languageServerProxy.ts @@ -30,10 +30,15 @@ import { ILanguageClientFactory, ILanguageServerProxy } from '../types'; @injectable() export class JediLanguageServerProxy implements ILanguageServerProxy { public languageClient: LanguageClient | undefined; + private startupCompleted: Deferred; + private cancellationStrategy: FileBasedCancellationStrategy | undefined; + private readonly disposables: Disposable[] = []; - private disposed: boolean = false; + + private disposed = false; + private lsVersion: string | undefined; constructor( @@ -53,7 +58,7 @@ export class JediLanguageServerProxy implements ILanguageServerProxy { } @traceDecorators.verbose('Stopping language server') - public dispose() { + public dispose(): void { if (this.languageClient) { // Do not await on this. this.languageClient.stop().then(noop, (ex) => traceError('Stopping language client failed', ex)); @@ -120,8 +125,10 @@ export class JediLanguageServerProxy implements ILanguageServerProxy { } } - // tslint:disable-next-line: no-empty - public loadExtension(_args?: {}) {} + // eslint-disable-next-line class-methods-use-this + public loadExtension(): void { + // No body. + } @captureTelemetry( EventName.LANGUAGE_SERVER_READY, @@ -141,7 +148,7 @@ export class JediLanguageServerProxy implements ILanguageServerProxy { } @swallowExceptions('Activating Unit Tests Manager for Jedi language server') - protected async registerTestServices() { + protected async registerTestServices(): Promise { if (!this.languageClient) { throw new Error('languageClient not initialized'); } diff --git a/src/client/activation/jedi/manager.ts b/src/client/activation/jedi/manager.ts index ee19d1f428f9..c7173ce9172b 100644 --- a/src/client/activation/jedi/manager.ts +++ b/src/client/activation/jedi/manager.ts @@ -27,11 +27,17 @@ import { @injectable() export class JediLanguageServerManager implements ILanguageServerManager { private languageServerProxy?: ILanguageServerProxy; + private resource!: Resource; + private interpreter: PythonEnvironment | undefined; + private middleware: LanguageClientMiddleware | undefined; + private disposables: IDisposable[] = []; - private connected: boolean = false; + + private connected = false; + private lsVersion: string | undefined; constructor( @@ -54,14 +60,14 @@ export class JediLanguageServerManager implements ILanguageServerManager { }; } - public dispose() { + public dispose(): void { if (this.languageProxy) { this.languageProxy.dispose(); } this.disposables.forEach((d) => d.dispose()); } - public get languageProxy() { + public get languageProxy(): ILanguageServerProxy | undefined { return this.languageServerProxy; } @@ -80,6 +86,7 @@ export class JediLanguageServerManager implements ILanguageServerManager { // Search using a regex in the text const match = /jedi-language-server==([0-9\.]*)/.exec(requirementsTxt); if (match && match.length > 1) { + // eslint-disable-next-line prefer-destructuring this.lsVersion = match[1]; } else { this.lsVersion = '0.19.3'; @@ -89,12 +96,12 @@ export class JediLanguageServerManager implements ILanguageServerManager { await this.startLanguageServer(); } - public connect() { + public connect(): void { this.connected = true; this.middleware?.connect(); } - public disconnect() { + public disconnect(): void { this.connected = false; this.middleware?.disconnect(); } @@ -125,12 +132,13 @@ export class JediLanguageServerManager implements ILanguageServerManager { this.languageServerProxy = this.serviceContainer.get(ILanguageServerProxy); const options = await this.analysisOptions.getAnalysisOptions(); - options.middleware = this.middleware = new LanguageClientMiddleware( + this.middleware = new LanguageClientMiddleware( this.serviceContainer, LanguageServerType.Jedi, () => this.languageServerProxy?.languageClient, this.lsVersion ); + options.middleware = this.middleware; // Make sure the middleware is connected if we restart and we we're already connected. if (this.connected) { diff --git a/src/client/activation/jedi/multiplexingActivator.ts b/src/client/activation/jedi/multiplexingActivator.ts index aec716c55c3f..f8819b13b9cf 100644 --- a/src/client/activation/jedi/multiplexingActivator.ts +++ b/src/client/activation/jedi/multiplexingActivator.ts @@ -11,6 +11,7 @@ import { SignatureHelpContext, TextDocument } from 'vscode'; +import { ServerCapabilities } from 'vscode-languageserver-protocol'; // tslint:disable-next-line: import-name import { IWorkspaceService } from '../../common/application/types'; import { isTestExecution } from '../../common/constants'; @@ -26,7 +27,7 @@ import { import { IServiceManager } from '../../ioc/types'; import { PythonEnvironment } from '../../pythonEnvironments/info'; import { JediExtensionActivator } from '../jedi'; -import { ILanguageServerActivator, ILanguageServerManager } from '../types'; +import { ILanguageServerActivator, ILanguageServerConnection, ILanguageServerManager } from '../types'; import { JediLanguageServerActivator } from './activator'; /** @@ -40,7 +41,9 @@ import { JediLanguageServerActivator } from './activator'; @injectable() export class MultiplexingJediLanguageServerActivator implements ILanguageServerActivator { private realLanguageServerPromise: Promise; + private realLanguageServer: ILanguageServerActivator | undefined; + private onDidChangeCodeLensesEmitter = new EventEmitter(); constructor( @@ -64,6 +67,7 @@ export class MultiplexingJediLanguageServerActivator implements ILanguageServerA return this.realLanguageServer; }); } + public async start(resource: Resource, interpreter: PythonEnvironment | undefined): Promise { const realServer = await this.realLanguageServerPromise; if (!isTestExecution()) { @@ -71,30 +75,35 @@ export class MultiplexingJediLanguageServerActivator implements ILanguageServerA } return realServer.start(resource, interpreter); } + public activate(): void { if (this.realLanguageServer) { this.realLanguageServer.activate(); } } + public deactivate(): void { if (this.realLanguageServer) { this.realLanguageServer.deactivate(); } } + public get onDidChangeCodeLenses(): Event { return this.onDidChangeCodeLensesEmitter.event; } - public get connection() { + public get connection(): ILanguageServerConnection | undefined { if (this.realLanguageServer) { return this.realLanguageServer.connection; } + return undefined; } - public get capabilities() { + public get capabilities(): ServerCapabilities | undefined { if (this.realLanguageServer) { return this.realLanguageServer.capabilities; } + return undefined; } public async provideRenameEdits( @@ -106,14 +115,17 @@ export class MultiplexingJediLanguageServerActivator implements ILanguageServerA const server = await this.realLanguageServerPromise; return server.provideRenameEdits(document, position, newName, token); } + public async provideDefinition(document: TextDocument, position: Position, token: CancellationToken) { const server = await this.realLanguageServerPromise; return server.provideDefinition(document, position, token); } + public async provideHover(document: TextDocument, position: Position, token: CancellationToken) { const server = await this.realLanguageServerPromise; return server.provideHover(document, position, token); } + public async provideReferences( document: TextDocument, position: Position, @@ -123,6 +135,7 @@ export class MultiplexingJediLanguageServerActivator implements ILanguageServerA const server = await this.realLanguageServerPromise; return server.provideReferences(document, position, context, token); } + public async provideCompletionItems( document: TextDocument, position: Position, @@ -132,14 +145,17 @@ export class MultiplexingJediLanguageServerActivator implements ILanguageServerA const server = await this.realLanguageServerPromise; return server.provideCompletionItems(document, position, token, context); } + public async provideCodeLenses(document: TextDocument, token: CancellationToken) { const server = await this.realLanguageServerPromise; return server.provideCodeLenses(document, token); } + public async provideDocumentSymbols(document: TextDocument, token: CancellationToken) { const server = await this.realLanguageServerPromise; return server.provideDocumentSymbols(document, token); } + public async provideSignatureHelp( document: TextDocument, position: Position, @@ -149,6 +165,7 @@ export class MultiplexingJediLanguageServerActivator implements ILanguageServerA const server = await this.realLanguageServerPromise; return server.provideSignatureHelp(document, position, token, context); } + public dispose(): void { if (this.realLanguageServer) { this.realLanguageServer.dispose(); diff --git a/src/client/common/application/webviewPanels/webviewPanelProvider.ts b/src/client/common/application/webviewPanels/webviewPanelProvider.ts index 514c0dfd6d21..441824c02f12 100644 --- a/src/client/common/application/webviewPanels/webviewPanelProvider.ts +++ b/src/client/common/application/webviewPanels/webviewPanelProvider.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + 'use strict'; + import { inject, injectable } from 'inversify'; import * as path from 'path'; import { Uri } from 'vscode'; diff --git a/src/client/common/application/webviews/webview.ts b/src/client/common/application/webviews/webview.ts index e840dc68773b..8ae82ddb0010 100644 --- a/src/client/common/application/webviews/webview.ts +++ b/src/client/common/application/webviews/webview.ts @@ -31,22 +31,25 @@ export class Webview implements IWebview { // tslint:disable-next-line:no-any protected async generateLocalReactHtml(): Promise { + let webview: vscodeWebview; if (!this.webview) { throw new Error('WebView not initialized, too early to get a Uri'); + } else { + webview = this.webview; } const uriBase = this.webview.asWebviewUri(Uri.file(this.options.cwd)).toString(); - const uris = this.options.scripts.map((script) => this.webview!.asWebviewUri(Uri.file(script))); + const uris = this.options.scripts.map((script) => webview.asWebviewUri(Uri.file(script))); // NOSONAR const testFiles = await this.fs.getFiles(this.options.rootPath); // This method must be called so VSC is aware of files that can be pulled. // Allow js and js.map files to be loaded by webpack in the webview. testFiles .filter((f) => f.toLowerCase().endsWith('.js') || f.toLowerCase().endsWith('.js.map')) - .forEach((f) => this.webview!.asWebviewUri(Uri.file(f))); + .forEach((f) => webview.asWebviewUri(Uri.file(f))); - const rootPath = this.webview.asWebviewUri(Uri.file(this.options.rootPath)).toString(); - const fontAwesomePath = this.webview + const rootPath = webview.asWebviewUri(Uri.file(this.options.rootPath)).toString(); + const fontAwesomePath = webview .asWebviewUri( Uri.file( path.join(this.options.rootPath, 'node_modules', 'font-awesome', 'css', 'font-awesome.min.css') @@ -59,8 +62,8 @@ export class Webview implements IWebview { + webview.cspSource + }; default-src 'unsafe-inline' 'unsafe-eval' data: https: http: blob: ${webview.cspSource};"> VS Code Python React UI diff --git a/src/client/common/experiments/debuggerDataViewerExperimentEnabler.ts b/src/client/common/experiments/debuggerDataViewerExperimentEnabler.ts index a6d0b2b76298..89c0ca37607a 100644 --- a/src/client/common/experiments/debuggerDataViewerExperimentEnabler.ts +++ b/src/client/common/experiments/debuggerDataViewerExperimentEnabler.ts @@ -1,9 +1,9 @@ import { inject, injectable } from 'inversify'; import { IExtensionSingleActivationService } from '../../activation/types'; -import { ICommandManager } from '../../common/application/types'; -import { ContextKey } from '../../common/contextKey'; -import { traceError } from '../../common/logger'; -import { IExperimentService } from '../../common/types'; +import { ICommandManager } from '../application/types'; +import { ContextKey } from '../contextKey'; +import { traceError } from '../logger'; +import { IExperimentService } from '../types'; @injectable() export class DebuggerDataViewerExperimentEnabler implements IExtensionSingleActivationService { @@ -11,10 +11,12 @@ export class DebuggerDataViewerExperimentEnabler implements IExtensionSingleActi @inject(ICommandManager) private readonly commandManager: ICommandManager, @inject(IExperimentService) private readonly experimentService: IExperimentService ) {} - public async activate() { + + public async activate(): Promise { this.activateInternal().catch(traceError.bind('Failed to activate debuggerDataViewerExperimentEnabler')); } - private async activateInternal() { + + private async activateInternal(): Promise { // This context key controls the visibility of the 'View Variable in Data Viewer' // context menu item from the variable window context menu during a debugging session const isDataViewerExperimentEnabled = new ContextKey( diff --git a/src/client/jupyter/jupyterIntegration.ts b/src/client/jupyter/jupyterIntegration.ts index 5281d07ff64c..5cf8f778fe94 100644 --- a/src/client/jupyter/jupyterIntegration.ts +++ b/src/client/jupyter/jupyterIntegration.ts @@ -196,7 +196,7 @@ export class JupyterExtensionIntegration { } } - public registerRemoteServerProvider(serverProvider: IJupyterUriProvider) { + public registerRemoteServerProvider(serverProvider: IJupyterUriProvider): void { this.getExtensionApi() .then((e) => { if (e) { @@ -206,18 +206,19 @@ export class JupyterExtensionIntegration { .ignoreErrors(); } - public async showDataViewer(dataProvider: IDataViewerDataProvider, title: string) { + public async showDataViewer(dataProvider: IDataViewerDataProvider, title: string): Promise { const api = await this.getExtensionApi(); if (api) { return api.showDataViewer(dataProvider, title); } + return undefined; } private async getExtensionApi(): Promise { if (!this.jupyterExtension) { const jupyterExtension = this.extensions.getExtension(JUPYTER_EXTENSION_ID); if (!jupyterExtension) { - return; + return undefined; } await jupyterExtension.activate(); if (jupyterExtension.isActive) { @@ -227,5 +228,6 @@ export class JupyterExtensionIntegration { } else { return this.jupyterExtension.exports; } + return undefined; } } diff --git a/src/client/jupyter/languageserver/notebookConcatDocument.ts b/src/client/jupyter/languageserver/notebookConcatDocument.ts index d644717c6cdf..cd622401800b 100644 --- a/src/client/jupyter/languageserver/notebookConcatDocument.ts +++ b/src/client/jupyter/languageserver/notebookConcatDocument.ts @@ -44,19 +44,30 @@ export class NotebookConcatDocument implements TextDocument, IDisposable { public get isClosed() { return this.concatDocument.isClosed; } - public get eol() { + + // eslint-disable-next-line class-methods-use-this + public get eol(): EndOfLine { return EndOfLine.LF; } - public get lineCount() { + + public get lineCount(): number { return this.notebook.cells.map((c) => c.document.lineCount).reduce((p, c) => p + c); } + public firedOpen = false; + public firedClose = false; + public concatDocument: NotebookConcatTextDocument; + private dummyFilePath: string; + private dummyUri: Uri; + private _version = 1; + private onDidChangeSubscription: Disposable; + constructor(public notebook: NotebookDocument, notebookApi: IVSCodeNotebook, selector: DocumentSelector) { const dir = path.dirname(notebook.uri.fsPath); // Note: Has to be different than the prefix for old notebook editor (HiddenFileFormat) so @@ -74,10 +85,13 @@ export class NotebookConcatDocument implements TextDocument, IDisposable { public isCellOfDocument(uri: Uri) { return this.concatDocument.contains(uri); } + + // eslint-disable-next-line class-methods-use-this public save(): Thenable { // Not used throw new Error('Not implemented'); } + public lineAt(posOrNumber: Position | number) { const position = typeof posOrNumber === 'number' ? new Position(posOrNumber, 0) : posOrNumber; diff --git a/src/client/jupyter/languageserver/notebookConverter.ts b/src/client/jupyter/languageserver/notebookConverter.ts index 29a7a00b75c9..40e66dda9ada 100644 --- a/src/client/jupyter/languageserver/notebookConverter.ts +++ b/src/client/jupyter/languageserver/notebookConverter.ts @@ -45,7 +45,9 @@ function toPosition(positionLike: Position): Position { export class NotebookConverter implements Disposable { private activeDocuments: Map = new Map(); + private activeDocumentsOutgoingMap: Map = new Map(); + private disposables: Disposable[] = []; constructor( @@ -61,6 +63,14 @@ export class NotebookConverter implements Disposable { api.notebookDocuments.forEach(this.onDidOpenNotebook.bind(this)); } + private static getDocumentKey(uri: Uri): string { + // Use the path of the doc uri. It should be the same for all cells + if (os.platform() === 'win32') { + return uri.fsPath.toLowerCase(); + } + return uri.fsPath; + } + public dispose() { this.disposables.forEach((d) => d.dispose()); } @@ -75,6 +85,7 @@ export class NotebookConverter implements Disposable { if (wrapper) { return wrapper.firedOpen; } + return undefined; } public firedOpen(cell: TextDocument) { @@ -89,6 +100,7 @@ export class NotebookConverter implements Disposable { if (wrapper) { return wrapper.firedClose; } + return undefined; } public firedClose(cell: TextDocument) { @@ -166,7 +178,7 @@ export class NotebookConverter implements Disposable { public toOutgoingDocument(cell: TextDocument): TextDocument { const result = this.getTextDocumentWrapper(cell); - return result ? result : cell; + return result || cell; } public toOutgoingUri(cell: TextDocument | Uri): Uri { @@ -225,6 +237,7 @@ export class NotebookConverter implements Disposable { } return hover; } + public toIncomingCompletions( cell: TextDocument, completions: CompletionItem[] | CompletionList | null | undefined @@ -232,12 +245,11 @@ export class NotebookConverter implements Disposable { if (completions) { if (Array.isArray(completions)) { return completions.map(this.toIncomingCompletion.bind(this, cell)); - } else { - return { - ...completions, - items: completions.items.map(this.toIncomingCompletion.bind(this, cell)) - }; } + return { + ...completions, + items: completions.items.map(this.toIncomingCompletion.bind(this, cell)) + }; } return completions; } @@ -249,7 +261,8 @@ export class NotebookConverter implements Disposable { if (Array.isArray(location)) { // tslint:disable-next-line: no-any return (location).map(this.toIncomingLocationFromLink.bind(this, cell)); - } else if (location?.range) { + } + if (location?.range) { return this.toIncomingLocation(location.uri, location.range); } return location; @@ -257,12 +270,10 @@ export class NotebookConverter implements Disposable { public toIncomingHighlight(cell: TextDocument, highlight: DocumentHighlight[] | null | undefined) { if (highlight) { - return highlight.map((h) => { - return { - ...h, - range: this.toIncomingRange(cell, h.range) - }; - }); + return highlight.map((h) => ({ + ...h, + range: this.toIncomingRange(cell, h.range) + })); } return highlight; } @@ -271,9 +282,8 @@ export class NotebookConverter implements Disposable { if (symbols && Array.isArray(symbols) && symbols.length) { if (symbols[0] instanceof DocumentSymbol) { return (symbols).map(this.toIncomingSymbolFromDocumentSymbol.bind(this, cell)); - } else { - return (symbols).map(this.toIncomingSymbolFromSymbolInformation.bind(this, cell)); } + return (symbols).map(this.toIncomingSymbolFromSymbolInformation.bind(this, cell)); } return symbols; } @@ -295,6 +305,7 @@ export class NotebookConverter implements Disposable { }; } + // eslint-disable-next-line class-methods-use-this public toIncomingActions(_cell: TextDocument, actions: (Command | CodeAction)[] | null | undefined) { if (Array.isArray(actions)) { // Disable for now because actions are handled directly by the LS sometimes (at least in pylance) @@ -308,24 +319,20 @@ export class NotebookConverter implements Disposable { public toIncomingCodeLenses(cell: TextDocument, lenses: CodeLens[] | null | undefined) { if (Array.isArray(lenses)) { - return lenses.map((c) => { - return { - ...c, - range: this.toIncomingRange(cell, c.range) - }; - }); + return lenses.map((c) => ({ + ...c, + range: this.toIncomingRange(cell, c.range) + })); } return lenses; } public toIncomingEdits(cell: TextDocument, edits: TextEdit[] | null | undefined) { if (Array.isArray(edits)) { - return edits.map((e) => { - return { - ...e, - range: this.toIncomingRange(cell, e.range) - }; - }); + return edits.map((e) => ({ + ...e, + range: this.toIncomingRange(cell, e.range) + })); } return edits; } @@ -344,12 +351,11 @@ export class NotebookConverter implements Disposable { if (rangeOrRename) { if (rangeOrRename instanceof Range) { return this.toIncomingLocation(cell, rangeOrRename).range; - } else { - return { - ...rangeOrRename, - range: this.toIncomingLocation(cell, rangeOrRename.range).range - }; } + return { + ...rangeOrRename, + range: this.toIncomingLocation(cell, rangeOrRename.range).range + }; } return rangeOrRename; } @@ -379,12 +385,13 @@ export class NotebookConverter implements Disposable { return this.toIncomingLocation(cell, new Range(position, position)).range.start; } - private getCellAtLocation(location: Location) { - const key = this.getDocumentKey(location.uri); + private getCellAtLocation(location: Location): NotebookCell | undefined { + const key = NotebookConverter.getDocumentKey(location.uri); const wrapper = this.activeDocuments.get(key); if (wrapper) { return wrapper.getCellAtPosition(location.range.start); } + return undefined; } private toIncomingWorkspaceSymbol(symbol: SymbolInformation): SymbolInformation { @@ -536,15 +543,14 @@ export class NotebookConverter implements Disposable { ...item, range: this.toIncomingRange(cell, item.range) }; - } else { - return { - ...item, - range: { - inserting: this.toIncomingRange(cell, item.range.inserting), - replacing: this.toIncomingRange(cell, item.range.replacing) - } - }; } + return { + ...item, + range: { + inserting: this.toIncomingRange(cell, item.range.inserting), + replacing: this.toIncomingRange(cell, item.range.replacing) + } + }; } return item; } @@ -575,14 +581,6 @@ export class NotebookConverter implements Disposable { }; } - private getDocumentKey(uri: Uri): string { - // Use the path of the doc uri. It should be the same for all cells - if (os.platform() === 'win32') { - return uri.fsPath.toLowerCase(); - } - return uri.fsPath; - } - private onDidOpenNotebook(doc: NotebookDocument) { if (this.notebookFilter.test(doc.fileName)) { this.getTextDocumentWrapper(doc.uri); @@ -591,20 +589,20 @@ export class NotebookConverter implements Disposable { private onDidCloseNotebook(doc: NotebookDocument) { if (this.notebookFilter.test(doc.fileName)) { - const key = this.getDocumentKey(doc.uri); + const key = NotebookConverter.getDocumentKey(doc.uri); const wrapper = this.getTextDocumentWrapper(doc.uri); this.activeDocuments.delete(key); - this.activeDocumentsOutgoingMap.delete(this.getDocumentKey(wrapper.uri)); + this.activeDocumentsOutgoingMap.delete(NotebookConverter.getDocumentKey(wrapper.uri)); } } private getWrapperFromOutgoingUri(outgoingUri: Uri): NotebookConcatDocument | undefined { - return this.activeDocumentsOutgoingMap.get(this.getDocumentKey(outgoingUri)); + return this.activeDocumentsOutgoingMap.get(NotebookConverter.getDocumentKey(outgoingUri)); } private getTextDocumentWrapper(cell: TextDocument | Uri): NotebookConcatDocument { const uri = cell instanceof Uri ? cell : cell.uri; - const key = this.getDocumentKey(uri); + const key = NotebookConverter.getDocumentKey(uri); let result = this.activeDocuments.get(key); if (!result) { const doc = this.api.notebookDocuments.find((n) => this.fs.arePathsSame(uri.fsPath, n.uri.fsPath)); @@ -613,7 +611,7 @@ export class NotebookConverter implements Disposable { } result = new NotebookConcatDocument(doc, this.api, this.cellSelector); this.activeDocuments.set(key, result); - this.activeDocumentsOutgoingMap.set(this.getDocumentKey(result.uri), result); + this.activeDocumentsOutgoingMap.set(NotebookConverter.getDocumentKey(result.uri), result); } return result; } diff --git a/src/client/jupyter/languageserver/notebookMiddlewareAddon.ts b/src/client/jupyter/languageserver/notebookMiddlewareAddon.ts index 6f8d40f082e8..1be63bda7a1b 100644 --- a/src/client/jupyter/languageserver/notebookMiddlewareAddon.ts +++ b/src/client/jupyter/languageserver/notebookMiddlewareAddon.ts @@ -118,6 +118,10 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { } else { next(document); } + + return () => { + // Do nothing + }; } public didClose(document: TextDocument, next: (ev: TextDocument) => void) { @@ -133,16 +137,23 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { } else { next(document); } + + return () => { + // Do nothing + }; } + // eslint-disable-next-line class-methods-use-this public didSave(event: TextDocument, next: (ev: TextDocument) => void) { return next(event); } + // eslint-disable-next-line class-methods-use-this public willSave(event: TextDocumentWillSaveEvent, next: (ev: TextDocumentWillSaveEvent) => void) { return next(event); } + // eslint-disable-next-line class-methods-use-this public willSaveWaitUntil( event: TextDocumentWillSaveEvent, next: (ev: TextDocumentWillSaveEvent) => Thenable @@ -187,6 +198,7 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { return next(document, position, token); } + // eslint-disable-next-line class-methods-use-this public resolveCompletionItem( item: CompletionItem, token: CancellationToken, @@ -299,6 +311,7 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { return this.converter.toIncomingWorkspaceSymbols(result); } + // eslint-disable-next-line class-methods-use-this public provideCodeActions( document: TextDocument, range: Range, @@ -307,24 +320,26 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { next: ProvideCodeActionsSignature ): ProviderResult<(Command | CodeAction)[]> { if (isNotebookCell(document.uri)) { - traceInfo(`provideCodeActions not currently supported for notebooks`); + traceInfo('provideCodeActions not currently supported for notebooks'); return undefined; } return next(document, range, context, token); } + // eslint-disable-next-line class-methods-use-this public provideCodeLenses( document: TextDocument, token: CancellationToken, next: ProvideCodeLensesSignature ): ProviderResult { if (isNotebookCell(document.uri)) { - traceInfo(`provideCodeLenses not currently supported for notebooks`); + traceInfo('provideCodeLenses not currently supported for notebooks'); return undefined; } return next(document, token); } + // eslint-disable-next-line class-methods-use-this public resolveCodeLens( codeLens: CodeLens, token: CancellationToken, @@ -337,6 +352,7 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { return next(codeLens, token); } + // eslint-disable-next-line class-methods-use-this public provideDocumentFormattingEdits( document: TextDocument, options: FormattingOptions, @@ -344,12 +360,13 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { next: ProvideDocumentFormattingEditsSignature ): ProviderResult { if (isNotebookCell(document.uri)) { - traceInfo(`provideDocumentFormattingEdits not currently supported for notebooks`); + traceInfo('provideDocumentFormattingEdits not currently supported for notebooks'); return undefined; } return next(document, options, token); } + // eslint-disable-next-line class-methods-use-this public provideDocumentRangeFormattingEdits( document: TextDocument, range: Range, @@ -358,12 +375,13 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { next: ProvideDocumentRangeFormattingEditsSignature ): ProviderResult { if (isNotebookCell(document.uri)) { - traceInfo(`provideDocumentRangeFormattingEdits not currently supported for notebooks`); + traceInfo('provideDocumentRangeFormattingEdits not currently supported for notebooks'); return undefined; } return next(document, range, options, token); } + // eslint-disable-next-line class-methods-use-this public provideOnTypeFormattingEdits( document: TextDocument, position: Position, @@ -373,12 +391,13 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { next: ProvideOnTypeFormattingEditsSignature ): ProviderResult { if (isNotebookCell(document.uri)) { - traceInfo(`provideOnTypeFormattingEdits not currently supported for notebooks`); + traceInfo('provideOnTypeFormattingEdits not currently supported for notebooks'); return undefined; } return next(document, position, ch, options, token); } + // eslint-disable-next-line class-methods-use-this public provideRenameEdits( document: TextDocument, position: Position, @@ -387,12 +406,13 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { next: ProvideRenameEditsSignature ): ProviderResult { if (isNotebookCell(document.uri)) { - traceInfo(`provideRenameEdits not currently supported for notebooks`); + traceInfo('provideRenameEdits not currently supported for notebooks'); return undefined; } return next(document, position, newName, token); } + // eslint-disable-next-line class-methods-use-this public prepareRename( document: TextDocument, position: Position, @@ -406,24 +426,26 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { } > { if (isNotebookCell(document.uri)) { - traceInfo(`prepareRename not currently supported for notebooks`); + traceInfo('prepareRename not currently supported for notebooks'); return undefined; } return next(document, position, token); } + // eslint-disable-next-line class-methods-use-this public provideDocumentLinks( document: TextDocument, token: CancellationToken, next: ProvideDocumentLinksSignature ): ProviderResult { if (isNotebookCell(document.uri)) { - traceInfo(`provideDocumentLinks not currently supported for notebooks`); + traceInfo('provideDocumentLinks not currently supported for notebooks'); return undefined; } return next(document, token); } + // eslint-disable-next-line class-methods-use-this public resolveDocumentLink( link: DocumentLink, token: CancellationToken, @@ -436,6 +458,7 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { return next(link, token); } + // eslint-disable-next-line class-methods-use-this public provideDeclaration( document: TextDocument, position: VPosition, @@ -443,7 +466,7 @@ export class NotebookMiddlewareAddon implements Middleware, Disposable { next: ProvideDeclarationSignature ): ProviderResult { if (isNotebookCell(document.uri)) { - traceInfo(`provideDeclaration not currently supported for notebooks`); + traceInfo('provideDeclaration not currently supported for notebooks'); return undefined; } return next(document, position, token); diff --git a/src/client/jupyter/types.ts b/src/client/jupyter/types.ts index f52edf3d632a..0ec6263eb9c5 100644 --- a/src/client/jupyter/types.ts +++ b/src/client/jupyter/types.ts @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + 'use strict'; import { QuickPickItem } from 'vscode'; diff --git a/src/client/pythonEnvironments/discovery/locators/services/cacheableLocatorService.ts b/src/client/pythonEnvironments/discovery/locators/services/cacheableLocatorService.ts index 0292f5521947..d91a172c7da7 100644 --- a/src/client/pythonEnvironments/discovery/locators/services/cacheableLocatorService.ts +++ b/src/client/pythonEnvironments/discovery/locators/services/cacheableLocatorService.ts @@ -3,6 +3,7 @@ // tslint:disable:no-any +// eslint-disable-next-line max-classes-per-file import { injectable, unmanaged } from 'inversify'; import * as md5 from 'md5'; import { @@ -146,7 +147,7 @@ export abstract class CacheableLocatorService implements IInterpreterLocatorServ } deferred.promise .then((items) => this._hasInterpreters.resolve(items.length > 0)) - .catch((_) => this._hasInterpreters.resolve(false)); + .catch(() => this._hasInterpreters.resolve(false)); if (deferred.completed) { return deferred.promise; @@ -176,6 +177,7 @@ export abstract class CacheableLocatorService implements IInterpreterLocatorServ }); } + // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars protected async getInterpreterWatchers(_resource: Uri | undefined): Promise { return []; } @@ -194,7 +196,7 @@ export abstract class CacheableLocatorService implements IInterpreterLocatorServ protected getCachedInterpreters(resource?: Uri): PythonEnvironment[] | undefined { const persistence = this.createPersistenceStore(resource); if (!Array.isArray(persistence.value)) { - return; + return undefined; } return persistence.value.map((item) => ({ ...item, diff --git a/src/client/pythonEnvironments/discovery/locators/services/conda.ts b/src/client/pythonEnvironments/discovery/locators/services/conda.ts index 875ddbcf5334..f77b4659a4e4 100644 --- a/src/client/pythonEnvironments/discovery/locators/services/conda.ts +++ b/src/client/pythonEnvironments/discovery/locators/services/conda.ts @@ -24,13 +24,13 @@ export type CondaEnvironmentInfo = { export type CondaInfo = { envs?: string[]; - envs_dirs?: string[]; + envsDirs?: string[]; 'sys.version'?: string; 'sys.prefix'?: string; - python_version?: string; - default_prefix?: string; - root_prefix?: string; - conda_version?: string; + pythonVersion?: string; + defaultPrefix?: string; + rootPrefix?: string; + condaVersion?: string; }; export type CondaEnvInfo = { @@ -50,8 +50,8 @@ export async function parseCondaInfo( // The root of the conda environment is itself a Python interpreter // envs reported as e.g.: /Users/bob/miniconda3/envs/someEnv. const envs = Array.isArray(info.envs) ? info.envs : []; - if (info.default_prefix && info.default_prefix.length > 0) { - envs.push(info.default_prefix); + if (info.defaultPrefix && info.defaultPrefix.length > 0) { + envs.push(info.defaultPrefix); } const promises = envs.map(async (envPath) => { @@ -152,6 +152,7 @@ export class Conda { items = await fsapi.readdir(prefix); } catch (ex) { // Directory doesn't exist or is not readable - not an error. + // eslint-disable-next-line no-continue continue; } yield* items @@ -216,19 +217,19 @@ export class Conda { */ public async getEnvList(): Promise { const info = await this.getInfo(); - const envs = info.envs; + const { envs } = info; if (envs === undefined) { return []; } function getName(prefix: string) { - if (prefix === info.root_prefix) { + if (prefix === info.rootPrefix) { return 'base'; } const parentDir = path.dirname(prefix); - if (info.envs_dirs !== undefined) { - for (const envsDir of info.envs_dirs) { + if (info.envsDirs !== undefined) { + for (const envsDir of info.envsDirs) { if (parentDir === envsDir) { return path.basename(prefix); } @@ -238,7 +239,7 @@ export class Conda { return undefined; } - return envs.map(prefix => ({ + return envs.map((prefix) => ({ prefix, name: getName(prefix) })); diff --git a/src/client/pythonEnvironments/discovery/locators/services/condaService.ts b/src/client/pythonEnvironments/discovery/locators/services/condaService.ts index 34163fccfb8e..dc179f447719 100644 --- a/src/client/pythonEnvironments/discovery/locators/services/condaService.ts +++ b/src/client/pythonEnvironments/discovery/locators/services/condaService.ts @@ -109,9 +109,9 @@ export class CondaService implements ICondaService { private static detectCondaEnvironment(env: PythonEnvironment): boolean { return ( env.envType === EnvironmentType.Conda - || (env.displayName ? env.displayName : '').toUpperCase().indexOf('ANACONDA') >= 0 - || (env.companyDisplayName ? env.companyDisplayName : '').toUpperCase().indexOf('ANACONDA') >= 0 - || (env.companyDisplayName ? env.companyDisplayName : '').toUpperCase().indexOf('CONTINUUM') >= 0 + || (env.displayName ? env.displayName : '').toUpperCase().includes('ANACONDA') + || (env.companyDisplayName ? env.companyDisplayName : '').toUpperCase().includes('ANACONDA') + || (env.companyDisplayName ? env.companyDisplayName : '').toUpperCase().includes('CONTINUUM') ); } @@ -160,8 +160,8 @@ export class CondaService implements ICondaService { const processService = await this.processServiceFactory.create(); const info = await this.getCondaInfo().catch(() => undefined); let versionString: string | undefined; - if (info && info.conda_version) { - versionString = info.conda_version; + if (info && info.condaVersion) { + versionString = info.condaVersion; } else { const stdOut = await this.getCondaFile() .then((condaFile) => processService.exec(condaFile, ['--version'], {})) diff --git a/src/client/pythonEnvironments/discovery/locators/services/windowsRegistryService.ts b/src/client/pythonEnvironments/discovery/locators/services/windowsRegistryService.ts index d72ad667ebcb..0ca04aedf81d 100644 --- a/src/client/pythonEnvironments/discovery/locators/services/windowsRegistryService.ts +++ b/src/client/pythonEnvironments/discovery/locators/services/windowsRegistryService.ts @@ -2,7 +2,6 @@ import { inject, injectable } from 'inversify'; import * as path from 'path'; -import { Uri } from 'vscode'; import { traceError } from '../../../../common/logger'; import { IFileSystem, IPlatformService, IRegistry, RegistryHive, @@ -18,7 +17,7 @@ import { CacheableLocatorService } from './cacheableLocatorService'; import { AnacondaCompanyName, AnacondaCompanyNames } from './conda'; import { WindowsStoreInterpreter } from './windowsStoreInterpreter'; -const flatten = require('lodash/flatten') as typeof import('lodash/flatten'); +const flatten = require('lodash/flatten'); // tslint:disable-next-line:variable-name const DefaultPythonExecutable = 'python.exe'; @@ -53,9 +52,11 @@ export class WindowsRegistryService extends CacheableLocatorService { } // tslint:disable-next-line:no-empty - public dispose() {} + public dispose(): void { + // Do nothing. + } - protected async getInterpretersImplementation(_resource?: Uri): Promise { + protected async getInterpretersImplementation(): Promise { return this.platform.isWindows ? this.getInterpretersFromRegistry().catch((ex) => { traceError('Fetching interpreters from registry failed with error', ex); @@ -64,7 +65,7 @@ export class WindowsRegistryService extends CacheableLocatorService { : []; } - private async getInterpretersFromRegistry() { + private async getInterpretersFromRegistry(): Promise { // https://github.com/python/peps/blob/master/pep-0514.txt#L357 const hkcuArch = this.platform.is64bit ? undefined : Architecture.x86; const promises: Promise[] = [ @@ -79,16 +80,14 @@ export class WindowsRegistryService extends CacheableLocatorService { const companies = await Promise.all(promises); const companyInterpreters = await Promise.all( flatten(companies) - .filter((item) => item !== undefined && item !== null) - .map((company) => this.getInterpretersForCompany(company.companyKey, company.hive, company.arch)), + .filter((item: CompanyInterpreter) => item !== undefined && item !== null) + .map((company: CompanyInterpreter) => this.getInterpretersForCompany(company.companyKey, company.hive, company.arch)), ); return ( flatten(companyInterpreters) - .filter((item) => item !== undefined && item !== null) - // tslint:disable-next-line:no-non-null-assertion - .map((item) => item!) - .reduce((prev, current) => { + .filter((item: PythonEnvironment | null | undefined) => item !== undefined && item !== null) + .reduce((prev: PythonEnvironment[], current: PythonEnvironment) => { if (prev.findIndex((item) => item.path.toUpperCase() === current.path.toUpperCase()) === -1) { prev.push(current); } @@ -159,7 +158,7 @@ export class WindowsRegistryService extends CacheableLocatorService { }) .then(async (interpreterInfo?: InterpreterInformation) => { if (!interpreterInfo) { - return; + return undefined; } const executablePath = interpreterInfo.executablePath && interpreterInfo.executablePath.length > 0 @@ -167,12 +166,12 @@ export class WindowsRegistryService extends CacheableLocatorService { : path.join(interpreterInfo.installPath, DefaultPythonExecutable); if (this.windowsStoreInterpreter.isHiddenInterpreter(executablePath)) { - return; + return undefined; } const helper = this.serviceContainer.get(IInterpreterHelper); const details = await helper.getInterpreterInformation(executablePath); if (!details) { - return; + return undefined; } const version = interpreterInfo.version ? this.pathUtils.basename(interpreterInfo.version) diff --git a/src/client/tensorBoard/tensorBoardFileWatcher.ts b/src/client/tensorBoard/tensorBoardFileWatcher.ts index 9fadfe22d46c..70fb7c9f9484 100644 --- a/src/client/tensorBoard/tensorBoardFileWatcher.ts +++ b/src/client/tensorBoard/tensorBoardFileWatcher.ts @@ -13,7 +13,9 @@ import { TensorBoardPrompt } from './tensorBoardPrompt'; @injectable() export class TensorBoardFileWatcher implements IExtensionSingleActivationService { private fileSystemWatchers = new Map(); + private globPattern1 = '*tfevents*'; + private globPattern2 = '*/*tfevents*'; constructor( @@ -85,10 +87,10 @@ export class TensorBoardFileWatcher implements IExtensionSingleActivationService // When a file is created or changed that matches `this.globPattern`, try to show our prompt this.disposables.push( - fileSystemWatcher.onDidCreate((_uri) => this.tensorBoardPrompt.showNativeTensorBoardPrompt()) + fileSystemWatcher.onDidCreate(() => this.tensorBoardPrompt.showNativeTensorBoardPrompt()) ); this.disposables.push( - fileSystemWatcher.onDidChange((_uri) => this.tensorBoardPrompt.showNativeTensorBoardPrompt()) + fileSystemWatcher.onDidChange(() => this.tensorBoardPrompt.showNativeTensorBoardPrompt()) ); this.disposables.push(fileSystemWatcher); fileWatchers.push(fileSystemWatcher); diff --git a/src/client/tensorBoard/tensorBoardImportTracker.ts b/src/client/tensorBoard/tensorBoardImportTracker.ts index 24d56840d88d..6fa196abbb38 100644 --- a/src/client/tensorBoard/tensorBoardImportTracker.ts +++ b/src/client/tensorBoard/tensorBoardImportTracker.ts @@ -18,6 +18,7 @@ const ImportRegEx = /^\s*from (?\w+(?:\.\w+)*) import (?(); + private _onDidImportTensorBoard = new EventEmitter(); constructor( @@ -49,7 +50,7 @@ export class TensorBoardImportTracker implements ITensorBoardImportTracker, IExt if (!editor || !editor.document) { return; } - const document = editor.document; + const { document } = editor; if ( (path.extname(document.fileName) === '.ipynb' && document.languageId === 'python') || path.extname(document.fileName) === '.py' @@ -64,6 +65,7 @@ export class TensorBoardImportTracker implements ITensorBoardImportTracker, IExt for (const s of lines) { const matches = s ? ImportRegEx.exec(s) : null; if (matches === null || matches.groups === undefined) { + // eslint-disable-next-line no-continue continue; } let componentsToCheck: string[] = []; diff --git a/src/client/tensorBoard/tensorBoardPrompt.ts b/src/client/tensorBoard/tensorBoardPrompt.ts index 8ddc18b4200a..e4de8769e839 100644 --- a/src/client/tensorBoard/tensorBoardPrompt.ts +++ b/src/client/tensorBoard/tensorBoardPrompt.ts @@ -15,9 +15,12 @@ enum TensorBoardPromptStateKeys { @injectable() export class TensorBoardPrompt { private state: IPersistentState; + private enabled: Promise | undefined; - private enabledInCurrentSession: boolean = true; - private waitingForUserSelection: boolean = false; + + private enabledInCurrentSession = true; + + private waitingForUserSelection = false; constructor( @inject(IApplicationShell) private applicationShell: IApplicationShell, @@ -34,7 +37,7 @@ export class TensorBoardPrompt { this.importTracker.onDidImportTensorBoard(this.showNativeTensorBoardPrompt, this, this.disposableRegistry); } - public async showNativeTensorBoardPrompt() { + public async showNativeTensorBoardPrompt(): Promise { if ((await this.enabled) && this.enabledInCurrentSession && !this.waitingForUserSelection) { const yes = Common.bannerLabelYes(); const no = Common.bannerLabelNo(); diff --git a/src/client/tensorBoard/tensorBoardSession.ts b/src/client/tensorBoard/tensorBoardSession.ts index b646f0d9df34..737e5c774953 100644 --- a/src/client/tensorBoard/tensorBoardSession.ts +++ b/src/client/tensorBoard/tensorBoardSession.ts @@ -17,7 +17,7 @@ import { import { ICommandManager, IWorkspaceService } from '../common/application/types'; import { createPromiseFromCancellation } from '../common/cancellation'; import { traceError, traceInfo } from '../common/logger'; -import { _SCRIPTS_DIR, tensorboardLauncher } from '../common/process/internal/scripts'; +import { tensorboardLauncher } from '../common/process/internal/scripts'; import { IProcessServiceFactory, ObservableExecutionResult } from '../common/process/types'; import { IInstaller, InstallerResponse, Product } from '../common/types'; import { createDeferred, sleep } from '../common/utils/async'; @@ -36,7 +36,9 @@ import { IInterpreterService } from '../interpreter/contracts'; */ export class TensorBoardSession { private webviewPanel: WebviewPanel | undefined; + private url: string | undefined; + private process: ChildProcess | undefined; constructor( @@ -47,7 +49,40 @@ export class TensorBoardSession { private readonly commandManager: ICommandManager ) {} - public async initialize() { + private static async showFilePicker(): Promise { + const selection = await window.showOpenDialog({ + canSelectFiles: false, + canSelectFolders: true, + canSelectMany: false + }); + // If the user selected a folder, return the uri.fsPath + // There will only be one selection since canSelectMany: false + if (selection) { + return selection[0].fsPath; + } + return undefined; + } + + private static getQuickPickItems(logDir: string | undefined) { + if (logDir) { + const useCwd = { + label: TensorBoard.useCurrentWorkingDirectory(), + detail: TensorBoard.useCurrentWorkingDirectoryDetail() + }; + const selectAnotherFolder = { + label: TensorBoard.selectAnotherFolder(), + detail: TensorBoard.selectAnotherFolderDetail() + }; + return [useCwd, selectAnotherFolder]; + } + const selectAFolder = { + label: TensorBoard.selectAFolder(), + detail: TensorBoard.selectAFolderDetail() + }; + return [selectAFolder]; + } + + public async initialize(): Promise { const tensorBoardWasInstalled = await this.ensureTensorboardIsInstalled(); if (!tensorBoardWasInstalled) { return; @@ -73,7 +108,7 @@ export class TensorBoardSession { (await this.interpreterService.getActiveInterpreter()) || (await this.commandManager.executeCommand('python.setInterpreter')); if (!interpreter) { - return; + return undefined; } const tokenSource = new CancellationTokenSource(); const installerToken = tokenSource.token; @@ -89,39 +124,6 @@ export class TensorBoardSession { return response === InstallerResponse.Installed; } - private async showFilePicker() { - const selection = await window.showOpenDialog({ - canSelectFiles: false, - canSelectFolders: true, - canSelectMany: false - }); - // If the user selected a folder, return the uri.fsPath - // There will only be one selection since canSelectMany: false - if (selection) { - return selection[0].fsPath; - } - } - - private getQuickPickItems(logDir: string | undefined) { - if (logDir) { - const useCwd = { - label: TensorBoard.useCurrentWorkingDirectory(), - detail: TensorBoard.useCurrentWorkingDirectoryDetail() - }; - const selectAnotherFolder = { - label: TensorBoard.selectAnotherFolder(), - detail: TensorBoard.selectAnotherFolderDetail() - }; - return [useCwd, selectAnotherFolder]; - } else { - const selectAFolder = { - label: TensorBoard.selectAFolder(), - detail: TensorBoard.selectAFolderDetail() - }; - return [selectAFolder]; - } - } - // Display a quickpick asking the user to acknowledge our autopopulated log directory or // select a new one using the file picker. Default this to the folder that is open in // the editor, if any, then the directory that the active text editor is in, if any. @@ -130,7 +132,7 @@ export class TensorBoardSession { const useCurrentWorkingDirectory = TensorBoard.useCurrentWorkingDirectory(); const selectAFolder = TensorBoard.selectAFolder(); const selectAnotherFolder = TensorBoard.selectAnotherFolder(); - const items: QuickPickItem[] = this.getQuickPickItems(logDir); + const items: QuickPickItem[] = TensorBoardSession.getQuickPickItems(logDir); const quickPick = window.createQuickPick(); quickPick.title = TensorBoard.logDirectoryPrompt(); quickPick.canSelectMany = false; @@ -152,7 +154,7 @@ export class TensorBoardSession { return logDir; case selectAFolder: case selectAnotherFolder: - return this.showFilePicker(); + return TensorBoardSession.showFilePicker(); default: return undefined; } @@ -185,7 +187,7 @@ export class TensorBoardSession { const result = await window.withProgress( progressOptions, - (_progress: Progress<{}>, token: CancellationToken) => { + (_progress: Progress, token: CancellationToken) => { traceInfo(`Starting TensorBoard with log directory ${logDir}...`); const spawnTensorBoard = this.waitForTensorBoardStart(observable); @@ -221,6 +223,7 @@ export class TensorBoardSession { if (output.source === 'stdout') { const match = output.out.match(/TensorBoard started at (.*)/); if (match && match[1]) { + // eslint-disable-next-line prefer-destructuring this.url = match[1]; urlThatTensorBoardIsRunningAt.resolve('success'); } @@ -253,7 +256,7 @@ export class TensorBoardSession { this.process?.kill(); this.process = undefined; }); - webviewPanel.onDidChangeViewState((_e) => { + webviewPanel.onDidChangeViewState(() => { if (webviewPanel.visible) { this.update(); } @@ -287,9 +290,10 @@ export class TensorBoardSession { if (this.workspaceService.rootPath) { return this.workspaceService.rootPath; } - const activeTextEditor = window.activeTextEditor; + const { activeTextEditor } = window; if (activeTextEditor) { return path.dirname(activeTextEditor.document.uri.fsPath); } + return undefined; } } diff --git a/src/test/languageServers/jedi/lspTeardown.ts b/src/test/languageServers/jedi/lspTeardown.ts index c05bfffda445..caee90daaa75 100644 --- a/src/test/languageServers/jedi/lspTeardown.ts +++ b/src/test/languageServers/jedi/lspTeardown.ts @@ -14,7 +14,6 @@ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, undefined, ' ')); const settingsJsonPath = path.join(__dirname, '..', '..', '..', '..', 'src', 'test', '.vscode', 'settings.json'); const settingsJsonPromise = import('../../.vscode/settings.json'); // tslint:disable-next-line: no-floating-promises -settingsJsonPromise.then((settingsJson) => { - // tslint:disable-next-line: no-any - return fs.writeFile(settingsJsonPath, JSON.stringify(settingsJson, undefined, ' ')); -}); +settingsJsonPromise.then((settingsJson) => + fs.writeFile(settingsJsonPath, JSON.stringify(settingsJson, undefined, ' ')) +); diff --git a/src/test/pythonEnvironments/base/watcher.unit.test.ts b/src/test/pythonEnvironments/base/watcher.unit.test.ts index 67b81afd2ce4..cb2a1ab54549 100644 --- a/src/test/pythonEnvironments/base/watcher.unit.test.ts +++ b/src/test/pythonEnvironments/base/watcher.unit.test.ts @@ -40,7 +40,7 @@ suite('Python envs watcher - PythonEnvsWatcher', () => { KINDS_TO_TEST.forEach((kind) => { test(`non-empty event ("${kind}")`, () => { const expected: PythonEnvsChangedEvent = { - kind: kind, + kind, searchLocation: location }; const watcher = new PythonEnvsWatcher(); @@ -99,7 +99,7 @@ suite('Python envs watcher - PythonEnvsWatcher', () => { KINDS_TO_TEST.forEach((kind) => { test(`non-empty event ("${kind}")`, () => { const expected: BasicPythonEnvsChangedEvent = { - kind: kind + kind }; const watcher = new PythonEnvsWatcher(); let event: BasicPythonEnvsChangedEvent | undefined; diff --git a/src/test/pythonEnvironments/discovery/locators/condaEnvService.unit.test.ts b/src/test/pythonEnvironments/discovery/locators/condaEnvService.unit.test.ts index f3aba85024cd..3e2d1724abd3 100644 --- a/src/test/pythonEnvironments/discovery/locators/condaEnvService.unit.test.ts +++ b/src/test/pythonEnvironments/discovery/locators/condaEnvService.unit.test.ts @@ -386,7 +386,7 @@ suite('Interpreters from Conda Environments', () => { async function includeDefaultPrefixIntoListOfInterpreters(isWindows: boolean) { const info = { - default_prefix: path.join(environmentsPath, 'conda', 'envs', 'numpy'), + defaultPrefix: path.join(environmentsPath, 'conda', 'envs', 'numpy'), }; condaService .setup((c) => c.getInterpreterPath(TypeMoq.It.isAny())) @@ -394,8 +394,8 @@ suite('Interpreters from Conda Environments', () => { ? path.join(environmentPath, 'python.exe') : path.join(environmentPath, 'bin', 'python'))); const pythonPath = isWindows - ? path.join(info.default_prefix, 'python.exe') - : path.join(info.default_prefix, 'bin', 'python'); + ? path.join(info.defaultPrefix, 'python.exe') + : path.join(info.defaultPrefix, 'bin', 'python'); fileSystem.setup((fs) => fs.fileExists(TypeMoq.It.isValue(pythonPath))).returns(() => Promise.resolve(true)); interpreterHelper .setup((i) => i.getInterpreterInformation(TypeMoq.It.isAny())) @@ -409,7 +409,7 @@ suite('Interpreters from Conda Environments', () => { ); assert.equal(interpreters.length, 1, 'Incorrect number of entries'); - const path1 = path.join(info.default_prefix, isWindows ? 'python.exe' : path.join('bin', 'python')); + const path1 = path.join(info.defaultPrefix, isWindows ? 'python.exe' : path.join('bin', 'python')); assert.equal(interpreters[0].path, path1, 'Incorrect path for first env'); assert.equal( interpreters[0].companyDisplayName, diff --git a/src/test/pythonEnvironments/discovery/locators/condaHelper.unit.test.ts b/src/test/pythonEnvironments/discovery/locators/condaHelper.unit.test.ts index db8c3ad9d274..cac3f33dd3de 100644 --- a/src/test/pythonEnvironments/discovery/locators/condaHelper.unit.test.ts +++ b/src/test/pythonEnvironments/discovery/locators/condaHelper.unit.test.ts @@ -25,7 +25,7 @@ suite('Interpreters display name from Conda Environments', () => { }); test('Must return at least Python Version', () => { const info: CondaInfo = { - python_version: '3.6.1.final.10', + pythonVersion: '3.6.1.final.10', }; const displayName = getDisplayName(info); assert.equal(displayName, AnacondaDisplayName, 'Incorrect display name'); @@ -40,7 +40,7 @@ suite('Interpreters display name from Conda Environments', () => { }); test("Must return info without prefixing with word 'Python'", () => { const info: CondaInfo = { - python_version: '3.6.1.final.10', + pythonVersion: '3.6.1.final.10', 'sys.version': '3.6.1 |Anaconda 4.4.0 (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]', }; @@ -49,7 +49,7 @@ suite('Interpreters display name from Conda Environments', () => { }); test('Must include Ananconda name if Company name not found', () => { const info: CondaInfo = { - python_version: '3.6.1.final.10', + pythonVersion: '3.6.1.final.10', 'sys.version': '3.6.1 |4.4.0 (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]', }; const displayName = getDisplayName(info); @@ -137,12 +137,10 @@ suite('Conda binary is located correctly', () => { for (const fileName of segments) { if (typeof dir !== 'object') { throw new Error(`${currentPath} is not a directory`); + } else if (fileName !== '') { + dir = dir[fileName]; + currentPath = `${currentPath}/${fileName}`; } - if (fileName === '') { - continue; - } - dir = dir[fileName]; - currentPath = `${currentPath}/${fileName}`; } return dir; } @@ -165,11 +163,11 @@ suite('Conda binary is located correctly', () => { function condaInfo(condaVersion: string): CondaInfo { return { - conda_version: condaVersion, - python_version: '3.9.0', + condaVersion, + pythonVersion: '3.9.0', 'sys.version': '3.9.0', 'sys.prefix': '/some/env', - default_prefix: '/conda/base', + defaultPrefix: '/conda/base', envs: [], }; } @@ -218,13 +216,11 @@ suite('Conda binary is located correctly', () => { async (command: string, args: string[]) => { for (const prefix of ['', ...execPath]) { const contents = getFile(path.join(prefix, command)); - if (typeof contents !== 'string' || !contents) { - continue; - } if (args[0] !== 'info' || args[1] !== '--json') { throw new Error(`Invalid arguments: ${util.inspect(args)}`); + } else if (typeof contents === 'string' && contents !== '') { + return { stdout: contents }; } - return { stdout: contents }; } throw new Error(`${command} is missing or is not executable`); }, @@ -349,7 +345,7 @@ suite('Conda binary is located correctly', () => { }); suite('Must find conda in environments.txt', () => { - test(`Must find conda in environments.txt on Unix`, async () => { + test('Must find conda in environments.txt on Unix', async () => { osType = platform.OSType.Linux; homeDir = '/home/user'; @@ -359,11 +355,11 @@ suite('Conda binary is located correctly', () => { '.conda': { 'environments.txt': [ '', - '/missing', // stale entries shouldn't break things + '/missing', // stale entries shouldn't break things '', '# comment', '', - ' /present ', // whitespace should be ignored + ' /present ', // whitespace should be ignored '', ].join('\n') }, @@ -379,22 +375,22 @@ suite('Conda binary is located correctly', () => { await expectConda('/present/bin/conda'); }); - test(`Must find conda in environments.txt on Windows`, async () => { + test('Must find conda in environments.txt on Windows', async () => { osType = platform.OSType.Windows; homeDir = 'D:\\Users\\user'; files = { - 'D:' : { + 'D:': { Users: { user: { '.conda': { 'environments.txt': [ '', - 'C:\\Missing', // stale entries shouldn't break things + 'C:\\Missing', // stale entries shouldn't break things '', '# comment', '', - ' E:\\Present ', // whitespace should be ignored + ' E:\\Present ', // whitespace should be ignored '', ].join('\r\n') }, @@ -463,14 +459,14 @@ suite('Conda binary is located correctly', () => { }); suite('Conda env list is parsed correctly', () => { - const condaInfo = { - conda_version: '4.8.0', - python_version: '3.9.0', + const condaInfo: CondaInfo = { + condaVersion: '4.8.0', + pythonVersion: '3.9.0', 'sys.version': '3.9.0', 'sys.prefix': '/some/env', - root_prefix: '/home/user/miniconda3', - default_prefix: '/home/user/miniconda3/envs/env1', - envs_dirs: [ + rootPrefix: '/home/user/miniconda3', + defaultPrefix: '/home/user/miniconda3/envs/env1', + envsDirs: [ '/home/user/miniconda3/envs', '/home/user/.conda/envs', ], @@ -503,7 +499,7 @@ suite('Conda env list is parsed correctly', () => { }); test('Must compute conda environment name from prefix', async () => { - const conda = new Conda("conda"); + const conda = new Conda('conda'); const envs = await conda.getEnvList(); expect(envs).to.have.deep.members([ { @@ -520,7 +516,7 @@ suite('Conda env list is parsed correctly', () => { }, { prefix: '/home/user/miniconda3/envs/dir/env3', - name: undefined // because it's not directly under envs_dirs + name: undefined // because it's not directly under envsDirs }, { prefix: '/home/user/.conda/envs/env4', @@ -532,10 +528,8 @@ suite('Conda env list is parsed correctly', () => { }, { prefix: '/env6', - name: undefined // because it's not directly under envs_dirs + name: undefined // because it's not directly under envsDirs }, ]); - }); }); -