From a672726b557d1458f07fb7d246ffc733031005f4 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 5 Apr 2023 15:12:21 +0200 Subject: [PATCH 01/13] feat: use typescript service to fetch help signatures VSCODE-403 --- src/language/server.ts | 20 ++++ src/language/tsLanguageService.ts | 161 ++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 src/language/tsLanguageService.ts diff --git a/src/language/server.ts b/src/language/server.ts index b21c9be51..ecb302925 100644 --- a/src/language/server.ts +++ b/src/language/server.ts @@ -9,10 +9,13 @@ import { RequestType, TextDocumentSyncKind, Connection, + SignatureHelpParams, } from 'vscode-languageserver/node'; import { TextDocument } from 'vscode-languageserver-textdocument'; import MongoDBService from './mongoDBService'; +import TypeScriptService from './tsLanguageService'; + import { ServerCommands } from './serverCommands'; import { PlaygroundEvaluateParams, @@ -30,6 +33,9 @@ const documents: TextDocuments = new TextDocuments(TextDocument); // MongoDB Playground Service Manager. const mongoDBService = new MongoDBService(connection); +// TypeScript language service. +const typeScriptService = new TypeScriptService(connection); + let hasConfigurationCapability = false; // let hasWorkspaceFolderCapability = false; // let hasDiagnosticRelatedInformationCapability = false; @@ -66,6 +72,10 @@ connection.onInitialize((params: InitializeParams) => { resolveProvider: true, triggerCharacters: ['.'], }, + signatureHelpProvider: { + resolveProvider: true, + triggerCharacters: [ ',' ] + } // documentFormattingProvider: true, // documentRangeFormattingProvider: true, // codeLensProvider: { @@ -223,6 +233,16 @@ connection.onCompletionResolve((item: CompletionItem): CompletionItem => { return item; }); +connection.onSignatureHelp((params: SignatureHelpParams) => { + const document = documents.get(params.textDocument.uri); + + if (!document) { + return; + } + + return typeScriptService.doSignatureHelp(document, params.position); +}); + connection.onRequest('textDocument/rangeFormatting', (event) => { // connection.console.log( // `textDocument/rangeFormatting: ${JSON.stringify({ event })}` diff --git a/src/language/tsLanguageService.ts b/src/language/tsLanguageService.ts new file mode 100644 index 000000000..1f4504536 --- /dev/null +++ b/src/language/tsLanguageService.ts @@ -0,0 +1,161 @@ +import { Connection } from 'vscode-languageserver/node'; +import type { SignatureHelp, SignatureInformation, ParameterInformation } from 'vscode-languageserver/node'; +import * as ts from 'typescript'; +import { TextDocument, Position } from 'vscode-languageserver-textdocument'; +import { readFileSync } from 'fs'; +import { join, basename, dirname } from 'path'; + +type TypeScriptServiceHost = { + getLanguageService(jsDocument: TextDocument): ts.LanguageService; + getCompilationSettings(): ts.CompilerOptions; + dispose(): void; +}; + +// Server folder. +const serverPath = basename(__dirname) === 'dist' ? dirname(__dirname) : dirname(dirname(__dirname)); +// TypeScript library folder. +const librarPath = join(serverPath, '../node_modules/typescript/lib'); +const contents: { [name: string]: string } = {}; + +export default class TypeScriptService { + _connection: Connection; + _host: TypeScriptServiceHost; + + constructor(connection: Connection) { + this._host = this._getTypeScriptServiceHost(); + this._connection = connection; + } + + _loadLibrary(name: string) { + let content = contents[name]; + if (typeof content !== 'string' && librarPath) { + const libPath = join(librarPath, name); // From source. + try { + content = readFileSync(libPath).toString(); + } catch (e) { + this._connection.console.error( + `Unable to load library ${name} at ${libPath}` + ); + content = ''; + } + contents[name] = content; + } + return content; + } + + _getTypeScriptServiceHost() { + const compilerOptions = { + allowNonTsExtensions: true, + allowJs: true, + lib: ['lib.es2020.full.d.ts'], + target: ts.ScriptTarget.Latest, + moduleResolution: ts.ModuleResolutionKind.Classic, + experimentalDecorators: false + }; + let currentTextDocument = TextDocument.create('init', 'javascript', 1, ''); + + // Create the language service host to allow the LS to communicate with the host. + const host: ts.LanguageServiceHost = { + getCompilationSettings: () => compilerOptions, + getScriptFileNames: () => [currentTextDocument.uri], + getScriptKind: () => { + return ts.ScriptKind.JS; + }, + getScriptVersion: (fileName: string) => { + if (fileName === currentTextDocument.uri) { + return String(currentTextDocument.version); + } + return '1'; + }, + getScriptSnapshot: (fileName: string) => { + let text = ''; + if (fileName === currentTextDocument.uri) { + text = currentTextDocument.getText(); + } else { + text = this._loadLibrary(fileName); + } + return { + getText: (start, end) => text.substring(start, end), + getLength: () => text.length, + getChangeRange: () => undefined + }; + }, + getCurrentDirectory: () => '', + getDefaultLibFileName: () => 'es2020.full', + readFile: (path: string): string | undefined => { + if (path === currentTextDocument.uri) { + return currentTextDocument.getText(); + } + return this._loadLibrary(path); + }, + fileExists: (path: string): boolean => { + if (path === currentTextDocument.uri) { + return true; + } + return !!this._loadLibrary(path); + }, + directoryExists: (path: string): boolean => { + // Typescript tries to first find libraries in node_modules/@types and node_modules/@typescript. + if (path.startsWith('node_modules')) { + return false; + } + return true; + } + }; + + // Create the language service files. + const jsLanguageService = ts.createLanguageService(host); + + return { + // Return a new instance of the language service. + getLanguageService(jsDocument: TextDocument): ts.LanguageService { + currentTextDocument = jsDocument; + return jsLanguageService; + }, + getCompilationSettings() { + return compilerOptions; + }, + dispose() { + jsLanguageService.dispose(); + } + }; + } + + doSignatureHelp(document: TextDocument, position: Position): SignatureHelp | null { + const jsDocument = TextDocument.create(document.uri, 'javascript', document.version, document.getText()); + const jsLanguageService = this._host.getLanguageService(jsDocument); + const signHelp = jsLanguageService.getSignatureHelpItems(jsDocument.uri, jsDocument.offsetAt(position), undefined); + if (signHelp) { + const ret: SignatureHelp = { + activeSignature: signHelp.selectedItemIndex, + activeParameter: signHelp.argumentIndex, + signatures: [] + }; + signHelp.items.forEach(item => { + const signature: SignatureInformation = { + label: '', + documentation: undefined, + parameters: [] + }; + + signature.label += ts.displayPartsToString(item.prefixDisplayParts); + item.parameters.forEach((p, i, a) => { + const label = ts.displayPartsToString(p.displayParts); + const parameter: ParameterInformation = { + label: label, + documentation: ts.displayPartsToString(p.documentation) + }; + signature.label += label; + signature.parameters!.push(parameter); + if (i < a.length - 1) { + signature.label += ts.displayPartsToString(item.separatorDisplayParts); + } + }); + signature.label += ts.displayPartsToString(item.suffixDisplayParts); + ret.signatures.push(signature); + }); + return ret; + } + return null; + } +} From 53d84418730cee757d5d2145eab2409bd7ed518d Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 5 Apr 2023 19:52:46 +0200 Subject: [PATCH 02/13] feat: show mongodb signatures where applicable --- src/language/mongoDBService.ts | 50 ++++++++++++++- src/language/server.ts | 20 +++++- src/language/tsLanguageService.ts | 61 +++++++++++++------ src/language/visitor.ts | 40 ++++++++++++ .../suite/language/mongoDBService.test.ts | 53 +++++++++++++++- tsconfig.json | 4 +- 6 files changed, 202 insertions(+), 26 deletions(-) diff --git a/src/language/mongoDBService.ts b/src/language/mongoDBService.ts index ed496ff9b..33a691ed0 100644 --- a/src/language/mongoDBService.ts +++ b/src/language/mongoDBService.ts @@ -4,6 +4,7 @@ import { InsertTextFormat, MarkupKind, DiagnosticSeverity, + SignatureHelpContext, } from 'vscode-languageserver/node'; import type { CancellationToken, @@ -842,10 +843,57 @@ export default class MongoDBService { } } - this._connection.console.log('VISITOR no completion'); + this._connection.console.log('VISITOR found no mongodb completion'); return []; } + provideSignatureHelp( + textFromEditor: string, + position: { line: number; character: number }, + context?: SignatureHelpContext + ) { + this._connection.console.log( + `LS current symbol position: ${util.inspect(position)}` + ); + + const state = this._visitor.parseASTWithPlaceholder( + textFromEditor, + position + ); + this._connection.console.log( + `VISITOR signature help state: ${util.inspect(state)}` + ); + + if (state.isFind) { + return { + activeSignatureHelp: context?.activeSignatureHelp, + signatures: [ + { + label: 'Collection.find(query, projection, options) : Cursor', + documentation: 'Selects documents in a collection or view.', + parameters: [], + }, + ], + }; + } + + if (state.isAggregation) { + return { + activeSignatureHelp: context?.activeSignatureHelp, + signatures: [ + { + label: 'Collection.aggregate(pipeline, options) : Cursor', + documentation: + 'Calculates aggregate values for the data in a collection or a view.', + parameters: [], + }, + ], + }; + } + + this._connection.console.log('VISITOR found no mongodb signature help'); + } + // Highlight the usage of commands that only works inside interactive session. // eslint-disable-next-line complexity provideDiagnostics(textFromEditor: string) { diff --git a/src/language/server.ts b/src/language/server.ts index ecb302925..00be60c7d 100644 --- a/src/language/server.ts +++ b/src/language/server.ts @@ -74,8 +74,8 @@ connection.onInitialize((params: InitializeParams) => { }, signatureHelpProvider: { resolveProvider: true, - triggerCharacters: [ ',' ] - } + triggerCharacters: [','], + }, // documentFormattingProvider: true, // documentRangeFormattingProvider: true, // codeLensProvider: { @@ -240,7 +240,21 @@ connection.onSignatureHelp((params: SignatureHelpParams) => { return; } - return typeScriptService.doSignatureHelp(document, params.position); + const textFromEditor = document.getText() || ''; + const mongodbSignatures = mongoDBService.provideSignatureHelp( + textFromEditor, + params.position, + params.context + ); + + if (mongodbSignatures) { + return mongodbSignatures; + } + + return typeScriptService.doSignatureHelp( + document, + params.position + ); }); connection.onRequest('textDocument/rangeFormatting', (event) => { diff --git a/src/language/tsLanguageService.ts b/src/language/tsLanguageService.ts index 1f4504536..6f498fb3b 100644 --- a/src/language/tsLanguageService.ts +++ b/src/language/tsLanguageService.ts @@ -1,6 +1,10 @@ import { Connection } from 'vscode-languageserver/node'; -import type { SignatureHelp, SignatureInformation, ParameterInformation } from 'vscode-languageserver/node'; -import * as ts from 'typescript'; +import type { + SignatureHelp, + SignatureInformation, + ParameterInformation, +} from 'vscode-languageserver/node'; +import ts from 'typescript'; import { TextDocument, Position } from 'vscode-languageserver-textdocument'; import { readFileSync } from 'fs'; import { join, basename, dirname } from 'path'; @@ -12,9 +16,13 @@ type TypeScriptServiceHost = { }; // Server folder. -const serverPath = basename(__dirname) === 'dist' ? dirname(__dirname) : dirname(dirname(__dirname)); +const serverPath = + basename(__dirname) === 'dist' + ? dirname(__dirname) + : dirname(dirname(__dirname)); + // TypeScript library folder. -const librarPath = join(serverPath, '../node_modules/typescript/lib'); +const librarPath = join(serverPath, 'node_modules/typescript/lib'); const contents: { [name: string]: string } = {}; export default class TypeScriptService { @@ -47,10 +55,10 @@ export default class TypeScriptService { const compilerOptions = { allowNonTsExtensions: true, allowJs: true, - lib: ['lib.es2020.full.d.ts'], + lib: ['lib.es2020.full.d.ts'], // Should match to lib from tsconfig.json. target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic, - experimentalDecorators: false + experimentalDecorators: false, }; let currentTextDocument = TextDocument.create('init', 'javascript', 1, ''); @@ -77,11 +85,11 @@ export default class TypeScriptService { return { getText: (start, end) => text.substring(start, end), getLength: () => text.length, - getChangeRange: () => undefined + getChangeRange: () => undefined, }; }, getCurrentDirectory: () => '', - getDefaultLibFileName: () => 'es2020.full', + getDefaultLibFileName: () => 'es2020.full', // Should match to lib from tsconfig.json. readFile: (path: string): string | undefined => { if (path === currentTextDocument.uri) { return currentTextDocument.getText(); @@ -100,7 +108,7 @@ export default class TypeScriptService { return false; } return true; - } + }, }; // Create the language service files. @@ -117,25 +125,38 @@ export default class TypeScriptService { }, dispose() { jsLanguageService.dispose(); - } + }, }; } - doSignatureHelp(document: TextDocument, position: Position): SignatureHelp | null { - const jsDocument = TextDocument.create(document.uri, 'javascript', document.version, document.getText()); + doSignatureHelp( + document: TextDocument, + position: Position + ): SignatureHelp | null { + const jsDocument = TextDocument.create( + document.uri, + 'javascript', + document.version, + document.getText() + ); const jsLanguageService = this._host.getLanguageService(jsDocument); - const signHelp = jsLanguageService.getSignatureHelpItems(jsDocument.uri, jsDocument.offsetAt(position), undefined); + const signHelp = jsLanguageService.getSignatureHelpItems( + jsDocument.uri, + jsDocument.offsetAt(position), + undefined + ); + if (signHelp) { const ret: SignatureHelp = { activeSignature: signHelp.selectedItemIndex, activeParameter: signHelp.argumentIndex, - signatures: [] + signatures: [], }; - signHelp.items.forEach(item => { + signHelp.items.forEach((item) => { const signature: SignatureInformation = { label: '', documentation: undefined, - parameters: [] + parameters: [], }; signature.label += ts.displayPartsToString(item.prefixDisplayParts); @@ -143,12 +164,14 @@ export default class TypeScriptService { const label = ts.displayPartsToString(p.displayParts); const parameter: ParameterInformation = { label: label, - documentation: ts.displayPartsToString(p.documentation) + documentation: ts.displayPartsToString(p.documentation), }; signature.label += label; - signature.parameters!.push(parameter); + signature.parameters?.push(parameter); if (i < a.length - 1) { - signature.label += ts.displayPartsToString(item.separatorDisplayParts); + signature.label += ts.displayPartsToString( + item.separatorDisplayParts + ); } }); signature.label += ts.displayPartsToString(item.suffixDisplayParts); diff --git a/src/language/visitor.ts b/src/language/visitor.ts index beb5de9ad..5c70d32d4 100644 --- a/src/language/visitor.ts +++ b/src/language/visitor.ts @@ -29,6 +29,8 @@ export interface CompletionState { isIdentifierObjectValue: boolean; isTextObjectValue: boolean; isStage: boolean; + isFind: boolean; + isAggregation: boolean; stageOperator: string | null; isCollectionSymbol: boolean; isUseCallExpression: boolean; @@ -56,6 +58,8 @@ export class Visitor { return; } + this._checkIsFind(path.node); + this._checkIsAggregation(path.node); this._checkIsBSONSelection(path.node); this._checkIsUseCall(path.node); this._checkIsCollectionNameAsCallExpression(path.node); @@ -190,6 +194,8 @@ export class Visitor { isIdentifierObjectValue: false, isTextObjectValue: false, isStage: false, + isFind: false, + isAggregation: false, stageOperator: null, isCollectionSymbol: false, isUseCallExpression: false, @@ -290,6 +296,40 @@ export class Visitor { }); } + _checkIsFind(node: babel.types.CallExpression) { + if ( + node.callee.type === 'MemberExpression' && + node.callee.property.type === 'Identifier' && + node.callee.property.name === 'find' && + node.loc && + ((node.loc.start.line < this._selection.start.line && + node.loc.end.line > this._selection.start.line + 1) || + (node.loc.start.line === this._selection.start.line && + node.loc.start.column <= this._selection.start.character) || + (node.loc.end.line === this._selection.start.line + 1 && + node.loc.end.column >= this._selection.start.character)) + ) { + this._state.isFind = true; + } + } + + _checkIsAggregation(node: babel.types.CallExpression): void { + if ( + node.callee.type === 'MemberExpression' && + node.callee.property.type === 'Identifier' && + node.callee.property.name === 'aggregate' && + node.loc && + ((node.loc.start.line < this._selection.start.line && + node.loc.end.line > this._selection.start.line + 1) || + (node.loc.start.line === this._selection.start.line && + node.loc.start.column <= this._selection.start.character) || + (node.loc.end.line === this._selection.start.line + 1 && + node.loc.end.column >= this._selection.start.character)) + ) { + this._state.isAggregation = true; + } + } + _checkIsStage(node: babel.types.ArrayExpression): void { if (node.elements) { node.elements.forEach((item) => { diff --git a/src/test/suite/language/mongoDBService.test.ts b/src/test/suite/language/mongoDBService.test.ts index 92f7d710c..b63708d85 100644 --- a/src/test/suite/language/mongoDBService.test.ts +++ b/src/test/suite/language/mongoDBService.test.ts @@ -7,7 +7,10 @@ import { DiagnosticSeverity, MarkupContent, } from 'vscode-languageclient/node'; -import type { CompletionItem } from 'vscode-languageclient/node'; +import type { + CompletionItem, + SignatureInformation, +} from 'vscode-languageclient/node'; import chai from 'chai'; import { createConnection } from 'vscode-languageserver/node'; import fs from 'fs'; @@ -2456,4 +2459,52 @@ suite('MongoDBService Test Suite', () => { ]); }); }); + + suite('Signature Help', function () { + const up = new StreamStub(); + const down = new StreamStub(); + const connection = createConnection(up, down); + + connection.listen(); + + const testMongoDBService = new MongoDBService(connection); + + before(async () => { + await testMongoDBService.connectToServiceProvider(params); + }); + + test('provide collection find signature', () => { + const result = testMongoDBService.provideSignatureHelp( + "db.getCollection('sales').find({ year: {}, });", + { line: 0, character: 42 } + ); + const completion = result?.signatures.find( + (item: SignatureInformation) => + item.label === 'Collection.find(query, projection, options) : Cursor' + ); + + expect(completion?.documentation).to.be.eql( + 'Selects documents in a collection or view.' + ); + }); + + test('provide collection aggregate signature', () => { + const result = testMongoDBService.provideSignatureHelp( + [ + "db.getCollection('sales').aggregate([", + " { $match: { date: { $gte: new Date('2014-01-01'), $lt: new Date('2015-01-01') } } },", + ']);', + ].join('\n'), + { line: 1, character: 86 } + ); + const completion = result?.signatures.find( + (item: SignatureInformation) => + item.label === 'Collection.aggregate(pipeline, options) : Cursor' + ); + + expect(completion?.documentation).to.be.eql( + 'Calculates aggregate values for the data in a collection or a view.' + ); + }); + }); }); diff --git a/tsconfig.json b/tsconfig.json index 869b9fd61..412b8f6ee 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,9 +2,9 @@ "compilerOptions": { "module": "commonjs", "noImplicitAny": false, - "target": "es2019", + "target": "es2020", "outDir": "out", - "lib": ["dom", "es2019"], + "lib": ["dom", "es2020"], "types": ["node"], "jsx": "react", "sourceMap": true, From 3f1bb2a0dd99fc5ee4f633bb019e33e0eeaebeb1 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 5 Apr 2023 22:20:47 +0200 Subject: [PATCH 03/13] refactor: track state depending on the use case --- src/language/mongoDBService.ts | 19 +-- src/language/server.ts | 7 +- src/language/visitor.ts | 225 +++++++++++++++++++++++---------- 3 files changed, 172 insertions(+), 79 deletions(-) diff --git a/src/language/mongoDBService.ts b/src/language/mongoDBService.ts index 33a691ed0..c9d87d6ce 100644 --- a/src/language/mongoDBService.ts +++ b/src/language/mongoDBService.ts @@ -400,7 +400,7 @@ export default class MongoDBService { getExportToLanguageMode( params: PlaygroundTextAndSelection ): ExportToLanguageMode { - const state = this._visitor.parseAST(params); + const state = this._visitor.parseASTForExportToLanguage(params); if (state.isArraySelection) { return ExportToLanguageMode.AGGREGATION; @@ -421,7 +421,7 @@ export default class MongoDBService { params: PlaygroundTextAndSelection ): ExportToLanguageNamespace { try { - const state = this._visitor.parseAST(params); + const state = this._visitor.parseASTForNamespace(params); return { databaseName: state.databaseName, collectionName: state.collectionName, @@ -803,13 +803,10 @@ export default class MongoDBService { position: { line: number; character: number } ): Promise { this._connection.console.log( - `LS current symbol position: ${util.inspect(position)}` + `Provide completion items for a position: ${util.inspect(position)}` ); - const state = this._visitor.parseASTWithPlaceholder( - textFromEditor, - position - ); + const state = this._visitor.parseASTForCompletion(textFromEditor, position); this._connection.console.log( `VISITOR completion state: ${util.inspect(state)}` ); @@ -847,16 +844,20 @@ export default class MongoDBService { return []; } + /** + * Parse code from a playground to identify + * where the cursor is and show mongodb method signature help items. + */ provideSignatureHelp( textFromEditor: string, position: { line: number; character: number }, context?: SignatureHelpContext ) { this._connection.console.log( - `LS current symbol position: ${util.inspect(position)}` + `Provide signature help for a position: ${util.inspect(position)}` ); - const state = this._visitor.parseASTWithPlaceholder( + const state = this._visitor.parseASTWForSignatureHelp( textFromEditor, position ); diff --git a/src/language/server.ts b/src/language/server.ts index 00be60c7d..422869570 100644 --- a/src/language/server.ts +++ b/src/language/server.ts @@ -128,8 +128,6 @@ connection.onDidChangeConfiguration((/* change */) => { // Only keep settings for open documents. documents.onDidClose((e) => { - // connection.console.log(`documents.onDidClose: ${JSON.stringify(e)}`); - documentSettings.delete(e.document.uri); }); @@ -251,10 +249,7 @@ connection.onSignatureHelp((params: SignatureHelpParams) => { return mongodbSignatures; } - return typeScriptService.doSignatureHelp( - document, - params.position - ); + return typeScriptService.doSignatureHelp(document, params.position); }); connection.onRequest('textDocument/rangeFormatting', (event) => { diff --git a/src/language/visitor.ts b/src/language/visitor.ts index 5c70d32d4..dc60d9b16 100644 --- a/src/language/visitor.ts +++ b/src/language/visitor.ts @@ -23,14 +23,10 @@ type ObjectKey = export interface CompletionState { databaseName: string | null; collectionName: string | null; - isObjectSelection: boolean; - isArraySelection: boolean; isObjectKey: boolean; isIdentifierObjectValue: boolean; isTextObjectValue: boolean; isStage: boolean; - isFind: boolean; - isAggregation: boolean; stageOperator: string | null; isCollectionSymbol: boolean; isUseCallExpression: boolean; @@ -41,12 +37,27 @@ export interface CompletionState { isFindCursor: boolean; } +export interface SignatureState { + isFind: boolean; + isAggregation: boolean; +} + +export interface ExportToLanguageState { + isObjectSelection: boolean; + isArraySelection: boolean; +} + +export interface NamespaceState { + databaseName: string | null; + collectionName: string | null; +} + export class Visitor { - _state: CompletionState; + _state: CompletionState | SignatureState | ExportToLanguageState | {}; _selection: VisitorSelection; constructor() { - this._state = this._getDefaultNodesValues(); + this._state = {}; this._selection = { start: { line: 0, character: 0 }, end: { line: 0, character: 0 }, @@ -137,7 +148,7 @@ export class Visitor { return textLines.join('\n'); } - parseASTWithPlaceholder( + parseASTForCompletion( textFromEditor: string, position: { line: number; character: number } ): CompletionState { @@ -146,16 +157,44 @@ export class Visitor { end: { line: 0, character: 0 }, }; + this._state = this._getDefaultNodesForCompletion(); + textFromEditor = this._handleTriggerCharacter(textFromEditor, position); + + this.parseAST({ textFromEditor, selection }); + + return this._state as CompletionState; + } + + parseASTWForSignatureHelp( + textFromEditor: string, + position: { line: number; character: number } + ): SignatureState { + const selection: VisitorSelection = { + start: position, + end: { line: 0, character: 0 }, + }; + + this._state = this._getDefaultNodesForSignatureHelp(); textFromEditor = this._handleTriggerCharacter(textFromEditor, position); - return this.parseAST({ textFromEditor, selection }); + this.parseAST({ textFromEditor, selection }); + + return this._state as SignatureState; } - parseAST({ - textFromEditor, - selection, - }: VisitorTextAndSelection): CompletionState { - this._state = this._getDefaultNodesValues(); + parseASTForExportToLanguage(params): ExportToLanguageState { + this._state = this._getDefaultNodesForExportToLanguagep(); + this.parseAST(params); + return this._state as ExportToLanguageState; + } + + parseASTForNamespace(params): NamespaceState { + this._state = this._getDefaultNodesForNamespace(); + this.parseAST(params); + return this._state as NamespaceState; + } + + parseAST({ textFromEditor, selection }: VisitorTextAndSelection) { this._selection = selection; let ast; @@ -166,7 +205,6 @@ export class Visitor { }); } catch (error) { console.error(`parseAST error: ${util.inspect(error)}`); - return this._state; } traverse(ast, { @@ -180,11 +218,9 @@ export class Visitor { this._visitObjectProperty(path); }, }); - - return this._state; } - _getDefaultNodesValues() { + _getDefaultNodesForCompletion() { return { databaseName: null, collectionName: null, @@ -207,13 +243,35 @@ export class Visitor { }; } + _getDefaultNodesForSignatureHelp() { + return { + isFind: false, + isAggregation: false, + }; + } + + _getDefaultNodesForExportToLanguagep() { + return { + isArraySelection: false, + isObjectSelection: false, + }; + } + + _getDefaultNodesForNamespace() { + return { + databaseName: null, + collectionName: null, + }; + } + _checkIsUseCallAsSimpleString(node: babel.types.CallExpression): void { if ( node.callee.type === 'Identifier' && node.callee.name === 'use' && node.arguments.length === 1 && node.arguments[0].type === 'StringLiteral' && - node.arguments[0].value.includes(PLACEHOLDER) + node.arguments[0].value.includes(PLACEHOLDER) && + 'isUseCallExpression' in this._state ) { this._state.isUseCallExpression = true; } @@ -226,7 +284,8 @@ export class Visitor { node.arguments[0].type === 'TemplateLiteral' && node.arguments[0].quasis.length === 1 && node.arguments[0].quasis[0].value?.raw && - node.arguments[0].quasis[0].value?.raw.includes(PLACEHOLDER) + node.arguments[0].quasis[0].value?.raw.includes(PLACEHOLDER) && + 'isUseCallExpression' in this._state ) { this._state.isUseCallExpression = true; } @@ -240,7 +299,8 @@ export class Visitor { _checkIsGlobalSymbol(node: babel.types.ExpressionStatement): void { if ( node.expression.type === 'Identifier' && - node.expression.name.includes('TRIGGER_CHARACTER') + node.expression.name.includes('TRIGGER_CHARACTER') && + 'isGlobalSymbol' in this._state ) { this._state.isGlobalSymbol = true; } @@ -250,7 +310,8 @@ export class Visitor { if ( node.expression.type === 'MemberExpression' && node.expression.object.type === 'Identifier' && - node.expression.object.name === 'db' + node.expression.object.name === 'db' && + 'isDbSymbol' in this._state ) { this._state.isDbSymbol = true; } @@ -261,7 +322,8 @@ export class Visitor { if ( item.type === 'ObjectProperty' && item.key.type === 'Identifier' && - item.key.name.includes(PLACEHOLDER) + item.key.name.includes(PLACEHOLDER) && + 'isObjectKey' in this._state ) { this._state.isObjectKey = true; } @@ -273,7 +335,8 @@ export class Visitor { if ( item.type === 'ObjectProperty' && item.value.type === 'Identifier' && - item.value.name.includes(PLACEHOLDER) + item.value.name.includes(PLACEHOLDER) && + 'isIdentifierObjectValue' in this._state ) { this._state.isIdentifierObjectValue = true; } @@ -283,48 +346,41 @@ export class Visitor { _checkIsTextObjectValue(node: babel.types.ObjectExpression): void { node.properties.find((item: ObjectKey) => { if ( - (item.type === 'ObjectProperty' && + ((item.type === 'ObjectProperty' && item.value.type === 'StringLiteral' && item.value.value.includes(PLACEHOLDER)) || - (item.type === 'ObjectProperty' && - item.value.type === 'TemplateLiteral' && - item.value?.quasis.length === 1 && - item.value.quasis[0].value?.raw.includes(PLACEHOLDER)) + (item.type === 'ObjectProperty' && + item.value.type === 'TemplateLiteral' && + item.value?.quasis.length === 1 && + item.value.quasis[0].value?.raw.includes(PLACEHOLDER))) && + 'isTextObjectValue' in this._state ) { this._state.isTextObjectValue = true; } }); } + // eslint-disable-next-line complexity _checkIsFind(node: babel.types.CallExpression) { if ( node.callee.type === 'MemberExpression' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'find' && - node.loc && - ((node.loc.start.line < this._selection.start.line && - node.loc.end.line > this._selection.start.line + 1) || - (node.loc.start.line === this._selection.start.line && - node.loc.start.column <= this._selection.start.character) || - (node.loc.end.line === this._selection.start.line + 1 && - node.loc.end.column >= this._selection.start.character)) + this._isWithinFunctionCall(node) && + 'isFind' in this._state ) { this._state.isFind = true; } } + // eslint-disable-next-line complexity _checkIsAggregation(node: babel.types.CallExpression): void { if ( node.callee.type === 'MemberExpression' && node.callee.property.type === 'Identifier' && node.callee.property.name === 'aggregate' && - node.loc && - ((node.loc.start.line < this._selection.start.line && - node.loc.end.line > this._selection.start.line + 1) || - (node.loc.start.line === this._selection.start.line && - node.loc.start.column <= this._selection.start.character) || - (node.loc.end.line === this._selection.start.line + 1 && - node.loc.end.column >= this._selection.start.character)) + this._isWithinFunctionCall(node) && + 'isAggregation' in this._state ) { this._state.isAggregation = true; } @@ -338,7 +394,8 @@ export class Visitor { if ( item.type === 'ObjectProperty' && item.key.type === 'Identifier' && - item.key.name.includes(PLACEHOLDER) + item.key.name.includes(PLACEHOLDER) && + 'isStage' in this._state ) { this._state.isStage = true; } @@ -364,7 +421,8 @@ export class Visitor { if ( path.node.type === 'ObjectProperty' && path.node.key.type === 'Identifier' && - path.node.key.name.includes(PLACEHOLDER) + path.node.key.name.includes(PLACEHOLDER) && + 'stageOperator' in this._state ) { this._state.stageOperator = name; } @@ -382,13 +440,13 @@ export class Visitor { ): boolean { if ( node.loc?.start?.line && - (node.loc.start.line - 1 < this._selection.start?.line || - (node.loc.start.line - 1 === this._selection.start?.line && - node.loc.start.column < this._selection.start?.character)) && - node.loc?.end?.line && - (node.loc.end.line - 1 > this._selection.end?.line || - (node.loc.end.line - 1 === this._selection.end?.line && - node.loc.end.column > this._selection.end?.character)) + (node.loc.start.line - 1 < this._selection.start.line || + (node.loc.start.line - 1 === this._selection.start.line && + node.loc.start.column < this._selection.start.character)) && + node.loc.end.line && + (node.loc.end.line - 1 > this._selection.end.line || + (node.loc.end.line - 1 === this._selection.end.line && + node.loc.end.column > this._selection.end.character)) ) { return true; } @@ -443,14 +501,38 @@ export class Visitor { return false; } + _isWithinFunctionCall(node: babel.types.CallExpression): boolean { + if ( + node.loc && + ((node.loc.start.line < this._selection.start.line && + node.loc.end.line > this._selection.start.line + 1) || + (node.loc.start.line === this._selection.start.line && + node.loc.start.column <= this._selection.start.character) || + (node.loc.end.line === this._selection.start.line + 1 && + node.loc.end.column >= this._selection.start.character)) + ) { + return true; + } + + return false; + } + _checkIsArrayWithinSelection(node: babel.types.Node): void { - if (node.type === 'ArrayExpression' && this._isWithinSelection(node)) { + if ( + node.type === 'ArrayExpression' && + this._isWithinSelection(node) && + 'isArraySelection' in this._state + ) { this._state.isArraySelection = true; } } _checkIsObjectWithinSelection(node: babel.types.Node): void { - if (node.type === 'ObjectExpression' && this._isWithinSelection(node)) { + if ( + node.type === 'ObjectExpression' && + this._isWithinSelection(node) && + 'isObjectSelection' in this._state + ) { this._state.isObjectSelection = true; } } @@ -517,7 +599,8 @@ export class Visitor { ((node.property.type === 'Identifier' && node.property.name.includes(PLACEHOLDER)) || (node.property.type === 'StringLiteral' && - node.property.value.includes(PLACEHOLDER))) + node.property.value.includes(PLACEHOLDER))) && + 'isCollectionName' in this._state ) { this._state.isCollectionName = true; } @@ -526,7 +609,8 @@ export class Visitor { _checkGetCollectionAsSimpleString(node: babel.types.CallExpression): void { if ( node.arguments[0].type === 'StringLiteral' && - node.arguments[0].value.includes(PLACEHOLDER) + node.arguments[0].value.includes(PLACEHOLDER) && + 'isCollectionName' in this._state ) { this._state.isCollectionName = true; } @@ -536,7 +620,8 @@ export class Visitor { if ( node.arguments[0].type === 'TemplateLiteral' && node.arguments[0].quasis.length === 1 && - node.arguments[0].quasis[0].value.raw.includes(PLACEHOLDER) + node.arguments[0].quasis[0].value.raw.includes(PLACEHOLDER) && + 'isCollectionName' in this._state ) { this._state.isCollectionName = true; } @@ -566,7 +651,8 @@ export class Visitor { node.object.callee.type === 'MemberExpression' && !node.object.callee.computed && node.object.callee.property.type === 'Identifier' && - node.object.callee.property.name === 'aggregate' + node.object.callee.property.name === 'aggregate' && + 'isAggregationCursor' in this._state ) { this._state.isAggregationCursor = true; } @@ -580,7 +666,8 @@ export class Visitor { node.object.callee.type === 'MemberExpression' && !node.object.callee.computed && node.object.callee.property.type === 'Identifier' && - node.object.callee.property.name === 'find' + node.object.callee.property.name === 'find' && + 'isFindCursor' in this._state ) { this._state.isFindCursor = true; } @@ -595,7 +682,8 @@ export class Visitor { node.loc && (this._selection.start.line > node.loc.end.line - 1 || (this._selection.start.line === node.loc.end.line - 1 && - this._selection.start.character >= node.loc.end.column)) + this._selection.start.character >= node.loc.end.column)) && + 'databaseName' in this._state ) { this._state.databaseName = node.arguments[0].value; } @@ -609,9 +697,15 @@ export class Visitor { node.object.object.type === 'Identifier' && node.object.object.name === 'db' ) { - if (node.object.property.type === 'Identifier') { + if ( + node.object.property.type === 'Identifier' && + 'collectionName' in this._state + ) { this._state.collectionName = node.object.property.name; - } else if (node.object.property.type === 'StringLiteral') { + } else if ( + node.object.property.type === 'StringLiteral' && + 'collectionName' in this._state + ) { this._state.collectionName = node.object.property.value; } } @@ -626,7 +720,8 @@ export class Visitor { node.object.callee.property.type === 'Identifier' && node.object.callee.property.name === 'getCollection' && node.object.arguments.length === 1 && - node.object.arguments[0].type === 'StringLiteral' + node.object.arguments[0].type === 'StringLiteral' && + 'collectionName' in this._state ) { this._state.collectionName = node.object.arguments[0].value; } @@ -643,7 +738,8 @@ export class Visitor { node.object.object.type === 'Identifier' && node.object.object.name === 'db' && node.property.type === 'Identifier' && - node.property.name.includes(PLACEHOLDER) + node.property.name.includes(PLACEHOLDER) && + 'isCollectionSymbol' in this._state ) { this._state.isCollectionSymbol = true; } @@ -658,7 +754,8 @@ export class Visitor { node.object.callee.property.type === 'Identifier' && node.object.callee.property.name === 'getCollection' && node.property.type === 'Identifier' && - node.property.name.includes(PLACEHOLDER) + node.property.name.includes(PLACEHOLDER) && + 'isCollectionSymbol' in this._state ) { this._state.isCollectionSymbol = true; } From b86a91236d7dcfa6899b15044a0db15c47ce47e0 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 5 Apr 2023 22:33:32 +0200 Subject: [PATCH 04/13] build: bump dependencies --- package-lock.json | 519 +++++++++++++++++++++++----------------------- package.json | 30 +-- 2 files changed, 279 insertions(+), 270 deletions(-) diff --git a/package-lock.json b/package-lock.json index ddcad6030..89509a742 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,10 @@ "version": "0.0.0-dev.0", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { - "@babel/parser": "^7.21.3", - "@babel/traverse": "^7.21.3", - "@fortawesome/fontawesome-svg-core": "^6.3.0", - "@fortawesome/free-solid-svg-icons": "^6.3.0", + "@babel/parser": "^7.21.4", + "@babel/traverse": "^7.21.4", + "@fortawesome/fontawesome-svg-core": "^6.4.0", + "@fortawesome/free-solid-svg-icons": "^6.4.0", "@fortawesome/react-fontawesome": "^0.2.0", "@iconify-icons/codicon": "^1.2.23", "@iconify/react": "^1.1.4", @@ -24,13 +24,13 @@ "@mongosh/service-provider-server": "^1.8.0", "@mongosh/shell-api": "^1.8.0", "analytics-node": "^6.2.0", - "bson": "^5.1.0", + "bson": "^5.2.0", "bson-transpilers": "^2.0.3", "classnames": "^2.3.2", "debug": "^4.3.4", "dotenv": "^16.0.3", "micromatch": "^4.0.5", - "mongodb": "^5.1.0", + "mongodb": "^5.2.0", "mongodb-build-info": "^1.5.0", "mongodb-cloud-info": "^1.1.3", "mongodb-connection-string-url": "^2.6.0", @@ -62,14 +62,14 @@ "@types/micromatch": "^4.0.2", "@types/mkdirp": "^2.0.0", "@types/mocha": "^8.2.3", - "@types/node": "^14.18.40", - "@types/react": "^17.0.53", + "@types/node": "^14.18.42", + "@types/react": "^17.0.56", "@types/react-dom": "^17.0.19", "@types/sinon": "^9.0.11", "@types/uuid": "^8.3.4", - "@types/vscode": "^1.76.0", - "@typescript-eslint/eslint-plugin": "^5.56.0", - "@typescript-eslint/parser": "^5.56.0", + "@types/vscode": "^1.77.0", + "@typescript-eslint/eslint-plugin": "^5.57.1", + "@typescript-eslint/parser": "^5.57.1", "@vscode/test-electron": "^2.3.0", "@vscode/vsce": "^2.18.0", "@wojtekmaj/enzyme-adapter-react-17": "^0.8.0", @@ -84,9 +84,9 @@ "css-loader": "^3.6.0", "depcheck": "^1.4.3", "download": "^8.0.0", - "electron": "^23.2.0", + "electron": "^23.2.2", "enzyme": "^3.11.0", - "eslint": "^8.36.0", + "eslint": "^8.37.0", "eslint-config-mongodb-js": "^5.0.3", "eslint-plugin-mocha": "^10.1.0", "execa": "^1.0.0", @@ -118,7 +118,7 @@ "ts-loader": "^9.4.2", "ts-node": "^10.9.1", "typescript": "^4.9.5", - "webpack": "^5.76.3", + "webpack": "^5.78.0", "webpack-cli": "^4.10.0", "xvfb-maybe": "^0.2.1", "yargs-parser": "^20.2.9" @@ -126,7 +126,7 @@ "engines": { "node": "^16.16.0", "npm": "^8.15.1", - "vscode": "^1.76.2" + "vscode": "^1.77.0" } }, "node_modules/@ampproject/remapping": { @@ -1406,9 +1406,9 @@ "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "dependencies": { "@babel/highlight": "^7.18.6" }, @@ -1464,11 +1464,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", - "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", + "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", "dependencies": { - "@babel/types": "^7.21.3", + "@babel/types": "^7.21.4", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -1676,9 +1676,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", - "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", + "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1875,18 +1875,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", - "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", + "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/parser": "^7.21.4", + "@babel/types": "^7.21.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1895,9 +1895,9 @@ } }, "node_modules/@babel/types": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", - "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", + "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -2308,14 +2308,14 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", - "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -2397,42 +2397,42 @@ } }, "node_modules/@eslint/js": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", - "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.37.0.tgz", + "integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@fortawesome/fontawesome-common-types": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz", - "integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz", + "integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==", "hasInstallScript": true, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/fontawesome-svg-core": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz", - "integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz", + "integrity": "sha512-Bertv8xOiVELz5raB2FlXDPKt+m94MQ3JgDfsVbrqNpLU9+UE2E18GKjLKw+d3XbeYPqg1pzyQKGsrzbw+pPaw==", "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "6.3.0" + "@fortawesome/fontawesome-common-types": "6.4.0" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-solid-svg-icons": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz", - "integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.0.tgz", + "integrity": "sha512-kutPeRGWm8V5dltFP1zGjQOEAzaLZj4StdQhWVZnfGFCvAPVvHh8qk5bRrU4KXnRRRNni5tKQI9PBAdI6MP8nQ==", "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "6.3.0" + "@fortawesome/fontawesome-common-types": "6.4.0" }, "engines": { "node": ">=6" @@ -4309,9 +4309,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "14.18.40", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.40.tgz", - "integrity": "sha512-pGteXO/JQX7wPxGR8lyT+doqjMa7XvlVowwrDwLfX92k5SdLkk4cwC7CYSLBxrenw/R5oQwKioVIak7ZgplM3g==" + "version": "14.18.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.42.tgz", + "integrity": "sha512-xefu+RBie4xWlK8hwAzGh3npDz/4VhF6icY/shU+zv/1fNn+ZVG7T7CRwe9LId9sAYRPxI+59QBPuKL3WpyGRg==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.0", @@ -4336,9 +4336,9 @@ "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" }, "node_modules/@types/react": { - "version": "17.0.53", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.53.tgz", - "integrity": "sha512-1yIpQR2zdYu1Z/dc1OxC+MA6GR240u3gcnP4l6mvj/PJiVaqHsQPmWttsvHsfnhfPbU2FuGmo0wSITPygjBmsw==", + "version": "17.0.56", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.56.tgz", + "integrity": "sha512-Z13f9Qz7Hg8f2g2NsBjiJSVWmON2b3K8RIqFK8mMKCIgvD0CD0ZChTukz87H3lI28X3ukXoNFGzo3ZW1ICTtPA==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4414,9 +4414,9 @@ "dev": true }, "node_modules/@types/vscode": { - "version": "1.76.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.76.0.tgz", - "integrity": "sha512-CQcY3+Fe5hNewHnOEAVYj4dd1do/QHliXaknAEYSXx2KEHUzFibDZSKptCon+HPgK55xx20pR+PBJjf0MomnBA==", + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.77.0.tgz", + "integrity": "sha512-MWFN5R7a33n8eJZJmdVlifjig3LWUNRrPeO1xemIcZ0ae0TEQuRc7G2xV0LUX78RZFECY1plYBn+dP/Acc3L0Q==", "dev": true }, "node_modules/@types/webidl-conversions": { @@ -4450,15 +4450,15 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.56.0.tgz", - "integrity": "sha512-ZNW37Ccl3oMZkzxrYDUX4o7cnuPgU+YrcaYXzsRtLB16I1FR5SHMqga3zGsaSliZADCWo2v8qHWqAYIj8nWCCg==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.1.tgz", + "integrity": "sha512-1MeobQkQ9tztuleT3v72XmY0XuKXVXusAhryoLuU5YZ+mXoYKZP9SQ7Flulh1NX4DTjpGTc2b/eMu4u7M7dhnQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.56.0", - "@typescript-eslint/type-utils": "5.56.0", - "@typescript-eslint/utils": "5.56.0", + "@typescript-eslint/scope-manager": "5.57.1", + "@typescript-eslint/type-utils": "5.57.1", + "@typescript-eslint/utils": "5.57.1", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -4493,14 +4493,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.56.0.tgz", - "integrity": "sha512-sn1OZmBxUsgxMmR8a8U5QM/Wl+tyqlH//jTqCg8daTAmhAk26L2PFhcqPLlYBhYUJMZJK276qLXlHN3a83o2cg==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.1.tgz", + "integrity": "sha512-hlA0BLeVSA/wBPKdPGxoVr9Pp6GutGoY380FEhbVi0Ph4WNe8kLvqIRx76RSQt1lynZKfrXKs0/XeEk4zZycuA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.56.0", - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/typescript-estree": "5.56.0", + "@typescript-eslint/scope-manager": "5.57.1", + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/typescript-estree": "5.57.1", "debug": "^4.3.4" }, "engines": { @@ -4520,13 +4520,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.56.0.tgz", - "integrity": "sha512-jGYKyt+iBakD0SA5Ww8vFqGpoV2asSjwt60Gl6YcO8ksQ8s2HlUEyHBMSa38bdLopYqGf7EYQMUIGdT/Luw+sw==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.1.tgz", + "integrity": "sha512-N/RrBwEUKMIYxSKl0oDK5sFVHd6VI7p9K5MyUlVYAY6dyNb/wHUqndkTd3XhpGlXgnQsBkRZuu4f9kAHghvgPw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/visitor-keys": "5.56.0" + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/visitor-keys": "5.57.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -4537,13 +4537,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.56.0.tgz", - "integrity": "sha512-8WxgOgJjWRy6m4xg9KoSHPzBNZeQbGlQOH7l2QEhQID/+YseaFxg5J/DLwWSsi9Axj4e/cCiKx7PVzOq38tY4A==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.1.tgz", + "integrity": "sha512-/RIPQyx60Pt6ga86hKXesXkJ2WOS4UemFrmmq/7eOyiYjYv/MUSHPlkhU6k9T9W1ytnTJueqASW+wOmW4KrViw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.56.0", - "@typescript-eslint/utils": "5.56.0", + "@typescript-eslint/typescript-estree": "5.57.1", + "@typescript-eslint/utils": "5.57.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -4564,9 +4564,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.56.0.tgz", - "integrity": "sha512-JyAzbTJcIyhuUhogmiu+t79AkdnqgPUEsxMTMc/dCZczGMJQh1MK2wgrju++yMN6AWroVAy2jxyPcPr3SWCq5w==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.1.tgz", + "integrity": "sha512-bSs4LOgyV3bJ08F5RDqO2KXqg3WAdwHCu06zOqcQ6vqbTJizyBhuh1o1ImC69X4bV2g1OJxbH71PJqiO7Y1RuA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -4577,13 +4577,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.56.0.tgz", - "integrity": "sha512-41CH/GncsLXOJi0jb74SnC7jVPWeVJ0pxQj8bOjH1h2O26jXN3YHKDT1ejkVz5YeTEQPeLCCRY0U2r68tfNOcg==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.1.tgz", + "integrity": "sha512-A2MZqD8gNT0qHKbk2wRspg7cHbCDCk2tcqt6ScCFLr5Ru8cn+TCfM786DjPhqwseiS+PrYwcXht5ztpEQ6TFTw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/visitor-keys": "5.56.0", + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/visitor-keys": "5.57.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4604,17 +4604,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.56.0.tgz", - "integrity": "sha512-XhZDVdLnUJNtbzaJeDSCIYaM+Tgr59gZGbFuELgF7m0IY03PlciidS7UQNKLE0+WpUTn1GlycEr6Ivb/afjbhA==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.1.tgz", + "integrity": "sha512-kN6vzzf9NkEtawECqze6v99LtmDiUJCVpvieTFA1uL7/jDghiJGubGZ5csicYHU1Xoqb3oH/R5cN5df6W41Nfg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.56.0", - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/typescript-estree": "5.56.0", + "@typescript-eslint/scope-manager": "5.57.1", + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/typescript-estree": "5.57.1", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, @@ -4630,12 +4630,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.56.0.tgz", - "integrity": "sha512-1mFdED7u5bZpX6Xxf5N9U2c18sb+8EvU3tyOIj6LQZ5OOvnmj8BVeNNP603OFPm5KkS1a7IvCIcwrdHXaEMG/Q==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.1.tgz", + "integrity": "sha512-RjQrAniDU0CEk5r7iphkm731zKlFiUjvcBS2yHAg8WWqFMCaCrD0rKEVOMUyMMcbGPZ0bPp56srkGWrgfZqLRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.56.0", + "@typescript-eslint/types": "5.57.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -4647,12 +4647,15 @@ } }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@ungap/promise-all-settled": { @@ -6220,9 +6223,9 @@ } }, "node_modules/bson": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.1.0.tgz", - "integrity": "sha512-FEecNHkhYRBe7X9KDkdG12xNuz5VHGeH6mCE0B5sBmYtiR/Ux/9vUH/v4NUoBCDr6NuEhvahjoLiiRogptVW0A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.2.0.tgz", + "integrity": "sha512-HevkSpDbpUfsrHWmWiAsNavANKYIErV2ePXllp1bwq5CDreAaFVj6RVlZpJnxK4WWDCJ/5jMUpaY6G526q3Hjg==", "engines": { "node": ">=14.20.1" } @@ -8732,9 +8735,9 @@ } }, "node_modules/electron": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-23.2.0.tgz", - "integrity": "sha512-De9e21cri0QYct/w6tTNOnKyCt9RVKUw5F8PEN4FPzGR9tr6IT53uyt42uH754uJWrZeLMCAdoXy6/0GmMmYZA==", + "version": "23.2.2", + "resolved": "https://registry.npmjs.org/electron/-/electron-23.2.2.tgz", + "integrity": "sha512-8UfC2NCaqLJvdWoAfzAi56DaF+8cD3QPbnabKMdYNxMhYJ54gAje4ChVRo3sUMD5uSMk6MbPYCdnoMusCrfzrQ==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -9097,15 +9100,15 @@ } }, "node_modules/eslint": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", - "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.1", - "@eslint/js": "8.36.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.37.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -9116,8 +9119,8 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.5.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -9705,12 +9708,15 @@ } }, "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/estraverse": { @@ -9959,14 +9965,14 @@ } }, "node_modules/espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -9988,12 +9994,15 @@ } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -16527,11 +16536,11 @@ } }, "node_modules/mongodb": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.1.0.tgz", - "integrity": "sha512-qgKb7y+EI90y4weY3z5+lIgm8wmexbonz0GalHkSElQXVKtRuwqXuhXKccyvIjXCJVy9qPV82zsinY0W1FBnJw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.2.0.tgz", + "integrity": "sha512-nLgo95eP1acvjBcOdrUV3aqpWwHZCZwhYA2opB8StybbtQL/WoE5pk92qUUfjbKOWcGLYJczTqQbfOQhYtrkKg==", "dependencies": { - "bson": "^5.0.1", + "bson": "^5.2.0", "mongodb-connection-string-url": "^2.6.0", "socks": "^2.7.1" }, @@ -23138,9 +23147,9 @@ } }, "node_modules/webpack": { - "version": "5.76.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.3.tgz", - "integrity": "sha512-18Qv7uGPU8b2vqGeEEObnfICyw2g39CHlDEK4I7NK13LOur1d0HGmGNKGT58Eluwddpn3oEejwvBPoP4M7/KSA==", + "version": "5.78.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.78.0.tgz", + "integrity": "sha512-gT5DP72KInmE/3azEaQrISjTvLYlSM0j1Ezhht/KLVkrqtv10JoP/RXhwmX/frrutOPuSq3o5Vq0ehR/4Vmd1g==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -25064,9 +25073,9 @@ } }, "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "requires": { "@babel/highlight": "^7.18.6" } @@ -25108,11 +25117,11 @@ } }, "@babel/generator": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", - "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", + "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", "requires": { - "@babel/types": "^7.21.3", + "@babel/types": "^7.21.4", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -25269,9 +25278,9 @@ } }, "@babel/parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", - "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==" + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", + "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==" }, "@babel/plugin-syntax-async-generators": { "version": "7.8.4", @@ -25432,26 +25441,26 @@ } }, "@babel/traverse": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", - "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", + "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/parser": "^7.21.4", + "@babel/types": "^7.21.4", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", - "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", + "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", "requires": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -25757,14 +25766,14 @@ "dev": true }, "@eslint/eslintrc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", - "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -25821,30 +25830,30 @@ } }, "@eslint/js": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", - "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.37.0.tgz", + "integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==", "dev": true }, "@fortawesome/fontawesome-common-types": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz", - "integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg==" + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz", + "integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==" }, "@fortawesome/fontawesome-svg-core": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz", - "integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz", + "integrity": "sha512-Bertv8xOiVELz5raB2FlXDPKt+m94MQ3JgDfsVbrqNpLU9+UE2E18GKjLKw+d3XbeYPqg1pzyQKGsrzbw+pPaw==", "requires": { - "@fortawesome/fontawesome-common-types": "6.3.0" + "@fortawesome/fontawesome-common-types": "6.4.0" } }, "@fortawesome/free-solid-svg-icons": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz", - "integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.0.tgz", + "integrity": "sha512-kutPeRGWm8V5dltFP1zGjQOEAzaLZj4StdQhWVZnfGFCvAPVvHh8qk5bRrU4KXnRRRNni5tKQI9PBAdI6MP8nQ==", "requires": { - "@fortawesome/fontawesome-common-types": "6.3.0" + "@fortawesome/fontawesome-common-types": "6.4.0" } }, "@fortawesome/react-fontawesome": { @@ -27462,9 +27471,9 @@ "dev": true }, "@types/node": { - "version": "14.18.40", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.40.tgz", - "integrity": "sha512-pGteXO/JQX7wPxGR8lyT+doqjMa7XvlVowwrDwLfX92k5SdLkk4cwC7CYSLBxrenw/R5oQwKioVIak7ZgplM3g==" + "version": "14.18.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.42.tgz", + "integrity": "sha512-xefu+RBie4xWlK8hwAzGh3npDz/4VhF6icY/shU+zv/1fNn+ZVG7T7CRwe9LId9sAYRPxI+59QBPuKL3WpyGRg==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -27489,9 +27498,9 @@ "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" }, "@types/react": { - "version": "17.0.53", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.53.tgz", - "integrity": "sha512-1yIpQR2zdYu1Z/dc1OxC+MA6GR240u3gcnP4l6mvj/PJiVaqHsQPmWttsvHsfnhfPbU2FuGmo0wSITPygjBmsw==", + "version": "17.0.56", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.56.tgz", + "integrity": "sha512-Z13f9Qz7Hg8f2g2NsBjiJSVWmON2b3K8RIqFK8mMKCIgvD0CD0ZChTukz87H3lI28X3ukXoNFGzo3ZW1ICTtPA==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -27567,9 +27576,9 @@ "dev": true }, "@types/vscode": { - "version": "1.76.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.76.0.tgz", - "integrity": "sha512-CQcY3+Fe5hNewHnOEAVYj4dd1do/QHliXaknAEYSXx2KEHUzFibDZSKptCon+HPgK55xx20pR+PBJjf0MomnBA==", + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.77.0.tgz", + "integrity": "sha512-MWFN5R7a33n8eJZJmdVlifjig3LWUNRrPeO1xemIcZ0ae0TEQuRc7G2xV0LUX78RZFECY1plYBn+dP/Acc3L0Q==", "dev": true }, "@types/webidl-conversions": { @@ -27603,15 +27612,15 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.56.0.tgz", - "integrity": "sha512-ZNW37Ccl3oMZkzxrYDUX4o7cnuPgU+YrcaYXzsRtLB16I1FR5SHMqga3zGsaSliZADCWo2v8qHWqAYIj8nWCCg==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.1.tgz", + "integrity": "sha512-1MeobQkQ9tztuleT3v72XmY0XuKXVXusAhryoLuU5YZ+mXoYKZP9SQ7Flulh1NX4DTjpGTc2b/eMu4u7M7dhnQ==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.56.0", - "@typescript-eslint/type-utils": "5.56.0", - "@typescript-eslint/utils": "5.56.0", + "@typescript-eslint/scope-manager": "5.57.1", + "@typescript-eslint/type-utils": "5.57.1", + "@typescript-eslint/utils": "5.57.1", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", @@ -27629,53 +27638,53 @@ } }, "@typescript-eslint/parser": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.56.0.tgz", - "integrity": "sha512-sn1OZmBxUsgxMmR8a8U5QM/Wl+tyqlH//jTqCg8daTAmhAk26L2PFhcqPLlYBhYUJMZJK276qLXlHN3a83o2cg==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.1.tgz", + "integrity": "sha512-hlA0BLeVSA/wBPKdPGxoVr9Pp6GutGoY380FEhbVi0Ph4WNe8kLvqIRx76RSQt1lynZKfrXKs0/XeEk4zZycuA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.56.0", - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/typescript-estree": "5.56.0", + "@typescript-eslint/scope-manager": "5.57.1", + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/typescript-estree": "5.57.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.56.0.tgz", - "integrity": "sha512-jGYKyt+iBakD0SA5Ww8vFqGpoV2asSjwt60Gl6YcO8ksQ8s2HlUEyHBMSa38bdLopYqGf7EYQMUIGdT/Luw+sw==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.1.tgz", + "integrity": "sha512-N/RrBwEUKMIYxSKl0oDK5sFVHd6VI7p9K5MyUlVYAY6dyNb/wHUqndkTd3XhpGlXgnQsBkRZuu4f9kAHghvgPw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/visitor-keys": "5.56.0" + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/visitor-keys": "5.57.1" } }, "@typescript-eslint/type-utils": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.56.0.tgz", - "integrity": "sha512-8WxgOgJjWRy6m4xg9KoSHPzBNZeQbGlQOH7l2QEhQID/+YseaFxg5J/DLwWSsi9Axj4e/cCiKx7PVzOq38tY4A==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.1.tgz", + "integrity": "sha512-/RIPQyx60Pt6ga86hKXesXkJ2WOS4UemFrmmq/7eOyiYjYv/MUSHPlkhU6k9T9W1ytnTJueqASW+wOmW4KrViw==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.56.0", - "@typescript-eslint/utils": "5.56.0", + "@typescript-eslint/typescript-estree": "5.57.1", + "@typescript-eslint/utils": "5.57.1", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.56.0.tgz", - "integrity": "sha512-JyAzbTJcIyhuUhogmiu+t79AkdnqgPUEsxMTMc/dCZczGMJQh1MK2wgrju++yMN6AWroVAy2jxyPcPr3SWCq5w==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.1.tgz", + "integrity": "sha512-bSs4LOgyV3bJ08F5RDqO2KXqg3WAdwHCu06zOqcQ6vqbTJizyBhuh1o1ImC69X4bV2g1OJxbH71PJqiO7Y1RuA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.56.0.tgz", - "integrity": "sha512-41CH/GncsLXOJi0jb74SnC7jVPWeVJ0pxQj8bOjH1h2O26jXN3YHKDT1ejkVz5YeTEQPeLCCRY0U2r68tfNOcg==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.1.tgz", + "integrity": "sha512-A2MZqD8gNT0qHKbk2wRspg7cHbCDCk2tcqt6ScCFLr5Ru8cn+TCfM786DjPhqwseiS+PrYwcXht5ztpEQ6TFTw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/visitor-keys": "5.56.0", + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/visitor-keys": "5.57.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -27684,35 +27693,35 @@ } }, "@typescript-eslint/utils": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.56.0.tgz", - "integrity": "sha512-XhZDVdLnUJNtbzaJeDSCIYaM+Tgr59gZGbFuELgF7m0IY03PlciidS7UQNKLE0+WpUTn1GlycEr6Ivb/afjbhA==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.1.tgz", + "integrity": "sha512-kN6vzzf9NkEtawECqze6v99LtmDiUJCVpvieTFA1uL7/jDghiJGubGZ5csicYHU1Xoqb3oH/R5cN5df6W41Nfg==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.56.0", - "@typescript-eslint/types": "5.56.0", - "@typescript-eslint/typescript-estree": "5.56.0", + "@typescript-eslint/scope-manager": "5.57.1", + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/typescript-estree": "5.57.1", "eslint-scope": "^5.1.1", "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.56.0.tgz", - "integrity": "sha512-1mFdED7u5bZpX6Xxf5N9U2c18sb+8EvU3tyOIj6LQZ5OOvnmj8BVeNNP603OFPm5KkS1a7IvCIcwrdHXaEMG/Q==", + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.1.tgz", + "integrity": "sha512-RjQrAniDU0CEk5r7iphkm731zKlFiUjvcBS2yHAg8WWqFMCaCrD0rKEVOMUyMMcbGPZ0bPp56srkGWrgfZqLRA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.56.0", + "@typescript-eslint/types": "5.57.1", "eslint-visitor-keys": "^3.3.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true } } @@ -29063,9 +29072,9 @@ } }, "bson": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.1.0.tgz", - "integrity": "sha512-FEecNHkhYRBe7X9KDkdG12xNuz5VHGeH6mCE0B5sBmYtiR/Ux/9vUH/v4NUoBCDr6NuEhvahjoLiiRogptVW0A==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.2.0.tgz", + "integrity": "sha512-HevkSpDbpUfsrHWmWiAsNavANKYIErV2ePXllp1bwq5CDreAaFVj6RVlZpJnxK4WWDCJ/5jMUpaY6G526q3Hjg==" }, "bson-transpilers": { "version": "2.0.3", @@ -31074,9 +31083,9 @@ } }, "electron": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-23.2.0.tgz", - "integrity": "sha512-De9e21cri0QYct/w6tTNOnKyCt9RVKUw5F8PEN4FPzGR9tr6IT53uyt42uH754uJWrZeLMCAdoXy6/0GmMmYZA==", + "version": "23.2.2", + "resolved": "https://registry.npmjs.org/electron/-/electron-23.2.2.tgz", + "integrity": "sha512-8UfC2NCaqLJvdWoAfzAi56DaF+8cD3QPbnabKMdYNxMhYJ54gAje4ChVRo3sUMD5uSMk6MbPYCdnoMusCrfzrQ==", "dev": true, "requires": { "@electron/get": "^2.0.0", @@ -31398,15 +31407,15 @@ } }, "eslint": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", - "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.1", - "@eslint/js": "8.36.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.37.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -31417,8 +31426,8 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.5.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -31474,9 +31483,9 @@ } }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true }, "estraverse": { @@ -32045,14 +32054,14 @@ "dev": true }, "espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "requires": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" }, "dependencies": { "acorn": { @@ -32062,9 +32071,9 @@ "dev": true }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true } } @@ -37456,11 +37465,11 @@ } }, "mongodb": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.1.0.tgz", - "integrity": "sha512-qgKb7y+EI90y4weY3z5+lIgm8wmexbonz0GalHkSElQXVKtRuwqXuhXKccyvIjXCJVy9qPV82zsinY0W1FBnJw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.2.0.tgz", + "integrity": "sha512-nLgo95eP1acvjBcOdrUV3aqpWwHZCZwhYA2opB8StybbtQL/WoE5pk92qUUfjbKOWcGLYJczTqQbfOQhYtrkKg==", "requires": { - "bson": "^5.0.1", + "bson": "^5.2.0", "mongodb-connection-string-url": "^2.6.0", "saslprep": "^1.0.3", "socks": "^2.7.1" @@ -42673,9 +42682,9 @@ "dev": true }, "webpack": { - "version": "5.76.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.3.tgz", - "integrity": "sha512-18Qv7uGPU8b2vqGeEEObnfICyw2g39CHlDEK4I7NK13LOur1d0HGmGNKGT58Eluwddpn3oEejwvBPoP4M7/KSA==", + "version": "5.78.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.78.0.tgz", + "integrity": "sha512-gT5DP72KInmE/3azEaQrISjTvLYlSM0j1Ezhht/KLVkrqtv10JoP/RXhwmX/frrutOPuSq3o5Vq0ehR/4Vmd1g==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", diff --git a/package.json b/package.json index 4db2fbf65..4d6e4f66c 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "reformat": "prettier --write ." }, "engines": { - "vscode": "^1.76.2", + "vscode": "^1.77.0", "node": "^16.16.0", "npm": "^8.15.1" }, @@ -959,10 +959,10 @@ } }, "dependencies": { - "@babel/parser": "^7.21.3", - "@babel/traverse": "^7.21.3", - "@fortawesome/fontawesome-svg-core": "^6.3.0", - "@fortawesome/free-solid-svg-icons": "^6.3.0", + "@babel/parser": "^7.21.4", + "@babel/traverse": "^7.21.4", + "@fortawesome/fontawesome-svg-core": "^6.4.0", + "@fortawesome/free-solid-svg-icons": "^6.4.0", "@fortawesome/react-fontawesome": "^0.2.0", "@iconify-icons/codicon": "^1.2.23", "@iconify/react": "^1.1.4", @@ -974,13 +974,13 @@ "@mongosh/service-provider-server": "^1.8.0", "@mongosh/shell-api": "^1.8.0", "analytics-node": "^6.2.0", - "bson": "^5.1.0", + "bson": "^5.2.0", "bson-transpilers": "^2.0.3", "classnames": "^2.3.2", "debug": "^4.3.4", "dotenv": "^16.0.3", "micromatch": "^4.0.5", - "mongodb": "^5.1.0", + "mongodb": "^5.2.0", "mongodb-build-info": "^1.5.0", "mongodb-cloud-info": "^1.1.3", "mongodb-connection-string-url": "^2.6.0", @@ -1012,14 +1012,14 @@ "@types/micromatch": "^4.0.2", "@types/mkdirp": "^2.0.0", "@types/mocha": "^8.2.3", - "@types/node": "^14.18.40", - "@types/react": "^17.0.53", + "@types/node": "^14.18.42", + "@types/react": "^17.0.56", "@types/react-dom": "^17.0.19", "@types/sinon": "^9.0.11", "@types/uuid": "^8.3.4", - "@types/vscode": "^1.76.0", - "@typescript-eslint/eslint-plugin": "^5.56.0", - "@typescript-eslint/parser": "^5.56.0", + "@types/vscode": "^1.77.0", + "@typescript-eslint/eslint-plugin": "^5.57.1", + "@typescript-eslint/parser": "^5.57.1", "@vscode/test-electron": "^2.3.0", "@vscode/vsce": "^2.18.0", "@wojtekmaj/enzyme-adapter-react-17": "^0.8.0", @@ -1034,9 +1034,9 @@ "css-loader": "^3.6.0", "depcheck": "^1.4.3", "download": "^8.0.0", - "electron": "^23.2.0", + "electron": "^23.2.2", "enzyme": "^3.11.0", - "eslint": "^8.36.0", + "eslint": "^8.37.0", "eslint-config-mongodb-js": "^5.0.3", "eslint-plugin-mocha": "^10.1.0", "execa": "^1.0.0", @@ -1068,7 +1068,7 @@ "ts-loader": "^9.4.2", "ts-node": "^10.9.1", "typescript": "^4.9.5", - "webpack": "^5.76.3", + "webpack": "^5.78.0", "webpack-cli": "^4.10.0", "xvfb-maybe": "^0.2.1", "yargs-parser": "^20.2.9" From b56197a6f0aa54ffa8d1b5966183c2bb75134ea0 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 5 Apr 2023 22:40:32 +0200 Subject: [PATCH 05/13] build: increase bundle size --- scripts/check-vsix-size.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check-vsix-size.ts b/scripts/check-vsix-size.ts index 02bd717e6..657fe2588 100644 --- a/scripts/check-vsix-size.ts +++ b/scripts/check-vsix-size.ts @@ -12,7 +12,7 @@ const vsixFileName = path.resolve( ); const size = fs.statSync(vsixFileName).size; -const maxSize = 7 * 1000000; // 7 MB +const maxSize = 9 * 1000000; // 9 MB if (size >= maxSize) { throw new Error( From ff1e4d179ebfc3ec07dd021982caba4b3f71e44d Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 6 Apr 2023 15:05:05 +0200 Subject: [PATCH 06/13] refactor: clean up --- src/language/mongoDBService.ts | 1 - src/language/server.ts | 8 +++++++- src/language/visitor.ts | 18 ++++++++---------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/language/mongoDBService.ts b/src/language/mongoDBService.ts index c9d87d6ce..acc7f12a7 100644 --- a/src/language/mongoDBService.ts +++ b/src/language/mongoDBService.ts @@ -896,7 +896,6 @@ export default class MongoDBService { } // Highlight the usage of commands that only works inside interactive session. - // eslint-disable-next-line complexity provideDiagnostics(textFromEditor: string) { const lines = textFromEditor.split(/\r?\n/g); const diagnostics: Diagnostic[] = []; diff --git a/src/language/server.ts b/src/language/server.ts index 422869570..69bf12dfa 100644 --- a/src/language/server.ts +++ b/src/language/server.ts @@ -168,6 +168,7 @@ connection.onRequest( } ); +// Pass the extension path to the MongoDB service. connection.onRequest(ServerCommands.SET_EXTENSION_PATH, (extensionPath) => { return mongoDBService.setExtensionPath(extensionPath); }); @@ -191,6 +192,7 @@ connection.onRequest( } ); +// Identify if the playground selection is an array or object. connection.onRequest( ServerCommands.GET_EXPORT_TO_LANGUAGE_MODE, (params: PlaygroundTextAndSelection) => { @@ -198,6 +200,7 @@ connection.onRequest( } ); +// Find the current namespace for a playground selection. connection.onRequest( ServerCommands.GET_NAMESPACE_FOR_SELECTION, (params: PlaygroundTextAndSelection) => { @@ -205,7 +208,7 @@ connection.onRequest( } ); -// This handler provides the list of the completion items. +// Provide MongoDB completion items. connection.onCompletion((params: TextDocumentPositionParams) => { const textFromEditor = documents.get(params.textDocument.uri)?.getText(); @@ -231,6 +234,7 @@ connection.onCompletionResolve((item: CompletionItem): CompletionItem => { return item; }); +// Provide MongoDB or TypeScript help signatures. connection.onSignatureHelp((params: SignatureHelpParams) => { const document = documents.get(params.textDocument.uri); @@ -287,6 +291,7 @@ connection.onDidOpenTextDocument((/* params */) => { // params.textDocument.text the initial full content of the document. // connection.console.log(`${params.textDocument.uri} opened.`); }); + connection.onDidChangeTextDocument((/* params */) => { // The content of a text document did change in VSCode. // params.textDocument.uri uniquely identifies the document. @@ -297,6 +302,7 @@ connection.onDidChangeTextDocument((/* params */) => { // )}` // ); }); + connection.onDidCloseTextDocument((/* params */) => { // A text document got closed in VSCode. // params.textDocument.uri uniquely identifies the document. diff --git a/src/language/visitor.ts b/src/language/visitor.ts index dc60d9b16..4cb89433a 100644 --- a/src/language/visitor.ts +++ b/src/language/visitor.ts @@ -157,7 +157,7 @@ export class Visitor { end: { line: 0, character: 0 }, }; - this._state = this._getDefaultNodesForCompletion(); + this._state = this._getDefaultsForCompletion(); textFromEditor = this._handleTriggerCharacter(textFromEditor, position); this.parseAST({ textFromEditor, selection }); @@ -174,7 +174,7 @@ export class Visitor { end: { line: 0, character: 0 }, }; - this._state = this._getDefaultNodesForSignatureHelp(); + this._state = this._getDefaultsForSignatureHelp(); textFromEditor = this._handleTriggerCharacter(textFromEditor, position); this.parseAST({ textFromEditor, selection }); @@ -183,13 +183,13 @@ export class Visitor { } parseASTForExportToLanguage(params): ExportToLanguageState { - this._state = this._getDefaultNodesForExportToLanguagep(); + this._state = this._getDefaultsForExportToLanguagep(); this.parseAST(params); return this._state as ExportToLanguageState; } parseASTForNamespace(params): NamespaceState { - this._state = this._getDefaultNodesForNamespace(); + this._state = this._getDefaultsForNamespace(); this.parseAST(params); return this._state as NamespaceState; } @@ -220,7 +220,7 @@ export class Visitor { }); } - _getDefaultNodesForCompletion() { + _getDefaultsForCompletion() { return { databaseName: null, collectionName: null, @@ -243,21 +243,21 @@ export class Visitor { }; } - _getDefaultNodesForSignatureHelp() { + _getDefaultsForSignatureHelp() { return { isFind: false, isAggregation: false, }; } - _getDefaultNodesForExportToLanguagep() { + _getDefaultsForExportToLanguagep() { return { isArraySelection: false, isObjectSelection: false, }; } - _getDefaultNodesForNamespace() { + _getDefaultsForNamespace() { return { databaseName: null, collectionName: null, @@ -360,7 +360,6 @@ export class Visitor { }); } - // eslint-disable-next-line complexity _checkIsFind(node: babel.types.CallExpression) { if ( node.callee.type === 'MemberExpression' && @@ -373,7 +372,6 @@ export class Visitor { } } - // eslint-disable-next-line complexity _checkIsAggregation(node: babel.types.CallExpression): void { if ( node.callee.type === 'MemberExpression' && From 25560ba38877e6bdde8930422275b505490ab52a Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Sat, 8 Apr 2023 11:27:51 +0200 Subject: [PATCH 07/13] feat: use all mongodb help signatures --- src/language/languageServerController.ts | 26 ++-- src/language/mongoDBService.ts | 52 ------- src/language/server.ts | 43 +++-- src/language/tsLanguageService.ts | 147 +++++++++++------- src/language/visitor.ts | 84 +--------- .../suite/language/mongoDBService.test.ts | 53 +------ src/types/global.d.ts | 5 + tsconfig.json | 4 +- 8 files changed, 136 insertions(+), 278 deletions(-) create mode 100644 src/types/global.d.ts diff --git a/src/language/languageServerController.ts b/src/language/languageServerController.ts index acc9977fb..8b8f23969 100644 --- a/src/language/languageServerController.ts +++ b/src/language/languageServerController.ts @@ -43,11 +43,11 @@ export default class LanguageServerController { // The debug options for the server // --inspect=6009: runs the server in Node's Inspector mode - // so VS Code can attach to the server for debugging + // so VS Code can attach to the server for debugging. const debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] }; - // If the extension is launched in debug mode then the debug server options are used - // Otherwise the run options are used + // If the extension is launched in debug mode then the debug server options are used. + // Otherwise the run options are used. const serverOptions: ServerOptions = { run: { module: serverModule, transport: TransportKind.ipc }, debug: { @@ -57,15 +57,15 @@ export default class LanguageServerController { }, }; - // Options to control the language client + // Options to control the language client. const clientOptions: LanguageClientOptions = { - // Register the server for mongodb documents + // Register the language server for mongodb documents. documentSelector: [ - { scheme: 'untitled', language: 'javascript' }, - { scheme: 'file', language: 'javascript' }, + { pattern: '**/*.mongodb.js' }, + { pattern: '**/*.mongodb' }, ], synchronize: { - // Notify the server about file changes in the workspace + // Notify the server about file changes in the workspace. fileEvents: workspace.createFileSystemWatcher('**/*'), }, outputChannel: vscode.window.createOutputChannel( @@ -78,7 +78,7 @@ export default class LanguageServerController { clientOptions, }); - // Create the language server client + // Create the language server client. this._client = new LanguageClient( 'mongodbLanguageServer', 'MongoDB Language Server', @@ -116,7 +116,7 @@ export default class LanguageServerController { } deactivate(): void { - // Stop the language server + // Stop the language server. void this._client.stop(); } @@ -126,12 +126,12 @@ export default class LanguageServerController { this._isExecutingInProgress = true; // Instantiate a new CancellationTokenSource object - // that generates a cancellation token for each run of a playground + // that generates a cancellation token for each run of a playground. this._source = new CancellationTokenSource(); // Send a request with a cancellation token - // to the language server server to execute scripts from a playground - // and return results to the playground controller when ready + // to the language server instance to execute scripts from a playground + // and return results to the playground controller when ready. const result: ShellEvaluateResult = await this._client.sendRequest( ServerCommands.EXECUTE_CODE_FROM_PLAYGROUND, playgroundExecuteParameters, diff --git a/src/language/mongoDBService.ts b/src/language/mongoDBService.ts index acc7f12a7..eb332daef 100644 --- a/src/language/mongoDBService.ts +++ b/src/language/mongoDBService.ts @@ -4,7 +4,6 @@ import { InsertTextFormat, MarkupKind, DiagnosticSeverity, - SignatureHelpContext, } from 'vscode-languageserver/node'; import type { CancellationToken, @@ -844,57 +843,6 @@ export default class MongoDBService { return []; } - /** - * Parse code from a playground to identify - * where the cursor is and show mongodb method signature help items. - */ - provideSignatureHelp( - textFromEditor: string, - position: { line: number; character: number }, - context?: SignatureHelpContext - ) { - this._connection.console.log( - `Provide signature help for a position: ${util.inspect(position)}` - ); - - const state = this._visitor.parseASTWForSignatureHelp( - textFromEditor, - position - ); - this._connection.console.log( - `VISITOR signature help state: ${util.inspect(state)}` - ); - - if (state.isFind) { - return { - activeSignatureHelp: context?.activeSignatureHelp, - signatures: [ - { - label: 'Collection.find(query, projection, options) : Cursor', - documentation: 'Selects documents in a collection or view.', - parameters: [], - }, - ], - }; - } - - if (state.isAggregation) { - return { - activeSignatureHelp: context?.activeSignatureHelp, - signatures: [ - { - label: 'Collection.aggregate(pipeline, options) : Cursor', - documentation: - 'Calculates aggregate values for the data in a collection or a view.', - parameters: [], - }, - ], - }; - } - - this._connection.console.log('VISITOR found no mongodb signature help'); - } - // Highlight the usage of commands that only works inside interactive session. provideDiagnostics(textFromEditor: string) { const lines = textFromEditor.split(/\r?\n/g); diff --git a/src/language/server.ts b/src/language/server.ts index 69bf12dfa..15a4c9d68 100644 --- a/src/language/server.ts +++ b/src/language/server.ts @@ -9,7 +9,6 @@ import { RequestType, TextDocumentSyncKind, Connection, - SignatureHelpParams, } from 'vscode-languageserver/node'; import { TextDocument } from 'vscode-languageserver-textdocument'; @@ -30,7 +29,7 @@ const connection: Connection = createConnection(ProposedFeatures.all); // The text document manager supports full document sync only. const documents: TextDocuments = new TextDocuments(TextDocument); -// MongoDB Playground Service Manager. +// MongoDB language service. const mongoDBService = new MongoDBService(connection); // TypeScript language service. @@ -67,14 +66,15 @@ connection.onInitialize((params: InitializeParams) => { }, }, }, - // Tell the client that the server supports code completion + // Tell the client that the server supports code completion. completionProvider: { resolveProvider: true, triggerCharacters: ['.'], }, + // Tell the client that the server supports help signatures. signatureHelpProvider: { resolveProvider: true, - triggerCharacters: [','], + triggerCharacters: [',', '('], }, // documentFormattingProvider: true, // documentRangeFormattingProvider: true, @@ -101,7 +101,7 @@ connection.onInitialized(() => { // } }); -// The example settings +// The example settings. interface ExampleSettings { maxNumberOfProblems: number; } @@ -160,7 +160,7 @@ connection.onDidChangeWatchedFiles((/* _change */) => { // ); }); -// Execute the entire playground script. +// Execute a playground. connection.onRequest( ServerCommands.EXECUTE_CODE_FROM_PLAYGROUND, (evaluateParams: PlaygroundEvaluateParams, token) => { @@ -168,12 +168,14 @@ connection.onRequest( } ); -// Pass the extension path to the MongoDB service. +// Pass the extension path to the MongoDB and TypeScript services. connection.onRequest(ServerCommands.SET_EXTENSION_PATH, (extensionPath) => { - return mongoDBService.setExtensionPath(extensionPath); + mongoDBService.setExtensionPath(extensionPath); + typeScriptService.setExtensionPath(extensionPath); }); -// Connect to CliServiceProvider to enable shell completions. +// Connect the MongoDB language service to CliServiceProvider +// using the current connection of the client. connection.onRequest(ServerCommands.CONNECT_TO_SERVICE_PROVIDER, (params) => { return mongoDBService.connectToServiceProvider(params); }); @@ -234,26 +236,19 @@ connection.onCompletionResolve((item: CompletionItem): CompletionItem => { return item; }); -// Provide MongoDB or TypeScript help signatures. -connection.onSignatureHelp((params: SignatureHelpParams) => { - const document = documents.get(params.textDocument.uri); +// Provide MongoDB help signatures. +connection.onSignatureHelp((signatureHelpParms) => { + const document = documents.get(signatureHelpParms.textDocument.uri); if (!document) { - return; + return Promise.resolve(null); } - const textFromEditor = document.getText() || ''; - const mongodbSignatures = mongoDBService.provideSignatureHelp( - textFromEditor, - params.position, - params.context + // Provide MongoDB or TypeScript help signatures. + return typeScriptService.doSignatureHelp( + document, + signatureHelpParms.position ); - - if (mongodbSignatures) { - return mongodbSignatures; - } - - return typeScriptService.doSignatureHelp(document, params.position); }); connection.onRequest('textDocument/rangeFormatting', (event) => { diff --git a/src/language/tsLanguageService.ts b/src/language/tsLanguageService.ts index 6f498fb3b..27f9f6f2a 100644 --- a/src/language/tsLanguageService.ts +++ b/src/language/tsLanguageService.ts @@ -7,7 +7,7 @@ import type { import ts from 'typescript'; import { TextDocument, Position } from 'vscode-languageserver-textdocument'; import { readFileSync } from 'fs'; -import { join, basename, dirname } from 'path'; +import { join } from 'path'; type TypeScriptServiceHost = { getLanguageService(jsDocument: TextDocument): ts.LanguageService; @@ -15,39 +15,70 @@ type TypeScriptServiceHost = { dispose(): void; }; -// Server folder. -const serverPath = - basename(__dirname) === 'dist' - ? dirname(__dirname) - : dirname(dirname(__dirname)); - -// TypeScript library folder. -const librarPath = join(serverPath, 'node_modules/typescript/lib'); const contents: { [name: string]: string } = {}; +// const TS_CONFIG_LIBRARY_NAME = 'es2022.full'; +const MDB_CONFIG_LIBRARY_NAME = 'mongodb'; +const GLOBAL_CONFIG_LIBRARY_NAME = 'global'; + export default class TypeScriptService { _connection: Connection; _host: TypeScriptServiceHost; + _extensionPath?: string; constructor(connection: Connection) { this._host = this._getTypeScriptServiceHost(); this._connection = connection; } + /** + * The absolute file path of the directory containing the extension. + */ + setExtensionPath(extensionPath: string): void { + this._extensionPath = extensionPath; + } + _loadLibrary(name: string) { + if (!this._extensionPath) { + this._connection.console.error( + 'Unable to load library ${name}: extensionPath is undefined' + ); + return ''; + } + let content = contents[name]; - if (typeof content !== 'string' && librarPath) { - const libPath = join(librarPath, name); // From source. - try { - content = readFileSync(libPath).toString(); - } catch (e) { - this._connection.console.error( - `Unable to load library ${name} at ${libPath}` - ); + + if (typeof content !== 'string') { + let libPath; + + /* if (name === `lib.${TS_CONFIG_LIBRARY_NAME}.d.ts`) { + libPath = join(this._extensionPath, 'node_modules/typescript/lib', name); + } else */ + + if (name === `${MDB_CONFIG_LIBRARY_NAME}.d.ts`) { + libPath = join(this._extensionPath, 'node_modules/mongodb', name); + } else if (name === `${GLOBAL_CONFIG_LIBRARY_NAME}.d.ts`) { + libPath = join(this._extensionPath, 'src/types', name); + } else { content = ''; } + + if (libPath) { + try { + content = readFileSync(libPath, 'utf8'); + } catch (e) { + this._connection.console.error( + `Unable to load library ${name} at ${libPath}` + ); + content = ''; + } + } else { + content = ''; + } + contents[name] = content; } + return content; } @@ -55,7 +86,10 @@ export default class TypeScriptService { const compilerOptions = { allowNonTsExtensions: true, allowJs: true, - lib: ['lib.es2020.full.d.ts'], // Should match to lib from tsconfig.json. + lib: [ + `${MDB_CONFIG_LIBRARY_NAME}.d.ts`, + `${GLOBAL_CONFIG_LIBRARY_NAME}.d.ts`, + ], // , `lib.${TS_CONFIG_LIBRARY_NAME}.d.ts`], target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic, experimentalDecorators: false, @@ -89,26 +123,15 @@ export default class TypeScriptService { }; }, getCurrentDirectory: () => '', - getDefaultLibFileName: () => 'es2020.full', // Should match to lib from tsconfig.json. + getDefaultLibFileName: () => GLOBAL_CONFIG_LIBRARY_NAME, readFile: (path: string): string | undefined => { if (path === currentTextDocument.uri) { return currentTextDocument.getText(); } return this._loadLibrary(path); }, - fileExists: (path: string): boolean => { - if (path === currentTextDocument.uri) { - return true; - } - return !!this._loadLibrary(path); - }, - directoryExists: (path: string): boolean => { - // Typescript tries to first find libraries in node_modules/@types and node_modules/@typescript. - if (path.startsWith('node_modules')) { - return false; - } - return true; - }, + fileExists: (): boolean => false, + directoryExists: (): boolean => false, }; // Create the language service files. @@ -132,7 +155,7 @@ export default class TypeScriptService { doSignatureHelp( document: TextDocument, position: Position - ): SignatureHelp | null { + ): Promise { const jsDocument = TextDocument.create( document.uri, 'javascript', @@ -152,33 +175,41 @@ export default class TypeScriptService { activeParameter: signHelp.argumentIndex, signatures: [], }; - signHelp.items.forEach((item) => { - const signature: SignatureInformation = { - label: '', - documentation: undefined, - parameters: [], - }; - - signature.label += ts.displayPartsToString(item.prefixDisplayParts); - item.parameters.forEach((p, i, a) => { - const label = ts.displayPartsToString(p.displayParts); - const parameter: ParameterInformation = { - label: label, - documentation: ts.displayPartsToString(p.documentation), + signHelp.items + .map((item) => { + const hasInt8Array = item.prefixDisplayParts.filter( + (prefix) => prefix.text !== 'Int8Array' + ); + item.prefixDisplayParts = hasInt8Array; + return item; + }) + .forEach((item) => { + const signature: SignatureInformation = { + label: '', + documentation: undefined, + parameters: [], }; - signature.label += label; - signature.parameters?.push(parameter); - if (i < a.length - 1) { - signature.label += ts.displayPartsToString( - item.separatorDisplayParts - ); - } + + signature.label += ts.displayPartsToString(item.prefixDisplayParts); + item.parameters.forEach((p, i, a) => { + const label = ts.displayPartsToString(p.displayParts); + const parameter: ParameterInformation = { + label: label, + documentation: ts.displayPartsToString(p.documentation), + }; + signature.label += label; + signature.parameters?.push(parameter); + if (i < a.length - 1) { + signature.label += ts.displayPartsToString( + item.separatorDisplayParts + ); + } + }); + signature.label += ts.displayPartsToString(item.suffixDisplayParts); + ret.signatures.push(signature); }); - signature.label += ts.displayPartsToString(item.suffixDisplayParts); - ret.signatures.push(signature); - }); - return ret; + return Promise.resolve(ret); } - return null; + return Promise.resolve(null); } } diff --git a/src/language/visitor.ts b/src/language/visitor.ts index 4cb89433a..4edf74649 100644 --- a/src/language/visitor.ts +++ b/src/language/visitor.ts @@ -37,11 +37,6 @@ export interface CompletionState { isFindCursor: boolean; } -export interface SignatureState { - isFind: boolean; - isAggregation: boolean; -} - export interface ExportToLanguageState { isObjectSelection: boolean; isArraySelection: boolean; @@ -53,7 +48,7 @@ export interface NamespaceState { } export class Visitor { - _state: CompletionState | SignatureState | ExportToLanguageState | {}; + _state: CompletionState | ExportToLanguageState | {}; _selection: VisitorSelection; constructor() { @@ -69,8 +64,6 @@ export class Visitor { return; } - this._checkIsFind(path.node); - this._checkIsAggregation(path.node); this._checkIsBSONSelection(path.node); this._checkIsUseCall(path.node); this._checkIsCollectionNameAsCallExpression(path.node); @@ -165,25 +158,8 @@ export class Visitor { return this._state as CompletionState; } - parseASTWForSignatureHelp( - textFromEditor: string, - position: { line: number; character: number } - ): SignatureState { - const selection: VisitorSelection = { - start: position, - end: { line: 0, character: 0 }, - }; - - this._state = this._getDefaultsForSignatureHelp(); - textFromEditor = this._handleTriggerCharacter(textFromEditor, position); - - this.parseAST({ textFromEditor, selection }); - - return this._state as SignatureState; - } - parseASTForExportToLanguage(params): ExportToLanguageState { - this._state = this._getDefaultsForExportToLanguagep(); + this._state = this._getDefaultsForExportToLanguage(); this.parseAST(params); return this._state as ExportToLanguageState; } @@ -204,7 +180,10 @@ export class Visitor { sourceType: 'module', }); } catch (error) { - console.error(`parseAST error: ${util.inspect(error)}`); + console.error(`parseAST error: ${util.inspect((error as any).message)}`); + console.error( + `parseAST error textFromEditor: ${util.inspect(textFromEditor)}` + ); } traverse(ast, { @@ -230,8 +209,6 @@ export class Visitor { isIdentifierObjectValue: false, isTextObjectValue: false, isStage: false, - isFind: false, - isAggregation: false, stageOperator: null, isCollectionSymbol: false, isUseCallExpression: false, @@ -243,14 +220,7 @@ export class Visitor { }; } - _getDefaultsForSignatureHelp() { - return { - isFind: false, - isAggregation: false, - }; - } - - _getDefaultsForExportToLanguagep() { + _getDefaultsForExportToLanguage() { return { isArraySelection: false, isObjectSelection: false, @@ -360,30 +330,6 @@ export class Visitor { }); } - _checkIsFind(node: babel.types.CallExpression) { - if ( - node.callee.type === 'MemberExpression' && - node.callee.property.type === 'Identifier' && - node.callee.property.name === 'find' && - this._isWithinFunctionCall(node) && - 'isFind' in this._state - ) { - this._state.isFind = true; - } - } - - _checkIsAggregation(node: babel.types.CallExpression): void { - if ( - node.callee.type === 'MemberExpression' && - node.callee.property.type === 'Identifier' && - node.callee.property.name === 'aggregate' && - this._isWithinFunctionCall(node) && - 'isAggregation' in this._state - ) { - this._state.isAggregation = true; - } - } - _checkIsStage(node: babel.types.ArrayExpression): void { if (node.elements) { node.elements.forEach((item) => { @@ -499,22 +445,6 @@ export class Visitor { return false; } - _isWithinFunctionCall(node: babel.types.CallExpression): boolean { - if ( - node.loc && - ((node.loc.start.line < this._selection.start.line && - node.loc.end.line > this._selection.start.line + 1) || - (node.loc.start.line === this._selection.start.line && - node.loc.start.column <= this._selection.start.character) || - (node.loc.end.line === this._selection.start.line + 1 && - node.loc.end.column >= this._selection.start.character)) - ) { - return true; - } - - return false; - } - _checkIsArrayWithinSelection(node: babel.types.Node): void { if ( node.type === 'ArrayExpression' && diff --git a/src/test/suite/language/mongoDBService.test.ts b/src/test/suite/language/mongoDBService.test.ts index b63708d85..92f7d710c 100644 --- a/src/test/suite/language/mongoDBService.test.ts +++ b/src/test/suite/language/mongoDBService.test.ts @@ -7,10 +7,7 @@ import { DiagnosticSeverity, MarkupContent, } from 'vscode-languageclient/node'; -import type { - CompletionItem, - SignatureInformation, -} from 'vscode-languageclient/node'; +import type { CompletionItem } from 'vscode-languageclient/node'; import chai from 'chai'; import { createConnection } from 'vscode-languageserver/node'; import fs from 'fs'; @@ -2459,52 +2456,4 @@ suite('MongoDBService Test Suite', () => { ]); }); }); - - suite('Signature Help', function () { - const up = new StreamStub(); - const down = new StreamStub(); - const connection = createConnection(up, down); - - connection.listen(); - - const testMongoDBService = new MongoDBService(connection); - - before(async () => { - await testMongoDBService.connectToServiceProvider(params); - }); - - test('provide collection find signature', () => { - const result = testMongoDBService.provideSignatureHelp( - "db.getCollection('sales').find({ year: {}, });", - { line: 0, character: 42 } - ); - const completion = result?.signatures.find( - (item: SignatureInformation) => - item.label === 'Collection.find(query, projection, options) : Cursor' - ); - - expect(completion?.documentation).to.be.eql( - 'Selects documents in a collection or view.' - ); - }); - - test('provide collection aggregate signature', () => { - const result = testMongoDBService.provideSignatureHelp( - [ - "db.getCollection('sales').aggregate([", - " { $match: { date: { $gte: new Date('2014-01-01'), $lt: new Date('2015-01-01') } } },", - ']);', - ].join('\n'), - { line: 1, character: 86 } - ); - const completion = result?.signatures.find( - (item: SignatureInformation) => - item.label === 'Collection.aggregate(pipeline, options) : Cursor' - ); - - expect(completion?.documentation).to.be.eql( - 'Calculates aggregate values for the data in a collection or a view.' - ); - }); - }); }); diff --git a/src/types/global.d.ts b/src/types/global.d.ts new file mode 100644 index 000000000..a676fefa1 --- /dev/null +++ b/src/types/global.d.ts @@ -0,0 +1,5 @@ +export {}; + +declare global { + let use: (dbName: string) => void; +} diff --git a/tsconfig.json b/tsconfig.json index 412b8f6ee..29e392c42 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,9 +2,9 @@ "compilerOptions": { "module": "commonjs", "noImplicitAny": false, - "target": "es2020", + "target": "es2022", "outDir": "out", - "lib": ["dom", "es2020"], + "lib": ["dom", "es2022"], "types": ["node"], "jsx": "react", "sourceMap": true, From af4dbaea51c2ae72f1f7a85c613be4f60201474a Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 12 Apr 2023 14:05:05 +0200 Subject: [PATCH 08/13] feat: completions via ts language service --- src/language/languageServerController.ts | 11 +- src/language/server.ts | 8 +- src/language/tsLanguageService.ts | 274 ++++++++++++++++------- src/test/suite/stubs.ts | 2 +- src/types/global.d.ts | 41 +++- 5 files changed, 249 insertions(+), 87 deletions(-) diff --git a/src/language/languageServerController.ts b/src/language/languageServerController.ts index 8b8f23969..86f2ce242 100644 --- a/src/language/languageServerController.ts +++ b/src/language/languageServerController.ts @@ -88,6 +88,9 @@ export default class LanguageServerController { } async startLanguageServer(): Promise { + // Start the client. This will also launch the server. + await this._client.start(); + // Push the disposable client to the context's subscriptions so that the // client can be deactivated on extension deactivation. if (!this._context.subscriptions.includes(this._client)) { @@ -115,9 +118,13 @@ export default class LanguageServerController { ); } - deactivate(): void { + deactivate(): Thenable | undefined { + if (!this._client) { + return undefined; + } + // Stop the language server. - void this._client.stop(); + return this._client.stop(); } async evaluate( diff --git a/src/language/server.ts b/src/language/server.ts index 15a4c9d68..43e500c43 100644 --- a/src/language/server.ts +++ b/src/language/server.ts @@ -33,7 +33,7 @@ const documents: TextDocuments = new TextDocuments(TextDocument); const mongoDBService = new MongoDBService(connection); // TypeScript language service. -const typeScriptService = new TypeScriptService(connection); +const typeScriptService = new TypeScriptService(); let hasConfigurationCapability = false; // let hasWorkspaceFolderCapability = false; @@ -218,6 +218,12 @@ connection.onCompletion((params: TextDocumentPositionParams) => { textFromEditor ? textFromEditor : '', params.position ); + + /* const document = documents.get(params.textDocument.uri); + if (!document) { + return Promise.resolve([]); + } + return typeScriptService.doComplete(document, params.position); */ }); // This handler resolves additional information for the item selected in diff --git a/src/language/tsLanguageService.ts b/src/language/tsLanguageService.ts index 27f9f6f2a..b23679adc 100644 --- a/src/language/tsLanguageService.ts +++ b/src/language/tsLanguageService.ts @@ -1,9 +1,15 @@ -import { Connection } from 'vscode-languageserver/node'; +/* --------------------------------------------------------------------------------------------- + * See the bundled JavaScript extension of VSCode: + * https://github.com/microsoft/vscode/blob/main/extensions/html-language-features/server/src/modes/javascriptMode.ts + *-------------------------------------------------------------------------------------------- */ + import type { SignatureHelp, SignatureInformation, ParameterInformation, + CompletionItem, } from 'vscode-languageserver/node'; +import { CompletionItemKind } from 'vscode-languageserver/node'; import ts from 'typescript'; import { TextDocument, Position } from 'vscode-languageserver-textdocument'; import { readFileSync } from 'fs'; @@ -15,20 +21,112 @@ type TypeScriptServiceHost = { dispose(): void; }; -const contents: { [name: string]: string } = {}; +const enum Kind { + alias = 'alias', + callSignature = 'call', + class = 'class', + const = 'const', + constructorImplementation = 'constructor', + constructSignature = 'construct', + directory = 'directory', + enum = 'enum', + enumMember = 'enum member', + externalModuleName = 'external module name', + function = 'function', + indexSignature = 'index', + interface = 'interface', + keyword = 'keyword', + let = 'let', + localFunction = 'local function', + localVariable = 'local var', + method = 'method', + memberGetAccessor = 'getter', + memberSetAccessor = 'setter', + memberVariable = 'property', + module = 'module', + primitiveType = 'primitive type', + script = 'script', + type = 'type', + variable = 'var', + warning = 'warning', + string = 'string', + parameter = 'parameter', + typeParameter = 'type parameter', +} + +// eslint-disable-next-line complexity +const convertKind = (kind: string): CompletionItemKind => { + switch (kind) { + case Kind.primitiveType: + case Kind.keyword: + return CompletionItemKind.Keyword; + + case Kind.const: + case Kind.let: + case Kind.variable: + case Kind.localVariable: + case Kind.alias: + case Kind.parameter: + return CompletionItemKind.Variable; + + case Kind.memberVariable: + case Kind.memberGetAccessor: + case Kind.memberSetAccessor: + return CompletionItemKind.Field; + + case Kind.function: + case Kind.localFunction: + return CompletionItemKind.Function; + + case Kind.method: + case Kind.constructSignature: + case Kind.callSignature: + case Kind.indexSignature: + return CompletionItemKind.Method; + + case Kind.enum: + return CompletionItemKind.Enum; + + case Kind.enumMember: + return CompletionItemKind.EnumMember; + + case Kind.module: + case Kind.externalModuleName: + return CompletionItemKind.Module; + + case Kind.class: + case Kind.type: + return CompletionItemKind.Class; + + case Kind.interface: + return CompletionItemKind.Interface; -// const TS_CONFIG_LIBRARY_NAME = 'es2022.full'; -const MDB_CONFIG_LIBRARY_NAME = 'mongodb'; -const GLOBAL_CONFIG_LIBRARY_NAME = 'global'; + case Kind.warning: + return CompletionItemKind.Text; + + case Kind.script: + return CompletionItemKind.File; + + case Kind.directory: + return CompletionItemKind.Folder; + + case Kind.string: + return CompletionItemKind.Constant; + + default: + return CompletionItemKind.Property; + } +}; + +const GLOBAL_CONFIG_LIBRARY_NAME = 'global.d.ts'; export default class TypeScriptService { - _connection: Connection; _host: TypeScriptServiceHost; _extensionPath?: string; + _contents: { [name: string]: string } = Object.create(null); - constructor(connection: Connection) { + constructor() { this._host = this._getTypeScriptServiceHost(); - this._connection = connection; } /** @@ -39,70 +137,57 @@ export default class TypeScriptService { } _loadLibrary(name: string) { + console.log('name----------------------'); + console.log(name); + console.log('----------------------'); + if (!this._extensionPath) { - this._connection.console.error( - 'Unable to load library ${name}: extensionPath is undefined' + console.error( + `Unable to load library ${name}: extensionPath is undefined` ); return ''; } - let content = contents[name]; - - if (typeof content !== 'string') { - let libPath; + let libPath; - /* if (name === `lib.${TS_CONFIG_LIBRARY_NAME}.d.ts`) { - libPath = join(this._extensionPath, 'node_modules/typescript/lib', name); - } else */ + if (name === GLOBAL_CONFIG_LIBRARY_NAME) { + libPath = join(this._extensionPath, 'src/types', name); + } - if (name === `${MDB_CONFIG_LIBRARY_NAME}.d.ts`) { - libPath = join(this._extensionPath, 'node_modules/mongodb', name); - } else if (name === `${GLOBAL_CONFIG_LIBRARY_NAME}.d.ts`) { - libPath = join(this._extensionPath, 'src/types', name); - } else { - content = ''; - } + let content = this._contents[name]; - if (libPath) { - try { - content = readFileSync(libPath, 'utf8'); - } catch (e) { - this._connection.console.error( - `Unable to load library ${name} at ${libPath}` - ); - content = ''; - } - } else { + if (typeof content !== 'string' && libPath) { + try { + content = readFileSync(libPath, 'utf8'); + } catch (e) { + console.error(`Unable to load library ${name} at ${libPath}`); content = ''; } - contents[name] = content; + this._contents[name] = content; } return content; } - _getTypeScriptServiceHost() { + _getTypeScriptServiceHost(): TypeScriptServiceHost { const compilerOptions = { allowNonTsExtensions: true, allowJs: true, - lib: [ - `${MDB_CONFIG_LIBRARY_NAME}.d.ts`, - `${GLOBAL_CONFIG_LIBRARY_NAME}.d.ts`, - ], // , `lib.${TS_CONFIG_LIBRARY_NAME}.d.ts`], target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic, experimentalDecorators: false, }; - let currentTextDocument = TextDocument.create('init', 'javascript', 1, ''); + let currentTextDocument = TextDocument.create('init', 'plaintext', 1, ''); // Create the language service host to allow the LS to communicate with the host. const host: ts.LanguageServiceHost = { getCompilationSettings: () => compilerOptions, - getScriptFileNames: () => [currentTextDocument.uri], - getScriptKind: () => { - return ts.ScriptKind.JS; - }, + getScriptFileNames: () => [ + currentTextDocument.uri, + GLOBAL_CONFIG_LIBRARY_NAME, + ], + getScriptKind: () => ts.ScriptKind.JS, getScriptVersion: (fileName: string) => { if (fileName === currentTextDocument.uri) { return String(currentTextDocument.version); @@ -124,12 +209,7 @@ export default class TypeScriptService { }, getCurrentDirectory: () => '', getDefaultLibFileName: () => GLOBAL_CONFIG_LIBRARY_NAME, - readFile: (path: string): string | undefined => { - if (path === currentTextDocument.uri) { - return currentTextDocument.getText(); - } - return this._loadLibrary(path); - }, + readFile: (): string | undefined => undefined, fileExists: (): boolean => false, directoryExists: (): boolean => false, }; @@ -175,41 +255,71 @@ export default class TypeScriptService { activeParameter: signHelp.argumentIndex, signatures: [], }; - signHelp.items - .map((item) => { - const hasInt8Array = item.prefixDisplayParts.filter( - (prefix) => prefix.text !== 'Int8Array' - ); - item.prefixDisplayParts = hasInt8Array; - return item; - }) - .forEach((item) => { - const signature: SignatureInformation = { - label: '', - documentation: undefined, - parameters: [], - }; + signHelp.items.forEach((item) => { + const signature: SignatureInformation = { + label: '', + documentation: undefined, + parameters: [], + }; - signature.label += ts.displayPartsToString(item.prefixDisplayParts); - item.parameters.forEach((p, i, a) => { - const label = ts.displayPartsToString(p.displayParts); - const parameter: ParameterInformation = { - label: label, - documentation: ts.displayPartsToString(p.documentation), - }; - signature.label += label; - signature.parameters?.push(parameter); - if (i < a.length - 1) { - signature.label += ts.displayPartsToString( - item.separatorDisplayParts - ); - } - }); - signature.label += ts.displayPartsToString(item.suffixDisplayParts); - ret.signatures.push(signature); + signature.label += ts.displayPartsToString(item.prefixDisplayParts); + item.parameters.forEach((p, i, a) => { + const label = ts.displayPartsToString(p.displayParts); + const parameter: ParameterInformation = { + label: label, + documentation: ts.displayPartsToString(p.documentation), + }; + signature.label += label; + signature.parameters?.push(parameter); + if (i < a.length - 1) { + signature.label += ts.displayPartsToString( + item.separatorDisplayParts + ); + } }); + signature.label += ts.displayPartsToString(item.suffixDisplayParts); + ret.signatures.push(signature); + }); return Promise.resolve(ret); } return Promise.resolve(null); } + + doComplete(document: TextDocument, position: Position): CompletionItem[] { + const jsDocument = TextDocument.create( + document.uri, + 'javascript', + document.version, + document.getText() + ); + const jsLanguageService = this._host.getLanguageService(jsDocument); + const offset = jsDocument.offsetAt(position); + const jsCompletion = jsLanguageService.getCompletionsAtPosition( + jsDocument.uri, + offset, + { + includeExternalModuleExports: false, + includeInsertTextCompletions: false, + } + ); + + return ( + jsCompletion?.entries.map((entry) => { + // Data used for resolving item details (see 'doResolve'). + const data = { + languageId: 'javascript', + uri: document.uri, + offset: offset, + }; + return { + uri: document.uri, + position: position, + label: entry.name, + sortText: entry.sortText, + kind: convertKind(entry.kind), + data, + }; + }) || [] + ); + } } diff --git a/src/test/suite/stubs.ts b/src/test/suite/stubs.ts index 6aed72f5a..f1686983f 100644 --- a/src/test/suite/stubs.ts +++ b/src/test/suite/stubs.ts @@ -304,7 +304,7 @@ class LanguageServerControllerStub { return Promise.resolve(); } - deactivate(): void { + deactivate(): Thenable | undefined { return; } diff --git a/src/types/global.d.ts b/src/types/global.d.ts index a676fefa1..9c34ab034 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -1,5 +1,44 @@ -export {}; +import type { + FindCursor, + AggregationCursor, +} from '@mongosh/service-provider-core'; +import { + Document, + FindOptions, + ExplainVerbosityLike, +} from '@mongosh/service-provider-core'; declare global { let use: (dbName: string) => void; + + enum Stages { + match = '$match', + } + + let db: { + getCollection(coll: string): { + find( + query?: Document, + projection?: Document, + options?: FindOptions + ): Promise; + aggregate( + pipeline: [{ [key in Stages]: Document }], + options: Document & { + explain?: never; + } + ): Promise; + aggregate( + pipeline: [{ [key in Stages]: Document }], + options: Document & { + explain: ExplainVerbosityLike; + } + ): Promise; + aggregate( + ...stages: [{ [key in Stages]: Document }] + ): Promise; + }; + }; } + +export {}; From c5e7691f0cf0a6c61ead047a105b500307b7c68f Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 12 Apr 2023 14:18:21 +0200 Subject: [PATCH 09/13] refactor: await ls deactivating --- src/language/tsLanguageService.ts | 2 +- src/mdbExtensionController.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/language/tsLanguageService.ts b/src/language/tsLanguageService.ts index b23679adc..8d9b24020 100644 --- a/src/language/tsLanguageService.ts +++ b/src/language/tsLanguageService.ts @@ -218,7 +218,7 @@ export default class TypeScriptService { const jsLanguageService = ts.createLanguageService(host); return { - // Return a new instance of the language service. + // Return a language service instance for a document. getLanguageService(jsDocument: TextDocument): ts.LanguageService { currentTextDocument = jsDocument; return jsLanguageService; diff --git a/src/mdbExtensionController.ts b/src/mdbExtensionController.ts index 5a45874b3..b408488e2 100644 --- a/src/mdbExtensionController.ts +++ b/src/mdbExtensionController.ts @@ -677,13 +677,13 @@ export default class MDBExtensionController implements vscode.Disposable { async deactivate(): Promise { await this._connectionController.disconnect(); + await this._languageServerController.deactivate(); this._explorerController.deactivate(); this._helpExplorer.deactivate(); this._playgroundsExplorer.deactivate(); this._playgroundController.deactivate(); this._telemetryService.deactivate(); - this._languageServerController.deactivate(); this._editorsController.deactivate(); } } From eba05dde029128aef50aa808c1ce325c28d315a9 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 12 Apr 2023 16:45:46 +0200 Subject: [PATCH 10/13] refactor: include types definition in the vsix --- .vscodeignore | 1 + src/types/global.d.ts => global.d.ts | 0 src/language/tsLanguageService.ts | 9 ++++----- 3 files changed, 5 insertions(+), 5 deletions(-) rename src/types/global.d.ts => global.d.ts (100%) diff --git a/.vscodeignore b/.vscodeignore index acf3d8d7f..d0aa10e62 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -16,3 +16,4 @@ webpack.test.config.js .eslintrc .eslintignore playgrounds/** +!global.d.ts diff --git a/src/types/global.d.ts b/global.d.ts similarity index 100% rename from src/types/global.d.ts rename to global.d.ts diff --git a/src/language/tsLanguageService.ts b/src/language/tsLanguageService.ts index 8d9b24020..1f26dbc1a 100644 --- a/src/language/tsLanguageService.ts +++ b/src/language/tsLanguageService.ts @@ -136,11 +136,10 @@ export default class TypeScriptService { this._extensionPath = extensionPath; } + /** + * Load files related to the language features. + */ _loadLibrary(name: string) { - console.log('name----------------------'); - console.log(name); - console.log('----------------------'); - if (!this._extensionPath) { console.error( `Unable to load library ${name}: extensionPath is undefined` @@ -151,7 +150,7 @@ export default class TypeScriptService { let libPath; if (name === GLOBAL_CONFIG_LIBRARY_NAME) { - libPath = join(this._extensionPath, 'src/types', name); + libPath = join(this._extensionPath, name); } let content = this._contents[name]; From 4a94eff1971c2c4189ca739c5ff9a68058c1c1cd Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 13 Apr 2023 14:39:47 +0200 Subject: [PATCH 11/13] refactor: extract helpers --- src/language/convertKind.ts | 97 ++++++++++++++++ src/language/loadLibrary.ts | 45 ++++++++ src/language/tsLanguageService.ts | 182 ++++++------------------------ 3 files changed, 175 insertions(+), 149 deletions(-) create mode 100644 src/language/convertKind.ts create mode 100644 src/language/loadLibrary.ts diff --git a/src/language/convertKind.ts b/src/language/convertKind.ts new file mode 100644 index 000000000..97a0d852f --- /dev/null +++ b/src/language/convertKind.ts @@ -0,0 +1,97 @@ +import { CompletionItemKind } from 'vscode-languageserver/node'; + +const enum Kind { + alias = 'alias', + callSignature = 'call', + class = 'class', + const = 'const', + constructorImplementation = 'constructor', + constructSignature = 'construct', + directory = 'directory', + enum = 'enum', + enumMember = 'enum member', + externalModuleName = 'external module name', + function = 'function', + indexSignature = 'index', + interface = 'interface', + keyword = 'keyword', + let = 'let', + localFunction = 'local function', + localVariable = 'local var', + method = 'method', + memberGetAccessor = 'getter', + memberSetAccessor = 'setter', + memberVariable = 'property', + module = 'module', + primitiveType = 'primitive type', + script = 'script', + type = 'type', + variable = 'var', + warning = 'warning', + string = 'string', + parameter = 'parameter', + typeParameter = 'type parameter', +} + +export const convertKind = (kind: string): CompletionItemKind => { + switch (kind) { + case Kind.primitiveType: + case Kind.keyword: + return CompletionItemKind.Keyword; + + case Kind.const: + case Kind.let: + case Kind.variable: + case Kind.localVariable: + case Kind.alias: + case Kind.parameter: + return CompletionItemKind.Variable; + + case Kind.memberVariable: + case Kind.memberGetAccessor: + case Kind.memberSetAccessor: + return CompletionItemKind.Field; + + case Kind.function: + case Kind.localFunction: + return CompletionItemKind.Function; + + case Kind.method: + case Kind.constructSignature: + case Kind.callSignature: + case Kind.indexSignature: + return CompletionItemKind.Method; + + case Kind.enum: + return CompletionItemKind.Enum; + + case Kind.enumMember: + return CompletionItemKind.EnumMember; + + case Kind.module: + case Kind.externalModuleName: + return CompletionItemKind.Module; + + case Kind.class: + case Kind.type: + return CompletionItemKind.Class; + + case Kind.interface: + return CompletionItemKind.Interface; + + case Kind.warning: + return CompletionItemKind.Text; + + case Kind.script: + return CompletionItemKind.File; + + case Kind.directory: + return CompletionItemKind.Folder; + + case Kind.string: + return CompletionItemKind.Constant; + + default: + return CompletionItemKind.Property; + } +}; diff --git a/src/language/loadLibrary.ts b/src/language/loadLibrary.ts new file mode 100644 index 000000000..f0704aa5e --- /dev/null +++ b/src/language/loadLibrary.ts @@ -0,0 +1,45 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; + +export const GLOBAL_CONFIG_LIBRARY_NAME = 'global.d.ts'; + +const contents: { [name: string]: string } = Object.create(null); + +/** + * Load files related to the language features. + */ +export const loadLibrary = ({ + libraryName, + extensionPath, +}: { + libraryName: string; + extensionPath?: string; +}) => { + if (!extensionPath) { + console.error( + `Unable to load library ${libraryName}: extensionPath is undefined` + ); + return ''; + } + + let libraryPath; + + if (libraryName === GLOBAL_CONFIG_LIBRARY_NAME) { + libraryPath = join(extensionPath, libraryName); + } + + let content = contents[libraryName]; + + if (typeof content !== 'string' && libraryPath) { + try { + content = readFileSync(libraryPath, 'utf8'); + } catch (e) { + console.error(`Unable to load library ${libraryName} at ${libraryPath}`); + content = ''; + } + + contents[libraryName] = content; + } + + return content; +}; diff --git a/src/language/tsLanguageService.ts b/src/language/tsLanguageService.ts index 1f26dbc1a..95681b74d 100644 --- a/src/language/tsLanguageService.ts +++ b/src/language/tsLanguageService.ts @@ -1,19 +1,18 @@ /* --------------------------------------------------------------------------------------------- - * See the bundled JavaScript extension of VSCode: + * See the bundled extension of VSCode as an example: * https://github.com/microsoft/vscode/blob/main/extensions/html-language-features/server/src/modes/javascriptMode.ts *-------------------------------------------------------------------------------------------- */ - +import ts from 'typescript'; import type { SignatureHelp, SignatureInformation, ParameterInformation, CompletionItem, } from 'vscode-languageserver/node'; -import { CompletionItemKind } from 'vscode-languageserver/node'; -import ts from 'typescript'; import { TextDocument, Position } from 'vscode-languageserver-textdocument'; -import { readFileSync } from 'fs'; -import { join } from 'path'; + +import { loadLibrary, GLOBAL_CONFIG_LIBRARY_NAME } from './loadLibrary'; +import { convertKind } from './convertKind'; type TypeScriptServiceHost = { getLanguageService(jsDocument: TextDocument): ts.LanguageService; @@ -21,109 +20,9 @@ type TypeScriptServiceHost = { dispose(): void; }; -const enum Kind { - alias = 'alias', - callSignature = 'call', - class = 'class', - const = 'const', - constructorImplementation = 'constructor', - constructSignature = 'construct', - directory = 'directory', - enum = 'enum', - enumMember = 'enum member', - externalModuleName = 'external module name', - function = 'function', - indexSignature = 'index', - interface = 'interface', - keyword = 'keyword', - let = 'let', - localFunction = 'local function', - localVariable = 'local var', - method = 'method', - memberGetAccessor = 'getter', - memberSetAccessor = 'setter', - memberVariable = 'property', - module = 'module', - primitiveType = 'primitive type', - script = 'script', - type = 'type', - variable = 'var', - warning = 'warning', - string = 'string', - parameter = 'parameter', - typeParameter = 'type parameter', -} - -// eslint-disable-next-line complexity -const convertKind = (kind: string): CompletionItemKind => { - switch (kind) { - case Kind.primitiveType: - case Kind.keyword: - return CompletionItemKind.Keyword; - - case Kind.const: - case Kind.let: - case Kind.variable: - case Kind.localVariable: - case Kind.alias: - case Kind.parameter: - return CompletionItemKind.Variable; - - case Kind.memberVariable: - case Kind.memberGetAccessor: - case Kind.memberSetAccessor: - return CompletionItemKind.Field; - - case Kind.function: - case Kind.localFunction: - return CompletionItemKind.Function; - - case Kind.method: - case Kind.constructSignature: - case Kind.callSignature: - case Kind.indexSignature: - return CompletionItemKind.Method; - - case Kind.enum: - return CompletionItemKind.Enum; - - case Kind.enumMember: - return CompletionItemKind.EnumMember; - - case Kind.module: - case Kind.externalModuleName: - return CompletionItemKind.Module; - - case Kind.class: - case Kind.type: - return CompletionItemKind.Class; - - case Kind.interface: - return CompletionItemKind.Interface; - - case Kind.warning: - return CompletionItemKind.Text; - - case Kind.script: - return CompletionItemKind.File; - - case Kind.directory: - return CompletionItemKind.Folder; - - case Kind.string: - return CompletionItemKind.Constant; - - default: - return CompletionItemKind.Property; - } -}; - -const GLOBAL_CONFIG_LIBRARY_NAME = 'global.d.ts'; - export default class TypeScriptService { _host: TypeScriptServiceHost; _extensionPath?: string; - _contents: { [name: string]: string } = Object.create(null); constructor() { this._host = this._getTypeScriptServiceHost(); @@ -137,38 +36,8 @@ export default class TypeScriptService { } /** - * Load files related to the language features. + * Create a TypeScript service host. */ - _loadLibrary(name: string) { - if (!this._extensionPath) { - console.error( - `Unable to load library ${name}: extensionPath is undefined` - ); - return ''; - } - - let libPath; - - if (name === GLOBAL_CONFIG_LIBRARY_NAME) { - libPath = join(this._extensionPath, name); - } - - let content = this._contents[name]; - - if (typeof content !== 'string' && libPath) { - try { - content = readFileSync(libPath, 'utf8'); - } catch (e) { - console.error(`Unable to load library ${name} at ${libPath}`); - content = ''; - } - - this._contents[name] = content; - } - - return content; - } - _getTypeScriptServiceHost(): TypeScriptServiceHost { const compilerOptions = { allowNonTsExtensions: true, @@ -177,9 +46,8 @@ export default class TypeScriptService { moduleResolution: ts.ModuleResolutionKind.Classic, experimentalDecorators: false, }; - let currentTextDocument = TextDocument.create('init', 'plaintext', 1, ''); + let currentTextDocument = TextDocument.create('init', 'javascript', 1, ''); - // Create the language service host to allow the LS to communicate with the host. const host: ts.LanguageServiceHost = { getCompilationSettings: () => compilerOptions, getScriptFileNames: () => [ @@ -193,12 +61,15 @@ export default class TypeScriptService { } return '1'; }, - getScriptSnapshot: (fileName: string) => { + getScriptSnapshot: (libraryName: string) => { let text = ''; - if (fileName === currentTextDocument.uri) { + if (libraryName === currentTextDocument.uri) { text = currentTextDocument.getText(); } else { - text = this._loadLibrary(fileName); + text = loadLibrary({ + libraryName, + extensionPath: this._extensionPath, + }); } return { getText: (start, end) => text.substring(start, end), @@ -214,23 +85,26 @@ export default class TypeScriptService { }; // Create the language service files. - const jsLanguageService = ts.createLanguageService(host); + const languageService = ts.createLanguageService(host); return { // Return a language service instance for a document. getLanguageService(jsDocument: TextDocument): ts.LanguageService { currentTextDocument = jsDocument; - return jsLanguageService; + return languageService; }, getCompilationSettings() { return compilerOptions; }, dispose() { - jsLanguageService.dispose(); + languageService.dispose(); }, }; } + /** + * Provide MongoDB signature help. + */ doSignatureHelp( document: TextDocument, position: Position @@ -241,8 +115,8 @@ export default class TypeScriptService { document.version, document.getText() ); - const jsLanguageService = this._host.getLanguageService(jsDocument); - const signHelp = jsLanguageService.getSignatureHelpItems( + const languageService = this._host.getLanguageService(jsDocument); + const signHelp = languageService.getSignatureHelpItems( jsDocument.uri, jsDocument.offsetAt(position), undefined @@ -284,6 +158,16 @@ export default class TypeScriptService { return Promise.resolve(null); } + /** + * Provide MongoDB completions. + * This is a draft method that can replace completions currently provided by the MongoDBService. + * + * TODO: + * - Provide the full completion list. + * - Use a proper icon. + * - Display description. + * - Include a link to the documentation. + */ doComplete(document: TextDocument, position: Position): CompletionItem[] { const jsDocument = TextDocument.create( document.uri, @@ -291,9 +175,9 @@ export default class TypeScriptService { document.version, document.getText() ); - const jsLanguageService = this._host.getLanguageService(jsDocument); + const languageService = this._host.getLanguageService(jsDocument); const offset = jsDocument.offsetAt(position); - const jsCompletion = jsLanguageService.getCompletionsAtPosition( + const jsCompletion = languageService.getCompletionsAtPosition( jsDocument.uri, offset, { From d278785b35dad89a208b83be95d35ea2967aa6c3 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 13 Apr 2023 14:45:55 +0200 Subject: [PATCH 12/13] refactor: disable complexity --- src/language/convertKind.ts | 1 + src/language/server.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/language/convertKind.ts b/src/language/convertKind.ts index 97a0d852f..39c86c29c 100644 --- a/src/language/convertKind.ts +++ b/src/language/convertKind.ts @@ -33,6 +33,7 @@ const enum Kind { typeParameter = 'type parameter', } +// eslint-disable-next-line complexity export const convertKind = (kind: string): CompletionItemKind => { switch (kind) { case Kind.primitiveType: diff --git a/src/language/server.ts b/src/language/server.ts index 43e500c43..11d9e2512 100644 --- a/src/language/server.ts +++ b/src/language/server.ts @@ -242,7 +242,7 @@ connection.onCompletionResolve((item: CompletionItem): CompletionItem => { return item; }); -// Provide MongoDB help signatures. +// Provide MongoDB signature help. connection.onSignatureHelp((signatureHelpParms) => { const document = documents.get(signatureHelpParms.textDocument.uri); From 91677a48deb12a74e684b984fa82735d8e58fc24 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Mon, 17 Apr 2023 13:29:02 +0200 Subject: [PATCH 13/13] build: bump to vscode 1.77.3 engine --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 14959edbc..c75a69e84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -126,7 +126,7 @@ "engines": { "node": "^16.16.0", "npm": "^8.15.1", - "vscode": "^1.77.0" + "vscode": "^1.77.3" } }, "node_modules/@ampproject/remapping": { diff --git a/package.json b/package.json index c015c9083..0589bd07f 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "reformat": "prettier --write ." }, "engines": { - "vscode": "^1.77.0", + "vscode": "^1.77.3", "node": "^16.16.0", "npm": "^8.15.1" },