From 0cc7c540a90e3b3f6f9f37c4c91e674789f64d12 Mon Sep 17 00:00:00 2001 From: Anthony Dresser Date: Tue, 16 Jan 2018 15:55:31 -0800 Subject: [PATCH] Revert "Update dataprotocol client" (#500) * Revert "Fix #494 Connection error when connecting to an Azure SQL Server with no firewall rule (#497)" This reverts commit edd867b6fcc8a8a3cf63147c4d09f42f10f62c8e. * Revert "Update dataprotocol client (#418)" This reverts commit 78084964161fbe72e011cef1778a87f16dbb7394. --- build/gulpfile.sql.js | 4 + build/npm/postinstall.js | 10 +- dataprotocol-client/.gitignore | 3 - dataprotocol-client/.npmignore | 3 - dataprotocol-client/package.json | 24 - dataprotocol-client/src/codeConverter.ts | 68 - dataprotocol-client/src/main.ts | 1311 --------- dataprotocol-client/src/protocol.ts | 633 ---- dataprotocol-client/src/protocolConverter.ts | 50 - dataprotocol-client/src/types.ts | 928 ------ dataprotocol-client/src/typings/ref.d.ts | 2 - dataprotocol-client/tsfmt.json | 17 - dataprotocol-node/.gitignore | 29 + dataprotocol-node/License.txt | 18 + dataprotocol-node/README.md | 4 + dataprotocol-node/client/.eslintrc | 24 + dataprotocol-node/client/.npmignore | 9 + dataprotocol-node/client/.vscode/launch.json | 32 + .../client/.vscode/settings.json | 11 + dataprotocol-node/client/.vscode/tasks.json | 9 + dataprotocol-node/client/README.md | 4 + dataprotocol-node/client/package.json | 32 + dataprotocol-node/client/src/codeConverter.ts | 526 ++++ dataprotocol-node/client/src/main.ts | 2612 +++++++++++++++++ dataprotocol-node/client/src/protocol.ts | 1601 ++++++++++ .../client/src/protocolCodeLens.ts | 16 + .../client/src/protocolCompletionItem.ts | 16 + .../client/src/protocolConverter.ts | 769 +++++ .../client}/src/tsconfig.json | 2 +- .../client/src/typings/es6-promise/index.d.ts | 84 + .../src/typings/es6-promise/tsconfig.json | 23 + dataprotocol-node/client/src/typings/ref.d.ts | 7 + dataprotocol-node/client/src/utils/async.ts | 82 + .../client/src/utils/electron.ts | 123 + .../client/src/utils/electronForkStart.ts | 183 ++ dataprotocol-node/client/src/utils/is.ts | 55 + .../client/src/utils/processes.ts | 44 + .../client/src/utils/terminateProcess.sh | 16 + .../client/thirdpartynotices.txt | 31 + dataprotocol-node/jsonrpc/.eslintrc | 24 + dataprotocol-node/jsonrpc/.npmignore | 9 + dataprotocol-node/jsonrpc/.vscode/launch.json | 32 + .../jsonrpc/.vscode/settings.json | 9 + dataprotocol-node/jsonrpc/.vscode/tasks.json | 9 + dataprotocol-node/jsonrpc/README.md | 4 + dataprotocol-node/jsonrpc/package.json | 29 + dataprotocol-node/jsonrpc/src/cancellation.ts | 97 + dataprotocol-node/jsonrpc/src/events.ts | 213 ++ dataprotocol-node/jsonrpc/src/is.ts | 47 + dataprotocol-node/jsonrpc/src/main.ts | 576 ++++ .../jsonrpc/src/messageReader.ts | 265 ++ .../jsonrpc/src/messageWriter.ts | 118 + dataprotocol-node/jsonrpc/src/messages.ts | 175 ++ dataprotocol-node/jsonrpc/src/tsconfig.json | 11 + .../jsonrpc/src/typings/promise.d.ts | 112 + .../jsonrpc/thirdpartynotices.txt | 31 + dataprotocol-node/types/.eslintrc | 24 + dataprotocol-node/types/.gitignore | 1 + dataprotocol-node/types/.npmignore | 9 + dataprotocol-node/types/.vscode/settings.json | 9 + dataprotocol-node/types/.vscode/tasks.json | 9 + dataprotocol-node/types/README.md | 4 + dataprotocol-node/types/package.json | 26 + dataprotocol-node/types/src/main.ts | 2541 ++++++++++++++++ dataprotocol-node/types/src/tsconfig.json | 10 + .../types/src/typings/promise.d.ts | 112 + extensions-modules/package.json | 5 +- .../src/languageservice/serviceClient.ts | 30 +- .../src/models/contracts/contracts.ts | 4 +- .../src/models/contracts/languageService.ts | 6 +- .../mssql/client/src/models/contracts.ts | 14 +- extensions/mssql/npm-shrinkwrap.json | 21 +- extensions/mssql/package.json | 5 +- .../base/browser/ui/modal/optionsDialog.ts | 11 +- .../browser/ui/modal/optionsDialogHelper.ts | 10 +- src/sql/data.d.ts | 113 +- .../connection/common/connectionManagement.ts | 20 +- .../connection/common/connectionStore.ts | 5 - .../common/providerConnectionInfo.ts | 9 +- .../connectionDialog/connectionController.ts | 3 +- .../connectionDialogWidget.ts | 3 +- .../connectionDialog/connectionWidget.ts | 10 +- .../backup/backup.component.ts | 24 +- .../common/disasterRecoveryService.ts | 149 + .../disasterRecoveryUiService.ts} | 100 +- .../backupService.ts => common/interfaces.ts} | 41 +- .../restore/common/restoreService.ts | 51 - .../disasterRecovery/restore/restoreDialog.ts | 2 +- ...viceImpl.ts => restoreDialogController.ts} | 133 +- .../restore/restoreViewModel.ts | 2 +- .../profiler/service/profilerTestBackend.ts | 1 - .../services/bootstrap/bootstrapService.ts | 8 +- .../bootstrap/bootstrapServiceImpl.ts | 8 +- .../workbench/api/node/extHostDataProtocol.ts | 351 ++- .../api/node/mainThreadDataProtocol.ts | 181 +- .../workbench/api/node/sqlExtHost.api.impl.ts | 219 +- .../workbench/api/node/sqlExtHost.protocol.ts | 13 +- .../api/{common => node}/sqlExtHostTypes.ts | 16 +- src/sql/workbench/common/actions.ts | 7 +- src/sql/workbench/common/taskUtilities.ts | 7 +- .../parts/common/optionsDialogHelper.test.ts | 2 +- .../connection/connectionProfile.test.ts | 11 +- .../parts/connection/connectionStore.test.ts | 11 +- .../connection/objectExplorerService.test.ts | 11 +- .../connection/providerConnectionInfo.test.ts | 11 +- .../disasterRecovery/restoreViewModel.test.ts | 2 +- src/sqltest/stubs/capabilitiesTestService.ts | 11 +- src/sqltest/stubs/connectionProviderStub.ts | 4 +- .../objectExplorerProviderTestService.ts | 2 - .../workbench/electron-browser/workbench.ts | 13 +- 110 files changed, 11677 insertions(+), 3904 deletions(-) delete mode 100644 dataprotocol-client/.gitignore delete mode 100644 dataprotocol-client/.npmignore delete mode 100644 dataprotocol-client/package.json delete mode 100644 dataprotocol-client/src/codeConverter.ts delete mode 100644 dataprotocol-client/src/main.ts delete mode 100644 dataprotocol-client/src/protocol.ts delete mode 100644 dataprotocol-client/src/protocolConverter.ts delete mode 100644 dataprotocol-client/src/types.ts delete mode 100644 dataprotocol-client/src/typings/ref.d.ts delete mode 100644 dataprotocol-client/tsfmt.json create mode 100644 dataprotocol-node/.gitignore create mode 100644 dataprotocol-node/License.txt create mode 100644 dataprotocol-node/README.md create mode 100644 dataprotocol-node/client/.eslintrc create mode 100644 dataprotocol-node/client/.npmignore create mode 100644 dataprotocol-node/client/.vscode/launch.json create mode 100644 dataprotocol-node/client/.vscode/settings.json create mode 100644 dataprotocol-node/client/.vscode/tasks.json create mode 100644 dataprotocol-node/client/README.md create mode 100644 dataprotocol-node/client/package.json create mode 100644 dataprotocol-node/client/src/codeConverter.ts create mode 100644 dataprotocol-node/client/src/main.ts create mode 100644 dataprotocol-node/client/src/protocol.ts create mode 100644 dataprotocol-node/client/src/protocolCodeLens.ts create mode 100644 dataprotocol-node/client/src/protocolCompletionItem.ts create mode 100644 dataprotocol-node/client/src/protocolConverter.ts rename {dataprotocol-client => dataprotocol-node/client}/src/tsconfig.json (90%) create mode 100644 dataprotocol-node/client/src/typings/es6-promise/index.d.ts create mode 100644 dataprotocol-node/client/src/typings/es6-promise/tsconfig.json create mode 100644 dataprotocol-node/client/src/typings/ref.d.ts create mode 100644 dataprotocol-node/client/src/utils/async.ts create mode 100644 dataprotocol-node/client/src/utils/electron.ts create mode 100644 dataprotocol-node/client/src/utils/electronForkStart.ts create mode 100644 dataprotocol-node/client/src/utils/is.ts create mode 100644 dataprotocol-node/client/src/utils/processes.ts create mode 100644 dataprotocol-node/client/src/utils/terminateProcess.sh create mode 100644 dataprotocol-node/client/thirdpartynotices.txt create mode 100644 dataprotocol-node/jsonrpc/.eslintrc create mode 100644 dataprotocol-node/jsonrpc/.npmignore create mode 100644 dataprotocol-node/jsonrpc/.vscode/launch.json create mode 100644 dataprotocol-node/jsonrpc/.vscode/settings.json create mode 100644 dataprotocol-node/jsonrpc/.vscode/tasks.json create mode 100644 dataprotocol-node/jsonrpc/README.md create mode 100644 dataprotocol-node/jsonrpc/package.json create mode 100644 dataprotocol-node/jsonrpc/src/cancellation.ts create mode 100644 dataprotocol-node/jsonrpc/src/events.ts create mode 100644 dataprotocol-node/jsonrpc/src/is.ts create mode 100644 dataprotocol-node/jsonrpc/src/main.ts create mode 100644 dataprotocol-node/jsonrpc/src/messageReader.ts create mode 100644 dataprotocol-node/jsonrpc/src/messageWriter.ts create mode 100644 dataprotocol-node/jsonrpc/src/messages.ts create mode 100644 dataprotocol-node/jsonrpc/src/tsconfig.json create mode 100644 dataprotocol-node/jsonrpc/src/typings/promise.d.ts create mode 100644 dataprotocol-node/jsonrpc/thirdpartynotices.txt create mode 100644 dataprotocol-node/types/.eslintrc create mode 100644 dataprotocol-node/types/.gitignore create mode 100644 dataprotocol-node/types/.npmignore create mode 100644 dataprotocol-node/types/.vscode/settings.json create mode 100644 dataprotocol-node/types/.vscode/tasks.json create mode 100644 dataprotocol-node/types/README.md create mode 100644 dataprotocol-node/types/package.json create mode 100644 dataprotocol-node/types/src/main.ts create mode 100644 dataprotocol-node/types/src/tsconfig.json create mode 100644 dataprotocol-node/types/src/typings/promise.d.ts create mode 100644 src/sql/parts/disasterRecovery/common/disasterRecoveryService.ts rename src/sql/parts/disasterRecovery/{backup/common/backupServiceImp.ts => common/disasterRecoveryUiService.ts} (62%) rename src/sql/parts/disasterRecovery/{backup/common/backupService.ts => common/interfaces.ts} (52%) delete mode 100644 src/sql/parts/disasterRecovery/restore/common/restoreService.ts rename src/sql/parts/disasterRecovery/restore/{common/restoreServiceImpl.ts => restoreDialogController.ts} (69%) rename src/sql/workbench/api/{common => node}/sqlExtHostTypes.ts (87%) diff --git a/build/gulpfile.sql.js b/build/gulpfile.sql.js index b6ecbde9d5..d0afc86d07 100644 --- a/build/gulpfile.sql.js +++ b/build/gulpfile.sql.js @@ -13,6 +13,10 @@ const filter = require('gulp-filter'); gulp.task('clean-mssql-extension', util.rimraf('extensions/mssql/node_modules')); gulp.task('clean-credentials-extension', util.rimraf('extensions/credentials/node_modules')); +gulp.task('clean-client', util.rimraf('dataprotocol-node/client/node_modules')); +gulp.task('clean-jsonrpc', util.rimraf('dataprotocol-node/jsonrpc/node_modules')); +gulp.task('clean-server', util.rimraf('dataprotocol-node/server/node_modules')); +gulp.task('clean-types', util.rimraf('dataprotocol-node/types/node_modules')); gulp.task('clean-extensions-modules', util.rimraf('extensions-modules/node_modules')); gulp.task('clean-protocol', ['clean-extensions-modules', 'clean-mssql-extension', 'clean-credentials-extension', 'clean-client', 'clean-jsonrpc', 'clean-server', 'clean-types']); diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js index 13f7c62bc5..d27ab70f06 100644 --- a/build/npm/postinstall.js +++ b/build/npm/postinstall.js @@ -20,7 +20,15 @@ function npmInstall(location, opts) { } // {{SQL CARBON EDIT}} -npmInstall('dataprotocol-client'); +const protocol = [ + 'jsonrpc', + 'types', + 'client' +]; + +protocol.forEach(item => npmInstall(`dataprotocol-node/${item}`)); + +// {{SQL CARBON EDIT}} npmInstall('extensions-modules'); npmInstall('extensions'); // node modules shared by all extensions diff --git a/dataprotocol-client/.gitignore b/dataprotocol-client/.gitignore deleted file mode 100644 index 6542feba08..0000000000 --- a/dataprotocol-client/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -lib -node_modules -npm-debug.log \ No newline at end of file diff --git a/dataprotocol-client/.npmignore b/dataprotocol-client/.npmignore deleted file mode 100644 index b318f418d6..0000000000 --- a/dataprotocol-client/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -src -.gitignore -tsfmt.json \ No newline at end of file diff --git a/dataprotocol-client/package.json b/dataprotocol-client/package.json deleted file mode 100644 index 450d7b4494..0000000000 --- a/dataprotocol-client/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "dataprotocol-client", - "version": "1.0.0", - "description": "SQL Operations Studio studio implementation of vscode-language-client", - "main": "lib/main.js", - "scripts": { - "prepublish": "node ./node_modules/vscode/bin/install && tsc -p ./src", - "compile": "tsc -p ./src", - "watch": "tsc -w -p ./src", - "update-vscode": "node ./node_modules/vscode/bin/install" - }, - "author": "Microsoft", - "license": "ISC", - "dependencies": { - "vscode": "1.1.5", - "vscode-languageclient": "3.5.0" - }, - "devDependencies": { - "typescript": "2.6.2" - }, - "engines": { - "vscode": "^1.15" - } -} diff --git a/dataprotocol-client/src/codeConverter.ts b/dataprotocol-client/src/codeConverter.ts deleted file mode 100644 index 8f9db2e14c..0000000000 --- a/dataprotocol-client/src/codeConverter.ts +++ /dev/null @@ -1,68 +0,0 @@ -import * as data from 'data'; -import * as proto from './protocol'; -import * as types from './types'; - -export interface Ic2p { - asConnectionParams(connectionUri: string, connectionInfo: data.ConnectionInfo): proto.ConnectParams; - asExecutionPlanOptions(planOptions: data.ExecutionPlanOptions): data.ExecutionPlanOptions; - asScriptingParams(connectionUri: string, operation: data.ScriptOperation, metadata: data.ObjectMetadata, paramDetails: data.ScriptingParamDetails): types.ScriptingParams; -} - -function asConnectionParams(ownerUri: string, connInfo: data.ConnectionInfo): proto.ConnectParams { - return { - ownerUri, - connection: { - options: connInfo.options - } - }; -} - -function asExecutionPlanOptions(planOptions: data.ExecutionPlanOptions): data.ExecutionPlanOptions { - return { - displayEstimatedQueryPlan: planOptions ? planOptions.displayEstimatedQueryPlan : undefined, - displayActualQueryPlan: planOptions ? planOptions.displayActualQueryPlan : undefined - }; -} - -function asScriptingParams(ownerURI: string, operation: data.ScriptOperation, metadata: data.ObjectMetadata, paramDetails: data.ScriptingParamDetails): types.ScriptingParams { - let scriptingObject: types.ScriptingObject = { - type: metadata.metadataTypeName, - schema: metadata.schema, - name: metadata.name - }; - let targetDatabaseEngineEdition = paramDetails.targetDatabaseEngineEdition; - let targetDatabaseEngineType = paramDetails.targetDatabaseEngineType; - let scriptCompatibilityOption = paramDetails.scriptCompatibilityOption; - let scriptOptions: types.ScriptOptions = { - scriptCreateDrop: (operation === types.ScriptOperation.Delete) ? 'ScriptDrop' : - (operation === types.ScriptOperation.Select) ? 'ScriptSelect' : 'ScriptCreate', - typeOfDataToScript: 'SchemaOnly', - scriptStatistics: 'ScriptStatsNone', - targetDatabaseEngineEdition: targetDatabaseEngineEdition ? targetDatabaseEngineEdition : 'SqlServerEnterpriseEdition', - targetDatabaseEngineType: targetDatabaseEngineType ? targetDatabaseEngineType : 'SingleInstance', - scriptCompatibilityOption: scriptCompatibilityOption ? scriptCompatibilityOption : 'Script140Compat' - }; - return { - connectionString: null, - filePath: paramDetails.filePath, - scriptingObjects: [scriptingObject], - scriptDestination: 'ToEditor', - includeObjectCriteria: null, - excludeObjectCriteria: null, - includeSchemas: null, - excludeSchemas: null, - includeTypes: null, - excludeTypes: null, - scriptOptions, - connectionDetails: null, - selectScript: null, - ownerURI, - operation - }; -} - -export const c2p: Ic2p = { - asConnectionParams, - asExecutionPlanOptions, - asScriptingParams -}; diff --git a/dataprotocol-client/src/main.ts b/dataprotocol-client/src/main.ts deleted file mode 100644 index 4c4558abaf..0000000000 --- a/dataprotocol-client/src/main.ts +++ /dev/null @@ -1,1311 +0,0 @@ -import { - LanguageClient, ServerOptions, LanguageClientOptions as VSLanguageClientOptions, DynamicFeature, ServerCapabilities, RegistrationData, - RPCMessageType, Disposable, -} from 'vscode-languageclient'; - -import * as is from 'vscode-languageclient/lib/utils/is'; -import * as UUID from 'vscode-languageclient/lib/utils/uuid'; - -import * as data from 'data'; - -import { c2p, Ic2p } from './codeConverter'; - -import * as protocol from './protocol'; -import * as types from './types'; -import { Ip2c, p2c } from './protocolConverter'; - -function ensure(target: T, key: K): T[K] { - if (target[key] === void 0) { - target[key] = {} as any; - } - return target[key]; -} - -export interface LanguageClientOptions extends VSLanguageClientOptions { - providerId: string; -} - -/** - * - */ -export abstract class SqlOpsFeature implements DynamicFeature { - - protected _providers: Map = new Map(); - - constructor(protected _client: SqlOpsDataClient, private _message: RPCMessageType | RPCMessageType[]) { - } - - public get messages(): RPCMessageType | RPCMessageType[] { - return this._message; - } - - public abstract fillClientCapabilities(capabilities: protocol.ClientCapabilities): void; - - public abstract initialize(capabilities: ServerCapabilities): void; - - public register(messages: RPCMessageType | RPCMessageType[], data: RegistrationData): void { - // Error catching - if (is.array(this.messages) && is.array(messages)) { - let valid = messages.every(v => !!(this.messages as RPCMessageType[]).find(i => i.method === v.method)); - if (!valid) { - throw new Error(`Register called on wrong feature.`); - } - } else if (is.array(this.messages) && !is.array(messages)) { - if (!this.messages.find(i => i.method === messages.method)) { - throw new Error(`Register called on wrong feature.`); - } - } else if (!is.array(this.messages) && !is.array(messages)) { - if (this.messages.method !== messages.method) { - throw new Error(`Register called on wrong feature. Requested ${messages.method} but reached feature ${this.messages.method}`); - } - } - - let provider = this.registerProvider(data.registerOptions); - if (provider) { - this._providers.set(data.id, provider); - } - } - - protected abstract registerProvider(options: T): Disposable; - - public unregister(id: string): void { - let provider = this._providers.get(id); - if (provider) { - provider.dispose(); - } - } - - public dispose(): void { - this._providers.forEach((value) => { - value.dispose(); - }); - } -} - -class CapabilitiesFeature extends SqlOpsFeature { - - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.CapabiltiesDiscoveryRequest.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, CapabilitiesFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'capabilities')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - - let getServerCapabilities = (cap: data.DataProtocolClientCapabilities): Thenable => { - return client.sendRequest(protocol.CapabiltiesDiscoveryRequest.type, cap).then( - r => r.capabilities, - e => { - client.logFailedRequest(protocol.CapabiltiesDiscoveryRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - return data.dataprotocol.registerCapabilitiesServiceProvider({ - providerId: client.providerId, - getServerCapabilities - }); - } -} - -class ConnectionFeature extends SqlOpsFeature { - - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.ConnectionRequest.type, - protocol.ConnectionCompleteNotification.type, - protocol.ConnectionChangedNotification.type, - protocol.DisconnectRequest.type, - protocol.CancelConnectRequest.type, - protocol.ChangeDatabaseRequest.type, - protocol.ListDatabasesRequest.type, - protocol.LanguageFlavorChangedNotification.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, ConnectionFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'connection')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - let connect = (connUri: string, connInfo: data.ConnectionInfo): Thenable => { - return client.sendRequest(protocol.ConnectionRequest.type, client.sqlc2p.asConnectionParams(connUri, connInfo)).then( - r => r, - e => { - client.logFailedRequest(protocol.ConnectionRequest.type, e); - return Promise.resolve(false); - } - ); - }; - - let disconnect = (ownerUri: string): Thenable => { - let params: protocol.DisconnectParams = { - ownerUri - }; - - return client.sendRequest(protocol.DisconnectRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.DisconnectRequest.type, e); - return Promise.resolve(false); - } - ); - }; - - let cancelConnect = (ownerUri: string): Thenable => { - let params: protocol.CancelConnectParams = { - ownerUri - }; - - return client.sendRequest(protocol.CancelConnectRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.CancelConnectRequest.type, e); - return Promise.resolve(false); - } - ); - }; - - let changeDatabase = (ownerUri: string, newDatabase: string): Thenable => { - let params: protocol.ChangeDatabaseParams = { - ownerUri, - newDatabase - }; - - return client.sendRequest(protocol.ChangeDatabaseRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.ChangeDatabaseRequest.type, e); - return Promise.resolve(false); - } - ); - }; - - let listDatabases = (ownerUri: string): Thenable => { - let params: protocol.ListDatabasesParams = { - ownerUri - }; - - return client.sendRequest(protocol.ListDatabasesRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.ListDatabasesRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let rebuildIntelliSenseCache = (ownerUri: string): Thenable => { - let params: protocol.RebuildIntelliSenseParams = { - ownerUri - }; - - client.sendNotification(protocol.RebuildIntelliSenseNotification.type, params); - return Promise.resolve(); - }; - - let registerOnConnectionComplete = (handler: (connSummary: data.ConnectionInfoSummary) => any): void => { - client.onNotification(protocol.ConnectionCompleteNotification.type, handler); - }; - - let registerOnIntelliSenseCacheComplete = (handler: (connectionUri: string) => any): void => { - client.onNotification(protocol.IntelliSenseReadyNotification.type, (params: types.IntelliSenseReadyParams) => { - handler(params.ownerUri); - }); - }; - - let registerOnConnectionChanged = (handler: (changedConnInfo: data.ChangedConnectionInfo) => any): void => { - client.onNotification(protocol.ConnectionChangedNotification.type, (params: protocol.ConnectionChangedParams) => { - handler({ - connectionUri: params.ownerUri, - connection: params.connection - }); - }); - }; - - return data.dataprotocol.registerConnectionProvider({ - providerId: client.providerId, - connect, - disconnect, - cancelConnect, - changeDatabase, - listDatabases, - rebuildIntelliSenseCache, - registerOnConnectionChanged, - registerOnIntelliSenseCacheComplete, - registerOnConnectionComplete - }); - } -} - -class QueryFeature extends SqlOpsFeature { - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.QueryExecuteRequest.type, - protocol.QueryCancelRequest.type, - protocol.QueryExecuteStatementRequest.type, - protocol.QueryExecuteStringRequest.type, - protocol.SimpleExecuteRequest.type, - protocol.QueryExecuteSubsetRequest.type, - protocol.QueryDisposeRequest.type, - protocol.QueryExecuteCompleteNotification.type, - protocol.QueryExecuteBatchStartNotification.type, - protocol.QueryExecuteBatchCompleteNotification.type, - protocol.QueryExecuteResultSetCompleteNotification.type, - protocol.QueryExecuteMessageNotification.type, - protocol.SaveResultsAsCsvRequest.type, - protocol.SaveResultsAsJsonRequest.type, - protocol.SaveResultsAsExcelRequest.type, - protocol.EditCommitRequest.type, - protocol.EditCreateRowRequest.type, - protocol.EditDeleteRowRequest.type, - protocol.EditDisposeRequest.type, - protocol.EditInitializeRequest.type, - protocol.EditRevertCellRequest.type, - protocol.EditRevertRowRequest.type, - protocol.EditUpdateCellRequest.type, - protocol.EditSubsetRequest.type, - protocol.EditSessionReadyNotification.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, QueryFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'query')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - let runQuery = (ownerUri: string, querySelection: data.ISelectionData, executionPlanOptions?: data.ExecutionPlanOptions): Thenable => { - let params: data.QueryExecuteParams = { - ownerUri, - querySelection, - executionPlanOptions: client.sqlc2p.asExecutionPlanOptions(executionPlanOptions) - }; - return client.sendRequest(protocol.QueryExecuteRequest.type, params).then( - r => undefined, - e => { - client.logFailedRequest(protocol.QueryExecuteRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let cancelQuery = (ownerUri: string): Thenable => { - let params: protocol.QueryCancelParams = { ownerUri }; - return client.sendRequest(protocol.QueryCancelRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.QueryCancelRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let runQueryStatement = (ownerUri: string, line: number, column: number): Thenable => { - let params: protocol.QueryExecuteStatementParams = { - ownerUri, - line, - column - }; - return client.sendRequest(protocol.QueryExecuteStatementRequest.type, params).then( - r => undefined, - e => { - client.logFailedRequest(protocol.QueryExecuteStatementRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let runQueryString = (ownerUri: string, query: string): Thenable => { - let params: protocol.QueryExecuteStringParams = { ownerUri, query }; - return client.sendRequest(protocol.QueryExecuteStringRequest.type, params).then( - r => undefined, - e => { - client.logFailedRequest(protocol.QueryExecuteStringRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let runQueryAndReturn = (ownerUri: string, queryString: string): Thenable => { - let params: data.SimpleExecuteParams = { ownerUri, queryString }; - return client.sendRequest(protocol.SimpleExecuteRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.SimpleExecuteRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let getQueryRows = (rowData: data.QueryExecuteSubsetParams): Thenable => { - return client.sendRequest(protocol.QueryExecuteSubsetRequest.type, rowData).then( - r => r, - e => { - client.logFailedRequest(protocol.QueryExecuteSubsetRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let disposeQuery = (ownerUri: string): Thenable => { - let params: protocol.QueryDisposeParams = { ownerUri }; - return client.sendRequest(protocol.QueryDisposeRequest.type, params).then( - r => undefined, - e => { - client.logFailedRequest(protocol.QueryDisposeRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let registerOnQueryComplete = (handler: (result: data.QueryExecuteCompleteNotificationResult) => any): void => { - client.onNotification(protocol.QueryExecuteCompleteNotification.type, handler); - }; - - let registerOnBatchStart = (handler: (batchInfo: data.QueryExecuteBatchNotificationParams) => any): void => { - client.onNotification(protocol.QueryExecuteBatchStartNotification.type, handler); - }; - - let registerOnBatchComplete = (handler: (batchInfo: data.QueryExecuteBatchNotificationParams) => any): void => { - client.onNotification(protocol.QueryExecuteBatchCompleteNotification.type, handler); - }; - - let registerOnResultSetComplete = (handler: (resultSetInfo: data.QueryExecuteResultSetCompleteNotificationParams) => any): void => { - client.onNotification(protocol.QueryExecuteResultSetCompleteNotification.type, handler); - }; - - let registerOnMessage = (handler: (message: data.QueryExecuteMessageParams) => any): void => { - client.onNotification(protocol.QueryExecuteMessageNotification.type, handler); - }; - - let saveResults = (requestParams: data.SaveResultsRequestParams): Thenable => { - switch (requestParams.resultFormat) { - case 'csv': - return client.sendRequest(protocol.SaveResultsAsCsvRequest.type, requestParams).then( - undefined, - e => { - client.logFailedRequest(protocol.SaveResultsAsCsvRequest.type, e); - return Promise.reject(e); - } - ); - case 'json': - return client.sendRequest(protocol.SaveResultsAsJsonRequest.type, requestParams).then( - undefined, - e => { - client.logFailedRequest(protocol.SaveResultsAsJsonRequest.type, e); - return Promise.reject(e); - } - ); - case 'excel': - return client.sendRequest(protocol.SaveResultsAsExcelRequest.type, requestParams).then( - undefined, - e => { - client.logFailedRequest(protocol.SaveResultsAsExcelRequest.type, e); - return Promise.reject(e); - } - ); - default: - return Promise.reject('unsupported format'); - } - }; - - // Edit Data Requests - let commitEdit = (ownerUri: string): Thenable => { - let params: data.EditCommitParams = { ownerUri }; - return client.sendRequest(protocol.EditCommitRequest.type, params).then( - r => undefined, - e => { - client.logFailedRequest(protocol.EditCommitRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let createRow = (ownerUri: string): Thenable => { - let params: data.EditCreateRowParams = { ownerUri: ownerUri }; - return client.sendRequest(protocol.EditCreateRowRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.EditCreateRowRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let deleteRow = (ownerUri: string, rowId: number): Thenable => { - let params: data.EditDeleteRowParams = { ownerUri, rowId }; - return client.sendRequest(protocol.EditDeleteRowRequest.type, params).then( - r => undefined, - e => { - client.logFailedRequest(protocol.EditDeleteRowRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let disposeEdit = (ownerUri: string): Thenable => { - let params: data.EditDisposeParams = { ownerUri }; - return client.sendRequest(protocol.EditDisposeRequest.type, params).then( - r => undefined, - e => { - client.logFailedRequest(protocol.EditDisposeRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let initializeEdit = (ownerUri: string, schemaName: string, objectName: string, objectType: string, LimitResults: number): Thenable => { - let filters: data.EditInitializeFiltering = { LimitResults }; - let params: data.EditInitializeParams = { ownerUri, schemaName, objectName, objectType, filters }; - return client.sendRequest(protocol.EditInitializeRequest.type, params).then( - r => undefined, - e => { - client.logFailedRequest(protocol.EditInitializeRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let revertCell = (ownerUri: string, rowId: number, columnId: number): Thenable => { - let params: data.EditRevertCellParams = { ownerUri, rowId, columnId }; - return client.sendRequest(protocol.EditRevertCellRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.EditRevertCellRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let revertRow = (ownerUri: string, rowId: number): Thenable => { - let params: data.EditRevertRowParams = { ownerUri, rowId }; - return client.sendRequest(protocol.EditRevertRowRequest.type, params).then( - r => undefined, - e => { - client.logFailedRequest(protocol.EditRevertRowRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let updateCell = (ownerUri: string, rowId: number, columnId: number, newValue: string): Thenable => { - let params: data.EditUpdateCellParams = { ownerUri, rowId, columnId, newValue }; - return client.sendRequest(protocol.EditUpdateCellRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.EditUpdateCellRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let getEditRows = (rowData: data.EditSubsetParams): Thenable => { - return client.sendRequest(protocol.EditSubsetRequest.type, rowData).then( - r => r, - e => { - client.logFailedRequest(protocol.EditSubsetRequest.type, e); - return Promise.reject(e); - } - ); - }; - - // Edit Data Event Handlers - let registerOnEditSessionReady = (handler: (ownerUri: string, success: boolean, message: string) => any): void => { - client.onNotification(protocol.EditSessionReadyNotification.type, (params: data.EditSessionReadyParams) => { - handler(params.ownerUri, params.success, params.message); - }); - }; - - return data.dataprotocol.registerQueryProvider({ - providerId: client.providerId, - cancelQuery, - commitEdit, - createRow, - deleteRow, - disposeEdit, - disposeQuery, - getEditRows, - getQueryRows, - initializeEdit, - registerOnBatchComplete, - registerOnBatchStart, - registerOnEditSessionReady, - registerOnMessage, - registerOnQueryComplete, - registerOnResultSetComplete, - revertCell, - revertRow, - runQuery, - runQueryAndReturn, - runQueryStatement, - runQueryString, - saveResults, - updateCell - }); - } -} - -class MetadataFeature extends SqlOpsFeature { - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.MetadataQueryRequest.type, - protocol.ListDatabasesRequest.type, - protocol.TableMetadataRequest.type, - protocol.ViewMetadataRequest.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, MetadataFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'metadata')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - - let getMetadata = (ownerUri: string): Thenable => { - let params: types.MetadataQueryParams = { ownerUri }; - return client.sendRequest(protocol.MetadataQueryRequest.type, params).then( - client.sqlp2c.asProviderMetadata, - e => { - client.logFailedRequest(protocol.MetadataQueryRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let getDatabases = (ownerUri: string): Thenable => { - let params: protocol.ListDatabasesParams = { ownerUri }; - return client.sendRequest(protocol.ListDatabasesRequest.type, params).then( - r => r.databaseNames, - e => { - client.logFailedRequest(protocol.ListDatabasesRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let getTableInfo = (ownerUri: string, metadata: data.ObjectMetadata): Thenable => { - let params: protocol.TableMetadataParams = { objectName: metadata.name, ownerUri, schema: metadata.schema }; - return client.sendRequest(protocol.TableMetadataRequest.type, params).then( - r => r.columns, - e => { - client.logFailedRequest(protocol.TableMetadataRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let getViewInfo = (ownerUri: string, metadata: data.ObjectMetadata): Thenable => { - let params: protocol.TableMetadataParams = { objectName: metadata.name, ownerUri, schema: metadata.schema }; - return client.sendRequest(protocol.ViewMetadataRequest.type, params).then( - r => r.columns, - e => { - client.logFailedRequest(protocol.ViewMetadataRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - return data.dataprotocol.registerMetadataProvider({ - providerId: client.providerId, - getDatabases, - getMetadata, - getTableInfo, - getViewInfo - }); - } -} - -class AdminServicesFeature extends SqlOpsFeature { - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.CreateDatabaseRequest.type, - protocol.DefaultDatabaseInfoRequest.type, - protocol.GetDatabaseInfoRequest.type, - protocol.CreateLoginRequest.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, AdminServicesFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'adminServices')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - - let createDatabase = (ownerUri: string, databaseInfo: data.DatabaseInfo): Thenable => { - let params: types.CreateDatabaseParams = { ownerUri, databaseInfo }; - return client.sendRequest(protocol.CreateDatabaseRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.CreateDatabaseRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let getDefaultDatabaseInfo = (ownerUri: string): Thenable => { - let params: types.DefaultDatabaseInfoParams = { ownerUri }; - return client.sendRequest(protocol.DefaultDatabaseInfoRequest.type, params).then( - r => r.defaultDatabaseInfo, - e => { - client.logFailedRequest(protocol.DefaultDatabaseInfoRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let getDatabaseInfo = (ownerUri: string): Thenable => { - let params: types.GetDatabaseInfoParams = { ownerUri }; - return client.sendRequest(protocol.GetDatabaseInfoRequest.type, params).then( - r => r.databaseInfo, - e => { - client.logFailedRequest(protocol.GetDatabaseInfoRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let createLogin = (ownerUri: string, loginInfo: data.LoginInfo): Thenable => { - let params: types.CreateLoginParams = { ownerUri, loginInfo }; - return client.sendRequest(protocol.CreateLoginRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.CreateLoginRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - return data.dataprotocol.registerAdminServicesProvider({ - providerId: client.providerId, - createDatabase, - createLogin, - getDatabaseInfo, - getDefaultDatabaseInfo - }); - } -} - -class BackupFeature extends SqlOpsFeature { - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.BackupRequest.type, - protocol.BackupConfigInfoRequest.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, BackupFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'backup')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - - let backup = (ownerUri: string, backupInfo: types.BackupInfo, taskExecutionMode: data.TaskExecutionMode): Thenable => { - let params: types.BackupParams = { ownerUri, backupInfo, taskExecutionMode }; - return client.sendRequest(protocol.BackupRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.BackupRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let getBackupConfigInfo = (connectionUri: string): Thenable => { - let params: types.DefaultDatabaseInfoParams = { ownerUri: connectionUri }; - return client.sendRequest(protocol.BackupConfigInfoRequest.type, params).then( - r => r.backupConfigInfo, - e => { - client.logFailedRequest(protocol.BackupConfigInfoRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - return data.dataprotocol.registerBackupProvider({ - providerId: client.providerId, - backup, - getBackupConfigInfo - }); - } -} - -class RestoreFeature extends SqlOpsFeature { - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.RestorePlanRequest.type, - protocol.RestoreRequest.type, - protocol.RestoreConfigInfoRequest.type, - protocol.CancelRestorePlanRequest.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, RestoreFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'restore')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - - let getRestorePlan = (ownerUri: string, restoreInfo: data.RestoreInfo): Thenable => { - let params: types.RestoreParams = { options: restoreInfo.options, ownerUri, taskExecutionMode: restoreInfo.taskExecutionMode }; - return client.sendRequest(protocol.RestorePlanRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.RestorePlanRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let restore = (ownerUri: string, restoreInfo: data.RestoreInfo): Thenable => { - let params: types.RestoreParams = { options: restoreInfo.options, ownerUri, taskExecutionMode: restoreInfo.taskExecutionMode }; - return client.sendRequest(protocol.RestoreRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.RestoreRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let getRestoreConfigInfo = (ownerUri: string): Thenable => { - let params: types.RestoreConfigInfoRequestParams = { ownerUri }; - return client.sendRequest(protocol.RestoreConfigInfoRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.RestoreConfigInfoRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let cancelRestorePlan = (ownerUri: string, restoreInfo: data.RestoreInfo): Thenable => { - let params: types.RestoreParams = { options: restoreInfo.options, ownerUri, taskExecutionMode: restoreInfo.taskExecutionMode }; - return client.sendRequest(protocol.CancelRestorePlanRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.CancelRestorePlanRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - return data.dataprotocol.registerRestoreProvider({ - providerId: client.providerId, - cancelRestorePlan, - getRestoreConfigInfo, - getRestorePlan, - restore - }); - } -} - -class ObjectExplorerFeature extends SqlOpsFeature { - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.ObjectExplorerCreateSessionRequest.type, - protocol.ObjectExplorerExpandRequest.type, - protocol.ObjectExplorerRefreshRequest.type, - protocol.ObjectExplorerCloseSessionRequest.type, - protocol.ObjectExplorerCreateSessionCompleteNotification.type, - protocol.ObjectExplorerExpandCompleteNotification.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, ObjectExplorerFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'objectExplorer')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - let createNewSession = (connInfo: data.ConnectionInfo): Thenable => { - return client.sendRequest(protocol.ObjectExplorerCreateSessionRequest.type, connInfo).then( - r => r, - e => { - client.logFailedRequest(protocol.ObjectExplorerCreateSessionRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let expandNode = (nodeInfo: data.ExpandNodeInfo): Thenable => { - return client.sendRequest(protocol.ObjectExplorerExpandRequest.type, nodeInfo).then( - r => r, - e => { - client.logFailedRequest(protocol.ObjectExplorerExpandRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let refreshNode = (nodeInfo: data.ExpandNodeInfo): Thenable => { - return client.sendRequest(protocol.ObjectExplorerRefreshRequest.type, nodeInfo).then( - r => r, - e => { - client.logFailedRequest(protocol.ObjectExplorerRefreshRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let closeSession = (closeSessionInfo: data.ObjectExplorerCloseSessionInfo): Thenable => { - return client.sendRequest(protocol.ObjectExplorerCloseSessionRequest.type, closeSessionInfo).then( - r => r, - e => { - client.logFailedRequest(protocol.ObjectExplorerCloseSessionRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let registerOnSessionCreated = (handler: (response: data.ObjectExplorerSession) => any): void => { - client.onNotification(protocol.ObjectExplorerCreateSessionCompleteNotification.type, handler); - }; - - let registerOnExpandCompleted = (handler: (response: data.ObjectExplorerExpandInfo) => any): void => { - client.onNotification(protocol.ObjectExplorerExpandCompleteNotification.type, handler); - }; - - return data.dataprotocol.registerObjectExplorerProvider({ - providerId: client.providerId, - closeSession, - createNewSession, - expandNode, - refreshNode, - registerOnExpandCompleted, - registerOnSessionCreated - }); - } -} - -class ScriptingFeature extends SqlOpsFeature { - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.ScriptingRequest.type, - protocol.ScriptingCompleteNotification.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, ScriptingFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'scripting')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - - let scriptAsOperation = (connectionUri: string, operation: data.ScriptOperation, metadata: data.ObjectMetadata, paramDetails: data.ScriptingParamDetails): Thenable => { - return client.sendRequest(protocol.ScriptingRequest.type, - client.sqlc2p.asScriptingParams(connectionUri, operation, metadata, paramDetails)).then( - r => r, - e => { - client.logFailedRequest(protocol.ScriptingRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let registerOnScriptingComplete = (handler: (scriptingCompleteResult: data.ScriptingCompleteResult) => any): void => { - client.onNotification(protocol.ScriptingCompleteNotification.type, handler); - }; - - return data.dataprotocol.registerScriptingProvider({ - providerId: client.providerId, - registerOnScriptingComplete, - scriptAsOperation - }); - } -} - -class TaskServicesFeature extends SqlOpsFeature { - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.ListTasksRequest.type, - protocol.CancelTaskRequest.type, - protocol.TaskCreatedNotification.type, - protocol.TaskStatusChangedNotification.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, TaskServicesFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'taskServices')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - - let getAllTasks = (listTasksParams: data.ListTasksParams): Thenable => { - return client.sendRequest(protocol.ListTasksRequest.type, listTasksParams).then( - r => r, - e => { - client.logFailedRequest(protocol.ListTasksRequest.type, e); - return Promise.resolve(undefined); - } - ); - - }; - - let cancelTask = (cancelTaskParams: data.CancelTaskParams): Thenable => { - return client.sendRequest(protocol.CancelTaskRequest.type, cancelTaskParams).then( - r => r, - e => { - client.logFailedRequest(protocol.CancelTaskRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let registerOnTaskCreated = (handler: (response: data.TaskInfo) => any): void => { - client.onNotification(protocol.TaskCreatedNotification.type, handler); - }; - - let registerOnTaskStatusChanged = (handler: (response: data.TaskProgressInfo) => any): void => { - client.onNotification(protocol.TaskStatusChangedNotification.type, handler); - }; - - return data.dataprotocol.registerTaskServicesProvider({ - providerId: client.providerId, - cancelTask, - getAllTasks, - registerOnTaskCreated, - registerOnTaskStatusChanged - }); - } -} - -class FileBrowserFeature extends SqlOpsFeature { - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.FileBrowserOpenRequest.type, - protocol.FileBrowserOpenedNotification.type, - protocol.FileBrowserExpandRequest.type, - protocol.FileBrowserExpandedNotification.type, - protocol.FileBrowserValidateRequest.type, - protocol.FileBrowserValidatedNotification.type, - protocol.FileBrowserCloseRequest.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, FileBrowserFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'fileBrowser')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - - let openFileBrowser = (ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean): Thenable => { - let params: types.FileBrowserOpenParams = { ownerUri, expandPath, fileFilters, changeFilter }; - return client.sendRequest(protocol.FileBrowserOpenRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.FileBrowserOpenRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let registerOnFileBrowserOpened = (handler: (response: data.FileBrowserOpenedParams) => any): void => { - client.onNotification(protocol.FileBrowserOpenedNotification.type, handler); - }; - - let expandFolderNode = (ownerUri: string, expandPath: string): Thenable => { - let params: types.FileBrowserExpandParams = { ownerUri, expandPath }; - return client.sendRequest(protocol.FileBrowserExpandRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.FileBrowserExpandRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let registerOnFolderNodeExpanded = (handler: (response: data.FileBrowserExpandedParams) => any): void => { - client.onNotification(protocol.FileBrowserExpandedNotification.type, handler); - }; - - let validateFilePaths = (ownerUri: string, serviceType: string, selectedFiles: string[]): Thenable => { - let params: types.FileBrowserValidateParams = { ownerUri, serviceType, selectedFiles }; - return client.sendRequest(protocol.FileBrowserValidateRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.FileBrowserValidateRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - let registerOnFilePathsValidated = (handler: (response: data.FileBrowserValidatedParams) => any): void => { - client.onNotification(protocol.FileBrowserValidatedNotification.type, handler); - }; - - let closeFileBrowser = (ownerUri: string): Thenable => { - let params: types.FileBrowserCloseParams = { ownerUri }; - return client.sendRequest(protocol.FileBrowserCloseRequest.type, params).then( - r => r, - e => { - client.logFailedRequest(protocol.FileBrowserCloseRequest.type, e); - return Promise.resolve(undefined); - } - ); - }; - - return data.dataprotocol.registerFileBrowserProvider({ - providerId: client.providerId, - closeFileBrowser, - expandFolderNode, - openFileBrowser, - registerOnFileBrowserOpened, - registerOnFilePathsValidated, - registerOnFolderNodeExpanded, - validateFilePaths - }); - } -} - -class ProfilerFeature extends SqlOpsFeature { - private static readonly messagesTypes: RPCMessageType[] = [ - protocol.StartProfilingRequest.type, - protocol.StopProfilingRequest.type, - protocol.ProfilerEventsAvailableNotification.type - ]; - - constructor(client: SqlOpsDataClient) { - super(client, ProfilerFeature.messagesTypes); - } - - public fillClientCapabilities(capabilities: protocol.ClientCapabilities): void { - ensure(ensure(capabilities, 'connection')!, 'profiler')!.dynamicRegistration = true; - } - - public initialize(capabilities: ServerCapabilities): void { - this.register(this.messages, { - id: UUID.generateUuid(), - registerOptions: undefined - }); - } - - protected registerProvider(options: undefined): Disposable { - const client = this._client; - - let startSession = (ownerUri: string): Thenable => { - let params: types.StartProfilingParams = { - ownerUri, - options: {} - }; - - return client.sendRequest(protocol.StartProfilingRequest.type, params).then( - r => true, - e => { - client.logFailedRequest(protocol.StartProfilingRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let stopSession = (ownerUri: string): Thenable => { - let params: types.StopProfilingParams = { - ownerUri - }; - - return client.sendRequest(protocol.StopProfilingRequest.type, params).then( - r => true, - e => { - client.logFailedRequest(protocol.StopProfilingRequest.type, e); - return Promise.reject(e); - } - ); - }; - - let pauseSession = (sessionId: string): Thenable => { - return undefined; - }; - - let connectSession = (sessionId: string): Thenable => { - return undefined; - }; - - let disconnectSession = (sessionId: string): Thenable => { - return undefined; - }; - - let registerOnSessionEventsAvailable = (handler: (response: data.ProfilerSessionEvents) => any): void => { - client.onNotification(protocol.ProfilerEventsAvailableNotification.type, (params: types.ProfilerEventsAvailableParams) => { - handler({ - sessionId: params.ownerUri, - events: params.events - }); - }); - }; - - return data.dataprotocol.registerProfilerProvider({ - providerId: client.providerId, - connectSession, - disconnectSession, - pauseSession, - registerOnSessionEventsAvailable, - startSession, - stopSession - }); - } -} - -/** - * - */ -export class SqlOpsDataClient extends LanguageClient { - - private _sqlc2p: Ic2p; - private _sqlp2c: Ip2c; - private _providerId: string; - - public get sqlc2p(): Ic2p { - return this._sqlc2p; - } - - public get sqlp2c(): Ip2c { - return this._sqlp2c; - } - - public get providerId(): string { - return this._providerId; - } - - public constructor(name: string, serverOptions: ServerOptions, clientOptions: LanguageClientOptions, forceDebug?: boolean); - public constructor(id: string, name: string, serverOptions: ServerOptions, clientOptions: LanguageClientOptions, forceDebug?: boolean); - public constructor(arg1: string, arg2: ServerOptions | string, arg3: LanguageClientOptions | ServerOptions, arg4?: boolean | LanguageClientOptions, arg5?: boolean) { - if (is.string(arg2)) { - super(arg1, arg2, arg3 as ServerOptions, arg4 as LanguageClientOptions, arg5); - this._providerId = (arg4 as LanguageClientOptions).providerId; - } else { - super(arg1, arg2 as ServerOptions, arg3 as LanguageClientOptions, arg4 as boolean); - this._providerId = (arg3 as LanguageClientOptions).providerId; - } - this._sqlc2p = c2p; - this._sqlp2c = p2c; - this.registerDataFeatures(); - } - - private registerDataFeatures() { - this.registerFeature(new ConnectionFeature(this)); - this.registerFeature(new CapabilitiesFeature(this)); - this.registerFeature(new QueryFeature(this)); - this.registerFeature(new MetadataFeature(this)); - this.registerFeature(new AdminServicesFeature(this)); - this.registerFeature(new BackupFeature(this)); - this.registerFeature(new RestoreFeature(this)); - this.registerFeature(new ObjectExplorerFeature(this)); - this.registerFeature(new ScriptingFeature(this)); - this.registerFeature(new TaskServicesFeature(this)); - this.registerFeature(new FileBrowserFeature(this)); - this.registerFeature(new ProfilerFeature(this)); - } -} diff --git a/dataprotocol-client/src/protocol.ts b/dataprotocol-client/src/protocol.ts deleted file mode 100644 index 114be781ab..0000000000 --- a/dataprotocol-client/src/protocol.ts +++ /dev/null @@ -1,633 +0,0 @@ -import { ClientCapabilities as VSClientCapabilities, RequestType, NotificationType } from 'vscode-languageclient'; - -import * as types from './types'; -import * as data from 'data'; - -export interface ConnectionClientCapabilities { - connection?: { - /** - * Whether the connection support dynamic registration - */ - dynamicRegistration?: boolean; - }; - backup?: { - /** - * Whether the backup support dynamic registration - */ - dynamicRegistration?: boolean; - }; - restore?: { - /** - * Whether the restore support dynamic registration - */ - dynamicRegistration?: boolean; - }; - query?: { - /** - * Whether the query support dynamic registration - */ - dynamicRegistration?: boolean; - }; - objectExplorer?: { - /** - * Whether the object explorer support dynamic registration - */ - dynamicRegistration?: boolean; - }; - scripting?: { - /** - * Whether the scripting support dynamic registration - */ - dynamicRegistration?: boolean; - }; - taskServices?: { - /** - * Whether the task services support dynamic registration - */ - dynamicRegistration?: boolean; - }; - fileBrowser?: { - /** - * Whether the file browser support dynamic registration - */ - dynamicRegistration?: boolean; - }; - profiler?: { - /** - * Whether the profiler support dynamic registration - */ - dynamicRegistration?: boolean; - }; - capabilities?: { - /** - * - */ - dynamicRegistration?: boolean; - }; - metadata?: { - /** - * - */ - dynamicRegistration?: boolean; - }; - adminServices?: { - /** - * - */ - dynamicRegistration?: boolean; - }; -} - -export interface ClientCapabilities extends VSClientCapabilities { - connection?: ConnectionClientCapabilities; -} - -//---- Refresh IntelliSense ---------------------------------------- - -/** - * Notification sent when the an IntelliSense cache invalidation is requested - */ -export namespace RebuildIntelliSenseNotification { - export const type = new NotificationType('textDocument/rebuildIntelliSense'); -} - -/** - * Rebuild IntelliSense notification parameters - */ -export class RebuildIntelliSenseParams { - /** - * URI identifying the text document - */ - public ownerUri: string; -} - - -// ------------------------------- < Connect Request > ---------------------------------------------- - -/** - * Connection request message format - */ -export interface ConnectParams { - /** - * URI identifying the owner of the connection - */ - ownerUri: string; - - /** - * Details for creating the connection - */ - connection: types.ConnectionDetails; -} - - -// Connection request message callback declaration -export namespace ConnectionRequest { - export const type = new RequestType('connection/connect'); -} - -// ------------------------------- < Connection Complete Event > ------------------------------------ - - -export namespace ConnectionCompleteNotification { - export const type = new NotificationType('connection/complete'); -} - -// ------------------------------- < Connection Changed Event > ------------------------------------- - -/** - * Parameters for the ConnectionChanged notification. - */ -export class ConnectionChangedParams { - /** - * Owner URI of the connection that changed. - */ - public ownerUri: string; - - /** - * Summary of details containing any connection changes. - */ - public connection: types.ConnectionSummary; -} - -/** - * Connection changed event callback declaration. - */ -export namespace ConnectionChangedNotification { - export const type = new NotificationType('connection/connectionchanged'); -} - -// ------------------------------- < Disconnect Request > ------------------------------------------- - -// Disconnect request message format -export class DisconnectParams { - // URI identifying the owner of the connection - public ownerUri: string; -} - -// Disconnect response format -export type DisconnectResult = boolean; - -// Disconnect request message callback declaration -export namespace DisconnectRequest { - export const type = new RequestType('connection/disconnect'); -} - -// ------------------------------- < Cancel Connect Request > --------------------------------------- - - -// Cancel connect request message format -export class CancelConnectParams { - /** - * URI identifying the owner of the connection - */ - public ownerUri: string; -} - -// Cancel connect response format. -export type CancelConnectResult = boolean; - -// Cancel connect request message callback declaration -export namespace CancelConnectRequest { - export const type = new RequestType('connection/cancelconnect'); -} - -// ------------------------------- < Change Database Request > ------------------------------------- - -export class ChangeDatabaseParams { - public ownerUri: string; - public newDatabase: string; -} - -export namespace ChangeDatabaseRequest { - export const type = new RequestType('connection/changedatabase'); -} - -// ------------------------------- < List Databases Request > --------------------------------------- - -// List databases request format -export class ListDatabasesParams { - // Connection information to use for querying master - public ownerUri: string; -} - -// List databases request callback declaration -export namespace ListDatabasesRequest { - export const type = new RequestType('connection/listdatabases'); -} - -// Language Flavor Changed ================================================================================ - -/** - * Parameters to provide when sending a language flavor changed notification - */ -export interface DidChangeLanguageFlavorParams { - uri: string; - language: string; - flavor: string; -} - -// ------------------------------- < Language Flavor Changed Notification > --------------------------------------- -export namespace LanguageFlavorChangedNotification { - export const type = new NotificationType('connection/languageflavorchanged'); -} - -// ------------------------------- < Table Metadata Request > --------------------------------------- - -// Table metadata request format -export class TableMetadataParams { - // Connection information to use for querying master - public ownerUri: string; - - public schema: string; - - public objectName: string; -} - -// Table metadata response format -export class TableMetadataResult { - public columns: data.ColumnMetadata[]; -} - -// Table metadata request callback declaration -export namespace TableMetadataRequest { - export const type = new RequestType('metadata/table'); -} - -// ------------------------------- < View Metadata Request > --------------------------------------- - -// Table metadata request callback declaration -export namespace ViewMetadataRequest { - export const type = new RequestType('metadata/view'); -} - -/** - * Event sent when the language service is finished updating after a connection - */ -export namespace IntelliSenseReadyNotification { - export const type = new NotificationType('textDocument/intelliSenseReady'); -} - -// ------------------------------- < Capabilties Discovery Event > ------------------------------------ - -export class CapabiltiesDiscoveryParams { - public hostName: string; - - public hostVersion: string; -} - -export namespace CapabiltiesDiscoveryRequest { - export const type = new RequestType('capabilities/list'); -} - -// Query Execution ================================================================================ -// ------------------------------- < Query Cancellation Request > ------------------------------------ -export namespace QueryCancelRequest { - export const type = new RequestType('query/cancel'); -} - -export interface QueryCancelParams { - ownerUri: string; -} - -// ------------------------------- < Query Dispose Request > ------------------------------------ - -export namespace QueryDisposeRequest { - export const type = new RequestType('query/dispose'); -} - -/** - * Parameters to provide when disposing of a query - */ -export interface QueryDisposeParams { - ownerUri: string; -} - -/** - * Result received upon successful disposal of a query - */ -export interface QueryDisposeResult { -} - -// ------------------------------- < Query Execution Complete Notification > ------------------------------------ -export namespace QueryExecuteCompleteNotification { - export const type = new NotificationType('query/complete'); -} - -// ------------------------------- < Query Batch Start Notification > ------------------------------------ -export namespace QueryExecuteBatchStartNotification { - export const type = new NotificationType('query/batchStart'); -} - -// ------------------------------- < Query Batch Complete Notification > ------------------------------------ -export namespace QueryExecuteBatchCompleteNotification { - export const type = new NotificationType('query/batchComplete'); -} - -// ------------------------------- < Query ResultSet Complete Notification > ------------------------------------ -export namespace QueryExecuteResultSetCompleteNotification { - export const type = new NotificationType('query/resultSetComplete'); -} - -// ------------------------------- < Query Message Notification > ------------------------------------ -export namespace QueryExecuteMessageNotification { - export const type = new NotificationType('query/message'); -} - -// ------------------------------- < Query Execution Request > ------------------------------------ -export namespace QueryExecuteRequest { - export const type = new RequestType('query/executeDocumentSelection'); -} - -export interface QueryExecuteResult { } - -// ------------------------------- < Query Results Request > ------------------------------------ -export namespace QueryExecuteSubsetRequest { - export const type = new RequestType('query/subset'); -} - -export interface ResultSetSubset { - rowCount: number; - rows: data.DbCellValue[][]; -} - -// ------------------------------- < Execute Statement > ------------------------------------ -export interface QueryExecuteStatementParams { - ownerUri: string; - line: number; - column: number; -} - -export namespace QueryExecuteStatementRequest { - export const type = new RequestType('query/executedocumentstatement'); -} - -// --------------------------------- < Save Results as CSV Request > ------------------------------------------ - -// save results in csv format -export namespace SaveResultsAsCsvRequest { - export const type = new RequestType('query/saveCsv'); -} -// --------------------------------- ------------------------------------------ - -// --------------------------------- < Save Results as JSON Request > ------------------------------------------ -// save results in json format -export namespace SaveResultsAsJsonRequest { - export const type = new RequestType('query/saveJson'); -} -// --------------------------------- ------------------------------------------ - -// --------------------------------- < Save Results as Excel Request > ------------------------------------------ -// save results in Excel format -export namespace SaveResultsAsExcelRequest { - export const type = new RequestType('query/saveExcel'); -} -// --------------------------------- ------------------------------------------ - -// ------------------------------- < Execute and Return > ----------------------------------- - -export namespace SimpleExecuteRequest { - export const type = new RequestType('query/simpleexecute'); -} - -// ------------------------------- < Execute String > ------------------------------------ -export interface QueryExecuteStringParams { - query: string; - ownerUri: string; -} - -export namespace QueryExecuteStringRequest { - export const type = new RequestType('query/executeString'); -} - -// ------------------------------- < Metadata Events > ------------------------------------ - -export namespace MetadataQueryRequest { - export const type = new RequestType('metadata/list'); -} - -// ------------------------------- < Scripting Events > ------------------------------------ - -export namespace ScriptingRequest { - export const type = new RequestType('scripting/script'); -} - -// ------------------------------- < Scripting Complete Event > ------------------------------------ - -export namespace ScriptingCompleteNotification { - export const type = new NotificationType('scripting/scriptComplete'); -} - - -// Edit Data ====================================================================================== -// Shared Interfaces -------------------------------------------------------------------------- -export interface EditSessionOperationParams { - ownerUri: string; -} - -export interface EditRowOperationParams extends EditSessionOperationParams { - rowId: number; -} - -export interface EditCellResult { - cell: data.EditCell; - isRowDirty: boolean; -} - -// edit/commit -------------------------------------------------------------------------------- -export namespace EditCommitRequest { - export const type = new RequestType('edit/commit'); -} - -export interface EditCommitResult { } - -// edit/createRow ----------------------------------------------------------------------------- -export namespace EditCreateRowRequest { - export const type = new RequestType('edit/createRow'); -} - -// edit/deleteRow ----------------------------------------------------------------------------- -export namespace EditDeleteRowRequest { - export const type = new RequestType('edit/deleteRow'); -} - -export interface EditDeleteRowResult { } - -// edit/dispose ------------------------------------------------------------------------------- -export namespace EditDisposeRequest { - export const type = new RequestType('edit/dispose'); -} - -export interface EditDisposeResult { } - -// edit/initialize ---------------------------------------------------------------------------- -export namespace EditInitializeRequest { - export const type = new RequestType('edit/initialize'); -} - -export interface EditInitializeResult { } - -// edit/revertCell -------------------------------------------------------------------------------- -export namespace EditRevertCellRequest { - export const type = new RequestType('edit/revertCell'); -} - -// edit/revertRow ----------------------------------------------------------------------------- -export namespace EditRevertRowRequest { - export const type = new RequestType('edit/revertRow'); -} - -export interface EditRevertRowResult { } - -// edit/sessionReady Event -------------------------------------------------------------------- -export namespace EditSessionReadyNotification { - export const type = new NotificationType('edit/sessionReady'); -} - -// edit/updateCell ---------------------------------------------------------------------------- -export namespace EditUpdateCellRequest { - export const type = new RequestType('edit/updateCell'); -} - -// edit/subset ------------------------------------------------------------------------------------ -export namespace EditSubsetRequest { - export const type = new RequestType('edit/subset'); -} - -// ------------------------------- < Object Explorer Events > ------------------------------------ - -export namespace ObjectExplorerCreateSessionRequest { - export const type = new RequestType('objectexplorer/createsession'); -} - -export namespace ObjectExplorerExpandRequest { - export const type = new RequestType('objectexplorer/expand'); -} - -export namespace ObjectExplorerRefreshRequest { - export const type = new RequestType('objectexplorer/refresh'); -} - -export namespace ObjectExplorerCloseSessionRequest { - export const type = new RequestType('objectexplorer/closesession'); -} - -// ------------------------------- < Object Explorer Events > ------------------------------------ - - -export namespace ObjectExplorerCreateSessionCompleteNotification { - export const type = new NotificationType('objectexplorer/sessioncreated'); -} - -export namespace ObjectExplorerExpandCompleteNotification { - export const type = new NotificationType('objectexplorer/expandCompleted'); -} - -// ------------------------------- < Task Service Events > ------------------------------------ - -export namespace ListTasksRequest { - export const type = new RequestType('tasks/listtasks'); -} - -export namespace CancelTaskRequest { - export const type = new RequestType('tasks/canceltask'); -} - -// ------------------------------- < Task Service Events > ------------------------------------ - - -export namespace TaskStatusChangedNotification { - export const type = new NotificationType('tasks/statuschanged'); -} - -export namespace TaskCreatedNotification { - export const type = new NotificationType('tasks/newtaskcreated'); -} - -// ------------------------------- < Admin Service Events > ------------------------------------ - -export namespace CreateDatabaseRequest { - export const type = new RequestType('admin/createdatabase'); -} - -export namespace DefaultDatabaseInfoRequest { - export const type = new RequestType('admin/defaultdatabaseinfo'); -} - -export namespace CreateLoginRequest { - export const type = new RequestType('admin/createlogin'); -} - -export namespace GetDatabaseInfoRequest { - export const type = new RequestType('admin/getdatabaseinfo'); -} - -// ------------------------------- < Disaster Recovery Events > ------------------------------------ - -export namespace BackupRequest { - export const type = new RequestType('backup/backup'); -} - -export namespace BackupConfigInfoRequest { - export const type = new RequestType('backup/backupconfiginfo'); -} - -export namespace RestoreRequest { - export const type = new RequestType('restore/restore'); -} - -export namespace RestorePlanRequest { - export const type = new RequestType('restore/restoreplan'); -} - -export namespace CancelRestorePlanRequest { - export const type = new RequestType('restore/cancelrestoreplan'); -} - -export namespace RestoreConfigInfoRequest { - export const type = new RequestType('restore/restoreconfiginfo'); -} - -// ------------------------------- < File Browser Events > ------------------------------------ - -export namespace FileBrowserOpenRequest { - export const type = new RequestType('filebrowser/open'); -} - -export namespace FileBrowserOpenedNotification { - export const type = new NotificationType('filebrowser/opencomplete'); -} - -export namespace FileBrowserExpandRequest { - export const type = new RequestType('filebrowser/expand'); -} - -export namespace FileBrowserExpandedNotification { - export const type = new NotificationType('filebrowser/expandcomplete'); -} - -export namespace FileBrowserValidateRequest { - export const type = new RequestType('filebrowser/validate'); -} - -export namespace FileBrowserValidatedNotification { - export const type = new NotificationType('filebrowser/validatecomplete'); -} - -export namespace FileBrowserCloseRequest { - export const type = new RequestType('filebrowser/close'); -} - - -// ------------------------------- < Profiler Events > ------------------------------------ - -export namespace StartProfilingRequest { - export const type = new RequestType('profiler/start'); -} - -export namespace StopProfilingRequest { - export const type = new RequestType('profiler/stop'); -} - -export namespace ProfilerEventsAvailableNotification { - export const type = new NotificationType('profiler/eventsavailable'); -} diff --git a/dataprotocol-client/src/protocolConverter.ts b/dataprotocol-client/src/protocolConverter.ts deleted file mode 100644 index b5c351a646..0000000000 --- a/dataprotocol-client/src/protocolConverter.ts +++ /dev/null @@ -1,50 +0,0 @@ -import * as data from 'data'; -import * as types from './types'; - -export interface Ip2c { - asProviderMetadata(params: types.MetadataQueryResult): data.ProviderMetadata; -} - -function asProviderMetadata(params: types.MetadataQueryResult): data.ProviderMetadata { - let objectMetadata: data.ObjectMetadata[] = []; - - if (!params.metadata || !params.metadata.length) { - return { - objectMetadata - }; - } - - for (let i = 0; i < params.metadata.length; ++i) { - let metadata: data.ObjectMetadata = params.metadata[i]; - - let metadataTypeName: string; - if (metadata.metadataTypeName) { - // Read from the provider since it's defined - metadataTypeName = metadata.metadataTypeName; - } else if (metadata.metadataType === types.MetadataType.View) { - metadataTypeName = 'View'; - } else if (metadata.metadataType === types.MetadataType.SProc) { - metadataTypeName = 'StoredProcedure'; - } else if (metadata.metadataType === types.MetadataType.Function) { - metadataTypeName = 'Function'; - } else { - metadataTypeName = 'Table'; - } - - objectMetadata.push({ - metadataTypeName, - metadataType: metadata.metadataType, - name: metadata.name, - schema: metadata.schema, - urn: metadata.urn - }); - } - - return { - objectMetadata - }; -} - -export const p2c: Ip2c = { - asProviderMetadata -}; diff --git a/dataprotocol-client/src/types.ts b/dataprotocol-client/src/types.ts deleted file mode 100644 index 28cb268b11..0000000000 --- a/dataprotocol-client/src/types.ts +++ /dev/null @@ -1,928 +0,0 @@ -import * as data from 'data'; - -export interface CreateSessionResponse { - sessionId: string; -} - -export interface SessionCreatedParameters { - success: boolean; - sessionId: string; - rootNode: NodeInfo; - errorMessage: string; -} - -export interface ExpandResponse { - nodePath: string; - sessionId: string; - nodes: NodeInfo[]; - errorMessage: string; -} - -export interface NodeInfo { - nodePath: string; - nodeType: string; - nodeSubType: string; - nodeStatus: string; - label: string; - isLeaf: boolean; - metadata: data.ObjectMetadata; - errorMessage: string; -} - -export interface ExpandParams { - sessionId: string; - nodePath: string; -} - -export interface CloseSessionParams { - sessionId: string; -} - -export interface CloseSessionResponse { - success: boolean; - sessionId: string; -} - -export interface CategoryValue { - displayName: string; - - name: string; -} - -export interface ServiceOption { - name: string; - - displayName: string; - - description: string; - - groupName: string; - - valueType: string; - - defaultValue: string; - - objectType: string; - - categoryValues: CategoryValue[]; - - isRequired: boolean; - - isArray: boolean; -} - -export interface ConnectionOption { - name: string; - - displayName: string; - - description: string; - - groupName: string; - - valueType: string; - - defaultValue: string; - - objectType: string; - - categoryValues: CategoryValue[]; - - specialValueType: string; - - isIdentity: boolean; - - isRequired: boolean; - - isArray: boolean; -} - -export interface ConnectionProviderOptions { - options: ConnectionOption[]; -} - -export interface AdminServicesProviderOptions { - databaseInfoOptions: ServiceOption[]; - - databaseFileInfoOptions: ServiceOption[]; - - fileGroupInfoOptions: ServiceOption[]; -} - -export interface FeatureMetadataProvider { - enabled: boolean; - featureName: string; - optionsMetadata: ServiceOption[]; -} - -/** - * Parameters to initialize a connection to a database - */ -export interface ConnectionDetails { - - /** - * connection options - */ - options: {}; -} - -/** - * Summary that identifies a unique database connection. - */ -export class ConnectionSummary { - /** - * server name - */ - public serverName: string; - - /** - * database name - */ - public databaseName: string; - - /** - * user name - */ - public userName: string; -} - -/** - * Connection response format. - */ -export class ConnectionCompleteParams { - /** - * URI identifying the owner of the connection - */ - public ownerUri: string; - - /** - * connection id returned from service host. - */ - public connectionId: string; - - /** - * any diagnostic messages return from the service host. - */ - public messages: string; - - /** - * Error message returned from the engine, if any. - */ - public errorMessage: string; - - /** - * Error number returned from the engine, if any. - */ - public errorNumber: number; - - /** - * Information about the connected server. - */ - public serverInfo: ServerInfo; - - /** - * information about the actual connection established - */ - public connectionSummary: ConnectionSummary; -} - -/** - * Update event parameters - */ -export class IntelliSenseReadyParams { - /** - * URI identifying the text document - */ - public ownerUri: string; -} - -/** - * Information about a SQL Server instance. - */ -export class ServerInfo { - /** - * The major version of the SQL Server instance. - */ - public serverMajorVersion: number; - - /** - * The minor version of the SQL Server instance. - */ - public serverMinorVersion: number; - - /** - * The build of the SQL Server instance. - */ - public serverReleaseVersion: number; - - /** - * The ID of the engine edition of the SQL Server instance. - */ - public engineEditionId: number; - - /** - * String containing the full server version text. - */ - public serverVersion: string; - - /** - * String describing the product level of the server. - */ - public serverLevel: string; - - /** - * The edition of the SQL Server instance. - */ - public serverEdition: string; - - /** - * Whether the SQL Server instance is running in the cloud (Azure) or not. - */ - public isCloud: boolean; - - /** - * The version of Azure that the SQL Server instance is running on, if applicable. - */ - public azureVersion: number; - - /** - * The Operating System version string of the machine running the SQL Server instance. - */ - public osVersion: string; -} - -export class CapabiltiesDiscoveryResult { - public capabilities: data.DataProtocolServerCapabilities; -} - -// Task Services types - -export enum TaskStatus { - notStarted = 0, - inProgress = 1, - succeeded = 2, - succeededWithWarning = 3, - failed = 4, - canceled = 5 -} - -// Admin Services types - -export interface CreateDatabaseParams { - ownerUri: string; - - databaseInfo: data.DatabaseInfo; -} - -export interface DefaultDatabaseInfoParams { - ownerUri: string; -} - -export interface DefaultDatabaseInfoResponse { - defaultDatabaseInfo: data.DatabaseInfo; -} - -export interface GetDatabaseInfoResponse { - databaseInfo: data.DatabaseInfo; -} - -export interface GetDatabaseInfoParams { - ownerUri: string; -} - -export interface BackupConfigInfoResponse { - backupConfigInfo: data.BackupConfigInfo; -} - -export interface CreateLoginParams { - ownerUri: string; - - loginInfo: data.LoginInfo; -} - -// Disaster Recovery types - -export interface BackupInfo { - ownerUri: string; - - databaseName: string; - - backupType: number; - - backupComponent: number; - - backupDeviceType: number; - - selectedFiles: string; - - backupsetName: string; - - selectedFileGroup: { [path: string]: string }; - - // List of {key: backup path, value: device type} - backupPathDevices: { [path: string]: number }; - - backupPathList: [string]; - - isCopyOnly: boolean; - - formatMedia: boolean; - - initialize: boolean; - - skipTapeHeader: boolean; - - mediaName: string; - - mediaDescription: string; - - checksum: boolean; - - continueAfterError: boolean; - - logTruncation: boolean; - - tailLogBackup: boolean; - - retainDays: number; - - compressionOption: number; - - verifyBackupRequired: boolean; - - encryptionAlgorithm: number; - - encryptorType: number; - - encryptorName: string; -} - -export interface BackupParams { - ownerUri: string; - - backupInfo: BackupInfo; - - taskExecutionMode: data.TaskExecutionMode; -} - -export interface RestoreParams { - ownerUri: string; - options: {}; - taskExecutionMode: data.TaskExecutionMode; -} - -export interface RestoreConfigInfoRequestParams { - ownerUri: string; -} - -export interface RestoreConfigInfoResponse { - configInfo: { [key: string]: any }; -} - -export interface RestoreDatabaseFileInfo { - fileType: string; - - logicalFileName: string; - - originalFileName: string; - - restoreAsFileName: string; -} - -export interface FileBrowserOpenParams { - ownerUri: string; - expandPath: string; - fileFilters: string[]; - changeFilter: boolean; -} - -export interface FileTreeNode { - children: FileTreeNode[]; - isExpanded: boolean; - isFile: boolean; - name: string; - fullPath: string; -} - -export interface FileTree { - rootNode: FileTreeNode; - selectedNode: FileTreeNode; -} - -export interface FileBrowserExpandParams { - ownerUri: string; - expandPath: string; -} - -export interface FileBrowserValidateParams { - ownerUri: string; - serviceType: string; - selectedFiles: string[]; -} - -export interface FileBrowserCloseParams { - ownerUri: string; -} - -export interface DatabaseFileInfo { - properties: LocalizedPropertyInfo[]; - id: string; - isSelected: boolean; -} - -export interface LocalizedPropertyInfo { - propertyName: string; - propertyValue: string; - propertyDisplayName: string; - propertyValueDisplayName: string; -} - -export interface RestorePlanDetailInfo { - name: string; - currentValue: any; - isReadOnly: boolean; - isVisible: boolean; - defaultValue: any; - -} - -// Query Execution types -export interface ResultSetSummary { - id: number; - batchId: number; - rowCount: number; - columnInfo: IDbColumn[]; -} - -export interface BatchSummary { - hasError: boolean; - id: number; - selection: data.ISelectionData; - resultSetSummaries: ResultSetSummary[]; - executionElapsed: string; - executionEnd: string; - executionStart: string; -} - -export interface IDbColumn { - allowDBNull?: boolean; - baseCatalogName: string; - baseColumnName: string; - baseSchemaName: string; - baseServerName: string; - baseTableName: string; - columnName: string; - columnOrdinal?: number; - columnSize?: number; - isAliased?: boolean; - isAutoIncrement?: boolean; - isExpression?: boolean; - isHidden?: boolean; - isIdentity?: boolean; - isKey?: boolean; - isBytes?: boolean; - isChars?: boolean; - isSqlVariant?: boolean; - isUdt?: boolean; - dataType: string; - isXml?: boolean; - isJson?: boolean; - isLong?: boolean; - isReadOnly?: boolean; - isUnique?: boolean; - numericPrecision?: number; - numericScale?: number; - udtAssemblyQualifiedName: string; - dataTypeName: string; -} - -export interface IGridResultSet { - columns: IDbColumn[]; - rowsUri: string; - numberOfRows: number; -} - -export interface IResultMessage { - batchId?: number; - isError: boolean; - time: string; - message: string; -} - -export enum EditRowState { - clean = 0, - dirtyInsert = 1, - dirtyDelete = 2, - dirtyUpdate = 3 -} - -export interface EditRow { - cells: data.DbCellValue[]; - id: number; - isDirty: boolean; - state: EditRowState; -} - -export class MetadataQueryParams { - /** - * Owner URI of the connection that changed. - */ - public ownerUri: string; -} - -/** - * Used as value version of data.MetadataType THESE SHOULD MIRROR - */ -export enum MetadataType { - Table = 0, - View = 1, - SProc = 2, - Function = 3 -} - -export class MetadataQueryResult { - public metadata: data.ObjectMetadata[]; -} - -export interface ScriptOptions { - /** - * Generate ANSI padding statements - */ - scriptANSIPadding?: boolean; - - /** - * Append the generated script to a file - */ - appendToFile?: boolean; - - /** - * Continue to script if an error occurs. Otherwise, stop. - */ - continueScriptingOnError?: boolean; - - /** - * Convert user-defined data types to base types. - */ - convertUDDTToBaseType?: boolean; - - /** - * Generate script for dependent objects for each object scripted. - */ - generateScriptForDependentObjects?: boolean; - - /** - * Include descriptive headers for each object generated. - */ - includeDescriptiveHeaders?: boolean; - - /** - * Check that an object with the given name exists before dropping or altering or that an object with the given name does not exist before creating. - */ - includeIfNotExists?: boolean; - - /** - * Script options to set vardecimal storage format. - */ - includeVarDecimal?: boolean; - - /** - * Include system generated constraint names to enforce declarative referential integrity. - */ - scriptDRIIncludeSystemNames?: boolean; - - /** - * Include statements in the script that are not supported on the specified SQL Server database engine type. - */ - includeUnsupportedStatements?: boolean; - - /** - * Prefix object names with the object schema. - */ - schemaQualify?: boolean; - - /** - * Script options to set bindings option. - */ - bindings?: boolean; - - /** - * Script the objects that use collation. - */ - collation?: boolean; - - /** - * Script the default values. - */ - default?: boolean; - - /** - * Script Object CREATE/DROP statements. - */ - scriptCreateDrop: string; - - /** - * Script the Extended Properties for each object scripted. - */ - scriptExtendedProperties?: boolean; - - /** - * Script only features compatible with the specified version of SQL Server. - */ - scriptCompatibilityOption: string; - - /** - * Script only features compatible with the specified SQL Server database engine type. - */ - targetDatabaseEngineType: string; - - /** - * Script only features compatible with the specified SQL Server database engine edition. - */ - targetDatabaseEngineEdition: string; - - /** - * Script all logins available on the server. Passwords will not be scripted. - */ - scriptLogins?: boolean; - - /** - * Generate object-level permissions. - */ - scriptObjectLevelPermissions?: boolean; - - /** - * Script owner for the objects. - */ - scriptOwner?: boolean; - - /** - * Script statistics, and optionally include histograms, for each selected table or view. - */ - scriptStatistics: string; - - /** - * Generate USE DATABASE statement. - */ - scripUseDatabase?: boolean; - - /** - * Generate script that contains schema only or schema and data. - */ - typeOfDataToScript: string; - - /** - * Scripts the change tracking information. - */ - scriptChangeTracking?: boolean; - - /** - * Script the check constraints for each table or view scripted. - */ - scriptCheckConstraints?: boolean; - - /** - * Scripts the data compression information. - */ - scriptDataCompressionOptions?: boolean; - - /** - * Script the foreign keys for each table scripted. - */ - scriptForeignKeys?: boolean; - - /** - * Script the full-text indexes for each table or indexed view scripted. - */ - scriptFullTextIndexes?: boolean; - - /** - * Script the indexes (including XML and clustered indexes) for each table or indexed view scripted. - */ - scriptIndexes?: boolean; - - /** - * Script the primary keys for each table or view scripted - */ - scriptPrimaryKeys?: boolean; - - /** - * Script the triggers for each table or view scripted - */ - scriptTriggers?: boolean; - - /** - * Script the unique keys for each table or view scripted. - */ - uniqueKeys?: boolean; -} - -export interface ScriptingObject { - /** - * The database object type - */ - type: string; - - /** - * The schema of the database object - */ - schema: string; - - /** - * The database object name - */ - name: string; -} - -export interface ScriptingParams { - /** - * File path used when writing out the script. - */ - filePath: string; - - /** - * Whether scripting to a single file or file per object. - */ - scriptDestination: string; - - /** - * Connection string of the target database the scripting operation will run against. - */ - connectionString: string; - - /** - * A list of scripting objects to script - */ - scriptingObjects: ScriptingObject[]; - - /** - * A list of scripting object which specify the include criteria of objects to script. - */ - includeObjectCriteria: ScriptingObject[]; - - /** - * A list of scripting object which specify the exclude criteria of objects to not script. - */ - excludeObjectCriteria: ScriptingObject[]; - - /** - * A list of schema name of objects to script. - */ - includeSchemas: string[]; - - /** - * A list of schema name of objects to not script. - */ - excludeSchemas: string[]; - - /** - * A list of type name of objects to script. - */ - includeTypes: string[]; - - /** - * A list of type name of objects to not script. - */ - excludeTypes: string[]; - - /** - * Scripting options for the ScriptingParams - */ - scriptOptions: ScriptOptions; - - /** - * Connection details for the ScriptingParams - */ - connectionDetails: ConnectionDetails; - - /** - * Owner URI of the connection - */ - ownerURI: string; - - /** - * Whether the scripting operation is for - * select script statements - */ - selectScript: boolean; - - /** - * Operation associated with the script request - */ - operation: data.ScriptOperation; -} - -export interface ScriptingCompleteParams { - /** - * The error details for an error that occurred during the scripting operation. - */ - errorDetails: string; - - /** - * The error message for an error that occurred during the scripting operation. - */ - errorMessage: string; - - /** - * A value to indicate an error occurred during the scripting operation. - */ - hasError: boolean; - - /** - * A value to indicate the scripting operation was canceled. - */ - canceled: boolean; - - /** - * A value to indicate the scripting operation successfully completed. - */ - success: boolean; -} - -export class TableMetadata { - - columns: data.ColumnMetadata[]; - -} - -/** - * Parameters to start a profiler session - */ -export interface StartProfilingParams { - /** - * Session Owner URI - */ - ownerUri: string; - - /** - * Session options - */ - options: {}; -} - -export interface StartProfilingResponse { - succeeded: string; - errorMessage: string; -} - -/** - * Parameters to start a profiler session - */ -export interface StopProfilingParams { - /** - * Session Owner URI - */ - ownerUri: string; -} - -export interface StopProfilingResponse { - succeeded: string; - errorMessage: string; -} - -/** - * Profiler Event - */ -export interface ProfilerEvent { - /** - * Event class name - */ - name: string; - - /** - * Event timestamp - */ - timestamp: string; - - /** - * Event values - */ - values: {}; -} - -/** - * Profiler events available notification parameters - */ -export interface ProfilerEventsAvailableParams { - /** - * Session owner URI - */ - ownerUri: string; - - /** - * New profiler events available - */ - events: ProfilerEvent[]; -} - -/** - * Used as value version of data.ScriptOperation THESE SHOULD BE THE SAME - */ -export enum ScriptOperation { - Select = 0, - Create = 1, - Insert = 2, - Update = 3, - Delete = 4, - Execute = 5, - Alter = 6 -} diff --git a/dataprotocol-client/src/typings/ref.d.ts b/dataprotocol-client/src/typings/ref.d.ts deleted file mode 100644 index 1c2a159cfc..0000000000 --- a/dataprotocol-client/src/typings/ref.d.ts +++ /dev/null @@ -1,2 +0,0 @@ - -/// diff --git a/dataprotocol-client/tsfmt.json b/dataprotocol-client/tsfmt.json deleted file mode 100644 index fffcf07c19..0000000000 --- a/dataprotocol-client/tsfmt.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "tabSize": 4, - "indentSize": 4, - "newLineCharacter": "\n", - "convertTabsToSpaces": false, - "insertSpaceAfterCommaDelimiter": true, - "insertSpaceAfterSemicolonInForStatements": true, - "insertSpaceBeforeAndAfterBinaryOperators": true, - "insertSpaceAfterKeywordsInControlFlowStatements": true, - "insertSpaceAfterFunctionKeywordForAnonymousFunctions": true, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, - "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, - "insertSpaceBeforeFunctionParenthesis": false, - "placeOpenBraceOnNewLineForFunctions": false, - "placeOpenBraceOnNewLineForControlBlocks": false -} diff --git a/dataprotocol-node/.gitignore b/dataprotocol-node/.gitignore new file mode 100644 index 0000000000..829e00dc84 --- /dev/null +++ b/dataprotocol-node/.gitignore @@ -0,0 +1,29 @@ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release +lib/ +out/ + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- +node_modules + +# Debug log from npm +npm-debug.log \ No newline at end of file diff --git a/dataprotocol-node/License.txt b/dataprotocol-node/License.txt new file mode 100644 index 0000000000..5ff4a3f7df --- /dev/null +++ b/dataprotocol-node/License.txt @@ -0,0 +1,18 @@ + +Copyright (c) Microsoft Corporation + +All rights reserved. + +Source EULA + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/dataprotocol-node/README.md b/dataprotocol-node/README.md new file mode 100644 index 0000000000..e432a91724 --- /dev/null +++ b/dataprotocol-node/README.md @@ -0,0 +1,4 @@ +# Microsoft Data Management Protocol - Node + +## License +[MIT](https://github.com/Microsoft/carbon/blob/dev/license.txt) diff --git a/dataprotocol-node/client/.eslintrc b/dataprotocol-node/client/.eslintrc new file mode 100644 index 0000000000..306df0be07 --- /dev/null +++ b/dataprotocol-node/client/.eslintrc @@ -0,0 +1,24 @@ +{ + "rules": { + "indent": [ + 2, + "tab" + ], + "quotes": [ + 2, + "single" + ], + "linebreak-style": [ + 2, + "windows" + ], + "semi": [ + 2, + "always" + ] + }, + "env": { + "node": true + }, + "extends": "eslint:recommended" +} \ No newline at end of file diff --git a/dataprotocol-node/client/.npmignore b/dataprotocol-node/client/.npmignore new file mode 100644 index 0000000000..2b1e5b19e1 --- /dev/null +++ b/dataprotocol-node/client/.npmignore @@ -0,0 +1,9 @@ +.vscode/ +lib/test/ +lib/*.map +src/ +test/ +.eslintrc +.gitignore +gulpfile.js +tsd.json \ No newline at end of file diff --git a/dataprotocol-node/client/.vscode/launch.json b/dataprotocol-node/client/.vscode/launch.json new file mode 100644 index 0000000000..19f1d6dac6 --- /dev/null +++ b/dataprotocol-node/client/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + "version": "0.1.0", + // List of configurations. Add new configurations or edit existing ones. + // ONLY "node" and "mono" are supported, change "type" to switch. + "configurations": [ + { + "request": "launch", + // Name of configuration; appears in the launch configuration drop down menu. + "name": "Mocha", + // Type of configuration. Possible values: "node", "mono". + "type": "node", + // Workspace relative or absolute path to the program. + "program": "node_modules/mocha/bin/_mocha", + // Automatically stop program after launch. + "stopOnEntry": false, + // Command line arguments passed to the program. + "args": ["--timeout", "999999"], + // Workspace relative or absolute path to the working directory of the program being debugged. Default is the current workspace. + "cwd": ".", + // Workspace relative or absolute path to the runtime executable to be used. Default is the runtime executable on the PATH. + "runtimeExecutable": null, + // Optional arguments passed to the runtime executable. + "runtimeArgs": [], + // Environment variables passed to the program. + "env": { }, + // Use JavaScript source maps (if they exist). + "sourceMaps": true, + // If JavaScript source maps are enabled, the generated code is expected in this directory. + "outDir": "lib" + } + ] +} diff --git a/dataprotocol-node/client/.vscode/settings.json b/dataprotocol-node/client/.vscode/settings.json new file mode 100644 index 0000000000..de8ee93ce0 --- /dev/null +++ b/dataprotocol-node/client/.vscode/settings.json @@ -0,0 +1,11 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "javascript.validate.enable": false, + "files.trimTrailingWhitespace": true, + "eslint.enable": false, + "editor.insertSpaces": false, + "editor.tabSize": 4, + "tslint.enable": false, + "typescript.tsdk": "./node_modules/typescript/lib", + "typescript.tsserver.trace": "off" +} \ No newline at end of file diff --git a/dataprotocol-node/client/.vscode/tasks.json b/dataprotocol-node/client/.vscode/tasks.json new file mode 100644 index 0000000000..0ed84877c1 --- /dev/null +++ b/dataprotocol-node/client/.vscode/tasks.json @@ -0,0 +1,9 @@ +{ + "version": "0.1.0", + "command": "npm", + "isShellCommand": true, + "args": ["run", "watch"], + "showOutput": "silent", + "isWatching": true, + "problemMatcher": "$tsc-watch" +} \ No newline at end of file diff --git a/dataprotocol-node/client/README.md b/dataprotocol-node/client/README.md new file mode 100644 index 0000000000..e432a91724 --- /dev/null +++ b/dataprotocol-node/client/README.md @@ -0,0 +1,4 @@ +# Microsoft Data Management Protocol - Node + +## License +[MIT](https://github.com/Microsoft/carbon/blob/dev/license.txt) diff --git a/dataprotocol-node/client/package.json b/dataprotocol-node/client/package.json new file mode 100644 index 0000000000..2d8865a3c4 --- /dev/null +++ b/dataprotocol-node/client/package.json @@ -0,0 +1,32 @@ +{ + "name": "dataprotocol-client", + "description": "VSCode Language client implementation", + "version": "2.6.3", + "author": "Microsoft Corporation", + "license": "MIT", + "engines": { + "vscode": "^1.5.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/Microsoft/vscode-languageserver-node.git" + }, + "bugs": { + "url": "https://github.com/Microsoft/vscode-languageserver-node/issues" + }, + "main": "./lib/main.js", + "typings": "./lib/main", + "devDependencies": { + "typescript": "2.0.3" + }, + "dependencies": { + "dataprotocol-jsonrpc": "file:../jsonrpc", + "dataprotocol-languageserver-types": "file:../types" + }, + "scripts": { + "prepublish": "tsc -p ./src", + "compile": "tsc -p ./src", + "watch": "tsc -w -p ./src", + "update-vscode": "node ./node_modules/vscode/bin/install" + } +} diff --git a/dataprotocol-node/client/src/codeConverter.ts b/dataprotocol-node/client/src/codeConverter.ts new file mode 100644 index 0000000000..1a641104c7 --- /dev/null +++ b/dataprotocol-node/client/src/codeConverter.ts @@ -0,0 +1,526 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import * as code from 'vscode'; +import * as data from 'data'; +import * as ls from 'dataprotocol-languageserver-types'; +import * as proto from './protocol'; +import * as is from './utils/is'; +import ProtocolCompletionItem from './protocolCompletionItem'; +import ProtocolCodeLens from './protocolCodeLens'; +import os = require('os'); +import path = require('path'); + +export interface Converter { + + asUri(uri: code.Uri): string; + + asTextDocumentIdentifier(textDocument: code.TextDocument): ls.TextDocumentIdentifier; + + asOpenTextDocumentParams(textDocument: code.TextDocument): proto.DidOpenTextDocumentParams; + + asChangeTextDocumentParams(textDocument: code.TextDocument): proto.DidChangeTextDocumentParams; + asChangeTextDocumentParams(event: code.TextDocumentChangeEvent): proto.DidChangeTextDocumentParams; + + asCloseTextDocumentParams(textDocument: code.TextDocument): proto.DidCloseTextDocumentParams; + + asSaveTextDocumentParams(textDocument: code.TextDocument): proto.DidSaveTextDocumentParams; + + asTextDocumentPositionParams(textDocument: code.TextDocument, position: code.Position): proto.TextDocumentPositionParams; + + asWorkerPosition(position: code.Position): ls.Position; + + asRange(value: code.Range): ls.Range; + + asPosition(value: code.Position): ls.Position; + + asDiagnosticSeverity(value: code.DiagnosticSeverity): ls.DiagnosticSeverity; + + asDiagnostic(item: code.Diagnostic): ls.Diagnostic; + asDiagnostics(items: code.Diagnostic[]): ls.Diagnostic[]; + + asCompletionItem(item: code.CompletionItem): ls.CompletionItem; + + asTextEdit(edit: code.TextEdit): ls.TextEdit; + + asReferenceParams(textDocument: code.TextDocument, position: code.Position, options: { includeDeclaration: boolean; }): proto.ReferenceParams; + + asCodeActionContext(context: code.CodeActionContext): ls.CodeActionContext; + + asCommand(item: code.Command): ls.Command; + + asCodeLens(item: code.CodeLens): ls.CodeLens; + + asFormattingOptions(item: code.FormattingOptions): ls.FormattingOptions; + + asDocumentSymbolParams(textDocument: code.TextDocument): proto.DocumentSymbolParams; + + asCodeLensParams(textDocument: code.TextDocument): proto.CodeLensParams; + + asDocumentLink(item: code.DocumentLink): ls.DocumentLink; + + asDocumentLinkParams(textDocument: code.TextDocument): proto.DocumentLinkParams; + + asConnectionParams(connectionUri: string, connectionInfo: data.ConnectionInfo): proto.ConnectParams; + + asCapabilitiesParams(client: data.DataProtocolClientCapabilities): proto.CapabiltiesDiscoveryParams; + + asMetadataQueryParams(connectionUri: string): ls.MetadataQueryParams; + + asListDatabasesParams(connectionUri: string): proto.ListDatabasesParams; + + asTableMetadataParams(connectionUri: string, metadata: data.ObjectMetadata): proto.TableMetadataParams; + + asScriptingParams(connectionUri: string, operation: ls.ScriptOperation, metadata: data.ObjectMetadata, paramDetails: data.ScriptingParamDetails): ls.ScriptingParams; + + asConnectionDetail(connInfo: data.ConnectionInfo): ls.ConnectionDetails; + + asExpandInfo(nodeInfo: data.ExpandNodeInfo): ls.ExpandParams; + + asCloseSessionInfo(nodeInfo: data.ObjectExplorerCloseSessionInfo): ls.CloseSessionParams; + + asExecutionPlanOptions(planOptions: data.ExecutionPlanOptions): proto.ExecutionPlanOptions; + + asListTasksParams(params: data.ListTasksParams): ls.ListTasksParams; + + asCancelTaskParams(params: data.CancelTaskParams): ls.CancelTaskParams; + + asRestoreParams(ownerUri: string, params: data.RestoreInfo): ls.RestoreParams; + + asRestoreConfigInfoParams(ownerUri: string): ls.RestoreConfigInfoRequestParams; +} + +export interface URIConverter { + (value: code.Uri): string; +} + +export function createConverter(uriConverter?: URIConverter): Converter { + + const nullConverter = (value: code.Uri) => value.toString(); + + const _uriConverter: URIConverter = uriConverter || nullConverter; + + function asUri(value: code.Uri): string { + return _uriConverter(value); + } + + function asTextDocumentIdentifier(textDocument: code.TextDocument): ls.TextDocumentIdentifier { + return { + uri: _uriConverter(textDocument.uri) + }; + } + + function asOpenTextDocumentParams(textDocument: code.TextDocument): proto.DidOpenTextDocumentParams { + return { + textDocument: { + uri: _uriConverter(textDocument.uri), + languageId: textDocument.languageId, + version: textDocument.version, + text: textDocument.getText() + } + }; + } + + function isTextDocumentChangeEvent(value: any): value is code.TextDocumentChangeEvent { + let candidate = value; + return is.defined(candidate.document) && is.defined(candidate.contentChanges); + } + + function isTextDocument(value: any): value is code.TextDocument { + let candidate = value; + return is.defined(candidate.uri) && is.defined(candidate.version); + } + + function asChangeTextDocumentParams(textDocument: code.TextDocument): proto.DidChangeTextDocumentParams; + function asChangeTextDocumentParams(event: code.TextDocumentChangeEvent): proto.DidChangeTextDocumentParams; + function asChangeTextDocumentParams(arg: code.TextDocumentChangeEvent | code.TextDocument): proto.DidChangeTextDocumentParams { + if (isTextDocument(arg)) { + let result: proto.DidChangeTextDocumentParams = { + textDocument: { + uri: _uriConverter(arg.uri), + version: arg.version + }, + contentChanges: [{ text: arg.getText() }] + } + return result; + } else if (isTextDocumentChangeEvent(arg)) { + let document = arg.document; + let result: proto.DidChangeTextDocumentParams = { + textDocument: { + uri: _uriConverter(document.uri), + version: document.version + }, + contentChanges: arg.contentChanges.map((change): proto.TextDocumentContentChangeEvent => { + let range = change.range; + return { + range: { + start: { line: range.start.line, character: range.start.character }, + end: { line: range.end.line, character: range.end.character } + }, + rangeLength: change.rangeLength, + text: change.text + } + }) + } + return result; + } else { + throw Error('Unsupported text document change parameter'); + } + } + + function asCloseTextDocumentParams(textDocument: code.TextDocument): proto.DidCloseTextDocumentParams { + return { + textDocument: asTextDocumentIdentifier(textDocument) + }; + } + + function asSaveTextDocumentParams(textDocument: code.TextDocument): proto.DidSaveTextDocumentParams { + return { + textDocument: asTextDocumentIdentifier(textDocument) + } + } + + function asTextDocumentPositionParams(textDocument: code.TextDocument, position: code.Position): proto.TextDocumentPositionParams { + return { + textDocument: asTextDocumentIdentifier(textDocument), + position: asWorkerPosition(position) + }; + } + + function asWorkerPosition(position: code.Position): ls.Position { + return { line: position.line, character: position.character }; + } + + function asRange(value: code.Range): ls.Range { + if (is.undefined(value)) { + return undefined; + } else if (is.nil(value)) { + return null; + } + return { start: asPosition(value.start), end: asPosition(value.end) }; + } + + function asPosition(value: code.Position): ls.Position { + if (is.undefined(value)) { + return undefined; + } else if (is.nil(value)) { + return null; + } + return { line: value.line, character: value.character }; + } + + function set(value, func: () => void): void { + if (is.defined(value)) { + func(); + } + } + + function asDiagnosticSeverity(value: code.DiagnosticSeverity): ls.DiagnosticSeverity { + switch (value) { + case code.DiagnosticSeverity.Error: + return ls.DiagnosticSeverity.Error; + case code.DiagnosticSeverity.Warning: + return ls.DiagnosticSeverity.Warning; + case code.DiagnosticSeverity.Information: + return ls.DiagnosticSeverity.Information; + case code.DiagnosticSeverity.Hint: + return ls.DiagnosticSeverity.Hint; + } + } + + function asDiagnostic(item: code.Diagnostic): ls.Diagnostic { + let result: ls.Diagnostic = ls.Diagnostic.create(asRange(item.range), item.message); + set(item.severity, () => result.severity = asDiagnosticSeverity(item.severity)); + set(item.code, () => result.code = item.code); + set(item.source, () => result.source = item.source); + return result; + } + + function asDiagnostics(items: code.Diagnostic[]): ls.Diagnostic[] { + if (is.undefined(items) || is.nil(items)) { + return items; + } + return items.map(asDiagnostic); + } + + function asCompletionItem(item: code.CompletionItem): ls.CompletionItem { + let result: ls.CompletionItem = { label: item.label }; + set(item.detail, () => result.detail = item.detail); + set(item.documentation, () => result.documentation = item.documentation); + set(item.filterText, () => result.filterText = item.filterText); + set(item.insertText, () => result.insertText = String(item.insertText)); + // Protocol item kind is 1 based, codes item kind is zero based. + set(item.kind, () => result.kind = item.kind + 1); + set(item.sortText, () => result.sortText = item.sortText); + set(item.textEdit, () => result.textEdit = asTextEdit(item.textEdit)); + set(item.additionalTextEdits, () => result.additionalTextEdits = asTextEdits(item.additionalTextEdits)); + set(item.command, () => result.command = asCommand(item.command)); + if (item instanceof ProtocolCompletionItem) { + set(item.data, () => result.data = item.data); + } + return result; + } + + function asTextEdit(edit: code.TextEdit): ls.TextEdit { + return { range: asRange(edit.range), newText: edit.newText }; + } + + function asTextEdits(edits: code.TextEdit[]): ls.TextEdit[] { + if (is.undefined(edits) || is.nil(edits)) { + return edits; + } + return edits.map(asTextEdit); + } + + function asReferenceParams(textDocument: code.TextDocument, position: code.Position, options: { includeDeclaration: boolean; }): proto.ReferenceParams { + return { + textDocument: asTextDocumentIdentifier(textDocument), + position: asWorkerPosition(position), + context: { includeDeclaration: options.includeDeclaration } + }; + } + + function asCodeActionContext(context: code.CodeActionContext): ls.CodeActionContext { + if (is.undefined(context) || is.nil(context)) { + return context; + } + return ls.CodeActionContext.create(asDiagnostics(context.diagnostics)); + } + + function asCommand(item: code.Command): ls.Command { + let result = ls.Command.create(item.title, item.command); + if (is.defined(item.arguments)) result.arguments = item.arguments; + return result; + } + + function asCodeLens(item: code.CodeLens): ls.CodeLens { + let result = ls.CodeLens.create(asRange(item.range)); + if (is.defined(item.command)) result.command = asCommand(item.command); + if (item instanceof ProtocolCodeLens) { + if (is.defined(item.data)) result.data = item.data; + } + return result; + } + + function asFormattingOptions(item: code.FormattingOptions): ls.FormattingOptions { + return { tabSize: item.tabSize, insertSpaces: item.insertSpaces }; + } + + function asDocumentSymbolParams(textDocument: code.TextDocument): proto.DocumentSymbolParams { + return { + textDocument: asTextDocumentIdentifier(textDocument) + } + } + + function asCodeLensParams(textDocument: code.TextDocument): proto.CodeLensParams { + return { + textDocument: asTextDocumentIdentifier(textDocument) + }; + } + + function asDocumentLink(item: code.DocumentLink): ls.DocumentLink { + let result = ls.DocumentLink.create(asRange(item.range)); + if (is.defined(item.target)) result.target = asUri(item.target); + return result; + } + + function asDocumentLinkParams(textDocument: code.TextDocument): proto.DocumentLinkParams { + return { + textDocument: asTextDocumentIdentifier(textDocument) + }; + } + + function asCapabilitiesParams(client: data.DataProtocolClientCapabilities): proto.CapabiltiesDiscoveryParams { + let params: proto.CapabiltiesDiscoveryParams = { + hostName: client.hostName, + hostVersion: client.hostVersion + }; + return params; + } + + function asConnectionParams(connUri: string, connInfo: data.ConnectionInfo): proto.ConnectParams { + return { + ownerUri: connUri, + connection: { + options: connInfo.options + } + }; + } + + function asMetadataQueryParams(connectionUri: string): ls.MetadataQueryParams { + return { + ownerUri: connectionUri + }; + } + + function asListDatabasesParams(connectionUri: string): proto.ListDatabasesParams { + return { + ownerUri: connectionUri + }; + } + + function asTableMetadataParams(connectionUri: string, metadata: data.ObjectMetadata): proto.TableMetadataParams { + return { + ownerUri: connectionUri, + schema: metadata.schema, + objectName: metadata.name + }; + } + + function asScriptingParams(connectionUri: string, operation: ls.ScriptOperation, metadata: data.ObjectMetadata, paramDetails: data.ScriptingParamDetails): ls.ScriptingParams { + let scriptingObject: ls.ScriptingObject = { + type: metadata.metadataTypeName, + schema: metadata.schema, + name: metadata.name + } + let targetDatabaseEngineEdition = paramDetails.targetDatabaseEngineEdition; + let targetDatabaseEngineType = paramDetails.targetDatabaseEngineType; + let scriptCompatibilityOption = paramDetails.scriptCompatibilityOption; + let options: ls.ScriptOptions = { + scriptCreateDrop: (operation === ls.ScriptOperation.Delete) ? "ScriptDrop" : + (operation === ls.ScriptOperation.Select) ? "ScriptSelect" : "ScriptCreate", + typeOfDataToScript: "SchemaOnly", + scriptStatistics: "ScriptStatsNone", + targetDatabaseEngineEdition: targetDatabaseEngineEdition ? targetDatabaseEngineEdition : "SqlServerEnterpriseEdition", + targetDatabaseEngineType: targetDatabaseEngineType ? targetDatabaseEngineType : "SingleInstance", + scriptCompatibilityOption: scriptCompatibilityOption ? scriptCompatibilityOption : "Script140Compat" + } + return { + connectionString: null, + filePath: paramDetails.filePath, + scriptingObjects: [scriptingObject], + scriptDestination: "ToEditor", + includeObjectCriteria: null, + excludeObjectCriteria: null, + includeSchemas: null, + excludeSchemas: null, + includeTypes: null, + excludeTypes: null, + scriptOptions: options, + connectionDetails: null, + ownerURI: connectionUri, + operation: operation + }; + } + + function asConnectionDetail(connInfo: data.ConnectionInfo): ls.ConnectionDetails { + return { + options: connInfo.options + }; + } + + function asExpandInfo(nodeInfo: data.ExpandNodeInfo): ls.ExpandParams { + return { + sessionId: nodeInfo.sessionId, + nodePath: nodeInfo.nodePath + }; + } + + function asCloseSessionInfo(nodeInfo: data.ObjectExplorerCloseSessionInfo): ls.CloseSessionParams { + return { + sessionId: nodeInfo.sessionId + }; + } + + function asExecutionPlanOptions(planOptions: data.ExecutionPlanOptions): proto.ExecutionPlanOptions { + return { + includeEstimatedExecutionPlanXml: planOptions ? planOptions.displayEstimatedQueryPlan : undefined, + includeActualExecutionPlanXml: planOptions ? planOptions.displayActualQueryPlan : undefined + }; + } + + function asListTasksParams(params: data.ListTasksParams): ls.ListTasksParams { + return { + listActiveTasksOnly: params.listActiveTasksOnly + }; + } + + function asCancelTaskParams(params: data.CancelTaskParams): ls.CancelTaskParams { + return { + taskId: params.taskId + }; + } + + function asRestoreParams(ownerUri: string, params: data.RestoreInfo): ls.RestoreParams { + return { + ownerUri: ownerUri, + options: params.options, + taskExecutionMode: params.taskExecutionMode + }; + } + + function asRestoreConfigInfoParams(ownerUri: string): ls.RestoreConfigInfoRequestParams { + return { + ownerUri: ownerUri + }; + } + + return { + asUri, + asTextDocumentIdentifier, + asOpenTextDocumentParams, + asChangeTextDocumentParams, + asCloseTextDocumentParams, + asSaveTextDocumentParams, + asTextDocumentPositionParams, + asWorkerPosition, + asRange, + asPosition, + asDiagnosticSeverity, + asDiagnostic, + asDiagnostics, + asCompletionItem, + asTextEdit, + asReferenceParams, + asCodeActionContext, + asCommand, + asCodeLens, + asFormattingOptions, + asDocumentSymbolParams, + asCodeLensParams, + asDocumentLink, + asDocumentLinkParams, + asCapabilitiesParams, + asConnectionParams, + asMetadataQueryParams, + asTableMetadataParams, + asListDatabasesParams, + asScriptingParams, + asConnectionDetail, + asExpandInfo, + asCloseSessionInfo, + asExecutionPlanOptions, + asListTasksParams, + asCancelTaskParams, + asRestoreParams, + asRestoreConfigInfoParams + }; +} + +// This for backward compatibility since we exported the converter functions as API. +let defaultConverter = createConverter(); + +export const asTextDocumentIdentifier: (textDocument: code.TextDocument) => ls.TextDocumentIdentifier = defaultConverter.asTextDocumentIdentifier; +export const asOpenTextDocumentParams: (textDocument: code.TextDocument) => proto.DidOpenTextDocumentParams = defaultConverter.asOpenTextDocumentParams; +export const asChangeTextDocumentParams: (arg: code.TextDocumentChangeEvent | code.TextDocument) => proto.DidChangeTextDocumentParams = defaultConverter.asChangeTextDocumentParams; +export const asCloseTextDocumentParams: (textDocument: code.TextDocument) => proto.DidCloseTextDocumentParams = defaultConverter.asCloseTextDocumentParams; +export const asSaveTextDocumentParams: (textDocument: code.TextDocument) => proto.DidSaveTextDocumentParams = defaultConverter.asSaveTextDocumentParams; +export const asTextDocumentPositionParams: (textDocument: code.TextDocument, position: code.Position) => proto.TextDocumentPositionParams = defaultConverter.asTextDocumentPositionParams; +export const asWorkerPosition: (position: code.Position) => ls.Position = defaultConverter.asWorkerPosition; +export const asRange: (value: code.Range) => ls.Range = defaultConverter.asRange; +export const asPosition: (value: code.Position) => ls.Position = defaultConverter.asPosition; +export const asDiagnosticSeverity: (value: code.DiagnosticSeverity) => ls.DiagnosticSeverity = defaultConverter.asDiagnosticSeverity; +export const asDiagnostic: (item: code.Diagnostic) => ls.Diagnostic = defaultConverter.asDiagnostic; +export const asDiagnostics: (items: code.Diagnostic[]) => ls.Diagnostic[] = defaultConverter.asDiagnostics; +export const asCompletionItem: (item: code.CompletionItem) => ls.CompletionItem = defaultConverter.asCompletionItem; +export const asTextEdit: (edit: code.TextEdit) => ls.TextEdit = defaultConverter.asTextEdit; +export const asReferenceParams: (textDocument: code.TextDocument, position: code.Position, options: { includeDeclaration: boolean; }) => proto.ReferenceParams = defaultConverter.asReferenceParams; +export const asCodeActionContext: (context: code.CodeActionContext) => ls.CodeActionContext = defaultConverter.asCodeActionContext; +export const asCommand: (item: code.Command) => ls.Command = defaultConverter.asCommand; +export const asCodeLens: (item: code.CodeLens) => ls.CodeLens = defaultConverter.asCodeLens; +export const asFormattingOptions: (item: code.FormattingOptions) => ls.FormattingOptions = defaultConverter.asFormattingOptions; +export const asDocumentSymbolParams: (textDocument: code.TextDocument) => proto.DocumentSymbolParams = defaultConverter.asDocumentSymbolParams; +export const asCodeLensParams: (textDocument: code.TextDocument) => proto.CodeLensParams = defaultConverter.asCodeLensParams; \ No newline at end of file diff --git a/dataprotocol-node/client/src/main.ts b/dataprotocol-node/client/src/main.ts new file mode 100644 index 0000000000..907eb80890 --- /dev/null +++ b/dataprotocol-node/client/src/main.ts @@ -0,0 +1,2612 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import * as cp from 'child_process'; +import * as stream from 'stream'; +import ChildProcess = cp.ChildProcess; + +import { + workspace as Workspace, window as Window, languages as Languages, extensions as Extensions, TextDocumentChangeEvent, TextDocument, Disposable, OutputChannel, + FileSystemWatcher, Uri, DiagnosticCollection, DocumentSelector, + CancellationToken, Hover as VHover, Position as VPosition, Location as VLocation, Range as VRange, + CompletionItem as VCompletionItem, CompletionList as VCompletionList, SignatureHelp as VSignatureHelp, Definition as VDefinition, DocumentHighlight as VDocumentHighlight, + SymbolInformation as VSymbolInformation, CodeActionContext as VCodeActionContext, Command as VCommand, CodeLens as VCodeLens, + FormattingOptions as VFormattingOptions, TextEdit as VTextEdit, WorkspaceEdit as VWorkspaceEdit, MessageItem, + DocumentLink as VDocumentLink +} from 'vscode'; + +import { + ConnectionInfo, ConnectionInfoSummary, dataprotocol, DataProtocolProvider, ConnectionProvider, + DataProtocolServerCapabilities as VDataProtocolServerCapabilities, + DataProtocolClientCapabilities, CapabilitiesProvider, MetadataProvider, + ScriptingProvider, ProviderMetadata, ScriptingResult, ScriptingCompleteResult, + QueryProvider, QueryCancelResult as VQueryCancelResult, ObjectMetadata, + ListDatabasesResult as VListDatabasesResult, ChangedConnectionInfo, + SaveResultRequestResult as VSaveResultRequestResult, ScriptingParamDetails, + SaveResultsRequestParams as VSaveResultsRequestParams, ObjectExplorerProvider, + ExpandNodeInfo, ObjectExplorerCloseSessionInfo, ObjectExplorerSession, ObjectExplorerExpandInfo, + TaskServicesProvider, ListTasksParams, ListTasksResponse, CancelTaskParams, TaskProgressInfo, TaskInfo, + AdminServicesProvider, DisasterRecoveryProvider, RestoreInfo, ExecutionPlanOptions, + SerializationProvider, FileBrowserProvider, FileBrowserOpenedParams, FileBrowserExpandedParams, FileBrowserValidatedParams, + RestoreConfigInfo, ProfilerProvider, ProfilerSessionEvents +} from 'data'; + +import { + Message, + RequestHandler, NotificationHandler, MessageConnection, ClientMessageConnection, Logger, createClientMessageConnection, + ErrorCodes, ResponseError, RequestType, NotificationType, + MessageReader, IPCMessageReader, MessageWriter, IPCMessageWriter, Trace, Tracer, Event, Emitter +} from 'dataprotocol-jsonrpc'; + +import { + Range, Position, Location, Diagnostic, DiagnosticSeverity, Command, + TextEdit, WorkspaceEdit, WorkspaceChange, TextEditChange, + TextDocumentIdentifier, CompletionItemKind, CompletionItem, CompletionList, + Hover, MarkedString, + SignatureHelp, SignatureInformation, ParameterInformation, + Definition, CodeActionContext, + DocumentHighlight, DocumentHighlightKind, + SymbolInformation, SymbolKind, + CodeLens, + FormattingOptions, DocumentLink, + ConnectionCompleteParams, IntelliSenseReadyParams, + ConnectionProviderOptions, DataProtocolServerCapabilities, + ISelectionData, QueryExecuteBatchNotificationParams, + MetadataQueryParams, MetadataQueryResult, + ScriptOperation, ScriptingCompleteParams, + DatabaseInfo, BackupConfigInfo, CreateDatabaseResponse, CreateDatabaseParams, + LoginInfo, CreateLoginResponse, CreateLoginParams, + BackupInfo, BackupResponse, BackupParams, TaskExecutionMode, + RestoreParams, RestoreResponse, RestorePlanResponse, + DefaultDatabaseInfoResponse, DefaultDatabaseInfoParams, + GetDatabaseInfoResponse, GetDatabaseInfoParams, + BackupConfigInfoResponse, FileBrowserOpenParams, FileBrowserCloseResponse, + FileBrowserCloseParams, FileBrowserExpandParams, FileBrowserValidateParams, + StartProfilingParams, StartProfilingResponse, StopProfilingParams, StopProfilingResponse, + ProfilerEventsAvailableParams +} from 'dataprotocol-languageserver-types'; + + +import { + InitializeRequest, InitializeParams, InitializeResult, InitializeError, ClientCapabilities, ServerCapabilities, TextDocumentSyncKind, + ShutdownRequest, + ExitNotification, + LogMessageNotification, LogMessageParams, MessageType, + ShowMessageNotification, ShowMessageParams, ShowMessageRequest, ShowMessageRequestParams, + TelemetryEventNotification, + DidChangeConfigurationNotification, DidChangeConfigurationParams, + TextDocumentPositionParams, + DidOpenTextDocumentNotification, DidOpenTextDocumentParams, DidChangeTextDocumentNotification, DidChangeTextDocumentParams, + DidCloseTextDocumentNotification, DidCloseTextDocumentParams, DidSaveTextDocumentNotification, DidSaveTextDocumentParams, + DidChangeWatchedFilesNotification, DidChangeWatchedFilesParams, FileEvent, FileChangeType, + PublishDiagnosticsNotification, PublishDiagnosticsParams, + CompletionRequest, CompletionResolveRequest, + HoverRequest, + SignatureHelpRequest, DefinitionRequest, ReferencesRequest, DocumentHighlightRequest, + DocumentSymbolRequest, WorkspaceSymbolRequest, WorkspaceSymbolParams, + CodeActionRequest, CodeActionParams, + CodeLensRequest, CodeLensResolveRequest, + DocumentFormattingRequest, DocumentFormattingParams, DocumentRangeFormattingRequest, DocumentRangeFormattingParams, + DocumentOnTypeFormattingRequest, DocumentOnTypeFormattingParams, + RenameRequest, RenameParams, + DocumentLinkRequest, DocumentLinkResolveRequest, DocumentLinkParams, + RebuildIntelliSenseNotification, RebuildIntelliSenseParams, + CapabiltiesDiscoveryRequest, + ConnectionRequest, ConnectParams, + DisconnectRequest, DisconnectParams, + CancelConnectRequest, CancelConnectParams, + ChangeDatabaseParams, ChangeDatabaseRequest, + ListDatabasesRequest, ListDatabasesParams, ListDatabasesResult, + ConnectionChangedNotification, ConnectionChangedParams, + ConnectionCompleteNotification, IntelliSenseReadyNotification, + TableMetadataRequest, ViewMetadataRequest, MetadataQueryRequest, + ScriptingRequest, ScriptingCompleteNotification, + QueryCancelRequest, QueryCancelResult, QueryCancelParams, + QueryExecuteRequest, QueryExecuteSubsetResult, QueryExecuteSubsetParams, + SimpleExecuteRequest, SimpleExecuteResult, SimpleExecuteParams, + QueryExecuteBatchStartNotification, QueryExecuteBatchCompleteNotification, QueryExecuteCompleteNotification, + QueryExecuteMessageNotification, QueryDisposeParams, QueryDisposeRequest, QueryExecuteCompleteNotificationResult, + QueryExecuteMessageParams, QueryExecuteParams, QueryExecuteResultSetCompleteNotification, QueryExecuteResultSetCompleteNotificationParams, + QueryExecuteStringParams, QueryExecuteStringRequest, + QueryExecuteStatementParams, QueryExecuteStatementRequest, + QueryExecuteSubsetRequest, SaveResultRequestResult, SaveResultsRequestParams, SaveResultsAsCsvRequest, SaveResultsAsJsonRequest, SaveResultsAsExcelRequest, + EditCommitRequest, EditCommitParams, + EditCreateRowRequest, EditCreateRowParams, EditCreateRowResult, + EditDeleteRowRequest, EditDeleteRowParams, + EditDisposeRequest, EditDisposeParams, + EditInitializeRequest, EditInitializeParams, EditInitializeFiltering, + EditRevertCellRequest, EditRevertCellParams, EditRevertCellResult, + EditRevertRowRequest, EditRevertRowParams, + EditSessionReadyNotification, EditSessionReadyParams, + EditUpdateCellRequest, EditUpdateCellParams, EditUpdateCellResult, + EditSubsetRequest, EditSubsetParams, EditSubsetResult, + ObjectExplorerCreateSessionRequest, ObjectExplorerExpandRequest, ObjectExplorerRefreshRequest, ObjectExplorerCloseSessionRequest, + ObjectExplorerCreateSessionCompleteNotification, ObjectExplorerExpandCompleteNotification, + CreateDatabaseRequest, CreateLoginRequest, BackupRequest, DefaultDatabaseInfoRequest, GetDatabaseInfoRequest, BackupConfigInfoRequest, + RestoreRequest, RestorePlanRequest, CancelRestorePlanRequest, RestoreConfigInfoRequest, + ListTasksRequest, CancelTaskRequest, TaskStatusChangedNotification, TaskCreatedNotification, + LanguageFlavorChangedNotification, DidChangeLanguageFlavorParams, FileBrowserOpenRequest, FileBrowserOpenedNotification, + FileBrowserValidateRequest, FileBrowserValidatedNotification, FileBrowserExpandRequest, FileBrowserExpandedNotification, FileBrowserCloseRequest, + StartProfilingRequest, StopProfilingRequest, ProfilerEventsAvailableNotification +} from './protocol'; + +import * as c2p from './codeConverter'; +import * as p2c from './protocolConverter'; + +import * as is from './utils/is'; +import * as electron from './utils/electron'; +import { terminate } from './utils/processes'; +import { Delayer } from './utils/async'; + +export { + RequestType, NotificationType, NotificationHandler, RequestHandler, + ResponseError, InitializeError, ErrorCodes, + Position, Range, Location, TextDocumentIdentifier, TextDocumentPositionParams, + TextEdit, TextEditChange, WorkspaceChange, + c2p as Code2Protocol, p2c as Protocol2Code +} + +declare var v8debug; + + +interface IConnection { + + listen(): void; + + sendRequest(type: RequestType, params: P, token?: CancellationToken): Thenable; + sendNotification

(type: NotificationType

, params: P): void; + onNotification

(type: NotificationType

, handler: NotificationHandler

): void; + onRequest(type: RequestType, handler: RequestHandler): void; + trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void; + + initialize(params: InitializeParams): Thenable; + shutdown(): Thenable; + exit(): void; + + onLogMessage(handle: NotificationHandler): void; + onShowMessage(handler: NotificationHandler): void; + onTelemetry(handler: NotificationHandler): void; + + didChangeConfiguration(params: DidChangeConfigurationParams): void; + didChangeWatchedFiles(params: DidChangeWatchedFilesParams): void; + + didOpenTextDocument(params: DidOpenTextDocumentParams): void; + didChangeTextDocument(params: DidChangeTextDocumentParams): void; + didCloseTextDocument(params: DidCloseTextDocumentParams): void; + didSaveTextDocument(params: DidSaveTextDocumentParams): void; + onDiagnostics(handler: NotificationHandler): void; + + dispose(): void; +} + +class ConsoleLogger implements Logger { + public error(message: string): void { + console.error(message); + } + public warn(message: string): void { + console.warn(message); + } + public info(message: string): void { + console.info(message); + } + public log(message: string): void { + console.log(message); + } +} + +interface ConnectionErrorHandler { + (error: Error, message: Message, count: number): void; +} + +interface ConnectionCloseHandler { + (): void; +} +function createConnection(inputStream: stream.Readable, outputStream: NodeJS.WritableStream, errorHandler: ConnectionErrorHandler, closeHandler: ConnectionCloseHandler): IConnection; +function createConnection(inputStream: NodeJS.ReadableStream, outputStream: NodeJS.WritableStream, errorHandler: ConnectionErrorHandler, closeHandler: ConnectionCloseHandler): IConnection; +function createConnection(reader: MessageReader, writer: MessageWriter, errorHandler: ConnectionErrorHandler, closeHandler: ConnectionCloseHandler): IConnection; +function createConnection(input: any, output: any, errorHandler: ConnectionErrorHandler, closeHandler: ConnectionCloseHandler): IConnection { + let logger = new ConsoleLogger(); + let connection = createClientMessageConnection(input, output, logger); + connection.onError((data) => { errorHandler(data[0], data[1], data[2]) }); + connection.onClose(closeHandler); + let result: IConnection = { + + listen: (): void => connection.listen(), + + sendRequest: (type: RequestType, params: P, token?: CancellationToken): Thenable => connection.sendRequest(type, params, token), + sendNotification:

(type: NotificationType

, params: P): void => connection.sendNotification(type, params), + onNotification:

(type: NotificationType

, handler: NotificationHandler

): void => connection.onNotification(type, handler), + onRequest: (type: RequestType, handler: RequestHandler): void => connection.onRequest(type, handler), + + trace: (value: Trace, tracer: Tracer, sendNotification: boolean = false): void => connection.trace(value, tracer, sendNotification), + + initialize: (params: InitializeParams) => connection.sendRequest(InitializeRequest.type, params), + shutdown: () => connection.sendRequest(ShutdownRequest.type, undefined), + exit: () => connection.sendNotification(ExitNotification.type), + + onLogMessage: (handler: NotificationHandler) => connection.onNotification(LogMessageNotification.type, handler), + onShowMessage: (handler: NotificationHandler) => connection.onNotification(ShowMessageNotification.type, handler), + onTelemetry: (handler: NotificationHandler) => connection.onNotification(TelemetryEventNotification.type, handler), + + didChangeConfiguration: (params: DidChangeConfigurationParams) => connection.sendNotification(DidChangeConfigurationNotification.type, params), + didChangeWatchedFiles: (params: DidChangeWatchedFilesParams) => connection.sendNotification(DidChangeWatchedFilesNotification.type, params), + + didOpenTextDocument: (params: DidOpenTextDocumentParams) => connection.sendNotification(DidOpenTextDocumentNotification.type, params), + didChangeTextDocument: (params: DidChangeTextDocumentParams | DidChangeTextDocumentParams[]) => connection.sendNotification(DidChangeTextDocumentNotification.type, params), + didCloseTextDocument: (params: DidCloseTextDocumentParams) => connection.sendNotification(DidCloseTextDocumentNotification.type, params), + didSaveTextDocument: (params: DidSaveTextDocumentParams) => connection.sendNotification(DidSaveTextDocumentNotification.type, params), + onDiagnostics: (handler: NotificationHandler) => connection.onNotification(PublishDiagnosticsNotification.type, handler), + + dispose: () => connection.dispose() + }; + + return result; +} + +export interface StreamInfo { + writer: NodeJS.WritableStream; + reader: NodeJS.ReadableStream; +} + +export interface ExecutableOptions { + cwd?: string; + stdio?: string | string[]; + env?: any; + detached?: boolean; +} + +export interface Executable { + command: string; + args?: string[]; + options?: ExecutableOptions; +} + +export interface ForkOptions { + cwd?: string; + env?: any; + encoding?: string; + execArgv?: string[]; +} + +export enum TransportKind { + stdio, + ipc +} + +export interface NodeModule { + module: string; + transport?: TransportKind; + args?: string[]; + runtime?: string; + options?: ForkOptions; +} + +export type ServerOptions = Executable | { run: Executable; debug: Executable; } | { run: NodeModule; debug: NodeModule } | NodeModule | (() => Thenable); + +/** + * An action to be performed when the connection is producing errors. + */ +export enum ErrorAction { + /** + * Continue running the server. + */ + Continue = 1, + /** + * Shutdown the server. + */ + Shutdown = 2 +} + +/** + * An action to be performed when the connection to a server got closed. + */ +export enum CloseAction { + /** + * Don't restart the server. The connection stays closed. + */ + DoNotRestart = 1, + /** + * Restart the server. + */ + Restart = 2, +} + + +/** + * A pluggable error handler that is invoked when the connection is either + * producing errors or got closed. + */ +export interface ErrorHandler { + /** + * An error has occurred while writing or reading from the connection. + * + * @param error - the error received + * @param message - the message to be delivered to the server if know. + * @param count - a count indicating how often an error is received. Will + * be reset if a message got successfully send or received. + */ + error(error: Error, message: Message, count: number): ErrorAction; + + /** + * The connection to the server got closed. + */ + closed(): CloseAction +} + +class DefaultErrorHandler implements ErrorHandler { + + private restarts: number[]; + + constructor(private name: string) { + this.restarts = []; + } + + public error(error: Error, message: Message, count): ErrorAction { + if (count && count <= 3) { + return ErrorAction.Continue; + } + return ErrorAction.Shutdown; + } + public closed(): CloseAction { + this.restarts.push(Date.now()); + if (this.restarts.length < 5) { + return CloseAction.Restart; + } else { + let diff = this.restarts[this.restarts.length - 1] - this.restarts[0]; + if (diff <= 3 * 60 * 1000) { + Window.showErrorMessage(`The ${this.name} server crashed 5 times in the last 3 minutes. The server will not be restarted.`); + return CloseAction.DoNotRestart; + } else { + this.restarts.shift(); + return CloseAction.Restart; + } + } + } +} + +export interface InitializationFailedHandler { + (error: ResponseError | Error | any): boolean; +} + +export interface SynchronizeOptions { + configurationSection?: string | string[]; + fileEvents?: FileSystemWatcher | FileSystemWatcher[]; + textDocumentFilter?: (textDocument: TextDocument) => boolean; +} + +export enum RevealOutputChannelOn { + Info = 1, + Warn = 2, + Error = 3, + Never = 4 +} + +export interface LanguageClientOptions { + documentSelector?: string | string[]; + providerId: string; + synchronize?: SynchronizeOptions; + diagnosticCollectionName?: string; + outputChannelName?: string; + revealOutputChannelOn?: RevealOutputChannelOn; + /** + * The encoding use to read stdout and stderr. Defaults + * to 'utf8' if ommitted. + */ + stdioEncoding?: string; + initializationOptions?: any | (() => any); + initializationFailedHandler?: InitializationFailedHandler; + errorHandler?: ErrorHandler; + uriConverters?: { + code2Protocol: c2p.URIConverter, + protocol2Code: p2c.URIConverter + }; + serverConnectionMetadata?: string; +} + +export enum State { + Stopped = 1, + Running = 2 +} + +export interface StateChangeEvent { + oldState: State; + newState: State; +} + +enum ClientState { + Initial, + Starting, + StartFailed, + Running, + Stopping, + Stopped +} + +interface SyncExpression { + evaluate(textDocument: TextDocument): boolean; +} + +class FalseSyncExpression implements SyncExpression { + public evaluate(textDocument: TextDocument): boolean { + return false; + } +} + +class LanguageIdExpression implements SyncExpression { + constructor(private _id: string) { + } + public evaluate(textDocument: TextDocument): boolean { + return this._id === textDocument.languageId; + } +} + +class FunctionSyncExpression implements SyncExpression { + constructor(private _func: (textDocument: TextDocument) => boolean) { + } + public evaluate(textDocument: TextDocument): boolean { + return this._func(textDocument); + } +} + +class CompositeSyncExpression implements SyncExpression { + private _expression: SyncExpression[]; + constructor(values: string[], func?: (textDocument: TextDocument) => boolean) { + this._expression = values.map(value => new LanguageIdExpression(value)); + if (func) { + this._expression.push(new FunctionSyncExpression(func)); + } + } + public evaluate(textDocument: TextDocument): boolean { + return this._expression.some(exp => exp.evaluate(textDocument)); + } +} + +export class LanguageClient { + + private _id: string; + private _name: string; + private _serverOptions: ServerOptions; + private _clientOptions: LanguageClientOptions; + private _forceDebug: boolean; + + private _state: ClientState; + private _onReady: Promise; + private _onReadyCallbacks: { resolve: () => void; reject: (error) => void; }; + private _connection: Thenable; + private _childProcess: ChildProcess; + private _outputChannel: OutputChannel; + private _capabilites: ServerCapabilities; + + private _listeners: Disposable[]; + private _providers: Disposable[]; + private _diagnostics: DiagnosticCollection; + + private _syncExpression: SyncExpression; + + private _documentSyncDelayer: Delayer; + + private _fileEvents: FileEvent[]; + private _fileEventDelayer: Delayer; + + private _telemetryEmitter: Emitter; + private _stateChangeEmitter: Emitter; + + private _trace: Trace; + private _tracer: Tracer; + + private _c2p: c2p.Converter; + private _p2c: p2c.Converter; + + public constructor(name: string, serverOptions: ServerOptions, clientOptions: LanguageClientOptions, forceDebug?: boolean); + public constructor(id: string, name: string, serverOptions: ServerOptions, clientOptions: LanguageClientOptions, forceDebug?: boolean); + public constructor(arg1: string, arg2: ServerOptions | string, arg3: LanguageClientOptions | ServerOptions, arg4: boolean | LanguageClientOptions, arg5?: boolean) { + let clientOptions: LanguageClientOptions; + let forceDebug: boolean; + if (is.string(arg2)) { + this._id = arg1; + this._name = arg2; + this._serverOptions = arg3 as ServerOptions; + clientOptions = arg4 as LanguageClientOptions; + forceDebug = arg5; + } else { + this._id = arg1.toLowerCase(); + this._name = arg1; + this._serverOptions = arg2 as ServerOptions; + clientOptions = arg3 as LanguageClientOptions; + forceDebug = arg4 as boolean; + } + if (forceDebug === void 0) { forceDebug = false; } + this._clientOptions = clientOptions || { providerId: '' }; + this._clientOptions.synchronize = this._clientOptions.synchronize || {}; + this._clientOptions.errorHandler = this._clientOptions.errorHandler || new DefaultErrorHandler(this._name); + this._clientOptions.revealOutputChannelOn == this._clientOptions.revealOutputChannelOn || RevealOutputChannelOn.Error; + this._syncExpression = this.computeSyncExpression(); + this._forceDebug = forceDebug; + + this.state = ClientState.Initial; + this._connection = null; + this._childProcess = null; + this._outputChannel = null; + + this._listeners = null; + this._providers = null; + this._diagnostics = null; + + this._fileEvents = []; + this._fileEventDelayer = new Delayer(250); + this._onReady = new Promise((resolve, reject) => { + this._onReadyCallbacks = { resolve, reject }; + }); + this._telemetryEmitter = new Emitter(); + this._stateChangeEmitter = new Emitter(); + this._tracer = { + log: (message: string, data?: string) => { + this.logTrace(message, data); + } + }; + this._c2p = c2p.createConverter(clientOptions.uriConverters ? clientOptions.uriConverters.code2Protocol : undefined); + this._p2c = p2c.createConverter(clientOptions.uriConverters ? clientOptions.uriConverters.protocol2Code : undefined); + } + + private get state(): ClientState { + return this._state; + } + + private set state(value: ClientState) { + let oldState = this.getPublicState(); + this._state = value; + let newState = this.getPublicState(); + if (newState !== oldState) { + this._stateChangeEmitter.fire({ oldState, newState }); + } + } + + private getPublicState(): State { + if (this.state === ClientState.Running) { + return State.Running; + } else { + return State.Stopped; + } + } + + private computeSyncExpression(): SyncExpression { + let documentSelector = this._clientOptions.documentSelector; + let textDocumentFilter = this._clientOptions.synchronize.textDocumentFilter; + + if (!documentSelector && !textDocumentFilter) { + return new FalseSyncExpression(); + } + if (textDocumentFilter && !documentSelector) { + return new FunctionSyncExpression(textDocumentFilter); + } + if (!textDocumentFilter && documentSelector) { + if (is.string(documentSelector)) { + return new LanguageIdExpression(documentSelector) + } else { + return new CompositeSyncExpression(documentSelector) + } + } + if (textDocumentFilter && documentSelector) { + return new CompositeSyncExpression( + is.string(documentSelector) ? [documentSelector] : documentSelector, + textDocumentFilter); + } + } + + public sendRequest(type: RequestType, params: P, token?: CancellationToken): Thenable { + return this.onReady().then(() => { + return this.resolveConnection().then((connection) => { + return this.doSendRequest(connection, type, params, token); + }); + }); + } + + private doSendRequest(connection: IConnection, type: RequestType, params: P, token?: CancellationToken): Thenable { + if (this.isConnectionActive()) { + this.forceDocumentSync(); + try { + return connection.sendRequest(type, params, token); + } catch (error) { + this.error(`Sending request ${type.method} failed.`, error); + } + } else { + return Promise.reject(new ResponseError(ErrorCodes.InternalError, 'Connection is closed.')); + } + } + + public sendNotification

(type: NotificationType

, params?: P): void { + this.onReady().then(() => { + this.resolveConnection().then((connection) => { + if (this.isConnectionActive()) { + this.forceDocumentSync(); + try { + connection.sendNotification(type, params); + } catch (error) { + this.error(`Sending notification ${type.method} failed.`, error); + } + } + }); + }, (error) => { + this.error(`Sending notification ${type.method} failed.`, error) + }); + } + + public onNotification

(type: NotificationType

, handler: NotificationHandler

): void { + this.onReady().then(() => { + this.resolveConnection().then((connection) => { + try { + connection.onNotification(type, handler); + } catch (error) { + this.error(`Registering notification handler ${type.method} failed.`, error); + } + }) + }, (error) => { + }); + } + + public onRequest(type: RequestType, handler: RequestHandler): void { + this.onReady().then(() => { + this.resolveConnection().then((connection) => { + try { + connection.onRequest(type, handler); + } catch (error) { + this.error(`Registering request handler ${type.method} failed.`, error); + } + }) + }, (error) => { + }); + } + + public get onTelemetry(): Event { + return this._telemetryEmitter.event; + } + + public get onDidChangeState(): Event { + return this._stateChangeEmitter.event; + } + + public get outputChannel(): OutputChannel { + if (!this._outputChannel) { + this._outputChannel = Window.createOutputChannel(this._clientOptions.outputChannelName ? this._clientOptions.outputChannelName : this._name); + } + return this._outputChannel; + } + + public get diagnostics(): DiagnosticCollection { + return this._diagnostics; + } + + public createDefaultErrorHandler(): ErrorHandler { + return new DefaultErrorHandler(this._name); + } + + public set trace(value: Trace) { + this._trace = value; + this.onReady().then(() => { + this.resolveConnection().then((connection) => { + connection.trace(value, this._tracer); + }) + }, (error) => { + }); + } + + private data2String(data: any): string { + if (data instanceof ResponseError) { + const responseError = data as ResponseError; + return ` Message: ${responseError.message}\n Code: ${responseError.code} ${responseError.data ? '\n' + responseError.data.toString() : ''}` + } + if (data instanceof Error) { + if (is.string(data.stack)) { + return data.stack; + } + return (data as Error).message; + } + if (is.string(data)) { + return data; + } + return data.toString(); + } + + public info(message: string, data?: any): void { + this.outputChannel.appendLine(`[Info - ${(new Date().toLocaleTimeString())}] ${message}`); + if (data) { + this.outputChannel.appendLine(this.data2String(data)); + } + if (this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Info) { + this.outputChannel.show(true); + } + } + + public warn(message: string, data?: any): void { + this.outputChannel.appendLine(`[Warn - ${(new Date().toLocaleTimeString())}] ${message}`); + if (data) { + this.outputChannel.appendLine(this.data2String(data)); + } + if (this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Warn) { + this.outputChannel.show(true); + } + } + + public error(message: string, data?: any): void { + this.outputChannel.appendLine(`[Error - ${(new Date().toLocaleTimeString())}] ${message}`); + if (data) { + this.outputChannel.appendLine(this.data2String(data)); + } + if (this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Error) { + this.outputChannel.show(true); + } + } + + private logTrace(message: string, data?: any): void { + this.outputChannel.appendLine(`[Trace - ${(new Date().toLocaleTimeString())}] ${message}`); + if (data) { + this.outputChannel.appendLine(this.data2String(data)); + } + this.outputChannel.show(true); + } + + public needsStart(): boolean { + return this.state === ClientState.Initial || this.state === ClientState.Stopping || this.state === ClientState.Stopped; + } + + public needsStop(): boolean { + return this.state === ClientState.Starting || this.state === ClientState.Running; + } + + public onReady(): Promise { + return this._onReady; + } + + private isConnectionActive(): boolean { + return this.state === ClientState.Running; + } + + public start(): Disposable { + this._listeners = []; + this._providers = []; + // If we restart then the diagnostics collection is reused. + if (!this._diagnostics) { + this._diagnostics = this._clientOptions.diagnosticCollectionName + ? Languages.createDiagnosticCollection(this._clientOptions.diagnosticCollectionName) + : Languages.createDiagnosticCollection(); + } + + this.state = ClientState.Starting; + if (this._clientOptions.providerId && this._clientOptions.providerId !== '') { + // hook-up SQL data protocol provider + this.hookDataProtocolProvider(this._clientOptions.providerId); + } + + this.resolveConnection().then((connection) => { + connection.onLogMessage((message) => { + switch (message.type) { + case MessageType.Error: + this.error(message.message); + break; + case MessageType.Warning: + this.warn(message.message); + break; + case MessageType.Info: + this.info(message.message); + break; + default: + this.outputChannel.appendLine(message.message); + } + }); + connection.onShowMessage((message) => { + switch (message.type) { + case MessageType.Error: + Window.showErrorMessage(message.message); + break; + case MessageType.Warning: + Window.showWarningMessage(message.message); + break; + case MessageType.Info: + Window.showInformationMessage(message.message); + break; + default: + Window.showInformationMessage(message.message); + } + }); + connection.onRequest(ShowMessageRequest.type, (params) => { + let messageFunc: (message: string, ...items: T[]) => Thenable = null; + switch (params.type) { + case MessageType.Error: + messageFunc = Window.showErrorMessage; + break; + case MessageType.Warning: + messageFunc = Window.showWarningMessage; + break; + case MessageType.Info: + messageFunc = Window.showInformationMessage; + break; + default: + messageFunc = Window.showInformationMessage; + } + return messageFunc(params.message, ...params.actions); + }); + connection.onTelemetry((data) => { + this._telemetryEmitter.fire(data); + }); + + connection.listen(); + // Error is handled in the intialize call. + this.initialize(connection).then(null, (error) => { }); + }, (error) => { + this.state = ClientState.StartFailed; + this._onReadyCallbacks.reject(error); + this.error('Starting client failed', error); + Window.showErrorMessage(`Couldn't start client ${this._name}`); + }); + return new Disposable(() => { + if (this.needsStop()) { + this.stop(); + } + }); + } + + private resolveConnection(): Thenable { + if (!this._connection) { + this._connection = this.createConnection(); + } + return this._connection; + } + + private initialize(connection: IConnection): Thenable { + this.refreshTrace(connection, false); + let initOption = this._clientOptions.initializationOptions; + let initParams: InitializeParams = { + processId: process.pid, + rootPath: Workspace.rootPath, + capabilities: {}, + initializationOptions: is.func(initOption) ? initOption() : initOption, + trace: Trace.toString(this._trace) + }; + return connection.initialize(initParams).then((result) => { + this.state = ClientState.Running; + this._capabilites = result.capabilities; + connection.onDiagnostics(params => this.handleDiagnostics(params)); + if (this._capabilites.textDocumentSync !== TextDocumentSyncKind.None) { + Workspace.onDidOpenTextDocument(t => this.onDidOpenTextDoument(connection, t), null, this._listeners); + Workspace.onDidChangeTextDocument(t => this.onDidChangeTextDocument(connection, t), null, this._listeners); + Workspace.onDidCloseTextDocument(t => this.onDidCloseTextDoument(connection, t), null, this._listeners); + Workspace.onDidSaveTextDocument(t => this.onDidSaveTextDocument(connection, t), null, this._listeners); + if (this._capabilites.textDocumentSync === TextDocumentSyncKind.Full) { + this._documentSyncDelayer = new Delayer(100); + } + } + this.hookFileEvents(connection); + this.hookConfigurationChanged(connection); + this.hookCapabilities(connection); + this._onReadyCallbacks.resolve(); + + Workspace.textDocuments.forEach(t => this.onDidOpenTextDoument(connection, t)); + return result; + }, (error: any) => { + if (this._clientOptions.initializationFailedHandler) { + if (this._clientOptions.initializationFailedHandler(error)) { + this.initialize(connection); + } else { + this.stop(); + this._onReadyCallbacks.reject(error); + } + } else if (error instanceof ResponseError && error.data && error.data.retry) { + Window.showErrorMessage(error.message, { title: 'Retry', id: "retry" }).then(item => { + if (is.defined(item) && item.id === 'retry') { + this.initialize(connection); + } else { + this.stop(); + this._onReadyCallbacks.reject(error); + } + }); + } else { + if (error && error.message) { + Window.showErrorMessage(error.message); + } + this.error('Server initialization failed.', error); + this.stop(); + this._onReadyCallbacks.reject(error); + } + }); + } + + public stop(): Thenable { + if (!this._connection) { + this.state = ClientState.Stopped; + return; + } + this.state = ClientState.Stopping; + this.cleanUp(); + // unkook listeners + return this.resolveConnection().then(connection => { + connection.shutdown().then(() => { + connection.exit(); + connection.dispose(); + this.state = ClientState.Stopped; + this._connection = null; + let toCheck = this._childProcess; + this._childProcess = null; + // Remove all markers + this.checkProcessDied(toCheck); + }); + }); + } + + private cleanUp(diagnostics: boolean = true): void { + if (this._listeners) { + this._listeners.forEach(listener => listener.dispose()); + this._listeners = null; + } + if (this._providers) { + this._providers.forEach(provider => provider.dispose()); + this._providers = null; + } + if (diagnostics) { + this._diagnostics.dispose(); + this._diagnostics = null; + } + } + + private notifyConfigurationChanged(settings: any): void { + this.onReady().then(() => { + this.resolveConnection().then(connection => { + if (this.isConnectionActive()) { + connection.didChangeConfiguration({ settings }); + } + }, (error) => { + this.error(`Syncing settings failed.`, JSON.stringify(error, null, 4)); + }); + }, (error) => { + this.error(`Syncing settings failed.`, JSON.stringify(error, null, 4)); + }); + } + + private notifyFileEvent(event: FileEvent): void { + this._fileEvents.push(event); + this._fileEventDelayer.trigger(() => { + this.onReady().then(() => { + this.resolveConnection().then(connection => { + if (this.isConnectionActive()) { + connection.didChangeWatchedFiles({ changes: this._fileEvents }); + } + this._fileEvents = []; + }); + }, (error) => { + this.error(`Notify file events failed.`, error); + }); + }); + } + + private onDidOpenTextDoument(connection: IConnection, textDocument: TextDocument): void { + if (!this._syncExpression.evaluate(textDocument)) { + return; + } + connection.didOpenTextDocument(this._c2p.asOpenTextDocumentParams(textDocument)); + } + + private onDidChangeTextDocument(connection: IConnection, event: TextDocumentChangeEvent): void { + if (!this._syncExpression.evaluate(event.document)) { + return; + } + let uri: string = event.document.uri.toString(); + if (this._capabilites.textDocumentSync === TextDocumentSyncKind.Incremental) { + connection.didChangeTextDocument(this._c2p.asChangeTextDocumentParams(event)); + } else { + if (this._documentSyncDelayer) { + this._documentSyncDelayer.trigger(() => { + connection.didChangeTextDocument(this._c2p.asChangeTextDocumentParams(event.document)); + }, -1); + } + } + } + + private onDidCloseTextDoument(connection: IConnection, textDocument: TextDocument): void { + if (!this._syncExpression.evaluate(textDocument)) { + return; + } + connection.didCloseTextDocument(this._c2p.asCloseTextDocumentParams(textDocument)); + } + + private onDidSaveTextDocument(conneciton: IConnection, textDocument: TextDocument): void { + if (!this._syncExpression.evaluate(textDocument)) { + return; + } + conneciton.didSaveTextDocument(this._c2p.asSaveTextDocumentParams(textDocument)); + } + + private forceDocumentSync(): void { + if (this._documentSyncDelayer) { + this._documentSyncDelayer.forceDelivery(); + } + } + + private handleDiagnostics(params: PublishDiagnosticsParams) { + let uri = Uri.parse(params.uri); + let diagnostics = this._p2c.asDiagnostics(params.diagnostics); + this._diagnostics.set(uri, diagnostics); + } + + private createConnection(): Thenable { + function getEnvironment(env: any): any { + if (!env) { + return process.env; + } + let result: any = Object.create(null); + Object.keys(process.env).forEach(key => result[key] = process.env[key]); + Object.keys(env).forEach(key => result[key] = env[key]); + } + + function startedInDebugMode(): boolean { + let args = (process as any).execArgv; + if (args) { + return args.some((arg) => /^--debug=?/.test(arg) || /^--debug-brk=?/.test(arg)); + }; + return false; + } + + let encoding = this._clientOptions.stdioEncoding || 'utf8'; + + let errorHandler = (error: Error, message: Message, count: number) => { + this.handleConnectionError(error, message, count); + } + + let closeHandler = () => { + this.handleConnectionClosed(); + } + + let server = this._serverOptions; + // We got a function. + if (is.func(server)) { + return server().then((result) => { + let info = result as StreamInfo; + if (info.writer && info.reader) { + return createConnection(info.reader, info.writer, errorHandler, closeHandler); + } else { + let cp = result as ChildProcess; + return createConnection(cp.stdout, cp.stdin, errorHandler, closeHandler); + } + }); + } + let json: { command?: string; module?: string } = null; + let runDebug = <{ run: any; debug: any; }>server; + if (is.defined(runDebug.run) || is.defined(runDebug.debug)) { + // We are under debugging. So use debug as well. + if (typeof v8debug === 'object' || this._forceDebug || startedInDebugMode()) { + json = runDebug.debug; + } else { + json = runDebug.run; + } + } else { + json = server; + } + if (is.defined(json.module)) { + let node: NodeModule = json; + if (node.runtime) { + let args: string[] = []; + let options: ForkOptions = node.options || Object.create(null); + if (options.execArgv) { + options.execArgv.forEach(element => args.push(element)); + } + args.push(node.module); + if (node.args) { + node.args.forEach(element => args.push(element)); + } + let execOptions: ExecutableOptions = Object.create(null); + execOptions.cwd = options.cwd || Workspace.rootPath; + execOptions.env = getEnvironment(options.env); + if (node.transport === TransportKind.ipc) { + execOptions.stdio = [null, null, null, 'ipc']; + args.push('--node-ipc'); + } else if (node.transport === TransportKind.stdio) { + args.push('--stdio'); + } + let process = cp.spawn(node.runtime, args, execOptions); + if (!process || !process.pid) { + return Promise.reject(`Launching server using runtime ${node.runtime} failed.`); + } + this._childProcess = process; + process.stderr.on('data', data => this.outputChannel.append(data.toString())); + if (node.transport === TransportKind.ipc) { + process.stdout.on('data', data => this.outputChannel.append(data.toString())); + return Promise.resolve(createConnection(new IPCMessageReader(process), new IPCMessageWriter(process), errorHandler, closeHandler)); + } else { + return Promise.resolve(createConnection(process.stdout, process.stdin, errorHandler, closeHandler)); + } + } else { + return new Promise((resolve, reject) => { + let args = node.args && node.args.slice() || []; + if (node.transport === TransportKind.ipc) { + args.push('--node-ipc'); + } else if (node.transport === TransportKind.stdio) { + args.push('--stdio'); + } + let options: ForkOptions = node.options || Object.create(null); + options.execArgv = options.execArgv || []; + options.cwd = options.cwd || Workspace.rootPath; + electron.fork(node.module, args || [], options, (error, cp) => { + if (error) { + reject(error); + } else { + this._childProcess = cp; + cp.stderr.on('data', data => this.outputChannel.append(data.toString())); + if (node.transport === TransportKind.ipc) { + cp.stdout.on('data', data => this.outputChannel.append(data.toString())); + resolve(createConnection(new IPCMessageReader(this._childProcess), new IPCMessageWriter(this._childProcess), errorHandler, closeHandler)); + } else { + resolve(createConnection(cp.stdout, cp.stdin, errorHandler, closeHandler)); + } + } + }); + }); + } + } else if (is.defined(json.command)) { + let command: Executable = json; + let options = command.options || {}; + options.cwd = options.cwd || Workspace.rootPath; + let process = cp.spawn(command.command, command.args, command.options); + if (!process || !process.pid) { + return Promise.reject(`Launching server using command ${command.command} failed.`); + } + process.stderr.on('data', data => this.outputChannel.append(data.toString())); + this._childProcess = process; + return Promise.resolve(createConnection(process.stdout, process.stdin, errorHandler, closeHandler)); + } + return Promise.reject(new Error(`Unsupported server configuartion ` + JSON.stringify(server, null, 4))); + } + + private handleConnectionClosed() { + + let self = this; + + // Check whether this is a normal shutdown in progress or the client stopped normally. + if (this.state === ClientState.Stopping || this.state === ClientState.Stopped) { + return; + } + + self._connection = null; + self._childProcess = null; + let action = this._clientOptions.errorHandler.closed(); + if (action === CloseAction.DoNotRestart) { + self.error('Connection to server got closed. Server will not be restarted.'); + self.state = ClientState.Stopped; + self.cleanUp(); + } else if (action === CloseAction.Restart && self.state !== ClientState.Stopping) { + self.info('Connection to server got closed. Server will restart.'); + self.cleanUp(false); + self.state = ClientState.Initial; + self.start(); + } + } + + private handleConnectionError(error: Error, message: Message, count: number) { + let action = this._clientOptions.errorHandler.error(error, message, count); + if (action === ErrorAction.Shutdown) { + this.error('Connection to server is erroring. Shutting down server.') + this.stop(); + } + } + + private checkProcessDied(childProcess: ChildProcess): void { + if (!childProcess) { + return; + } + setTimeout(() => { + // Test if the process is still alive. Throws an exception if not + try { + process.kill(childProcess.pid, 0); + terminate(childProcess); + } catch (error) { + // All is fine. + } + }, 2000); + } + + private hookConfigurationChanged(connection: IConnection): void { + if (!this._clientOptions.synchronize.configurationSection) { + return; + } + Workspace.onDidChangeConfiguration(e => this.onDidChangeConfiguration(connection), this, this._listeners); + this.onDidChangeConfiguration(connection); + } + + private refreshTrace(connection: IConnection, sendNotification: boolean = false): void { + let config = Workspace.getConfiguration(this._id); + let trace: Trace = Trace.Off; + if (config) { + trace = Trace.fromString(config.get('trace.server', 'off')); + } + this._trace = trace; + connection.trace(this._trace, this._tracer, sendNotification); + } + + private onDidChangeConfiguration(connection: IConnection): void { + this.refreshTrace(connection, true); + let keys: string[] = null; + let configurationSection = this._clientOptions.synchronize.configurationSection; + if (is.string(configurationSection)) { + keys = [configurationSection]; + } else if (is.stringArray(configurationSection)) { + keys = configurationSection; + } + if (keys) { + if (this.isConnectionActive()) { + connection.didChangeConfiguration({ settings: this.extractSettingsInformation(keys) }); + } + } + } + + private extractSettingsInformation(keys: string[]): any { + function ensurePath(config: any, path: string[]): any { + let current = config; + for (let i = 0; i < path.length - 1; i++) { + let obj = current[path[i]]; + if (!obj) { + obj = Object.create(null); + current[path[i]] = obj; + } + current = obj; + } + return current; + } + let result = Object.create(null); + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + let index: number = key.indexOf('.'); + let config: any = null; + if (index >= 0) { + config = Workspace.getConfiguration(key.substr(0, index)).get(key.substr(index + 1)); + } else { + config = Workspace.getConfiguration(key); + } + if (config) { + let path = keys[i].split('.'); + ensurePath(result, path)[path[path.length - 1]] = config; + } + } + return result; + } + + private hookFileEvents(connection: IConnection): void { + let fileEvents = this._clientOptions.synchronize.fileEvents; + if (!fileEvents) { + return; + } + let watchers: FileSystemWatcher[] = null; + if (is.array(fileEvents)) { + watchers = fileEvents; + } else { + watchers = [fileEvents]; + } + if (!watchers) { + return; + } + watchers.forEach(watcher => { + watcher.onDidCreate((resource) => this.notifyFileEvent( + { + uri: resource.toString(), + type: FileChangeType.Created + } + ), null, this._listeners); + watcher.onDidChange((resource) => this.notifyFileEvent( + { + uri: resource.toString(), + type: FileChangeType.Changed + } + + ), null, this._listeners); + watcher.onDidDelete((resource) => this.notifyFileEvent( + { + uri: resource.toString(), + type: FileChangeType.Deleted + } + ), null, this._listeners); + }); + } + + private hookCapabilities(connection: IConnection): void { + let documentSelector = this._clientOptions.documentSelector; + if (!documentSelector) { + return; + } + this.hookCompletionProvider(documentSelector, connection); + this.hookHoverProvider(documentSelector, connection); + this.hookSignatureHelpProvider(documentSelector, connection); + this.hookDefinitionProvider(documentSelector, connection); + this.hookReferencesProvider(documentSelector, connection); + this.hookDocumentHighlightProvider(documentSelector, connection); + this.hookDocumentSymbolProvider(documentSelector, connection); + this.hookWorkspaceSymbolProvider(connection); + this.hookCodeActionsProvider(documentSelector, connection); + this.hookCodeLensProvider(documentSelector, connection); + this.hookDocumentFormattingProvider(documentSelector, connection); + this.hookDocumentRangeFormattingProvider(documentSelector, connection); + this.hookDocumentOnTypeFormattingProvider(documentSelector, connection); + this.hookRenameProvider(documentSelector, connection); + this.hookDocumentLinkProvider(documentSelector, connection); + } + + private logFailedRequest(type: RequestType, error: any): void { + this.error(`Request ${type.method} failed.`, error); + } + + /** + * SQL-Carbon Edit + * The helper method to add connection notifications after waiting for connections to be ready. + * This is needed for early DMP registration, which can be done without waiting for connection setup to finish. + * + * @param type + * @param handler + */ + private onConnectionReadyNotification

(type: NotificationType

, handler: NotificationHandler

): void { + this.onReady().then(() => { + this.resolveConnection().then((connection) => { + connection.onNotification(type, handler); + }); + } + ); + } + + private hookDataProtocolProvider(providerId: string): void { + let self = this; + + let capabilitiesProvider: CapabilitiesProvider = { + getServerCapabilities(client: DataProtocolClientCapabilities): Thenable { + let capabilitiesPromise = self._clientOptions.serverConnectionMetadata === undefined ? + self.sendRequest(CapabiltiesDiscoveryRequest.type, self._c2p.asCapabilitiesParams(client), undefined) : + new Promise((resolve, reject) => resolve(self._clientOptions.serverConnectionMetadata)); + + return capabilitiesPromise.then(self._p2c.asServerCapabilities, (error) => { + self.logFailedRequest(ConnectionRequest.type, error); + return Promise.resolve([]); + } + ); + } + }; + + let connectionProvider: ConnectionProvider = { + handle: -1, + + connect(connUri: string, connInfo: ConnectionInfo): Thenable { + return self.sendRequest(ConnectionRequest.type, self._c2p.asConnectionParams(connUri, connInfo), undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(ConnectionRequest.type, error); + return Promise.resolve(false); + } + ); + }, + + disconnect(connUri: string): Thenable { + let params: DisconnectParams = { + ownerUri: connUri + }; + + return self.sendRequest(DisconnectRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(DisconnectRequest.type, error); + return Promise.resolve(false); + } + ); + }, + + cancelConnect(connUri: string): Thenable { + let params: CancelConnectParams = { + ownerUri: connUri + }; + + return self.sendRequest(CancelConnectRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(CancelConnectRequest.type, error); + return Promise.resolve(false); + } + ); + }, + + changeDatabase(connUri: string, newDatabase: string): Thenable { + let params: ChangeDatabaseParams = { + ownerUri: connUri, + newDatabase: newDatabase + }; + + return self.sendRequest(ChangeDatabaseRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(ChangeDatabaseRequest.type, error); + return Promise.resolve(false); + } + ); + }, + + listDatabases(connectionUri: string): Thenable { + let params: ListDatabasesParams = { + ownerUri: connectionUri + }; + + return self.sendRequest(ListDatabasesRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(ListDatabasesRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + + rebuildIntelliSenseCache(connectionUri: string): Thenable { + let params: RebuildIntelliSenseParams = { + ownerUri: connectionUri + }; + + self.sendNotification(RebuildIntelliSenseNotification.type, params); + return Promise.resolve(undefined); + }, + + registerOnConnectionComplete(handler: (connSummary: ConnectionInfoSummary) => any) { + self.onConnectionReadyNotification(ConnectionCompleteNotification.type, (params: ConnectionCompleteParams) => { + handler({ + ownerUri: params.ownerUri, + connectionId: params.connectionId, + messages: params.messages, + errorMessage: params.errorMessage, + errorNumber: params.errorNumber, + serverInfo: params.serverInfo, + connectionSummary: params.connectionSummary + }); + }); + }, + + registerOnIntelliSenseCacheComplete(handler: (connectionUri: string) => any) { + self.onConnectionReadyNotification(IntelliSenseReadyNotification.type, (params: IntelliSenseReadyParams) => { + handler(params.ownerUri); + }); + }, + + registerOnConnectionChanged(handler: (changedConnInfo: ChangedConnectionInfo) => any) { + self.onConnectionReadyNotification(ConnectionChangedNotification.type, (params: ConnectionChangedParams) => { + handler({ + connectionUri: params.ownerUri, + connection: params.connection + }); + }); + } + }; + + let queryProvider: QueryProvider = { + handle: -1, + queryType: 'MSSQL', + cancelQuery(ownerUri: string): Thenable { + let params: QueryCancelParams = { ownerUri: ownerUri }; + return self.sendRequest(QueryCancelRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(QueryCancelRequest.type, error); + return Promise.reject(error); + } + ); + }, + + runQuery(ownerUri: string, selection: ISelectionData, executionPlanOptions?: ExecutionPlanOptions): Thenable { + let params: QueryExecuteParams = { + ownerUri: ownerUri, + querySelection: selection, + executionPlanOptions: self._c2p.asExecutionPlanOptions(executionPlanOptions) + }; + return self.sendRequest(QueryExecuteRequest.type, params, undefined).then( + (result) => { + return undefined; + }, + (error) => { + self.logFailedRequest(QueryExecuteRequest.type, error); + return Promise.reject(error); + } + ); + }, + + runQueryStatement(ownerUri: string, line: number, column: number): Thenable { + let params: QueryExecuteStatementParams = { + ownerUri: ownerUri, + line: line, + column: column + }; + return self.sendRequest(QueryExecuteStatementRequest.type, params, undefined).then( + (result) => { + return undefined; + }, + (error) => { + self.logFailedRequest(QueryExecuteStatementRequest.type, error); + return Promise.reject(error); + } + ); + }, + + runQueryString(ownerUri: string, queryString: string): Thenable { + let params: QueryExecuteStringParams = { ownerUri: ownerUri, query: queryString }; + return self.sendRequest(QueryExecuteStringRequest.type, params, undefined).then( + (result) => { + return undefined; + }, + (error) => { + self.logFailedRequest(QueryExecuteStringRequest.type, error); + return Promise.reject(error); + } + ); + }, + + runQueryAndReturn(ownerUri: string, queryString: string): Thenable { + let params: SimpleExecuteParams = { ownerUri: ownerUri, queryString: queryString }; + return self.sendRequest(SimpleExecuteRequest.type, params, undefined).then( + result => { + return result; + }, + error => { + self.logFailedRequest(SimpleExecuteRequest.type, error); + return Promise.reject(error); + } + ); + }, + + getQueryRows(rowData: QueryExecuteSubsetParams): Thenable { + return self.sendRequest(QueryExecuteSubsetRequest.type, rowData, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(QueryExecuteSubsetRequest.type, error); + return Promise.reject(error); + } + ); + }, + + disposeQuery(ownerUri: string): Thenable { + let params: QueryDisposeParams = { ownerUri: ownerUri }; + return self.sendRequest(QueryDisposeRequest.type, params, undefined).then( + (result) => { + return undefined; + }, + (error) => { + self.logFailedRequest(QueryDisposeRequest.type, error); + return Promise.reject(error); + } + ); + }, + + registerOnQueryComplete(handler: (result: QueryExecuteCompleteNotificationResult) => any) { + self.onConnectionReadyNotification(QueryExecuteCompleteNotification.type, (params: QueryExecuteCompleteNotificationResult) => { + handler({ + ownerUri: params.ownerUri, + batchSummaries: params.batchSummaries + }); + }); + }, + + registerOnBatchStart(handler: (batchInfo: QueryExecuteBatchNotificationParams) => any) { + self.onConnectionReadyNotification(QueryExecuteBatchStartNotification.type, (params: QueryExecuteBatchNotificationParams) => { + handler({ + batchSummary: params.batchSummary, + ownerUri: params.ownerUri + }); + }); + }, + + registerOnBatchComplete(handler: (batchInfo: QueryExecuteBatchNotificationParams) => any) { + self.onConnectionReadyNotification(QueryExecuteBatchCompleteNotification.type, (params: QueryExecuteBatchNotificationParams) => { + handler({ + batchSummary: params.batchSummary, + ownerUri: params.ownerUri + }); + }); + }, + registerOnResultSetComplete(handler: (resultSetInfo: QueryExecuteResultSetCompleteNotificationParams) => any) { + self.onConnectionReadyNotification(QueryExecuteResultSetCompleteNotification.type, (params: QueryExecuteResultSetCompleteNotificationParams) => { + handler({ + ownerUri: params.ownerUri, + resultSetSummary: params.resultSetSummary + }); + }); + }, + registerOnMessage(handler: (message: QueryExecuteMessageParams) => any) { + self.onConnectionReadyNotification(QueryExecuteMessageNotification.type, (params: QueryExecuteMessageParams) => { + handler({ + message: params.message, + ownerUri: params.ownerUri + }); + }); + }, + saveResults(requestParams: VSaveResultsRequestParams): Thenable { + switch (requestParams.resultFormat) { + case 'csv': + return self.sendRequest(SaveResultsAsCsvRequest.type, requestParams, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(EditCommitRequest.type, error); + return Promise.reject(error); + } + ); + case 'json': + return self.sendRequest(SaveResultsAsJsonRequest.type, requestParams, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(EditCommitRequest.type, error); + return Promise.reject(error); + } + ); + case 'excel': + return self.sendRequest(SaveResultsAsExcelRequest.type, requestParams, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(EditCommitRequest.type, error); + return Promise.reject(error); + } + ); + default: + return Promise.reject('unsupported format'); + } + }, + + // Edit Data Requests + commitEdit(ownerUri: string): Thenable { + let params: EditCommitParams = { ownerUri: ownerUri }; + return self.sendRequest(EditCommitRequest.type, params, undefined).then( + (result) => { + return undefined; + }, + (error) => { + self.logFailedRequest(EditCommitRequest.type, error); + return Promise.reject(error); + } + ); + }, + + createRow(ownerUri: string): Thenable { + let params: EditCreateRowParams = { ownerUri: ownerUri }; + return self.sendRequest(EditCreateRowRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(EditCreateRowRequest.type, error); + return Promise.reject(error); + } + ); + }, + + deleteRow(ownerUri: string, rowId: number): Thenable { + let params: EditDeleteRowParams = { ownerUri: ownerUri, rowId: rowId }; + return self.sendRequest(EditDeleteRowRequest.type, params, undefined).then( + (result) => { + return undefined; + }, + (error) => { + self.logFailedRequest(EditDeleteRowRequest.type, error); + return Promise.reject(error); + } + ); + }, + + disposeEdit(ownerUri: string): Thenable { + let params: EditDisposeParams = { ownerUri: ownerUri }; + return self.sendRequest(EditDisposeRequest.type, params, undefined).then( + (result) => { + return undefined; + }, + (error) => { + self.logFailedRequest(EditDisposeRequest.type, error); + return Promise.reject(error); + } + ); + }, + + initializeEdit(ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number): Thenable { + let filters: EditInitializeFiltering = { LimitResults: rowLimit }; + let params: EditInitializeParams = { ownerUri: ownerUri, schemaName: schemaName, objectName: objectName, objectType: objectType, filters: filters }; + return self.sendRequest(EditInitializeRequest.type, params, undefined).then( + (result) => { + return undefined; + }, + (error) => { + self.logFailedRequest(EditInitializeRequest.type, error); + return Promise.reject(error); + } + ); + }, + + revertCell(ownerUri: string, rowId: number, columnId: number): Thenable { + let params: EditRevertCellParams = { ownerUri: ownerUri, rowId: rowId, columnId: columnId }; + return self.sendRequest(EditRevertCellRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(EditRevertCellRequest.type, error); + return Promise.reject(error); + } + ); + }, + + revertRow(ownerUri: string, rowId: number): Thenable { + let params: EditRevertRowParams = { ownerUri: ownerUri, rowId: rowId }; + return self.sendRequest(EditRevertRowRequest.type, params, undefined).then( + (result) => { + return undefined; + }, + (error) => { + self.logFailedRequest(EditRevertRowRequest.type, error); + return Promise.reject(error); + } + ); + }, + + updateCell(ownerUri: string, rowId: number, columnId: number, newValue: string): Thenable { + let params: EditUpdateCellParams = { ownerUri: ownerUri, rowId: rowId, columnId: columnId, newValue: newValue }; + return self.sendRequest(EditUpdateCellRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(EditUpdateCellRequest.type, error); + return Promise.reject(error); + } + ); + }, + + getEditRows(rowData: EditSubsetParams): Thenable { + return self.sendRequest(EditSubsetRequest.type, rowData, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(EditSubsetRequest.type, error); + return Promise.reject(error); + } + ); + }, + + // Edit Data Event Handlers + registerOnEditSessionReady(handler: (ownerUri: string, success: boolean, message: string) => any): void { + self.onConnectionReadyNotification(EditSessionReadyNotification.type, (params: EditSessionReadyParams) => { + handler(params.ownerUri, params.success, params.message); + }); + }, + }; + + let metadataProvider: MetadataProvider = { + getMetadata(connectionUri: string): Thenable { + return self.sendRequest(MetadataQueryRequest.type, + self._c2p.asMetadataQueryParams(connectionUri), undefined).then( + self._p2c.asProviderMetadata, + (error) => { + self.logFailedRequest(MetadataQueryRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + getDatabases(connectionUri: string): Thenable { + return self.sendRequest(ListDatabasesRequest.type, + self._c2p.asListDatabasesParams(connectionUri), undefined).then( + (result) => { + return result.databaseNames; + }, + (error) => { + self.logFailedRequest(ListDatabasesRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + getTableInfo(connectionUri: string, metadata: ObjectMetadata) { + return self.sendRequest(TableMetadataRequest.type, + self._c2p.asTableMetadataParams(connectionUri, metadata), undefined).then( + (result) => { + return result.columns; + }, + (error) => { + self.logFailedRequest(TableMetadataRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + getViewInfo(connectionUri: string, metadata: ObjectMetadata) { + return self.sendRequest(ViewMetadataRequest.type, + self._c2p.asTableMetadataParams(connectionUri, metadata), undefined).then( + (result) => { + return result.columns; + }, + (error) => { + self.logFailedRequest(ViewMetadataRequest.type, error); + return Promise.resolve(undefined); + } + ); + } + }; + + let adminServicesProvider: AdminServicesProvider = { + createDatabase(connectionUri: string, database: DatabaseInfo): Thenable { + let params: CreateDatabaseParams = { ownerUri: connectionUri, databaseInfo: database }; + return self.sendRequest(CreateDatabaseRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(CreateDatabaseRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + getDefaultDatabaseInfo(connectionUri: string): Thenable { + let params: DefaultDatabaseInfoParams = { ownerUri: connectionUri }; + return self.sendRequest(DefaultDatabaseInfoRequest.type, params, undefined).then( + (result) => { + return result.defaultDatabaseInfo; + }, + (error) => { + self.logFailedRequest(DefaultDatabaseInfoRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + getDatabaseInfo(connectionUri: string): Thenable { + let params: GetDatabaseInfoParams = { ownerUri: connectionUri }; + return self.sendRequest(GetDatabaseInfoRequest.type, params, undefined).then( + (result) => { + return result.databaseInfo; + }, + (error) => { + self.logFailedRequest(GetDatabaseInfoRequest.type, error); + return Promise.reject(error); + } + ); + }, + createLogin(connectionUri: string, login: LoginInfo): Thenable { + let params: CreateLoginParams = { ownerUri: connectionUri, loginInfo: login }; + return self.sendRequest(CreateLoginRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(CreateLoginRequest.type, error); + return Promise.resolve(undefined); + } + ); + } + }; + + let disasterRecoveryProvider: DisasterRecoveryProvider = { + backup(connectionUri: string, backupInfo: BackupInfo, taskExecutionMode: TaskExecutionMode): Thenable { + let params: BackupParams = { ownerUri: connectionUri, backupInfo: backupInfo, taskExecutionMode: taskExecutionMode }; + return self.sendRequest(BackupRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(BackupRequest.type, error); + return Promise.resolve([]); + } + ); + }, + getBackupConfigInfo(connectionUri: string): Thenable { + let params: DefaultDatabaseInfoParams = { ownerUri: connectionUri }; + return self.sendRequest(BackupConfigInfoRequest.type, params, undefined).then( + (result) => { + return result.backupConfigInfo; + }, + (error) => { + self.logFailedRequest(BackupConfigInfoRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + getRestorePlan(ownerUri: string, restoreInfo: RestoreInfo): Thenable { + return self.sendRequest(RestorePlanRequest.type, self._c2p.asRestoreParams(ownerUri, restoreInfo), undefined).then( + self._p2c.asRestorePlanResponse, + error => { + self.logFailedRequest(RestorePlanRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + restore(ownerUri: string, restoreInfo: RestoreInfo): Thenable { + return self.sendRequest(RestoreRequest.type, self._c2p.asRestoreParams(ownerUri, restoreInfo), undefined).then( + self._p2c.asRestoreResponse, + error => { + self.logFailedRequest(RestoreRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + getRestoreConfigInfo(ownerUri: string): Thenable { + return self.sendRequest(RestoreConfigInfoRequest.type, self._c2p.asRestoreConfigInfoParams(ownerUri), undefined).then( + self._p2c.asRestoreConfigInfo, + error => { + self.logFailedRequest(RestorePlanRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + cancelRestorePlan(ownerUri: string, restoreInfo: RestoreInfo): Thenable { + return self.sendRequest(CancelRestorePlanRequest.type, self._c2p.asRestoreParams(ownerUri, restoreInfo), undefined).then( + (result) => { + return result; + }, + error => { + self.logFailedRequest(CancelRestorePlanRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + }; + + let objectExplorer: ObjectExplorerProvider = { + createNewSession(connInfo: ConnectionInfo) { + return self.sendRequest(ObjectExplorerCreateSessionRequest.type, + self._c2p.asConnectionDetail(connInfo), undefined).then( + self._p2c.asObjectExplorerCreateSessionResponse, + (error) => { + self.logFailedRequest(ObjectExplorerCreateSessionRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + + expandNode(nodeInfo: ExpandNodeInfo) { + return self.sendRequest(ObjectExplorerExpandRequest.type, + self._c2p.asExpandInfo(nodeInfo), undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(ObjectExplorerExpandRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + + refreshNode(nodeInfo: ExpandNodeInfo) { + return self.sendRequest(ObjectExplorerRefreshRequest.type, + self._c2p.asExpandInfo(nodeInfo), undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(ObjectExplorerRefreshRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + + closeSession(closeSessionInfo: ObjectExplorerCloseSessionInfo) { + return self.sendRequest(ObjectExplorerCloseSessionRequest.type, + self._c2p.asCloseSessionInfo(closeSessionInfo), undefined).then( + self._p2c.asObjectExplorerCloseSessionResponse, + (error) => { + self.logFailedRequest(ObjectExplorerCloseSessionRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + + registerOnSessionCreated(handler: (response: ObjectExplorerSession) => any) { + self.onConnectionReadyNotification(ObjectExplorerCreateSessionCompleteNotification.type, (params: ObjectExplorerSession) => { + handler({ + sessionId: params.sessionId, + success: params.success, + rootNode: params.rootNode, + errorMessage: params.errorMessage + }); + }); + }, + + registerOnExpandCompleted(handler: (response: ObjectExplorerExpandInfo) => any) { + self.onConnectionReadyNotification(ObjectExplorerExpandCompleteNotification.type, (params: ObjectExplorerExpandInfo) => { + handler({ + sessionId: params.sessionId, + nodes: params.nodes, + errorMessage: params.errorMessage, + nodePath: params.nodePath + }); + }); + }, + }; + + + + let scriptingProvider: ScriptingProvider = { + + scriptAsOperation(connectionUri: string, operation: ScriptOperation, metadata: ObjectMetadata, paramDetails: ScriptingParamDetails): Thenable { + return self.sendRequest(ScriptingRequest.type, + self._c2p.asScriptingParams(connectionUri, operation, metadata, paramDetails), undefined).then( + self._p2c.asScriptingResult, + (error) => { + self.logFailedRequest(ScriptingRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + + registerOnScriptingComplete(handler: (scriptingCompleteResult: ScriptingCompleteResult) => any) { + self.onConnectionReadyNotification(ScriptingCompleteNotification.type, (params: ScriptingCompleteResult) => { + handler({ + canceled: params.canceled, + errorDetails: params.errorDetails, + errorMessage: params.errorMessage, + hasError: params.hasError, + success: params.success, + operationId: params.operationId + }); + }); + }, + }; + + let taskServicesProvider: TaskServicesProvider = { + getAllTasks(listTasksParams: ListTasksParams): Thenable { + return self.sendRequest(ListTasksRequest.type, + self._c2p.asListTasksParams(listTasksParams), undefined).then( + self._p2c.asListTasksResponse, + (error) => { + self.logFailedRequest(ListTasksRequest.type, error); + return Promise.resolve(undefined); + } + ); + + }, + cancelTask(cancelTaskParams: CancelTaskParams): Thenable { + return self.sendRequest(CancelTaskRequest.type, + self._c2p.asCancelTaskParams(cancelTaskParams), undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(CancelTaskRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + + registerOnTaskCreated(handler: (response: TaskInfo) => any) { + self.onConnectionReadyNotification(TaskCreatedNotification.type, (params: TaskInfo) => { + handler(self._p2c.asTaskInfo(params)); + }); + }, + + registerOnTaskStatusChanged(handler: (response: TaskProgressInfo) => any) { + self.onConnectionReadyNotification(TaskStatusChangedNotification.type, (params: TaskProgressInfo) => { + handler({ + taskId: params.taskId, + status: params.status, + message: params.message, + script: params.script, + duration: params.duration + }); + }); + } + }; + + let fileBrowserProvider: FileBrowserProvider = { + openFileBrowser(ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean): Thenable { + let params: FileBrowserOpenParams = { ownerUri: ownerUri, expandPath: expandPath, fileFilters: fileFilters, changeFilter: changeFilter }; + return self.sendRequest(FileBrowserOpenRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(FileBrowserOpenRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + + registerOnFileBrowserOpened(handler: (response: FileBrowserOpenedParams) => any) { + self.onConnectionReadyNotification(FileBrowserOpenedNotification.type, (params: FileBrowserOpenedParams) => { + handler(params); + }); + }, + + expandFolderNode(ownerUri: string, expandPath: string): Thenable { + let params: FileBrowserExpandParams = { ownerUri: ownerUri, expandPath: expandPath }; + return self.sendRequest(FileBrowserExpandRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(FileBrowserExpandRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + + registerOnFolderNodeExpanded(handler: (response: FileBrowserExpandedParams) => any) { + self.onConnectionReadyNotification(FileBrowserExpandedNotification.type, (params: FileBrowserExpandedParams) => { + handler(params); + }); + }, + + validateFilePaths(ownerUri: string, serviceType: string, selectedFiles: string[]): Thenable { + let params: FileBrowserValidateParams = { ownerUri: ownerUri, serviceType: serviceType, selectedFiles: selectedFiles }; + return self.sendRequest(FileBrowserValidateRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(FileBrowserValidateRequest.type, error); + return Promise.resolve(undefined); + } + ); + }, + + registerOnFilePathsValidated(handler: (response: FileBrowserValidatedParams) => any) { + self.onConnectionReadyNotification(FileBrowserValidatedNotification.type, (params: FileBrowserValidatedParams) => { + handler(params); + }); + }, + + closeFileBrowser(ownerUri: string): Thenable { + let params: FileBrowserCloseParams = { ownerUri: ownerUri }; + return self.sendRequest(FileBrowserCloseRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(FileBrowserCloseRequest.type, error); + return Promise.resolve(undefined); + } + ); + } + }; + + let profilerProvider: ProfilerProvider = { + startSession(sessionId: string): Thenable { + let params: StartProfilingParams = { + ownerUri: sessionId, + options: { } + }; + + return self.sendRequest(StartProfilingRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(StartProfilingRequest.type, error); + return Promise.reject(error); + } + ); + }, + + stopSession(sessionId: string): Thenable { + let params: StopProfilingParams = { + ownerUri: sessionId + }; + + return self.sendRequest(StopProfilingRequest.type, params, undefined).then( + (result) => { + return result; + }, + (error) => { + self.logFailedRequest(StopProfilingRequest.type, error); + return Promise.reject(error); + } + ); + }, + + pauseSession(sessionId: string): Thenable { + return undefined; + }, + + connectSession(sessionId: string): Thenable { + return undefined; + }, + + disconnectSession(sessionId: string): Thenable { + return undefined; + }, + + registerOnSessionEventsAvailable(handler: (response: ProfilerSessionEvents) => any) { + self.onNotification(ProfilerEventsAvailableNotification.type, (params: ProfilerEventsAvailableParams) => { + handler({ + sessionId: params.ownerUri, + events: params.events + }); + }); + } + }; + + this._providers.push(dataprotocol.registerProvider({ + handle: -1, + + providerId: providerId, + + capabilitiesProvider: capabilitiesProvider, + + connectionProvider: connectionProvider, + + queryProvider: queryProvider, + + metadataProvider: metadataProvider, + + scriptingProvider: scriptingProvider, + + objectExplorerProvider: objectExplorer, + + adminServicesProvider: adminServicesProvider, + + disasterRecoveryProvider: disasterRecoveryProvider, + + taskServicesProvider: taskServicesProvider, + + fileBrowserProvider: fileBrowserProvider, + + profilerProvider: profilerProvider + })); + + // Hook to the workspace-wide notifications that aren't routed to a specific provider + dataprotocol.onDidChangeLanguageFlavor(e => { + self.sendNotification(LanguageFlavorChangedNotification.type, e); + }, this, this._listeners); + } + + private hookCompletionProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.completionProvider) { + return; + } + + this._providers.push(Languages.registerCompletionItemProvider(documentSelector, { + provideCompletionItems: (document: TextDocument, position: VPosition, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, CompletionRequest.type, this._c2p.asTextDocumentPositionParams(document, position), token).then( + this._p2c.asCompletionResult, + (error) => { + this.logFailedRequest(CompletionRequest.type, error); + return Promise.resolve([]); + } + ); + }, + resolveCompletionItem: this._capabilites.completionProvider.resolveProvider + ? (item: VCompletionItem, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, CompletionResolveRequest.type, this._c2p.asCompletionItem(item), token).then( + this._p2c.asCompletionItem, + (error) => { + this.logFailedRequest(CompletionResolveRequest.type, error); + return Promise.resolve(item); + } + ); + } + : undefined + }, ...this._capabilites.completionProvider.triggerCharacters)); + } + + private hookHoverProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.hoverProvider) { + return; + } + + this._providers.push(Languages.registerHoverProvider(documentSelector, { + provideHover: (document: TextDocument, position: VPosition, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, HoverRequest.type, this._c2p.asTextDocumentPositionParams(document, position), token).then( + this._p2c.asHover, + (error) => { + this.logFailedRequest(HoverRequest.type, error); + return Promise.resolve(null); + } + ); + } + })); + } + + private hookSignatureHelpProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.signatureHelpProvider) { + return; + } + this._providers.push(Languages.registerSignatureHelpProvider(documentSelector, { + provideSignatureHelp: (document: TextDocument, position: VPosition, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, SignatureHelpRequest.type, this._c2p.asTextDocumentPositionParams(document, position), token).then( + this._p2c.asSignatureHelp, + (error) => { + this.logFailedRequest(SignatureHelpRequest.type, error); + return Promise.resolve(null); + } + ); + } + }, ...this._capabilites.signatureHelpProvider.triggerCharacters)); + } + + private hookDefinitionProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.definitionProvider) { + return; + } + this._providers.push(Languages.registerDefinitionProvider(documentSelector, { + provideDefinition: (document: TextDocument, position: VPosition, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, DefinitionRequest.type, this._c2p.asTextDocumentPositionParams(document, position), token).then( + this._p2c.asDefinitionResult, + (error) => { + this.logFailedRequest(DefinitionRequest.type, error); + return Promise.resolve(null); + } + ); + } + })); + } + + private hookReferencesProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.referencesProvider) { + return; + } + this._providers.push(Languages.registerReferenceProvider(documentSelector, { + provideReferences: (document: TextDocument, position: VPosition, options: { includeDeclaration: boolean; }, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, ReferencesRequest.type, this._c2p.asReferenceParams(document, position, options), token).then( + this._p2c.asReferences, + (error) => { + this.logFailedRequest(ReferencesRequest.type, error); + return Promise.resolve([]); + } + ); + } + })); + } + + private hookDocumentHighlightProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.documentHighlightProvider) { + return; + } + this._providers.push(Languages.registerDocumentHighlightProvider(documentSelector, { + provideDocumentHighlights: (document: TextDocument, position: VPosition, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, DocumentHighlightRequest.type, this._c2p.asTextDocumentPositionParams(document, position), token).then( + this._p2c.asDocumentHighlights, + (error) => { + this.logFailedRequest(DocumentHighlightRequest.type, error); + return Promise.resolve([]); + } + ); + } + })); + } + + private hookDocumentSymbolProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.documentSymbolProvider) { + return; + } + this._providers.push(Languages.registerDocumentSymbolProvider(documentSelector, { + provideDocumentSymbols: (document: TextDocument, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, DocumentSymbolRequest.type, this._c2p.asDocumentSymbolParams(document), token).then( + this._p2c.asSymbolInformations, + (error) => { + this.logFailedRequest(DocumentSymbolRequest.type, error); + return Promise.resolve([]); + } + ); + } + })); + } + + private hookWorkspaceSymbolProvider(connection: IConnection): void { + if (!this._capabilites.workspaceSymbolProvider) { + return; + } + this._providers.push(Languages.registerWorkspaceSymbolProvider({ + provideWorkspaceSymbols: (query: string, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, WorkspaceSymbolRequest.type, { query }, token).then( + this._p2c.asSymbolInformations, + (error) => { + this.logFailedRequest(WorkspaceSymbolRequest.type, error); + return Promise.resolve([]); + } + ); + } + })); + } + + private hookCodeActionsProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.codeActionProvider) { + return; + } + this._providers.push(Languages.registerCodeActionsProvider(documentSelector, { + provideCodeActions: (document: TextDocument, range: VRange, context: VCodeActionContext, token: CancellationToken): Thenable => { + let params: CodeActionParams = { + textDocument: this._c2p.asTextDocumentIdentifier(document), + range: this._c2p.asRange(range), + context: this._c2p.asCodeActionContext(context) + }; + return this.doSendRequest(connection, CodeActionRequest.type, params, token).then( + this._p2c.asCommands, + (error) => { + this.logFailedRequest(CodeActionRequest.type, error); + return Promise.resolve([]); + } + ); + } + })); + } + + private hookCodeLensProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.codeLensProvider) { + return; + } + this._providers.push(Languages.registerCodeLensProvider(documentSelector, { + provideCodeLenses: (document: TextDocument, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, CodeLensRequest.type, this._c2p.asCodeLensParams(document), token).then( + this._p2c.asCodeLenses, + (error) => { + this.logFailedRequest(CodeLensRequest.type, error); + return Promise.resolve([]); + } + ); + }, + resolveCodeLens: (this._capabilites.codeLensProvider.resolveProvider) + ? (codeLens: VCodeLens, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, CodeLensResolveRequest.type, this._c2p.asCodeLens(codeLens), token).then( + this._p2c.asCodeLens, + (error) => { + this.logFailedRequest(CodeLensResolveRequest.type, error); + return codeLens; + } + ); + } + : undefined + })); + } + + private hookDocumentFormattingProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.documentFormattingProvider) { + return; + } + this._providers.push(Languages.registerDocumentFormattingEditProvider(documentSelector, { + provideDocumentFormattingEdits: (document: TextDocument, options: VFormattingOptions, token: CancellationToken): Thenable => { + let params: DocumentFormattingParams = { + textDocument: this._c2p.asTextDocumentIdentifier(document), + options: this._c2p.asFormattingOptions(options) + }; + return this.doSendRequest(connection, DocumentFormattingRequest.type, params, token).then( + this._p2c.asTextEdits, + (error) => { + this.logFailedRequest(DocumentFormattingRequest.type, error); + return Promise.resolve([]); + } + ); + } + })); + } + + private hookDocumentRangeFormattingProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.documentRangeFormattingProvider) { + return; + } + this._providers.push(Languages.registerDocumentRangeFormattingEditProvider(documentSelector, { + provideDocumentRangeFormattingEdits: (document: TextDocument, range: VRange, options: VFormattingOptions, token: CancellationToken): Thenable => { + let params: DocumentRangeFormattingParams = { + textDocument: this._c2p.asTextDocumentIdentifier(document), + range: this._c2p.asRange(range), + options: this._c2p.asFormattingOptions(options) + }; + return this.doSendRequest(connection, DocumentRangeFormattingRequest.type, params, token).then( + this._p2c.asTextEdits, + (error) => { + this.logFailedRequest(DocumentRangeFormattingRequest.type, error); + return Promise.resolve([]); + } + ); + } + })); + } + + private hookDocumentOnTypeFormattingProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.documentOnTypeFormattingProvider) { + return; + } + let formatCapabilities = this._capabilites.documentOnTypeFormattingProvider; + this._providers.push(Languages.registerOnTypeFormattingEditProvider(documentSelector, { + provideOnTypeFormattingEdits: (document: TextDocument, position: VPosition, ch: string, options: VFormattingOptions, token: CancellationToken): Thenable => { + let params: DocumentOnTypeFormattingParams = { + textDocument: this._c2p.asTextDocumentIdentifier(document), + position: this._c2p.asPosition(position), + ch: ch, + options: this._c2p.asFormattingOptions(options) + }; + return this.doSendRequest(connection, DocumentOnTypeFormattingRequest.type, params, token).then( + this._p2c.asTextEdits, + (error) => { + this.logFailedRequest(DocumentOnTypeFormattingRequest.type, error); + return Promise.resolve([]); + } + ); + } + }, formatCapabilities.firstTriggerCharacter, ...formatCapabilities.moreTriggerCharacter)); + } + + private hookRenameProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.renameProvider) { + return; + } + this._providers.push(Languages.registerRenameProvider(documentSelector, { + provideRenameEdits: (document: TextDocument, position: VPosition, newName: string, token: CancellationToken): Thenable => { + let params: RenameParams = { + textDocument: this._c2p.asTextDocumentIdentifier(document), + position: this._c2p.asPosition(position), + newName: newName + }; + return this.doSendRequest(connection, RenameRequest.type, params, token).then( + this._p2c.asWorkspaceEdit, + (error: ResponseError) => { + this.logFailedRequest(RenameRequest.type, error); + Promise.resolve(new Error(error.message)); + } + ); + } + })); + } + + private hookDocumentLinkProvider(documentSelector: DocumentSelector, connection: IConnection): void { + if (!this._capabilites.documentLinkProvider) { + return; + } + this._providers.push(Languages.registerDocumentLinkProvider(documentSelector, { + provideDocumentLinks: (document: TextDocument, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, DocumentLinkRequest.type, this._c2p.asDocumentLinkParams(document), token).then( + this._p2c.asDocumentLinks, + (error: ResponseError) => { + this.logFailedRequest(DocumentLinkRequest.type, error); + Promise.resolve(new Error(error.message)); + } + ); + }, + resolveDocumentLink: this._capabilites.documentLinkProvider.resolveProvider + ? (link: VDocumentLink, token: CancellationToken): Thenable => { + return this.doSendRequest(connection, DocumentLinkResolveRequest.type, this._c2p.asDocumentLink(link), token).then( + this._p2c.asDocumentLink, + (error: ResponseError) => { + this.logFailedRequest(DocumentLinkResolveRequest.type, error); + Promise.resolve(new Error(error.message)); + } + ); + } + : undefined + })); + } +} + +export class SettingMonitor { + + private _listeners: Disposable[]; + + constructor(private _client: LanguageClient, private _setting: string) { + this._listeners = []; + } + + public start(): Disposable { + Workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this._listeners); + this.onDidChangeConfiguration(); + return new Disposable(() => { + if (this._client.needsStop()) { + this._client.stop(); + } + }); + } + + private onDidChangeConfiguration(): void { + let index = this._setting.indexOf('.'); + let primary = index >= 0 ? this._setting.substr(0, index) : this._setting; + let rest = index >= 0 ? this._setting.substr(index + 1) : undefined; + let enabled = rest ? Workspace.getConfiguration(primary).get(rest, false) : Workspace.getConfiguration(primary); + if (enabled && this._client.needsStart()) { + this._client.start(); + } else if (!enabled && this._client.needsStop()) { + this._client.stop(); + } + } +} \ No newline at end of file diff --git a/dataprotocol-node/client/src/protocol.ts b/dataprotocol-node/client/src/protocol.ts new file mode 100644 index 0000000000..d59d3bced6 --- /dev/null +++ b/dataprotocol-node/client/src/protocol.ts @@ -0,0 +1,1601 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import { RequestType, NotificationType, ResponseError } from 'dataprotocol-jsonrpc'; + +import { + TextDocument, TextDocumentChangeEvent, TextDocumentContentChangeEvent, + Range, Position, Location, Diagnostic, DiagnosticSeverity, Command, + TextEdit, WorkspaceEdit, WorkspaceChange, TextEditChange, + TextDocumentIdentifier, VersionedTextDocumentIdentifier, TextDocumentItem, + CompletionItemKind, CompletionItem, CompletionList, + Hover, MarkedString, + SignatureHelp, SignatureInformation, ParameterInformation, + Definition, ReferenceContext, + DocumentHighlight, DocumentHighlightKind, + SymbolInformation, SymbolKind, + CodeLens, CodeActionContext, + FormattingOptions, DocumentLink, + ConnectionDetails, ServerInfo, + ConnectionSummary, ConnectionCompleteParams, IntelliSenseReadyParams, + ColumnMetadata, IDbColumn, + ConnectionProviderOptions, DataProtocolServerCapabilities, + CapabiltiesDiscoveryResult, MetadataQueryParams, MetadataQueryResult, + ScriptingParams, ScriptingResult, ScriptingCompleteParams, + BatchSummary, QueryExecuteBatchNotificationParams, ResultSetSummary, IResultMessage, ISelectionData, + DbCellValue, EditCell, EditRow, CreateSessionResponse, SessionCreatedParameters, ExpandParams, ExpandResponse, CloseSessionParams, CloseSessionResponse, + BackupInfo, BackupParams, BackupResponse, + RestoreParams, RestoreResponse, RestorePlanResponse, RestoreConfigInfoRequestParams, RestoreConfigInfoResponse, + LoginInfo, CreateLoginParams, CreateLoginResponse, GetDatabaseInfoParams, GetDatabaseInfoResponse, + DatabaseInfo, BackupConfigInfo, CreateDatabaseParams, CreateDatabaseResponse, + TaskInfo, ListTasksParams, ListTasksResponse, CancelTaskParams, TaskProgressInfo, + DefaultDatabaseInfoParams, DefaultDatabaseInfoResponse, BackupConfigInfoResponse, FileBrowserOpenParams, FileBrowserOpenedParams, + FileBrowserCloseParams, FileBrowserExpandParams, FileBrowserValidateParams, + FileBrowserCloseResponse, FileBrowserExpandedParams, FileBrowserValidatedParams, + StartProfilingParams, StartProfilingResponse, StopProfilingParams, StopProfilingResponse, + ProfilerEventsAvailableParams +} from 'dataprotocol-languageserver-types'; + + +/** + * A parameter literal used in requests to pass a text document and a position inside that + * document. + */ +export interface TextDocumentPositionParams { + /** + * The text document. + */ + textDocument: TextDocumentIdentifier; + + /** + * The position inside the text document. + */ + position: Position; +} + + +//---- Initialize Method ---- + +/** + * Defines the capabilities provided by the client. + */ +export interface ClientCapabilities { +} + +/** + * Defines how the host (editor) should sync + * document changes to the language server. + */ +export enum TextDocumentSyncKind { + /** + * Documents should not be synced at all. + */ + None = 0, + + /** + * Documents are synced by always sending the full content + * of the document. + */ + Full = 1, + + /** + * Documents are synced by sending the full content on open. + * After that only incremental updates to the document are + * send. + */ + Incremental = 2 +} + +/** + * Completion options. + */ +export interface CompletionOptions { + /** + * The server provides support to resolve additional + * information for a completion item. + */ + resolveProvider?: boolean; + + /** + * The characters that trigger completion automatically. + */ + triggerCharacters?: string[]; +} + +/** + * Signature help options. + */ +export interface SignatureHelpOptions { + /** + * The characters that trigger signature help + * automatically. + */ + triggerCharacters?: string[]; +} + +/** + * Code Lens options. + */ +export interface CodeLensOptions { + /** + * Code lens has a resolve provider as well. + */ + resolveProvider?: boolean; +} + +/** + * Format document on type options + */ +export interface DocumentOnTypeFormattingOptions { + /** + * A character on which formatting should be triggered, like `}`. + */ + firstTriggerCharacter: string; + /** + * More trigger characters. + */ + moreTriggerCharacter?: string[] +} + +/** + * Document link options + */ +export interface DocumentLinkOptions { + /** + * Document links have a resolve provider as well. + */ + resolveProvider?: boolean; +} + +/** + * Defines the capabilities provided by a language + * server. + */ +export interface ServerCapabilities { + /** + * Defines how text documents are synced. + */ + textDocumentSync?: number; + /** + * The server provides hover support. + */ + hoverProvider?: boolean; + /** + * The server provides completion support. + */ + completionProvider?: CompletionOptions; + /** + * The server provides signature help support. + */ + signatureHelpProvider?: SignatureHelpOptions; + /** + * The server provides goto definition support. + */ + definitionProvider?: boolean; + /** + * The server provides find references support. + */ + referencesProvider?: boolean; + /** + * The server provides document highlight support. + */ + documentHighlightProvider?: boolean; + /** + * The server provides document symbol support. + */ + documentSymbolProvider?: boolean; + /** + * The server provides workspace symbol support. + */ + workspaceSymbolProvider?: boolean; + /** + * The server provides code actions. + */ + codeActionProvider?: boolean; + /** + * The server provides code lens. + */ + codeLensProvider?: CodeLensOptions; + /** + * The server provides document formatting. + */ + documentFormattingProvider?: boolean; + /** + * The server provides document range formatting. + */ + documentRangeFormattingProvider?: boolean; + /** + * The server provides document formatting on typing. + */ + documentOnTypeFormattingProvider?: DocumentOnTypeFormattingOptions; + /** + * The server provides rename support. + */ + renameProvider?: boolean; + /** + * The server provides document link support. + */ + documentLinkProvider?: DocumentLinkOptions; + + connectionProvider?: boolean; +} + +/** + * The initialize method is sent from the client to the server. + * It is send once as the first method after starting up the + * worker. The requests parameter is of type [InitializeParams](#InitializeParams) + * the response if of type [InitializeResult](#InitializeResult) of a Thenable that + * resolves to such. + */ +export namespace InitializeRequest { + export const type: RequestType = { get method() { return 'initialize'; } }; +} + +/** + * The initialize parameters + */ +export interface InitializeParams { + /** + * The process Id of the parent process that started + * the server. + */ + processId: number; + + /** + * The rootPath of the workspace. Is null + * if no folder is open. + */ + rootPath: string; + + /** + * The capabilities provided by the client (editor) + */ + capabilities: ClientCapabilities; + + /** + * User provided initialization options. + */ + initializationOptions?: any; + + /** + * The initial trace setting. If omitted trace is disabled ('off'). + */ + trace?: 'off' | 'messages' | 'verbose'; +} + +/** + * The result returned from an initilize request. + */ +export interface InitializeResult { + /** + * The capabilities the language server provides. + */ + capabilities: ServerCapabilities; +} + +/** + * The data type of the ResponseError if the + * initialize request fails. + */ +export interface InitializeError { + /** + * Indicates whether the client should retry to send the + * initilize request after showing the message provided + * in the {@link ResponseError} + */ + retry: boolean; +} + +//---- Shutdown Method ---- + +/** + * A shutdown request is sent from the client to the server. + * It is send once when the client descides to shutdown the + * server. The only notification that is sent after a shudown request + * is the exit event. + */ +export namespace ShutdownRequest { + export const type: RequestType = { get method() { return 'shutdown'; } }; +} + +//---- Exit Notification ---- + +/** + * The exit event is sent from the client to the server to + * ask the server to exit its process. + */ +export namespace ExitNotification { + export const type: NotificationType = { get method() { return 'exit'; } }; +} + +//---- Configuration notification ---- + +/** + * The configuration change notification is sent from the client to the server + * when the client's configuration has changed. The notification contains + * the changed configuration as defined by the language client. + */ +export namespace DidChangeConfigurationNotification { + export const type: NotificationType = { get method() { return 'workspace/didChangeConfiguration'; } }; +} + +/** + * The parameters of a change configuration notification. + */ +export interface DidChangeConfigurationParams { + /** + * The actual changed settings + */ + settings: any; +} + +//---- Message show and log notifications ---- + +/** + * The message type + */ +export enum MessageType { + /** + * An error message. + */ + Error = 1, + /** + * A warning message. + */ + Warning = 2, + /** + * An information message. + */ + Info = 3, + /** + * A log message. + */ + Log = 4 +} + +/** + * The parameters of a notification message. + */ +export interface ShowMessageParams { + /** + * The message type. See {@link MessageType} + */ + type: number; + + /** + * The actual message + */ + message: string; +} + +/** + * The show message notification is sent from a server to a client to ask + * the client to display a particular message in the user interface. + */ +export namespace ShowMessageNotification { + export const type: NotificationType = { get method() { return 'window/showMessage'; } }; +} + +export interface MessageActionItem { + /** + * A short title like 'Retry', 'Open Log' etc. + */ + title: string; +} + +export interface ShowMessageRequestParams { + /** + * The message type. See {@link MessageType} + */ + type: number; + + /** + * The actual message + */ + message: string; + + /** + * The message action items to present. + */ + actions?: MessageActionItem[]; +} + +/** + * The show message request is send from the server to the clinet to show a message + * and a set of options actions to the user. + */ +export namespace ShowMessageRequest { + export const type: RequestType = { get method() { return 'window/showMessageRequest'; } }; +} + +/** + * The log message notification is send from the server to the client to ask + * the client to log a particular message. + */ +export namespace LogMessageNotification { + export let type: NotificationType = { get method() { return 'window/logMessage'; } }; +} + +/** + * The log message parameters. + */ +export interface LogMessageParams { + /** + * The message type. See {@link MessageType} + */ + type: number; + + /** + * The actual message + */ + message: string; +} + +//---- Telemetry notification + +/** + * The telemetry event notification is send from the server to the client to ask + * the client to log telemetry data. + */ +export namespace TelemetryEventNotification { + export let type: NotificationType = { get method() { return 'telemetry/event'; } }; +} + +//---- Text document notifications ---- + +/** + * The parameters send in a open text document notification + */ +export interface DidOpenTextDocumentParams { + /** + * The document that was opened. + */ + textDocument: TextDocumentItem; +} + +/** + * The document open notification is sent from the client to the server to signal + * newly opened text documents. The document's truth is now managed by the client + * and the server must not try to read the document's truth using the document's + * uri. + */ +export namespace DidOpenTextDocumentNotification { + export const type: NotificationType = { get method() { return 'textDocument/didOpen'; } }; +} + +/** + * An event describing a change to a text document. If range and rangeLength are omitted + * the new text is considered to be the full content of the document. + */ +export interface TextDocumentContentChangeEvent { + /** + * The range of the document that changed. + */ + range?: Range; + + /** + * The length of the range that got replaced. + */ + rangeLength?: number; + + /** + * The new text of the document. + */ + text: string; +} + +/** + * The change text document notification's parameters. + */ +export interface DidChangeTextDocumentParams { + /** + * The document that did change. The version number points + * to the version after all provided content changes have + * been applied. + */ + textDocument: VersionedTextDocumentIdentifier; + + /** + * The actual content changes. + */ + contentChanges: TextDocumentContentChangeEvent[]; +} + +/** + * The document change notification is sent from the client to the server to signal + * changes to a text document. + */ +export namespace DidChangeTextDocumentNotification { + export const type: NotificationType = { get method() { return 'textDocument/didChange'; } }; +} + +/** + * The parameters send in a close text document notification + */ +export interface DidCloseTextDocumentParams { + /** + * The document that was closed. + */ + textDocument: TextDocumentIdentifier; +} + +/** + * The document close notification is sent from the client to the server when + * the document got closed in the client. The document's truth now exists + * where the document's uri points to (e.g. if the document's uri is a file uri + * the truth now exists on disk). + */ +export namespace DidCloseTextDocumentNotification { + export const type: NotificationType = { get method() { return 'textDocument/didClose'; } }; +} + +/** + * The parameters send in a save text document notification + */ +export interface DidSaveTextDocumentParams { + /** + * The document that was closed. + */ + textDocument: TextDocumentIdentifier; +} + +/** + * The document save notification is sent from the client to the server when + * the document got saved in the client. + */ +export namespace DidSaveTextDocumentNotification { + export const type: NotificationType = { get method() { return 'textDocument/didSave'; } }; +} + +//---- File eventing ---- + +/** + * The watched files notification is sent from the client to the server when + * the client detects changes to file watched by the lanaguage client. + */ +export namespace DidChangeWatchedFilesNotification { + export const type: NotificationType = { get method() { return 'workspace/didChangeWatchedFiles'; } }; +} + +/** + * The watched files change notification's parameters. + */ +export interface DidChangeWatchedFilesParams { + /** + * The actual file events. + */ + changes: FileEvent[]; +} + +/** + * The file event type + */ +export enum FileChangeType { + /** + * The file got created. + */ + Created = 1, + /** + * The file got changed. + */ + Changed = 2, + /** + * The file got deleted. + */ + Deleted = 3 +} + +/** + * An event describing a file change. + */ +export interface FileEvent { + /** + * The file's uri. + */ + uri: string; + /** + * The change type. + */ + type: number; +} + +//---- Diagnostic notification ---- + +/** + * Diagnostics notification are sent from the server to the client to signal + * results of validation runs. + */ +export namespace PublishDiagnosticsNotification { + export const type: NotificationType = { get method() { return 'textDocument/publishDiagnostics'; } }; +} + +/** + * The publish diagnostic notification's parameters. + */ +export interface PublishDiagnosticsParams { + /** + * The URI for which diagnostic information is reported. + */ + uri: string; + + /** + * An array of diagnostic information items. + */ + diagnostics: Diagnostic[]; +} + +//---- Completion Support -------------------------- + +/** + * Request to request completion at a given text document position. The request's + * parameter is of type [TextDocumentPosition](#TextDocumentPosition) the response + * is of type [CompletionItem[]](#CompletionItem) or [CompletionList](#CompletionList) + * or a Thenable that resolves to such. + */ +export namespace CompletionRequest { + export const type: RequestType = { get method() { return 'textDocument/completion'; } }; +} + +/** + * Request to resolve additional information for a given completion item.The request's + * parameter is of type [CompletionItem](#CompletionItem) the response + * is of type [CompletionItem](#CompletionItem) or a Thenable that resolves to such. + */ +export namespace CompletionResolveRequest { + export const type: RequestType = { get method() { return 'completionItem/resolve'; } }; +} + +//---- Hover Support ------------------------------- + +export type MarkedString = string | { language: string; value: string }; + +/** + * Request to request hover information at a given text document position. The request's + * parameter is of type [TextDocumentPosition](#TextDocumentPosition) the response is of + * type [Hover](#Hover) or a Thenable that resolves to such. + */ +export namespace HoverRequest { + export const type: RequestType = { get method() { return 'textDocument/hover'; } }; +} + +//---- SignatureHelp ---------------------------------- + +export namespace SignatureHelpRequest { + export const type: RequestType = { get method() { return 'textDocument/signatureHelp'; } }; +} + +//---- Goto Definition ------------------------------------- + + +/** + * A request to resolve the defintion location of a symbol at a given text + * document position. The request's parameter is of type [TextDocumentPosition] + * (#TextDocumentPosition) the response is of type [Definition](#Definition) or a + * Thenable that resolves to such. + */ +export namespace DefinitionRequest { + export const type: RequestType = { get method() { return 'textDocument/definition'; } }; +} + +//---- Reference Provider ---------------------------------- + +/** + * Parameters for a [ReferencesRequest](#ReferencesRequest). + */ +export interface ReferenceParams extends TextDocumentPositionParams { + context: ReferenceContext +} + +/** + * A request to resolve project-wide references for the symbol denoted + * by the given text document position. The request's parameter is of + * type [ReferenceParams](#ReferenceParams) the response is of type + * [Location[]](#Location) or a Thenable that resolves to such. + */ +export namespace ReferencesRequest { + export const type: RequestType = { get method() { return 'textDocument/references'; } }; +} + +//---- Document Highlight ---------------------------------- + +/** + * Request to resolve a [DocumentHighlight](#DocumentHighlight) for a given + * text document position. The request's parameter is of type [TextDocumentPosition] + * (#TextDocumentPosition) the request reponse is of type [DocumentHighlight[]] + * (#DocumentHighlight) or a Thenable that resolves to such. + */ +export namespace DocumentHighlightRequest { + export const type: RequestType = { get method() { return 'textDocument/documentHighlight'; } }; +} + +//---- Document Symbol Provider --------------------------- + +/** + * Parameters for a [DocumentSymbolRequest](#DocumentSymbolRequest). + */ +export interface DocumentSymbolParams { + /** + * The text document. + */ + textDocument: TextDocumentIdentifier; +} + +/** + * A request to list all symbols found in a given text document. The request's + * parameter is of type [TextDocumentIdentifier](#TextDocumentIdentifier) the + * response is of type [SymbolInformation[]](#SymbolInformation) or a Thenable + * that resolves to such. + */ +export namespace DocumentSymbolRequest { + export const type: RequestType = { get method() { return 'textDocument/documentSymbol'; } }; +} + +//---- Workspace Symbol Provider --------------------------- + +/** + * The parameters of a [WorkspaceSymbolRequest](#WorkspaceSymbolRequest). + */ +export interface WorkspaceSymbolParams { + /** + * A non-empty query string + */ + query: string; +} + +/** + * A request to list project-wide symbols matching the query string given + * by the [WorkspaceSymbolParams](#WorkspaceSymbolParams). The response is + * of type [SymbolInformation[]](#SymbolInformation) or a Thenable that + * resolves to such. + */ +export namespace WorkspaceSymbolRequest { + export const type: RequestType = { get method() { return 'workspace/symbol'; } }; +} + +//---- Code Action Provider ---------------------------------- + + + +/** + * Params for the CodeActionRequest + */ +export interface CodeActionParams { + /** + * The document in which the command was invoked. + */ + textDocument: TextDocumentIdentifier; + + /** + * The range for which the command was invoked. + */ + range: Range; + + /** + * Context carrying additional information. + */ + context: CodeActionContext; +} + +/** + * A request to provide commands for the given text document and range. + */ +export namespace CodeActionRequest { + export const type: RequestType = { get method() { return 'textDocument/codeAction'; } }; +} + +//---- Code Lens Provider ------------------------------------------- + +/** + * Params for the Code Lens request. + */ +export interface CodeLensParams { + /** + * The document to request code lens for. + */ + textDocument: TextDocumentIdentifier; +} + +/** + * A request to provide code lens for the given text document. + */ +export namespace CodeLensRequest { + export const type: RequestType = { get method() { return 'textDocument/codeLens'; } }; +} + +/** + * A request to resolve a command for a given code lens. + */ +export namespace CodeLensResolveRequest { + export const type: RequestType = { get method() { return 'codeLens/resolve'; } }; +} + +//---- Formatting ---------------------------------------------- + +export interface DocumentFormattingParams { + /** + * The document to format. + */ + textDocument: TextDocumentIdentifier; + + /** + * The format options + */ + options: FormattingOptions; +} + +/** + * A request to to format a whole document. + */ +export namespace DocumentFormattingRequest { + export const type: RequestType = { get method() { return 'textDocument/formatting'; } }; +} + +export interface DocumentRangeFormattingParams { + /** + * The document to format. + */ + textDocument: TextDocumentIdentifier; + + /** + * The range to format + */ + range: Range; + + /** + * The format options + */ + options: FormattingOptions; +} + +/** + * A request to to format a range in a document. + */ +export namespace DocumentRangeFormattingRequest { + export const type: RequestType = { get method() { return 'textDocument/rangeFormatting'; } }; +} + +export interface DocumentOnTypeFormattingParams { + /** + * The document to format. + */ + textDocument: TextDocumentIdentifier; + + /** + * The position at which this request was send. + */ + position: Position; + + /** + * The character that has been typed. + */ + ch: string; + + /** + * The format options. + */ + options: FormattingOptions; +} + +/** + * A request to format a document on type. + */ +export namespace DocumentOnTypeFormattingRequest { + export const type: RequestType = { get method() { return 'textDocument/onTypeFormatting'; } }; +} + +//---- Rename ---------------------------------------------- + +export interface RenameParams { + /** + * The document to format. + */ + textDocument: TextDocumentIdentifier; + + /** + * The position at which this request was send. + */ + position: Position; + + /** + * The new name of the symbol. If the given name is not valid the + * request must return a [ResponseError](#ResponseError) with an + * appropriate message set. + */ + newName: string; +} + +/** + * A request to rename a symbol. + */ +export namespace RenameRequest { + export const type: RequestType = { get method() { return 'textDocument/rename'; } }; +} + +//---- Document Links ---------------------------------------------- + +export interface DocumentLinkParams { + /** + * The document to provide document links for. + */ + textDocument: TextDocumentIdentifier; +} + +/** + * A request to provide document links + */ +export namespace DocumentLinkRequest { + export const type: RequestType = { get method() { return 'textDocument/documentLink'; } }; +} + +/** + * Request to resolve additional information for a given document link. The request's + * parameter is of type [DocumentLink](#DocumentLink) the response + * is of type [DocumentLink](#DocumentLink) or a Thenable that resolves to such. + */ +export namespace DocumentLinkResolveRequest { + export const type: RequestType = { get method() { return 'documentLink/resolve'; } }; +} + +//---- Refresh IntelliSense ---------------------------------------- + +/** + * Notification sent when the an IntelliSense cache invalidation is requested + */ +export namespace RebuildIntelliSenseNotification { + export const type: NotificationType = { get method(): string { return 'textDocument/rebuildIntelliSense'; } }; +} + +/** + * Rebuild IntelliSense notification parameters + */ +export class RebuildIntelliSenseParams { + /** + * URI identifying the text document + */ + public ownerUri: string; +} + +// ------------------------------- < Connect Request > ---------------------------------------------- + +/** + * Connection request message format + */ +export interface ConnectParams { + /** + * URI identifying the owner of the connection + */ + ownerUri: string; + + /** + * Details for creating the connection + */ + connection: ConnectionDetails; +} + + +// Connection request message callback declaration +export namespace ConnectionRequest { + export const type: RequestType = { get method(): string { return 'connection/connect'; } }; +} + +// ------------------------------- < Connection Complete Event > ------------------------------------ + + +export namespace ConnectionCompleteNotification { + export const type: NotificationType = { get method(): string { return 'connection/complete'; } }; +} + +// ------------------------------- < Connection Changed Event > ------------------------------------- + +/** + * Parameters for the ConnectionChanged notification. + */ +export class ConnectionChangedParams { + /** + * Owner URI of the connection that changed. + */ + public ownerUri: string; + + /** + * Summary of details containing any connection changes. + */ + public connection: ConnectionSummary; +} + +/** + * Connection changed event callback declaration. + */ +export namespace ConnectionChangedNotification { + export const type: NotificationType = { get method(): string { return 'connection/connectionchanged'; } }; +} + +// ------------------------------- < Disconnect Request > ------------------------------------------- + +// Disconnect request message format +export class DisconnectParams { + // URI identifying the owner of the connection + public ownerUri: string; +} + +// Disconnect response format +export type DisconnectResult = boolean; + +// Disconnect request message callback declaration +export namespace DisconnectRequest { + export const type: RequestType = { get method(): string { return 'connection/disconnect'; } }; +} + +// ------------------------------- < Cancel Connect Request > --------------------------------------- + + +// Cancel connect request message format +export class CancelConnectParams { + /** + * URI identifying the owner of the connection + */ + public ownerUri: string; +} + +// Cancel connect response format. +export type CancelConnectResult = boolean; + +// Cancel connect request message callback declaration +export namespace CancelConnectRequest { + export const type: RequestType = { get method(): string { return 'connection/cancelconnect'; } }; +} + +// ------------------------------- < Change Database Request > ------------------------------------- + +export class ChangeDatabaseParams { + public ownerUri: string; + public newDatabase: string; +} + +export namespace ChangeDatabaseRequest { + export const type: RequestType = { get method(): string { return 'connection/changedatabase'; } }; +} + +// ------------------------------- < List Databases Request > --------------------------------------- + +// List databases request format +export class ListDatabasesParams { + // Connection information to use for querying master + public ownerUri: string; +} + +// List databases response format +export class ListDatabasesResult { + public databaseNames: Array; +} + +// List databases request callback declaration +export namespace ListDatabasesRequest { + export const type: RequestType = { get method(): string { return 'connection/listdatabases'; } }; +} + +// Language Flavor Changed ================================================================================ + +/** + * Parameters to provide when sending a language flavor changed notification + */ +export interface DidChangeLanguageFlavorParams { + uri: string; + language: string; + flavor: string; +} + +// ------------------------------- < Language Flavor Changed Notification > --------------------------------------- +export namespace LanguageFlavorChangedNotification { + export const type: NotificationType = { get method(): string { return 'connection/languageflavorchanged'; } }; +} + +// ------------------------------- < Table Metadata Request > --------------------------------------- + +// Table metadata request format +export class TableMetadataParams { + // Connection information to use for querying master + public ownerUri: string; + + public schema: string; + + public objectName: string; +} + +// Table metadata response format +export class TableMetadataResult { + public columns: ColumnMetadata[]; +} + +// Table metadata request callback declaration +export namespace TableMetadataRequest { + export const type: RequestType = { get method(): string { return 'metadata/table'; } }; +} + +// ------------------------------- < View Metadata Request > --------------------------------------- + +// Table metadata request callback declaration +export namespace ViewMetadataRequest { + export const type: RequestType = { get method(): string { return 'metadata/view'; } }; +} + +/** + * Event sent when the language service is finished updating after a connection + */ +export namespace IntelliSenseReadyNotification { + export const type: NotificationType = { get method(): string { return 'textDocument/intelliSenseReady'; } }; +} + +// ------------------------------- < Capabilties Discovery Event > ------------------------------------ + +export class CapabiltiesDiscoveryParams { + public hostName: string; + + public hostVersion: string; +} + +export namespace CapabiltiesDiscoveryRequest { + export const type: RequestType = { get method(): string { return 'capabilities/list'; } }; +} + +// Query Execution ================================================================================ +// ------------------------------- < Query Cancellation Request > ------------------------------------ +export namespace QueryCancelRequest { + export const type: RequestType = { get method(): string { return 'query/cancel'; } }; +} + +export interface QueryCancelParams { + ownerUri: string; +} + +export interface QueryCancelResult { + messages: string; +} + +// ------------------------------- < Query Dispose Request > ------------------------------------ + +export namespace QueryDisposeRequest { + export const type: RequestType = { get method(): string { return 'query/dispose'; } }; +} + +/** + * Parameters to provide when disposing of a query + */ +export interface QueryDisposeParams { + ownerUri: string; +} + +/** + * Result received upon successful disposal of a query + */ +export interface QueryDisposeResult { +} + +// ------------------------------- < Query Execution Complete Notification > ------------------------------------ +export namespace QueryExecuteCompleteNotification { + export const type: NotificationType = { get method(): string { return 'query/complete'; } }; +} + +/** + * Result received upon successful execution of a query + */ +export interface QueryExecuteCompleteNotificationResult { + ownerUri: string; + batchSummaries: BatchSummary[]; +} + +// ------------------------------- < Query Batch Start Notification > ------------------------------------ +export namespace QueryExecuteBatchStartNotification { + export const type: NotificationType = { get method(): string { return 'query/batchStart'; } }; +} + +// ------------------------------- < Query Batch Complete Notification > ------------------------------------ +export namespace QueryExecuteBatchCompleteNotification { + export const type: NotificationType = { get method(): string { return 'query/batchComplete'; } }; +} + +// ------------------------------- < Query ResultSet Complete Notification > ------------------------------------ +export namespace QueryExecuteResultSetCompleteNotification { + export const type: NotificationType = { get method(): string { return 'query/resultSetComplete'; } }; +} + +export interface QueryExecuteResultSetCompleteNotificationParams { + resultSetSummary: ResultSetSummary; + ownerUri: string; +} + +// ------------------------------- < Query Message Notification > ------------------------------------ +export namespace QueryExecuteMessageNotification { + export const type: NotificationType = { get method(): string { return 'query/message'; } }; +} + +export class QueryExecuteMessageParams { + message: IResultMessage; + ownerUri: string; +} + +// ------------------------------- < Query Execution Request > ------------------------------------ +export namespace QueryExecuteRequest { + export const type: RequestType = { get method(): string { return 'query/executeDocumentSelection'; } }; +} + +export interface ExecutionPlanOptions { + includeEstimatedExecutionPlanXml?: boolean; + includeActualExecutionPlanXml?: boolean; +} + +export interface QueryExecuteParams { + ownerUri: string; + querySelection: ISelectionData; + executionPlanOptions?: ExecutionPlanOptions; +} + +export interface QueryExecuteResult { } + +// ------------------------------- < Query Results Request > ------------------------------------ +export namespace QueryExecuteSubsetRequest { + export const type: RequestType = { get method(): string { return 'query/subset'; } }; +} + +export interface QueryExecuteSubsetParams { + ownerUri: string; + batchIndex: number; + resultSetIndex: number; + rowsStartIndex: number; + rowsCount: number; +} + +export interface ResultSetSubset { + rowCount: number; + rows: DbCellValue[][]; +} + +export interface QueryExecuteSubsetResult { + message: string; + resultSubset: ResultSetSubset; +} + +// ------------------------------- < Execute Statement > ------------------------------------ +export interface QueryExecuteStatementParams { + ownerUri: string; + line: number; + column: number; +} + +export namespace QueryExecuteStatementRequest { + export const type: RequestType = { get method(): string { return 'query/executedocumentstatement'; } }; +} + +// --------------------------------- < Save Results as CSV Request > ------------------------------------------ +export interface SaveResultsRequestParams { + ownerUri: string; + filePath: string; + batchIndex: number; + resultSetIndex: number; + rowStartIndex: number; + rowEndIndex: number; + columnStartIndex: number; + columnEndIndex: number; + includeHeaders?: boolean; +} + +export class SaveResultRequestResult { + messages: string; +} +// save results in csv format +export namespace SaveResultsAsCsvRequest { + export const type: RequestType = { get method(): string { return 'query/saveCsv'; } }; +} +// --------------------------------- ------------------------------------------ + +// --------------------------------- < Save Results as JSON Request > ------------------------------------------ +// save results in json format +export namespace SaveResultsAsJsonRequest { + export const type: RequestType = { get method(): string { return 'query/saveJson'; } }; +} +// --------------------------------- ------------------------------------------ + +// --------------------------------- < Save Results as Excel Request > ------------------------------------------ +// save results in Excel format +export namespace SaveResultsAsExcelRequest { + export const type: RequestType = { get method(): string { return 'query/saveExcel'; } }; +} +// --------------------------------- ------------------------------------------ + +// ------------------------------- < Execute and Return > ----------------------------------- + +export interface SimpleExecuteParams { + queryString: string; + ownerUri: string; +} + +export interface SimpleExecuteResult { + rowCount: number; + columnInfo: IDbColumn[]; + rows: DbCellValue[][]; +} + +export namespace SimpleExecuteRequest { + export const type: RequestType = { get method(): string { return 'query/simpleexecute'; } }; +} + +// ------------------------------- < Execute String > ------------------------------------ +export interface QueryExecuteStringParams { + query: string; + ownerUri: string; +} + +export namespace QueryExecuteStringRequest { + export const type: RequestType = { get method(): string { return 'query/executeString'; } }; +} + +// ------------------------------- < Metadata Events > ------------------------------------ + +export namespace MetadataQueryRequest { + export const type: RequestType = { get method(): string { return 'metadata/list'; } }; +} + +// ------------------------------- < Scripting Events > ------------------------------------ + +export namespace ScriptingRequest { + export const type: RequestType = { get method(): string { return 'scripting/script'; } }; +} + +// ------------------------------- < Scripting Complete Event > ------------------------------------ + +export namespace ScriptingCompleteNotification { + export const type: NotificationType = { get method(): string { return 'scripting/scriptComplete'; } }; +} + + +// Edit Data ====================================================================================== +// Shared Interfaces -------------------------------------------------------------------------- +export interface EditSessionOperationParams { + ownerUri: string; +} + +export interface EditRowOperationParams extends EditSessionOperationParams { + rowId: number; +} + +export interface EditCellResult { + cell: EditCell; + isRowDirty: boolean; +} + +// edit/commit -------------------------------------------------------------------------------- +export namespace EditCommitRequest { + export const type: RequestType = { get method(): string { return 'edit/commit'; } }; +} +export interface EditCommitParams extends EditSessionOperationParams { } +export interface EditCommitResult { } + +// edit/createRow ----------------------------------------------------------------------------- +export namespace EditCreateRowRequest { + export const type: RequestType = { get method(): string { return 'edit/createRow'; } }; +} +export interface EditCreateRowParams extends EditSessionOperationParams { } +export interface EditCreateRowResult { + defaultValues: string[]; + newRowId: number; +} + +// edit/deleteRow ----------------------------------------------------------------------------- +export namespace EditDeleteRowRequest { + export const type: RequestType = { get method(): string { return 'edit/deleteRow'; } }; +} +export interface EditDeleteRowParams extends EditRowOperationParams { } +export interface EditDeleteRowResult { } + +// edit/dispose ------------------------------------------------------------------------------- +export namespace EditDisposeRequest { + export const type: RequestType = { get method(): string { return 'edit/dispose'; } }; +} +export interface EditDisposeParams extends EditSessionOperationParams { } +export interface EditDisposeResult { } + +// edit/initialize ---------------------------------------------------------------------------- +export namespace EditInitializeRequest { + export const type: RequestType = { get method(): string { return 'edit/initialize'; } }; +} +export interface EditInitializeFiltering { + LimitResults?: number; +} +export interface EditInitializeParams extends EditSessionOperationParams { + filters: EditInitializeFiltering; + objectName: string; + schemaName: string; + objectType: string; +} +export interface EditInitializeResult { } + +// edit/revertCell -------------------------------------------------------------------------------- +export namespace EditRevertCellRequest { + export const type: RequestType = { get method(): string { return 'edit/revertCell'; } }; +} +export interface EditRevertCellParams extends EditRowOperationParams { + columnId: number; +} +export interface EditRevertCellResult extends EditCellResult { +} + +// edit/revertRow ----------------------------------------------------------------------------- +export namespace EditRevertRowRequest { + export const type: RequestType = { get method(): string { return 'edit/revertRow'; } }; +} +export interface EditRevertRowParams extends EditRowOperationParams { } +export interface EditRevertRowResult { } + +// edit/sessionReady Event -------------------------------------------------------------------- +export namespace EditSessionReadyNotification { + export const type: NotificationType = { get method(): string { return 'edit/sessionReady'; } }; +} +export interface EditSessionReadyParams { + ownerUri: string; + success: boolean; + message: string; +} + +// edit/updateCell ---------------------------------------------------------------------------- +export namespace EditUpdateCellRequest { + export const type: RequestType = { get method(): string { return 'edit/updateCell'; } }; +} +export interface EditUpdateCellParams extends EditRowOperationParams { + columnId: number; + newValue: string; +} +export interface EditUpdateCellResult extends EditCellResult { } + +// edit/subset ------------------------------------------------------------------------------------ +export namespace EditSubsetRequest { + export const type: RequestType = { get method(): string { return 'edit/subset'; } }; +} +export interface EditSubsetParams extends EditSessionOperationParams { + rowStartIndex: number; + rowCount: number; +} +export interface EditSubsetResult { + rowCount: number; + subset: EditRow[]; +} + +// ------------------------------- < Object Explorer Events > ------------------------------------ + +export namespace ObjectExplorerCreateSessionRequest { + export const type: RequestType = { get method(): string { return 'objectexplorer/createsession'; } }; +} + +export namespace ObjectExplorerExpandRequest { + export const type: RequestType = { get method(): string { return 'objectexplorer/expand'; } }; +} + +export namespace ObjectExplorerRefreshRequest { + export const type: RequestType = { get method(): string { return 'objectexplorer/refresh'; } }; +} + +export namespace ObjectExplorerCloseSessionRequest { + export const type: RequestType = { get method(): string { return 'objectexplorer/closesession'; } }; +} + +// ------------------------------- < Object Explorer Events > ------------------------------------ + + +export namespace ObjectExplorerCreateSessionCompleteNotification { + export const type: NotificationType = { get method(): string { return 'objectexplorer/sessioncreated'; } }; +} + + +export namespace ObjectExplorerExpandCompleteNotification { + export const type: NotificationType = { get method(): string { return 'objectexplorer/expandCompleted'; } }; +} + +// ------------------------------- < Task Service Events > ------------------------------------ + +export namespace ListTasksRequest { + export const type: RequestType = { get method(): string { return 'tasks/listtasks'; } }; +} + +export namespace CancelTaskRequest { + export const type: RequestType = { get method(): string { return 'tasks/canceltask'; } }; +} + +// ------------------------------- < Task Service Events > ------------------------------------ + + +export namespace TaskStatusChangedNotification { + export const type: NotificationType = { get method(): string { return 'tasks/statuschanged'; } }; +} + +export namespace TaskCreatedNotification { + export const type: NotificationType = { get method(): string { return 'tasks/newtaskcreated'; } }; +} + +// ------------------------------- < Admin Service Events > ------------------------------------ + +export namespace CreateDatabaseRequest { + export const type: RequestType = { get method(): string { return 'admin/createdatabase'; } }; +} + +export namespace DefaultDatabaseInfoRequest { + export const type: RequestType = { get method(): string { return 'admin/defaultdatabaseinfo'; } }; +} + +export namespace CreateLoginRequest { + export const type: RequestType = { get method(): string { return 'admin/createlogin'; } }; +} + +export namespace GetDatabaseInfoRequest { + export const type: RequestType = { get method(): string { return 'admin/getdatabaseinfo'; } }; +} + +// ------------------------------- < Disaster Recovery Events > ------------------------------------ + +export namespace BackupRequest { + export const type: RequestType = { get method(): string { return 'disasterrecovery/backup'; } }; +} + +export namespace BackupConfigInfoRequest { + export const type: RequestType = { get method(): string { return 'disasterrecovery/backupconfiginfo'; } }; +} + +export namespace RestoreRequest { + export const type: RequestType = { get method(): string { return 'disasterrecovery/restore'; } }; +} + +export namespace RestorePlanRequest { + export const type: RequestType = { get method(): string { return 'disasterrecovery/restoreplan'; } }; +} + +export namespace CancelRestorePlanRequest { + export const type: RequestType = { get method(): string { return 'disasterrecovery/cancelrestoreplan'; } }; +} + +export namespace RestoreConfigInfoRequest { + export const type: RequestType = { get method(): string { return 'disasterrecovery/restoreconfiginfo'; } }; +} + +// ------------------------------- < File Browser Events > ------------------------------------ + +export namespace FileBrowserOpenRequest { + export const type: RequestType = { get method(): string { return 'filebrowser/open'; } }; +} + +export namespace FileBrowserOpenedNotification { + export const type: NotificationType = { get method(): string { return 'filebrowser/opencomplete'; } }; +} + +export namespace FileBrowserExpandRequest { + export const type: RequestType = { get method(): string { return 'filebrowser/expand'; } }; +} + +export namespace FileBrowserExpandedNotification { + export const type: NotificationType = { get method(): string { return 'filebrowser/expandcomplete'; } }; +} + +export namespace FileBrowserValidateRequest { + export const type: RequestType = { get method(): string { return 'filebrowser/validate'; } }; +} + +export namespace FileBrowserValidatedNotification { + export const type: NotificationType = { get method(): string { return 'filebrowser/validatecomplete'; } }; +} + +export namespace FileBrowserCloseRequest { + export const type: RequestType = { get method(): string { return 'filebrowser/close'; } }; +} + + +// ------------------------------- < Profiler Events > ------------------------------------ + +export namespace StartProfilingRequest { + export const type: RequestType = { get method(): string { return 'profiler/start'; } }; +} + +export namespace StopProfilingRequest { + export const type: RequestType = { get method(): string { return 'profiler/stop'; } }; +} +export namespace ProfilerEventsAvailableNotification { + export const type: NotificationType = { get method(): string { return 'profiler/eventsavailable'; } }; +} diff --git a/dataprotocol-node/client/src/protocolCodeLens.ts b/dataprotocol-node/client/src/protocolCodeLens.ts new file mode 100644 index 0000000000..9dbd4a4bf9 --- /dev/null +++ b/dataprotocol-node/client/src/protocolCodeLens.ts @@ -0,0 +1,16 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import * as code from 'vscode'; + +export default class ProtocolCodeLens extends code.CodeLens { + + public data: any; + + constructor(range: code.Range) { + super(range); + } +} \ No newline at end of file diff --git a/dataprotocol-node/client/src/protocolCompletionItem.ts b/dataprotocol-node/client/src/protocolCompletionItem.ts new file mode 100644 index 0000000000..120f7a605b --- /dev/null +++ b/dataprotocol-node/client/src/protocolCompletionItem.ts @@ -0,0 +1,16 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import * as code from 'vscode'; + +export default class ProtocolCompletionItem extends code.CompletionItem { + + public data: any; + + constructor(label: string) { + super(label); + } +} \ No newline at end of file diff --git a/dataprotocol-node/client/src/protocolConverter.ts b/dataprotocol-node/client/src/protocolConverter.ts new file mode 100644 index 0000000000..b3708fd84d --- /dev/null +++ b/dataprotocol-node/client/src/protocolConverter.ts @@ -0,0 +1,769 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import * as code from 'vscode'; +import * as data from 'data'; +import * as ls from 'dataprotocol-languageserver-types'; +import * as is from './utils/is'; +import ProtocolCompletionItem from './protocolCompletionItem'; +import ProtocolCodeLens from './protocolCodeLens'; + +export interface Converter { + + asUri(value: string): code.Uri; + + asDiagnostics(diagnostics: ls.Diagnostic[]): code.Diagnostic[]; + + asDiagnostic(diagnostic: ls.Diagnostic): code.Diagnostic; + + asRange(value: ls.Range): code.Range; + + asPosition(value: ls.Position): code.Position; + + asDiagnosticSeverity(value: number): code.DiagnosticSeverity; + + asHover(hover: ls.Hover): code.Hover; + + asCompletionResult(result: ls.CompletionItem[] | ls.CompletionList): code.CompletionItem[] | code.CompletionList + + asCompletionItem(item: ls.CompletionItem): ProtocolCompletionItem; + + asTextEdit(edit: ls.TextEdit): code.TextEdit; + + asTextEdits(items: ls.TextEdit[]): code.TextEdit[]; + + asSignatureHelp(item: ls.SignatureHelp): code.SignatureHelp; + + asSignatureInformations(items: ls.SignatureInformation[]): code.SignatureInformation[]; + + asSignatureInformation(item: ls.SignatureInformation): code.SignatureInformation; + + asParameterInformations(item: ls.ParameterInformation[]): code.ParameterInformation[]; + + asParameterInformation(item: ls.ParameterInformation): code.ParameterInformation; + + asDefinitionResult(item: ls.Definition): code.Definition; + + asLocation(item: ls.Location): code.Location; + + asReferences(values: ls.Location[]): code.Location[]; + + asDocumentHighlights(values: ls.DocumentHighlight[]): code.DocumentHighlight[]; + + asDocumentHighlight(item: ls.DocumentHighlight): code.DocumentHighlight; + + asDocumentHighlightKind(item: ls.DocumentHighlightKind): code.DocumentHighlightKind; + + asSymbolInformations(values: ls.SymbolInformation[], uri?: code.Uri): code.SymbolInformation[]; + + asSymbolInformation(item: ls.SymbolInformation, uri?: code.Uri): code.SymbolInformation; + + asCommand(item: ls.Command): code.Command; + + asCommands(items: ls.Command[]): code.Command[]; + + asCodeLens(item: ls.CodeLens): code.CodeLens; + + asCodeLenses(items: ls.CodeLens[]): code.CodeLens[]; + + asWorkspaceEdit(item: ls.WorkspaceEdit): code.WorkspaceEdit; + + asDocumentLink(item: ls.DocumentLink): code.DocumentLink; + + asDocumentLinks(items: ls.DocumentLink[]): code.DocumentLink[]; + + asConnectionSummary(params: ls.ConnectionCompleteParams): data.ConnectionInfoSummary; + + asServerCapabilities(params: ls.CapabiltiesDiscoveryResult): data.DataProtocolServerCapabilities; + + asProviderMetadata(params: ls.MetadataQueryResult): data.ProviderMetadata; + + asScriptingResult(params: ls.ScriptingResult): data.ScriptingResult; + + asObjectExplorerSession(params: ls.SessionCreatedParameters): data.ObjectExplorerSession; + + asObjectExplorerCreateSessionResponse(params: ls.CreateSessionResponse): data.ObjectExplorerSessionResponse; + + asObjectExplorerNodeInfo(params: ls.ExpandResponse): data.ObjectExplorerExpandInfo; + + asObjectExplorerCloseSessionResponse(params: ls.CloseSessionResponse): data.ObjectExplorerCloseSessionResponse; + + asListTasksResponse(response: ls.ListTasksResponse): data.ListTasksResponse; + + asTaskInfo(params: ls.TaskInfo): data.TaskInfo; + + asRestorePlanResponse(params: ls.RestorePlanResponse): data.RestorePlanResponse; + + asRestoreResponse(params: ls.RestoreResponse): data.RestoreResponse; + + asRestoreConfigInfo(params: ls.RestoreConfigInfoResponse): data.RestoreConfigInfo; +} + +export interface URIConverter { + (value: string): code.Uri; +} + +export function createConverter(uriConverter?: URIConverter): Converter { + + const nullConverter = (value: string) => code.Uri.parse(value); + + const _uriConverter: URIConverter = uriConverter || nullConverter; + + function asUri(value: string): code.Uri { + return _uriConverter(value); + } + + function asDiagnostics(diagnostics: ls.Diagnostic[]): code.Diagnostic[] { + return diagnostics.map(asDiagnostic); + } + + function asDiagnostic(diagnostic: ls.Diagnostic): code.Diagnostic { + let result = new code.Diagnostic(asRange(diagnostic.range), diagnostic.message, asDiagnosticSeverity(diagnostic.severity)); + if (is.defined(diagnostic.code)) { + result.code = diagnostic.code; + } + if (is.defined(diagnostic.source)) { + result.source = diagnostic.source; + } + return result; + } + + function asRange(value: ls.Range): code.Range { + if (is.undefined(value)) { + return undefined; + } else if (is.nil(value)) { + return null; + } + return new code.Range(asPosition(value.start), asPosition(value.end)); + } + + function asPosition(value: ls.Position): code.Position { + if (is.undefined(value)) { + return undefined; + } else if (is.nil(value)) { + return null; + } + return new code.Position(value.line, value.character); + } + + function asDiagnosticSeverity(value: number): code.DiagnosticSeverity { + if (is.undefined(value) || is.nil(value)) { + return code.DiagnosticSeverity.Error; + } + switch (value) { + case ls.DiagnosticSeverity.Error: + return code.DiagnosticSeverity.Error; + case ls.DiagnosticSeverity.Warning: + return code.DiagnosticSeverity.Warning; + case ls.DiagnosticSeverity.Information: + return code.DiagnosticSeverity.Information; + case ls.DiagnosticSeverity.Hint: + return code.DiagnosticSeverity.Hint; + } + return code.DiagnosticSeverity.Error; + } + + function asHover(hover: ls.Hover): code.Hover { + if (is.undefined(hover)) { + return undefined; + } + if (is.nil(hover)) { + return null; + } + if (is.nil(hover.contents) || is.undefined(hover.contents)) { + // Contents must be defined or hover will throw + return null; + } + return new code.Hover(hover.contents, is.defined(hover.range) ? asRange(hover.range) : undefined); + } + + function asCompletionResult(result: ls.CompletionItem[] | ls.CompletionList): code.CompletionItem[] | code.CompletionList { + if (is.undefined(result)) { + return undefined; + } else if (is.nil(result)) { + return null; + } + if (Array.isArray(result)) { + let items = result; + return items.map(asCompletionItem); + } + let list = result; + return new code.CompletionList(list.items.map(asCompletionItem), list.isIncomplete); + } + + function set(value: T, func: () => void): void { + if (is.defined(value)) { + func(); + } + } + + function asCompletionItem(item: ls.CompletionItem): ProtocolCompletionItem { + let result = new ProtocolCompletionItem(item.label); + set(item.detail, () => result.detail = item.detail); + set(item.documentation, () => result.documentation = item.documentation); + set(item.filterText, () => result.filterText = item.filterText); + set(item.insertText, () => result.insertText = item.insertText); + // Protocol item kind is 1 based, codes item kind is zero based. + set(item.kind, () => result.kind = item.kind - 1); + set(item.sortText, () => result.sortText = item.sortText); + set(item.textEdit, () => result.textEdit = asTextEdit(item.textEdit)); + set(item.additionalTextEdits, () => result.additionalTextEdits = asTextEdits(item.additionalTextEdits)); + set(item.command, () => result.command = asCommand(item.command)); + set(item.data, () => result.data = item.data); + return result; + } + + function asTextEdit(edit: ls.TextEdit): code.TextEdit { + return new code.TextEdit(asRange(edit.range), edit.newText); + } + + function asTextEdits(items: ls.TextEdit[]): code.TextEdit[] { + if (is.undefined(items)) { + return undefined; + } else if (is.nil(items)) { + return null; + } + return items.map(asTextEdit); + } + + function asSignatureHelp(item: ls.SignatureHelp): code.SignatureHelp { + if (is.undefined(item)) { + return undefined; + } else if (is.nil(item)) { + return null; + } + let result = new code.SignatureHelp(); + set(item.activeParameter, () => result.activeParameter = item.activeParameter); + set(item.activeSignature, () => result.activeSignature = item.activeSignature); + set(item.signatures, () => result.signatures = asSignatureInformations(item.signatures)); + return result; + } + + function asSignatureInformations(items: ls.SignatureInformation[]): code.SignatureInformation[] { + return items ? items.map(asSignatureInformation) : undefined; + } + + function asSignatureInformation(item: ls.SignatureInformation): code.SignatureInformation { + if (!item) { + return undefined; + } + let result = new code.SignatureInformation(item.label); + set(item.documentation, () => result.documentation = item.documentation); + set(item.parameters, () => result.parameters = asParameterInformations(item.parameters)); + return result; + } + + function asParameterInformations(item: ls.ParameterInformation[]): code.ParameterInformation[] { + return item.map(asParameterInformation); + } + + function asParameterInformation(item: ls.ParameterInformation): code.ParameterInformation { + let result = new code.ParameterInformation(item.label); + set(item.documentation, () => result.documentation = item.documentation); + return result; + } + + function asDefinitionResult(item: ls.Definition): code.Definition { + if (is.undefined(item)) { + return undefined; + } else if (is.nil(item)) { + return null; + } + if (is.array(item)) { + return item.map(asLocation); + } else { + return asLocation(item); + } + } + + function asLocation(item: ls.Location): code.Location { + if (is.undefined(item)) { + return undefined; + } + if (is.nil(item)) { + return null; + } + return new code.Location(_uriConverter(item.uri), asRange(item.range)); + } + + function asReferences(values: ls.Location[]): code.Location[] { + if (is.undefined(values)) { + return undefined; + } + if (is.nil(values)) { + return null; + } + return values.map(asLocation); + } + + function asDocumentHighlights(values: ls.DocumentHighlight[]): code.DocumentHighlight[] { + if (is.undefined(values)) { + return undefined; + } + if (is.nil(values)) { + return null; + } + return values.map(asDocumentHighlight); + } + + function asDocumentHighlight(item: ls.DocumentHighlight): code.DocumentHighlight { + let result = new code.DocumentHighlight(asRange(item.range)); + set(item.kind, () => result.kind = asDocumentHighlightKind(item.kind)); + return result; + } + + function asDocumentHighlightKind(item: ls.DocumentHighlightKind): code.DocumentHighlightKind { + switch (item) { + case ls.DocumentHighlightKind.Text: + return code.DocumentHighlightKind.Text; + case ls.DocumentHighlightKind.Read: + return code.DocumentHighlightKind.Read; + case ls.DocumentHighlightKind.Write: + return code.DocumentHighlightKind.Write; + } + return code.DocumentHighlightKind.Text; + } + + function asSymbolInformations(values: ls.SymbolInformation[], uri?: code.Uri): code.SymbolInformation[] { + if (is.undefined(values)) { + return undefined; + } + if (is.nil(values)) { + return null; + } + return values.map(information => asSymbolInformation(information, uri)); + } + + function asSymbolInformation(item: ls.SymbolInformation, uri?: code.Uri): code.SymbolInformation { + // Symbol kind is one based in the protocol and zero based in code. + let result = new code.SymbolInformation( + item.name, item.kind - 1, + asRange(item.location.range), + item.location.uri ? _uriConverter(item.location.uri) : uri); + set(item.containerName, () => result.containerName = item.containerName); + return result; + } + + function asCommand(item: ls.Command): code.Command { + let result: code.Command = { title: item.title, command: item.command }; + set(item.arguments, () => result.arguments = item.arguments); + return result; + } + + function asCommands(items: ls.Command[]): code.Command[] { + if (is.undefined(items)) { + return undefined; + } + if (is.nil(items)) { + return null; + } + return items.map(asCommand); + } + + function asCodeLens(item: ls.CodeLens): code.CodeLens { + let result: ProtocolCodeLens = new ProtocolCodeLens(asRange(item.range)); + if (is.defined(item.command)) { result.command = asCommand(item.command); } + if (is.defined(item.data)) { result.data = item.data; } + return result; + } + + function asCodeLenses(items: ls.CodeLens[]): code.CodeLens[] { + if (is.undefined(items)) { + return undefined; + } + if (is.nil(items)) { + return null; + } + return items.map(asCodeLens); + } + + function asWorkspaceEdit(item: ls.WorkspaceEdit): code.WorkspaceEdit { + if (is.undefined(item)) { + return undefined; + } + if (is.nil(item)) { + return null; + } + let result = new code.WorkspaceEdit(); + let keys = Object.keys(item.changes); + keys.forEach(key => result.set(_uriConverter(key), asTextEdits(item.changes[key]))); + return result; + } + + function asDocumentLink(item: ls.DocumentLink): code.DocumentLink { + let range = asRange(item.range); + let target = is.defined(item.target) && asUri(item.target); + return new code.DocumentLink(range, target); + } + + function asDocumentLinks(items: ls.DocumentLink[]): code.DocumentLink[] { + if (is.undefined(items)) { + return undefined; + } + if (is.nil(items)) { + return null; + } + return items.map(asDocumentLink); + } + + function asConnectionSummary(params: ls.ConnectionCompleteParams): data.ConnectionInfoSummary { + let connSummary: data.ConnectionInfoSummary = { + ownerUri: params.ownerUri, + connectionId: params.connectionId, + messages: params.messages, + errorMessage: params.errorMessage, + errorNumber: params.errorNumber, + serverInfo: params.serverInfo, + connectionSummary: params.connectionSummary + }; + return connSummary; + } + + function asServiceOptionType(val: string): data.ServiceOptionType { + if (val === 'string') { + return data.ServiceOptionType.string; + } else if (val === 'multistring') { + return data.ServiceOptionType.multistring; + } else if (val === 'password') { + return data.ServiceOptionType.password; + } else if (val === 'number') { + return data.ServiceOptionType.number; + } else if (val === 'boolean') { + return data.ServiceOptionType.boolean; + } else if (val === 'category') { + return data.ServiceOptionType.category; + } else if (val === 'object') { + return data.ServiceOptionType.object; + } + + // assume string for unknown value types + return data.ServiceOptionType.string; + } + + function asServerCapabilities(result: ls.CapabiltiesDiscoveryResult): data.DataProtocolServerCapabilities { + let capabilities: data.DataProtocolServerCapabilities = { + protocolVersion: result.capabilities.protocolVersion, + providerName: result.capabilities.providerName, + providerDisplayName: result.capabilities.providerDisplayName, + connectionProvider: undefined, + adminServicesProvider: undefined, + features: [] + }; + + if (result.capabilities.adminServicesProvider) { + capabilities.adminServicesProvider = { + databaseInfoOptions: new Array(), + databaseFileInfoOptions: new Array(), + fileGroupInfoOptions: new Array() + }; + + if (result.capabilities.adminServicesProvider.databaseInfoOptions + && result.capabilities.adminServicesProvider.databaseInfoOptions.length > 0) { + for (let i = 0; i < result.capabilities.adminServicesProvider.databaseInfoOptions.length; ++i) { + let srcOption: ls.ServiceOption = result.capabilities.adminServicesProvider.databaseInfoOptions[i]; + let descOption: data.ServiceOption = buildServiceOption(srcOption); + capabilities.adminServicesProvider.databaseInfoOptions.push(descOption); + } + } + + if (result.capabilities.adminServicesProvider.databaseFileInfoOptions + && result.capabilities.adminServicesProvider.databaseFileInfoOptions.length > 0) { + for (let i = 0; i < result.capabilities.adminServicesProvider.databaseFileInfoOptions.length; ++i) { + let srcOption: ls.ServiceOption = result.capabilities.adminServicesProvider.databaseFileInfoOptions[i]; + let descOption: data.ServiceOption = buildServiceOption(srcOption); + capabilities.adminServicesProvider.databaseFileInfoOptions.push(descOption); + } + } + + if (result.capabilities.adminServicesProvider.fileGroupInfoOptions + && result.capabilities.adminServicesProvider.fileGroupInfoOptions.length > 0) { + for (let i = 0; i < result.capabilities.adminServicesProvider.fileGroupInfoOptions.length; ++i) { + let srcOption: ls.ServiceOption = result.capabilities.adminServicesProvider.fileGroupInfoOptions[i]; + let descOption: data.ServiceOption = buildServiceOption(srcOption); + capabilities.adminServicesProvider.fileGroupInfoOptions.push(descOption); + } + } + } + + if (result.capabilities.connectionProvider + && result.capabilities.connectionProvider.options + && result.capabilities.connectionProvider.options.length > 0) { + capabilities.connectionProvider = { + options: new Array() + }; + for (let i = 0; i < result.capabilities.connectionProvider.options.length; ++i) { + let srcOption: ls.ConnectionOption = result.capabilities.connectionProvider.options[i]; + let descOption: data.ConnectionOption = { + name: srcOption.name, + displayName: srcOption.displayName ? srcOption.displayName : srcOption.name, + description: srcOption.description, + groupName: srcOption.groupName, + defaultValue: srcOption.defaultValue, + categoryValues: srcOption.categoryValues, + isIdentity: srcOption.isIdentity, + isRequired: srcOption.isRequired, + valueType: asServiceOptionType(srcOption.valueType), + specialValueType: undefined + }; + + if (srcOption.specialValueType === 'serverName') { + descOption.specialValueType = data.ConnectionOptionSpecialType.serverName; + } else if (srcOption.specialValueType === 'databaseName') { + descOption.specialValueType = data.ConnectionOptionSpecialType.databaseName; + } else if (srcOption.specialValueType === 'authType') { + descOption.specialValueType = data.ConnectionOptionSpecialType.authType; + } else if (srcOption.specialValueType === 'userName') { + descOption.specialValueType = data.ConnectionOptionSpecialType.userName; + } else if (srcOption.specialValueType === 'password') { + descOption.specialValueType = data.ConnectionOptionSpecialType.password; + } else if (srcOption.specialValueType === 'appName') { + descOption.specialValueType = data.ConnectionOptionSpecialType.appName; + } + + capabilities.connectionProvider.options.push(descOption); + } + } + + if (result.capabilities.features + && result.capabilities.features.length > 0) { + result.capabilities.features.forEach(feature => { + let descFeature: data.FeatureMetadataProvider = { + enabled: feature.enabled, + featureName: feature.featureName, + optionsMetadata: [] + }; + capabilities.features.push(descFeature); + if (feature.optionsMetadata) { + feature.optionsMetadata.forEach(srcOption => { + descFeature.optionsMetadata.push(buildServiceOption(srcOption)); + }); + } + }); + } + + return capabilities; + } + + function buildServiceOption(srcOption: ls.ServiceOption): data.ServiceOption { + return { + name: srcOption.name, + displayName: srcOption.displayName ? srcOption.displayName : srcOption.name, + description: srcOption.description, + groupName: srcOption.groupName, + defaultValue: srcOption.defaultValue, + categoryValues: srcOption.categoryValues, + isRequired: srcOption.isRequired, + isArray: srcOption.isArray, + objectType: srcOption.objectType, + valueType: asServiceOptionType(srcOption.valueType), + }; + } + + function asProviderMetadata(params: ls.MetadataQueryResult): data.ProviderMetadata { + let objectMetadata: data.ObjectMetadata[] = []; + + if (!params.metadata || !params.metadata.length) { + return { + objectMetadata: objectMetadata + }; + } + + for (let i = 0; i < params.metadata.length; ++i) { + let metadata: ls.ObjectMetadata = params.metadata[i]; + + let metadataTypeName: string; + if (metadata.metadataTypeName) { + // Read from the provider since it's defined + metadataTypeName = metadata.metadataTypeName; + } else if (metadata.metadataType === ls.MetadataType.View) { + metadataTypeName = 'View'; + } else if (metadata.metadataType === ls.MetadataType.SProc) { + metadataTypeName = 'StoredProcedure'; + } else if (metadata.metadataType === ls.MetadataType.Function) { + metadataTypeName = 'Function'; + } else { + metadataTypeName = 'Table'; + } + + objectMetadata.push({ + metadataTypeName: metadataTypeName, + metadataType: metadata.metadataType, + name: metadata.name, + schema: metadata.schema, + urn: metadata.urn + }); + } + + return { + objectMetadata: objectMetadata + }; + } + + function asObjectExplorerSession(params: ls.SessionCreatedParameters): data.ObjectExplorerSession { + return { + success: params.success, + sessionId: params.sessionId, + rootNode: params.rootNode, + errorMessage: params.errorMessage + }; + } + + function asObjectExplorerCreateSessionResponse(params: ls.CreateSessionResponse): data.ObjectExplorerSessionResponse { + return { + sessionId: params.sessionId + }; + } + + function asObjectExplorerNodeInfo(params: ls.ExpandResponse): data.ObjectExplorerExpandInfo { + return { + sessionId: params.sessionId, + nodes: params.nodes, + errorMessage: params.errorMessage, + nodePath: params.nodePath + }; + } + + function asObjectExplorerCloseSessionResponse(params: ls.CloseSessionResponse): data.ObjectExplorerCloseSessionResponse { + return { + sessionId: params.sessionId, + success: params.success + }; + } + + function asScriptingResult(params: ls.ScriptingResult): data.ScriptingResult { + return { + operationId: params.operationId, + script: params.script + }; + } + + function asListTasksResponse(response: ls.ListTasksResponse): data.ListTasksResponse { + return { + tasks: response.tasks + }; + } + + function asTaskInfo(params: ls.TaskInfo): data.TaskInfo { + return { + taskId: params.taskId, + status: params.status, + taskExecutionMode: params.taskExecutionMode, + serverName: params.serverName, + name: params.name, + databaseName: params.databaseName, + description: params.description, + providerName: params.providerName, + isCancelable: params.isCancelable, + }; + } + + function asRestorePlanResponse(params: ls.RestorePlanResponse): data.RestorePlanResponse { + return { + backupSetsToRestore: params.backupSetsToRestore, + canRestore: params.canRestore, + databaseNamesFromBackupSets: params.databaseNamesFromBackupSets, + dbFiles: params.dbFiles, + errorMessage: params.errorMessage, + planDetails: params.planDetails, + sessionId: params.sessionId + }; + } + + function asRestoreResponse(params: ls.RestoreResponse): data.RestoreResponse { + return { + result: params.result, + errorMessage: params.errorMessage, + taskId: params.taskId + }; + } + + function asRestoreConfigInfo(params: ls.RestoreConfigInfoResponse): data.RestoreConfigInfo { + return { + configInfo: params.configInfo + }; + } + + return { + asUri, + asDiagnostics, + asDiagnostic, + asRange, + asPosition, + asDiagnosticSeverity, + asHover, + asCompletionResult, + asCompletionItem, + asTextEdit, + asTextEdits, + asSignatureHelp, + asSignatureInformations, + asSignatureInformation, + asParameterInformations, + asParameterInformation, + asDefinitionResult, + asLocation, + asReferences, + asDocumentHighlights, + asDocumentHighlight, + asDocumentHighlightKind, + asSymbolInformations, + asSymbolInformation, + asCommand, + asCommands, + asCodeLens, + asCodeLenses, + asWorkspaceEdit, + asDocumentLink, + asDocumentLinks, + asConnectionSummary, + asServerCapabilities, + asProviderMetadata, + asScriptingResult, + asObjectExplorerSession, + asObjectExplorerCreateSessionResponse, + asObjectExplorerNodeInfo, + asObjectExplorerCloseSessionResponse, + asListTasksResponse, + asTaskInfo, + asRestorePlanResponse, + asRestoreResponse, + asRestoreConfigInfo + }; +} + +// This for backward compatibility since we exported the converter functions as API. +const defaultConverter = createConverter(); + +export const asDiagnostics: (diagnostics: ls.Diagnostic[]) => code.Diagnostic[] = defaultConverter.asDiagnostics; +export const asDiagnostic: (diagnostic: ls.Diagnostic) => code.Diagnostic = defaultConverter.asDiagnostic; +export const asRange: (value: ls.Range) => code.Range = defaultConverter.asRange; +export const asPosition: (value: ls.Position) => code.Position = defaultConverter.asPosition; +export const asDiagnosticSeverity: (value: number) => code.DiagnosticSeverity = defaultConverter.asDiagnosticSeverity; +export const asHover: (hover: ls.Hover) => code.Hover = defaultConverter.asHover; +export const asCompletionResult: (result: ls.CompletionItem[] | ls.CompletionList) => code.CompletionItem[] | code.CompletionList = defaultConverter.asCompletionResult; +export const asCompletionItem: (item: ls.CompletionItem) => ProtocolCompletionItem = defaultConverter.asCompletionItem; +export const asTextEdit: (edit: ls.TextEdit) => code.TextEdit = defaultConverter.asTextEdit; +export const asTextEdits: (items: ls.TextEdit[]) => code.TextEdit[] = defaultConverter.asTextEdits; +export const asSignatureHelp: (item: ls.SignatureHelp) => code.SignatureHelp = defaultConverter.asSignatureHelp; +export const asSignatureInformations: (items: ls.SignatureInformation[]) => code.SignatureInformation[] = defaultConverter.asSignatureInformations; +export const asSignatureInformation: (item: ls.SignatureInformation) => code.SignatureInformation = defaultConverter.asSignatureInformation; +export const asParameterInformations: (item: ls.ParameterInformation[]) => code.ParameterInformation[] = defaultConverter.asParameterInformations; +export const asParameterInformation: (item: ls.ParameterInformation) => code.ParameterInformation = defaultConverter.asParameterInformation; +export const asDefinitionResult: (item: ls.Definition) => code.Definition = defaultConverter.asDefinitionResult; +export const asLocation: (item: ls.Location) => code.Location = defaultConverter.asLocation; +export const asReferences: (values: ls.Location[]) => code.Location[] = defaultConverter.asReferences; +export const asDocumentHighlights: (values: ls.DocumentHighlight[]) => code.DocumentHighlight[] = defaultConverter.asDocumentHighlights; +export const asDocumentHighlight: (item: ls.DocumentHighlight) => code.DocumentHighlight = defaultConverter.asDocumentHighlight; +export const asDocumentHighlightKind: (item: ls.DocumentHighlightKind) => code.DocumentHighlightKind = defaultConverter.asDocumentHighlightKind; +export const asSymbolInformations: (values: ls.SymbolInformation[], uri?: code.Uri) => code.SymbolInformation[] = defaultConverter.asSymbolInformations; +export const asSymbolInformation: (item: ls.SymbolInformation, uri?: code.Uri) => code.SymbolInformation = defaultConverter.asSymbolInformation; +export const asCommand: (item: ls.Command) => code.Command = defaultConverter.asCommand; +export const asCommands: (items: ls.Command[]) => code.Command[] = defaultConverter.asCommands; +export const asCodeLens: (item: ls.CodeLens) => code.CodeLens = defaultConverter.asCodeLens; +export const asCodeLenses: (items: ls.CodeLens[]) => code.CodeLens[] = defaultConverter.asCodeLenses; +export const asWorkspaceEdit: (item: ls.WorkspaceEdit) => code.WorkspaceEdit = defaultConverter.asWorkspaceEdit; +export const asDocumentLink: (item: ls.DocumentLink) => code.DocumentLink = defaultConverter.asDocumentLink; +export const asDocumentLinks: (item: ls.DocumentLink[]) => code.DocumentLink[] = defaultConverter.asDocumentLinks; \ No newline at end of file diff --git a/dataprotocol-client/src/tsconfig.json b/dataprotocol-node/client/src/tsconfig.json similarity index 90% rename from dataprotocol-client/src/tsconfig.json rename to dataprotocol-node/client/src/tsconfig.json index cc92c023fc..79b9f99c48 100644 --- a/dataprotocol-client/src/tsconfig.json +++ b/dataprotocol-node/client/src/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es6", + "target": "es5", "module": "commonjs", "moduleResolution": "node", "sourceMap": false, diff --git a/dataprotocol-node/client/src/typings/es6-promise/index.d.ts b/dataprotocol-node/client/src/typings/es6-promise/index.d.ts new file mode 100644 index 0000000000..4af46edfa6 --- /dev/null +++ b/dataprotocol-node/client/src/typings/es6-promise/index.d.ts @@ -0,0 +1,84 @@ +// Type definitions for es6-promise +// Project: https://github.com/jakearchibald/ES6-Promise +// Definitions by: François de Campredon , vvakame +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +interface Thenable { + then(onFulfilled?: (value: T) => U | Thenable, onRejected?: (error: any) => U | Thenable): Thenable; + then(onFulfilled?: (value: T) => U | Thenable, onRejected?: (error: any) => void): Thenable; +} + +declare class Promise implements Thenable { + /** + * If you call resolve in the body of the callback passed to the constructor, + * your promise is fulfilled with result object passed to resolve. + * If you call reject your promise is rejected with the object passed to reject. + * For consistency and debugging (eg stack traces), obj should be an instanceof Error. + * Any errors thrown in the constructor callback will be implicitly passed to reject(). + */ + constructor(callback: (resolve : (value?: T | Thenable) => void, reject: (error?: any) => void) => void); + + /** + * onFulfilled is called when/if "promise" resolves. onRejected is called when/if "promise" rejects. + * Both are optional, if either/both are omitted the next onFulfilled/onRejected in the chain is called. + * Both callbacks have a single parameter , the fulfillment value or rejection reason. + * "then" returns a new promise equivalent to the value you return from onFulfilled/onRejected after being passed through Promise.resolve. + * If an error is thrown in the callback, the returned promise rejects with that error. + * + * @param onFulfilled called when/if "promise" resolves + * @param onRejected called when/if "promise" rejects + */ + then(onFulfilled?: (value: T) => U | Thenable, onRejected?: (error: any) => U | Thenable): Promise; + then(onFulfilled?: (value: T) => U | Thenable, onRejected?: (error: any) => void): Promise; + + /** + * Sugar for promise.then(undefined, onRejected) + * + * @param onRejected called when/if "promise" rejects + */ + catch(onRejected?: (error: any) => U | Thenable): Promise; +} + +declare namespace Promise { + /** + * Make a new promise from the thenable. + * A thenable is promise-like in as far as it has a "then" method. + */ + function resolve(value?: T | Thenable): Promise; + + /** + * Make a promise that rejects to obj. For consistency and debugging (eg stack traces), obj should be an instanceof Error + */ + function reject(error: any): Promise; + function reject(error: T): Promise; + + /** + * Make a promise that fulfills when every item in the array fulfills, and rejects if (and when) any item rejects. + * the array passed to all can be a mixture of promise-like objects and other objects. + * The fulfillment value is an array (in order) of fulfillment values. The rejection value is the first rejection value. + */ + function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable, T6 | Thenable, T7 | Thenable, T8 | Thenable, T9 | Thenable, T10 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>; + function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable, T6 | Thenable, T7 | Thenable, T8 | Thenable, T9 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>; + function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable, T6 | Thenable, T7 | Thenable, T8 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>; + function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable, T6 | Thenable, T7 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7]>; + function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable, T6 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6]>; + function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable]): Promise<[T1, T2, T3, T4, T5]>; + function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable ]): Promise<[T1, T2, T3, T4]>; + function all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable]): Promise<[T1, T2, T3]>; + function all(values: [T1 | Thenable, T2 | Thenable]): Promise<[T1, T2]>; + function all(values: (T | Thenable)[]): Promise; + + /** + * Make a Promise that fulfills when any item fulfills, and rejects if any item rejects. + */ + function race(promises: (T | Thenable)[]): Promise; +} + +declare module 'es6-promise' { + var foo: typeof Promise; // Temp variable to reference Promise in local context + namespace rsvp { + export var Promise: typeof foo; + export function polyfill(): void; + } + export = rsvp; +} diff --git a/dataprotocol-node/client/src/typings/es6-promise/tsconfig.json b/dataprotocol-node/client/src/typings/es6-promise/tsconfig.json new file mode 100644 index 0000000000..bc50e7c4fb --- /dev/null +++ b/dataprotocol-node/client/src/typings/es6-promise/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es5", + "dom" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": false, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "es6-promise-tests.ts" + ] +} \ No newline at end of file diff --git a/dataprotocol-node/client/src/typings/ref.d.ts b/dataprotocol-node/client/src/typings/ref.d.ts new file mode 100644 index 0000000000..e21045c0c8 --- /dev/null +++ b/dataprotocol-node/client/src/typings/ref.d.ts @@ -0,0 +1,7 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/// +/// diff --git a/dataprotocol-node/client/src/utils/async.ts b/dataprotocol-node/client/src/utils/async.ts new file mode 100644 index 0000000000..691901c20d --- /dev/null +++ b/dataprotocol-node/client/src/utils/async.ts @@ -0,0 +1,82 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +export interface ITask { + (): T; +} + +export class Delayer { + + public defaultDelay: number; + private timeout: NodeJS.Timer; + private completionPromise: Promise; + private onSuccess: (value?: T | Thenable) => void; + private task: ITask; + + constructor(defaultDelay: number) { + this.defaultDelay = defaultDelay; + this.timeout = null; + this.completionPromise = null; + this.onSuccess = null; + this.task = null; + } + + public trigger(task: ITask, delay: number = this.defaultDelay): Promise { + this.task = task; + if (delay >= 0) { + this.cancelTimeout(); + } + + if (!this.completionPromise) { + this.completionPromise = new Promise((resolve) => { + this.onSuccess = resolve + }).then(() => { + this.completionPromise = null; + this.onSuccess = null; + var result = this.task(); + this.task = null; + return result; + }); + } + + if (delay >= 0 || this.timeout === null) { + this.timeout = setTimeout(() => { + this.timeout = null; + this.onSuccess(null); + }, delay >= 0 ? delay : this.defaultDelay); + } + + return this.completionPromise; + } + + public forceDelivery(): T { + if (!this.completionPromise) { + return null; + } + this.cancelTimeout(); + let result: T = this.task(); + this.completionPromise = null; + this.onSuccess = null; + this.task = null; + return result; + } + + public isTriggered(): boolean { + return this.timeout !== null; + } + + public cancel(): void { + this.cancelTimeout(); + this.completionPromise = null; + } + + private cancelTimeout(): void { + if (this.timeout !== null) { + clearTimeout(this.timeout); + this.timeout = null; + } + } +} \ No newline at end of file diff --git a/dataprotocol-node/client/src/utils/electron.ts b/dataprotocol-node/client/src/utils/electron.ts new file mode 100644 index 0000000000..f55c1c344f --- /dev/null +++ b/dataprotocol-node/client/src/utils/electron.ts @@ -0,0 +1,123 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import path = require('path'); +import os = require('os'); +import net = require('net'); +import cp = require('child_process'); + +export interface IForkOptions { + cwd?: string; + env?: any; + encoding?: string; + execArgv?: string[]; +} + +function makeRandomHexString(length: number): string { + let chars = ['0', '1', '2', '3', '4', '5', '6', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; + let result = ''; + for (let i = 0; i < length; i++) { + let idx = Math.floor(chars.length * Math.random()); + result += chars[idx]; + } + return result; +} + +function generatePipeName(): string { + var randomName = 'vscode-' + makeRandomHexString(40); + if (process.platform === 'win32') { + return '\\\\.\\pipe\\' + randomName + '-sock'; + } + + // Mac/Unix: use socket file + return path.join(os.tmpdir(), randomName + '.sock'); +} + +function generatePatchedEnv(env: any, stdInPipeName: string, stdOutPipeName: string): any { + // Set the two unique pipe names and the electron flag as process env + + var newEnv: any = {}; + for (var key in env) { + newEnv[key] = env[key]; + } + + newEnv['STDIN_PIPE_NAME'] = stdInPipeName; + newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName; + newEnv['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = '1'; + + return newEnv; +} + +export function fork(modulePath: string, args: string[], options: IForkOptions, callback: (error: any, cp: cp.ChildProcess) => void): void { + + var callbackCalled = false; + var resolve = (result: cp.ChildProcess) => { + if (callbackCalled) { + return; + } + callbackCalled = true; + callback(null, result); + }; + var reject = (err: any) => { + if (callbackCalled) { + return; + } + callbackCalled = true; + callback(err, null); + }; + + // Generate two unique pipe names + var stdInPipeName = generatePipeName(); + var stdOutPipeName = generatePipeName(); + + var newEnv = generatePatchedEnv(options.env || process.env, stdInPipeName, stdOutPipeName); + + var childProcess: cp.ChildProcess; + + // Begin listening to stdout pipe + var server = net.createServer((stream) => { + // The child process will write exactly one chunk with content `ready` when it has installed a listener to the stdin pipe + + stream.once('data', (chunk: Buffer) => { + // The child process is sending me the `ready` chunk, time to connect to the stdin pipe + childProcess.stdin = net.connect(stdInPipeName); + + // From now on the childProcess.stdout is available for reading + childProcess.stdout = stream; + + resolve(childProcess); + }); + }); + server.listen(stdOutPipeName); + + var serverClosed = false; + var closeServer = () => { + if (serverClosed) { + return; + } + serverClosed = true; + server.close(); + } + + // Create the process + let bootstrapperPath = path.join(__dirname, 'electronForkStart'); + childProcess = cp.fork(bootstrapperPath, [modulePath].concat(args), { + silent: true, + cwd: options.cwd, + env: newEnv, + execArgv: options.execArgv + }); + + childProcess.once('error', (err: Error) => { + closeServer(); + reject(err); + }); + + childProcess.once('exit', (err: Error) => { + closeServer(); + reject(err); + }); +} diff --git a/dataprotocol-node/client/src/utils/electronForkStart.ts b/dataprotocol-node/client/src/utils/electronForkStart.ts new file mode 100644 index 0000000000..53c7c6e2c4 --- /dev/null +++ b/dataprotocol-node/client/src/utils/electronForkStart.ts @@ -0,0 +1,183 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +var net = require('net'), + fs = require('fs'), + stream = require('stream'), + util = require('util'); + +var ENABLE_LOGGING = false; + +var log = (function () { + if (!ENABLE_LOGGING) { + return function () { }; + } + var isFirst = true; + var LOG_LOCATION = 'C:\\stdFork.log'; + return function log(str) { + if (isFirst) { + isFirst = false; + fs.writeFileSync(LOG_LOCATION, str + '\n'); + return; + } + fs.appendFileSync(LOG_LOCATION, str + '\n'); + } +})(); + +var stdInPipeName = process.env['STDIN_PIPE_NAME']; +var stdOutPipeName = process.env['STDOUT_PIPE_NAME']; + +log('STDIN_PIPE_NAME: ' + stdInPipeName); +log('STDOUT_PIPE_NAME: ' + stdOutPipeName); +log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']); + +// stdout redirection to named pipe +(function () { + log('Beginning stdout redirection...'); + + // Create a writing stream to the stdout pipe + var stdOutStream = net.connect(stdOutPipeName); + + // unref stdOutStream to behave like a normal standard out + stdOutStream.unref(); + + // handle process.stdout + (process).__defineGetter__('stdout', function () { return stdOutStream; }); + + // handle process.stderr + (process).__defineGetter__('stderr', function () { return stdOutStream; }); + + var fsWriteSyncString = function (fd, str, position, encoding) { + // fs.writeSync(fd, string[, position[, encoding]]); + var buf = new Buffer(str, encoding || 'utf8'); + return fsWriteSyncBuffer(fd, buf, 0, buf.length); + }; + + var fsWriteSyncBuffer = function (fd, buffer, off, len) { + off = Math.abs(off | 0); + len = Math.abs(len | 0); + + // fs.writeSync(fd, buffer, offset, length[, position]); + var buffer_length = buffer.length; + + if (off > buffer_length) { + throw new Error('offset out of bounds'); + } + if (len > buffer_length) { + throw new Error('length out of bounds'); + } + if (((off + len) | 0) < off) { + throw new Error('off + len overflow'); + } + if (buffer_length - off < len) { + // Asking for more than is left over in the buffer + throw new Error('off + len > buffer.length'); + } + + var slicedBuffer = buffer; + if (off !== 0 || len !== buffer_length) { + slicedBuffer = buffer.slice(off, off + len); + } + + stdOutStream.write(slicedBuffer); + return slicedBuffer.length; + }; + + // handle fs.writeSync(1, ...) + var originalWriteSync = fs.writeSync; + fs.writeSync = function (fd, data, position, encoding) { + if (fd !== 1) { + return originalWriteSync.apply(fs, arguments); + } + // usage: + // fs.writeSync(fd, buffer, offset, length[, position]); + // OR + // fs.writeSync(fd, string[, position[, encoding]]); + + if (data instanceof Buffer) { + return fsWriteSyncBuffer.apply(null, arguments); + } + + // For compatibility reasons with fs.writeSync, writing null will write "null", etc + if (typeof data !== 'string') { + data += ''; + } + + return fsWriteSyncString.apply(null, arguments); + }; + + log('Finished defining process.stdout, process.stderr and fs.writeSync'); +})(); + +// stdin redirection to named pipe +(function () { + + // Begin listening to stdin pipe + var server = net.createServer(function (stream) { + // Stop accepting new connections, keep the existing one alive + server.close(); + + log('Parent process has connected to my stdin. All should be good now.'); + + // handle process.stdin + (process).__defineGetter__('stdin', function () { + return stream; + }); + + // Remove myself from process.argv + process.argv.splice(1, 1); + + // Load the actual program + var program = process.argv[1]; + log('Loading program: ' + program); + + // Unset the custom environmental variables that should not get inherited + delete process.env['STDIN_PIPE_NAME']; + delete process.env['STDOUT_PIPE_NAME']; + delete process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']; + + require(program); + + log('Finished loading program.'); + + var stdinIsReferenced = true; + var timer = setInterval(function () { + var listenerCount = ( + stream.listeners('data').length + + stream.listeners('end').length + + stream.listeners('close').length + + stream.listeners('error').length + ); + // log('listenerCount: ' + listenerCount); + if (listenerCount <= 1) { + // No more "actual" listeners, only internal node + if (stdinIsReferenced) { + stdinIsReferenced = false; + // log('unreferencing stream!!!'); + stream.unref(); + } + } else { + // There are "actual" listeners + if (!stdinIsReferenced) { + stdinIsReferenced = true; + stream.ref(); + } + } + // log( + // '' + stream.listeners('data').length + + // ' ' + stream.listeners('end').length + + // ' ' + stream.listeners('close').length + + // ' ' + stream.listeners('error').length + // ); + }, 1000); + timer.unref(); + }); + + + server.listen(stdInPipeName, function () { + // signal via stdout that the parent process can now begin writing to stdin pipe + process.stdout.write('ready'); + }); + +})(); \ No newline at end of file diff --git a/dataprotocol-node/client/src/utils/is.ts b/dataprotocol-node/client/src/utils/is.ts new file mode 100644 index 0000000000..f155ae89ae --- /dev/null +++ b/dataprotocol-node/client/src/utils/is.ts @@ -0,0 +1,55 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +const toString = Object.prototype.toString; + +export function defined(value: any): boolean { + return typeof value !== 'undefined'; +} + +export function undefined(value: any): boolean { + return typeof value === 'undefined'; +} + +export function nil(value: any): boolean { + return value === null; +} + +export function boolean(value: any): value is boolean { + return value === true || value === false; +} + +export function string(value: any): value is string { + return toString.call(value) === '[object String]'; +} + +export function number(value: any): value is number { + return toString.call(value) === '[object Number]'; +} + +export function error(value: any): value is Error { + return toString.call(value) === '[object Error]'; +} + +export function func(value: any): value is Function { + return toString.call(value) === '[object Function]'; +} + +export function array(value: any): value is T[] { + return Array.isArray(value); +} + +export function stringArray(value: any): value is string[] { + return array(value) && (value).every(elem => string(elem)); +} + +export function typedArray(value: any, check: (value: any) => boolean): value is T[] { + return Array.isArray(value) && (value).every(check); +} + +export function thenable(value: any): value is Thenable { + return value && func(value.then); +} \ No newline at end of file diff --git a/dataprotocol-node/client/src/utils/processes.ts b/dataprotocol-node/client/src/utils/processes.ts new file mode 100644 index 0000000000..abfebb53fa --- /dev/null +++ b/dataprotocol-node/client/src/utils/processes.ts @@ -0,0 +1,44 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import * as cp from 'child_process'; +import ChildProcess = cp.ChildProcess; + +import { join } from 'path'; + +const isWindows = (process.platform === 'win32'); +const isMacintosh = (process.platform === 'darwin'); +const isLinux = (process.platform === 'linux'); +export function terminate(process: ChildProcess, cwd?: string): boolean { + if (isWindows) { + try { + // This we run in Atom execFileSync is available. + // Ignore stderr since this is otherwise piped to parent.stderr + // which might be already closed. + let options: any = { + stdio: ['pipe', 'pipe', 'ignore'] + }; + if (cwd) { + options.cwd = cwd + } + (cp).execFileSync('taskkill', ['/T', '/F', '/PID', process.pid.toString()], options); + return true; + } catch (err) { + return false; + } + } else if (isLinux || isMacintosh) { + try { + var cmd = join(__dirname, 'terminateProcess.sh'); + var result = (cp).spawnSync(cmd, [process.pid.toString()]); + return result.error ? false : true; + } catch (err) { + return false; + } + } else { + process.kill('SIGKILL'); + return true; + } +} \ No newline at end of file diff --git a/dataprotocol-node/client/src/utils/terminateProcess.sh b/dataprotocol-node/client/src/utils/terminateProcess.sh new file mode 100644 index 0000000000..8ef631053a --- /dev/null +++ b/dataprotocol-node/client/src/utils/terminateProcess.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the Source EULA. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +terminateTree() { + for cpid in $(pgrep -P $1); do + terminateTree $cpid + done + kill -9 $1 > /dev/null 2>&1 +} + +for pid in $*; do + terminateTree $pid +done \ No newline at end of file diff --git a/dataprotocol-node/client/thirdpartynotices.txt b/dataprotocol-node/client/thirdpartynotices.txt new file mode 100644 index 0000000000..35cb195abb --- /dev/null +++ b/dataprotocol-node/client/thirdpartynotices.txt @@ -0,0 +1,31 @@ +THIRD-PARTY SOFTWARE NOTICES AND INFORMATION +For Microsoft vscode-languageclient + +This project incorporates material from the project(s) listed below (collectively, “Third Party Code”). +Microsoft is not the original author of the Third Party Code. The original copyright notice and license +under which Microsoft received such Third Party Code are set out below. This Third Party Code is licensed +to you under their original license terms set forth below. Microsoft reserves all other rights not expressly +granted, whether by implication, estoppel or otherwise. + +1. DefinitelyTyped version 0.0.1 (https://github.com/borisyankov/DefinitelyTyped) + +This project is licensed under the MIT license. +Copyrights are respective of each contributor listed at the beginning of each definition file. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/.eslintrc b/dataprotocol-node/jsonrpc/.eslintrc new file mode 100644 index 0000000000..306df0be07 --- /dev/null +++ b/dataprotocol-node/jsonrpc/.eslintrc @@ -0,0 +1,24 @@ +{ + "rules": { + "indent": [ + 2, + "tab" + ], + "quotes": [ + 2, + "single" + ], + "linebreak-style": [ + 2, + "windows" + ], + "semi": [ + 2, + "always" + ] + }, + "env": { + "node": true + }, + "extends": "eslint:recommended" +} \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/.npmignore b/dataprotocol-node/jsonrpc/.npmignore new file mode 100644 index 0000000000..2b1e5b19e1 --- /dev/null +++ b/dataprotocol-node/jsonrpc/.npmignore @@ -0,0 +1,9 @@ +.vscode/ +lib/test/ +lib/*.map +src/ +test/ +.eslintrc +.gitignore +gulpfile.js +tsd.json \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/.vscode/launch.json b/dataprotocol-node/jsonrpc/.vscode/launch.json new file mode 100644 index 0000000000..10cab6e424 --- /dev/null +++ b/dataprotocol-node/jsonrpc/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + "version": "0.1.0", + // List of configurations. Add new configurations or edit existing ones. + // ONLY "node" and "mono" are supported, change "type" to switch. + "configurations": [ + { + "request": "launch", + // Name of configuration; appears in the launch configuration drop down menu. + "name": "Mocha", + // Type of configuration. Possible values: "node", "mono". + "type": "node", + // Workspace relative or absolute path to the program. + "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + // Automatically stop program after launch. + "stopOnEntry": false, + // Command line arguments passed to the program. + "args": ["--timeout", "999999"], + // Workspace relative or absolute path to the working directory of the program being debugged. Default is the current workspace. + "cwd": "${workspaceRoot}", + // Workspace relative or absolute path to the runtime executable to be used. Default is the runtime executable on the PATH. + "runtimeExecutable": null, + // Optional arguments passed to the runtime executable. + "runtimeArgs": [], + // Environment variables passed to the program. + "env": { }, + // Use JavaScript source maps (if they exist). + "sourceMaps": true, + // If JavaScript source maps are enabled, the generated code is expected in this directory. + "outDir": "${workspaceRoot}/lib" + } + ] +} diff --git a/dataprotocol-node/jsonrpc/.vscode/settings.json b/dataprotocol-node/jsonrpc/.vscode/settings.json new file mode 100644 index 0000000000..0c0c4bcd8e --- /dev/null +++ b/dataprotocol-node/jsonrpc/.vscode/settings.json @@ -0,0 +1,9 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "javascript.validate.enable": false, + "files.trimTrailingWhitespace": true, + "eslint.enable": false, + "editor.insertSpaces": false, + "editor.tabSize": 4, + "typescript.tsdk": "./node_modules/typescript/lib" +} \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/.vscode/tasks.json b/dataprotocol-node/jsonrpc/.vscode/tasks.json new file mode 100644 index 0000000000..0ed84877c1 --- /dev/null +++ b/dataprotocol-node/jsonrpc/.vscode/tasks.json @@ -0,0 +1,9 @@ +{ + "version": "0.1.0", + "command": "npm", + "isShellCommand": true, + "args": ["run", "watch"], + "showOutput": "silent", + "isWatching": true, + "problemMatcher": "$tsc-watch" +} \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/README.md b/dataprotocol-node/jsonrpc/README.md new file mode 100644 index 0000000000..cdfdf7fbf9 --- /dev/null +++ b/dataprotocol-node/jsonrpc/README.md @@ -0,0 +1,4 @@ +# Microsoft Data Management Protocol - Node + +## License +[MIT](https://github.com/Microsoft/carbon/blob/dev/license.txt) \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/package.json b/dataprotocol-node/jsonrpc/package.json new file mode 100644 index 0000000000..32d46ce19d --- /dev/null +++ b/dataprotocol-node/jsonrpc/package.json @@ -0,0 +1,29 @@ +{ + "name": "dataprotocol-jsonrpc", + "description": "A json rpc implementation over streams", + "version": "2.4.0", + "author": "Microsoft Corporation", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/Microsoft/vscode-languageserver-node.git" + }, + "bugs": { + "url": "https://github.com/Microsoft/vscode-languageserver-node/issues" + }, + "engines": { + "node": ">=4.0.0 || >=6.0.0" + }, + "main": "./lib/main.js", + "typings": "./lib/main", + "devDependencies": { + "mocha": "^3.0.2", + "typescript": "2.0.3" + }, + "scripts": { + "prepublish": "tsc -p ./src", + "compile": "tsc -p ./src", + "watch": "tsc -w -p ./src", + "test": "mocha" + } +} diff --git a/dataprotocol-node/jsonrpc/src/cancellation.ts b/dataprotocol-node/jsonrpc/src/cancellation.ts new file mode 100644 index 0000000000..75e165e351 --- /dev/null +++ b/dataprotocol-node/jsonrpc/src/cancellation.ts @@ -0,0 +1,97 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { Event, Emitter } from './events'; + +export interface CancellationToken { + /** + * Is `true` when the token has been cancelled, `false` otherwise. + */ + isCancellationRequested: boolean; + + /** + * An [event](#Event) which fires upon cancellation. + */ + onCancellationRequested: Event; +} + +export namespace CancellationToken { + + export const None: CancellationToken = Object.freeze({ + isCancellationRequested: false, + onCancellationRequested: Event.None + }); + + export const Cancelled: CancellationToken = Object.freeze({ + isCancellationRequested: true, + onCancellationRequested: Event.None + }); +} + +const shortcutEvent: Event = Object.freeze(function (callback, context?) { + let handle = setTimeout(callback.bind(context), 0); + return { dispose() { clearTimeout(handle); } }; +}); + +class MutableToken implements CancellationToken { + + private _isCancelled: boolean = false; + private _emitter: Emitter; + + public cancel() { + if (!this._isCancelled) { + this._isCancelled = true; + if (this._emitter) { + this._emitter.fire(undefined); + this._emitter = undefined; + } + } + } + + get isCancellationRequested(): boolean { + return this._isCancelled; + } + + get onCancellationRequested(): Event { + if (this._isCancelled) { + return shortcutEvent; + } + if (!this._emitter) { + this._emitter = new Emitter(); + } + return this._emitter.event; + } +} + +export class CancellationTokenSource { + + private _token: CancellationToken; + + get token(): CancellationToken { + if (!this._token) { + // be lazy and create the token only when + // actually needed + this._token = new MutableToken(); + } + return this._token; + } + + cancel(): void { + if (!this._token) { + // save an object by returning the default + // cancelled token when cancellation happens + // before someone asks for the token + this._token = CancellationToken.Cancelled; + } else { + (this._token).cancel(); + } + } + + dispose(): void { + this.cancel(); + } +} \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/src/events.ts b/dataprotocol-node/jsonrpc/src/events.ts new file mode 100644 index 0000000000..9b2c612d4d --- /dev/null +++ b/dataprotocol-node/jsonrpc/src/events.ts @@ -0,0 +1,213 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +export interface Disposable { + /** + * Dispose this object. + */ + dispose(); +} + +/** + * Represents a typed event. + */ +export interface Event { + + /** + * + * @param listener The listener function will be call when the event happens. + * @param thisArgs The 'this' which will be used when calling the event listener. + * @param disposables An array to which a {{IDisposable}} will be added. The + * @return + */ + (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]): Disposable; +} + +export namespace Event { + const _disposable = { dispose() { } }; + export const None: Event = function () { return _disposable; }; +} + +/** + * Represents a type which can release resources, such + * as event listening or a timer. + */ +class DisposableImpl implements Disposable { + + /** + * Combine many disposable-likes into one. Use this method + * when having objects with a dispose function which are not + * instances of Disposable. + * + * @return Returns a new disposable which, upon dispose, will + * dispose all provides disposable-likes. + */ + static from(...disposables: { dispose(): any }[]): DisposableImpl { + return new DisposableImpl(function () { + if (disposables) { + for (let disposable of disposables) { + disposable.dispose(); + } + disposables = undefined; + } + }); + } + + private _callOnDispose: Function; + + constructor(callOnDispose: Function) { + this._callOnDispose = callOnDispose; + } + + /** + * Dispose this object. + */ + dispose(): any { + if (typeof this._callOnDispose === 'function') { + this._callOnDispose(); + this._callOnDispose = undefined; + } + } +} + +class CallbackList { + + private _callbacks: Function[]; + private _contexts: any[]; + + public add(callback: Function, context: any = null, bucket?: Disposable[]): void { + if (!this._callbacks) { + this._callbacks = []; + this._contexts = []; + } + this._callbacks.push(callback); + this._contexts.push(context); + + if (Array.isArray(bucket)) { + bucket.push({ dispose: () => this.remove(callback, context) }); + } + } + + public remove(callback: Function, context: any = null): void { + if (!this._callbacks) { + return; + } + + var foundCallbackWithDifferentContext = false; + for (var i = 0, len = this._callbacks.length; i < len; i++) { + if (this._callbacks[i] === callback) { + if (this._contexts[i] === context) { + // callback & context match => remove it + this._callbacks.splice(i, 1); + this._contexts.splice(i, 1); + return; + } else { + foundCallbackWithDifferentContext = true; + } + } + } + + if (foundCallbackWithDifferentContext) { + throw new Error('When adding a listener with a context, you should remove it with the same context'); + } + } + + public invoke(...args: any[]): any[] { + if (!this._callbacks) { + return; + } + + var ret: any[] = [], + callbacks = this._callbacks.slice(0), + contexts = this._contexts.slice(0); + + for (var i = 0, len = callbacks.length; i < len; i++) { + try { + ret.push(callbacks[i].apply(contexts[i], args)); + } catch (e) { + console.error(e); + } + } + return ret; + } + + public isEmpty(): boolean { + return !this._callbacks || this._callbacks.length === 0; + } + + public dispose(): void { + this._callbacks = undefined; + this._contexts = undefined; + } +} + +export interface EmitterOptions { + onFirstListenerAdd?: Function; + onLastListenerRemove?: Function; +} + +export class Emitter { + + private static _noop = function () { }; + + private _event: Event; + private _callbacks: CallbackList; + + constructor(private _options?: EmitterOptions) { + } + + /** + * For the public to allow to subscribe + * to events from this Emitter + */ + get event(): Event { + if (!this._event) { + this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]) => { + if (!this._callbacks) { + this._callbacks = new CallbackList(); + } + if (this._options && this._options.onFirstListenerAdd && this._callbacks.isEmpty()) { + this._options.onFirstListenerAdd(this); + } + this._callbacks.add(listener, thisArgs); + + let result: Disposable; + result = { + dispose: () => { + this._callbacks.remove(listener, thisArgs); + result.dispose = Emitter._noop; + if (this._options && this._options.onLastListenerRemove && this._callbacks.isEmpty()) { + this._options.onLastListenerRemove(this); + } + } + }; + if (Array.isArray(disposables)) { + disposables.push(result); + } + + return result; + }; + } + return this._event; + } + + /** + * To be kept private to fire an event to + * subscribers + */ + fire(event: T): any { + if (this._callbacks) { + this._callbacks.invoke.call(this._callbacks, event); + } + } + + dispose() { + if (this._callbacks) { + this._callbacks.dispose(); + this._callbacks = undefined; + } + } +} diff --git a/dataprotocol-node/jsonrpc/src/is.ts b/dataprotocol-node/jsonrpc/src/is.ts new file mode 100644 index 0000000000..182ef48358 --- /dev/null +++ b/dataprotocol-node/jsonrpc/src/is.ts @@ -0,0 +1,47 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +const toString = Object.prototype.toString; + +export function defined(value: any): boolean { + return typeof value !== 'undefined'; +} + +export function undefined(value: any): boolean { + return typeof value === 'undefined'; +} + +export function nil(value: any): boolean { + return value === null; +} + +export function boolean(value: any): value is boolean { + return value === true || value === false; +} + +export function string(value: any): value is string { + return toString.call(value) === '[object String]'; +} + +export function number(value: any): value is number { + return toString.call(value) === '[object Number]'; +} + +export function error(value: any): value is Error { + return toString.call(value) === '[object Error]'; +} + +export function func(value: any): value is Function { + return toString.call(value) === '[object Function]'; +} + +export function array(value: any): value is T[] { + return Array.isArray(value); +} + +export function stringArray(value: any): value is string[] { + return array(value) && (value).every(elem => string(elem)); +} \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/src/main.ts b/dataprotocol-node/jsonrpc/src/main.ts new file mode 100644 index 0000000000..d27c0fc7fa --- /dev/null +++ b/dataprotocol-node/jsonrpc/src/main.ts @@ -0,0 +1,576 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import * as is from './is'; + +import { + Message, + RequestMessage, RequestType, isRequestMessage, + ResponseMessage, isReponseMessage, ResponseError, ErrorCodes, + NotificationMessage, NotificationType, isNotificationMessage +} from './messages'; + +import { MessageReader, DataCallback, StreamMessageReader, IPCMessageReader } from './messageReader'; +import { MessageWriter, StreamMessageWriter, IPCMessageWriter } from './messageWriter'; +import { Disposable, Event, Emitter } from './events'; +import { CancellationTokenSource, CancellationToken } from './cancellation'; + +export { + Message, ErrorCodes, ResponseError, + RequestMessage, RequestType, + NotificationMessage, NotificationType, + MessageReader, DataCallback, StreamMessageReader, IPCMessageReader, + MessageWriter, StreamMessageWriter, IPCMessageWriter, + CancellationTokenSource, CancellationToken, + Disposable, Event, Emitter +} + +interface CancelParams { + /** + * The request id to cancel. + */ + id: number | string; +} + +namespace CancelNotification { + export const type: NotificationType = { get method() { return '$/cancelRequest'; } }; +} + +export interface RequestHandler { + (params: P, token: CancellationToken): R | ResponseError | Thenable>; +} + +export interface NotificationHandler

{ + (params: P): void; +} + +export interface Logger { + error(message: string): void; + warn(message: string): void; + info(message: string): void; + log(message: string): void; +} + +export enum Trace { + Off, Messages, Verbose +} + +export type TraceValues = 'off' | 'messages' | 'verbose'; +export namespace Trace { + export function fromString(value: string): Trace { + value = value.toLowerCase(); + switch (value) { + case 'off': + return Trace.Off; + case 'messages': + return Trace.Messages; + case 'verbose': + return Trace.Verbose; + default: + return Trace.Off; + } + } + + export function toString(value: Trace): TraceValues { + switch (value) { + case Trace.Off: + return 'off'; + case Trace.Messages: + return 'messages'; + case Trace.Verbose: + return 'verbose'; + default: + return 'off'; + } + } +} + +export interface SetTraceParams { + value: TraceValues; +} + +export namespace SetTraceNotification { + export const type: NotificationType = { get method() { return '$/setTraceNotification'; } }; +} + +export interface LogTraceParams { + message: string; + verbose?: string; +} + +export namespace LogTraceNotification { + export const type: NotificationType = { get method() { return '$/logTraceNotification'; } }; +} + +export interface Tracer { + log(message: string, data?: string): void; +} + +export interface MessageConnection { + sendRequest(type: RequestType, params: P, token?: CancellationToken): Thenable; + onRequest(type: RequestType, handler: RequestHandler): void; + sendNotification

(type: NotificationType

, params?: P): void; + onNotification

(type: NotificationType

, handler: NotificationHandler

): void; + trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void; + onError: Event<[Error, Message, number]>; + onClose: Event; + onUnhandledNotification: Event; + listen(); + onDispose: Event; + dispose(): void; +} + +export interface ServerMessageConnection extends MessageConnection { +} + +export interface ClientMessageConnection extends MessageConnection { +} + +interface ResponsePromise { + method: string; + timerStart: number; + resolve: (response) => void; + reject: (error: any) => void +} + +enum ConnectionState { + New = 1, + Listening = 2, + Closed = 3, + Disposed = 4 +} + +function createMessageConnection(messageReader: MessageReader, messageWriter: MessageWriter, logger: Logger, client: boolean = false): T { + let sequenceNumber = 0; + const version: string = '2.0'; + + let requestHandlers: { [name: string]: RequestHandler } = Object.create(null); + let eventHandlers: { [name: string]: NotificationHandler } = Object.create(null); + + let responsePromises: { [name: string]: ResponsePromise } = Object.create(null); + let requestTokens: { [id: string]: CancellationTokenSource } = Object.create(null); + + let trace: Trace = Trace.Off; + let tracer: Tracer; + + let state: ConnectionState = ConnectionState.New; + let errorEmitter: Emitter<[Error, Message, number]> = new Emitter<[Error, Message, number]>(); + let closeEmitter: Emitter = new Emitter(); + let unhandledNotificationEmitter: Emitter = new Emitter(); + let disposeEmitter: Emitter = new Emitter(); + + function isListening(): boolean { + return state === ConnectionState.Listening; + } + + function isClosed(): boolean { + return state === ConnectionState.Closed; + } + + function isDisposed(): boolean { + return state === ConnectionState.Disposed; + } + + function closeHandler(): void { + if (state === ConnectionState.New || state === ConnectionState.Listening) { + state = ConnectionState.Closed; + closeEmitter.fire(undefined); + } + // If the connection is disposed don't sent close events. + }; + + function readErrorHandler(error: Error): void { + errorEmitter.fire([error, undefined, undefined]); + } + + function writeErrorHandler(data: [Error, Message, number]): void { + errorEmitter.fire(data); + } + + messageReader.onClose(closeHandler); + messageReader.onError(readErrorHandler); + + messageWriter.onClose(closeHandler); + messageWriter.onError(writeErrorHandler); + + function handleRequest(requestMessage: RequestMessage) { + if (isDisposed()) { + // we return here silently since we fired an event when the + // connection got disposed. + return; + } + + function reply(resultOrError: any | ResponseError): void { + let message: ResponseMessage = { + jsonrpc: version, + id: requestMessage.id + }; + if (resultOrError instanceof ResponseError) { + message.error = (>resultOrError).toJson(); + } else { + message.result = is.undefined(resultOrError) ? null : resultOrError; + } + messageWriter.write(message); + } + function replyError(error: ResponseError) { + let message: ResponseMessage = { + jsonrpc: version, + id: requestMessage.id, + error: error.toJson() + }; + messageWriter.write(message); + } + function replySuccess(result: any) { + // The JSON RPC defines that a response must either have a result or an error + // So we can't treat undefined as a valid response result. + if (is.undefined(result)) { + result = null; + } + let message: ResponseMessage = { + jsonrpc: version, + id: requestMessage.id, + result: result + }; + messageWriter.write(message); + } + + let requestHandler = requestHandlers[requestMessage.method]; + if (requestHandler) { + let cancellationSource = new CancellationTokenSource(); + let tokenKey = String(requestMessage.id); + requestTokens[tokenKey] = cancellationSource; + try { + let handlerResult = requestHandler(requestMessage.params, cancellationSource.token); + let promise = >>handlerResult; + if (!handlerResult) { + delete requestTokens[tokenKey]; + replySuccess(handlerResult); + } else if (promise.then) { + promise.then((resultOrError): any | ResponseError => { + delete requestTokens[tokenKey]; + reply(resultOrError); + }, error => { + delete requestTokens[tokenKey]; + if (error instanceof ResponseError) { + replyError(>error); + } else if (error && is.string(error.message)) { + replyError(new ResponseError(ErrorCodes.InternalError, `Request ${requestMessage.method} failed with message: ${error.message}`)); + } else { + replyError(new ResponseError(ErrorCodes.InternalError, `Request ${requestMessage.method} failed unexpectedly without providing any details.`)); + } + }); + } else { + delete requestTokens[tokenKey]; + reply(handlerResult); + } + } catch (error) { + delete requestTokens[tokenKey]; + if (error instanceof ResponseError) { + reply(>error); + } else if (error && is.string(error.message)) { + replyError(new ResponseError(ErrorCodes.InternalError, `Request ${requestMessage.method} failed with message: ${error.message}`)); + } else { + replyError(new ResponseError(ErrorCodes.InternalError, `Request ${requestMessage.method} failed unexpectedly without providing any details.`)); + } + } + } else { + replyError(new ResponseError(ErrorCodes.MethodNotFound, `Unhandled method ${requestMessage.method}`)); + } + } + + function handleResponse(responseMessage: ResponseMessage) { + if (isDisposed()) { + // See handle request. + return; + } + + let key = String(responseMessage.id); + let responsePromise = responsePromises[key]; + if (trace != Trace.Off && tracer) { + traceResponse(responseMessage, responsePromise); + } + if (responsePromise) { + delete responsePromises[key]; + try { + if (is.defined(responseMessage.error)) { + let error = responseMessage.error; + responsePromise.reject(new ResponseError(error.code, error.message, error.data)); + } else if (is.defined(responseMessage.result)) { + responsePromise.resolve(responseMessage.result); + } else { + throw new Error('Should never happen.'); + } + } catch (error) { + if (error.message) { + logger.error(`Response handler '${responsePromise.method}' failed with message: ${error.message}`); + } else { + logger.error(`Response handler '${responsePromise.method}' failed unexpectedly.`); + } + } + } + } + + function handleNotification(message: NotificationMessage) { + if (isDisposed()) { + // See handle request. + return; + } + let eventHandler: NotificationHandler; + if (message.method === CancelNotification.type.method) { + eventHandler = (params: CancelParams) => { + let id = params.id; + let source = requestTokens[String(id)]; + if (source) { + source.cancel(); + } + } + } else { + eventHandler = eventHandlers[message.method]; + } + if (eventHandler) { + try { + if (trace != Trace.Off && tracer) { + traceReceivedNotification(message); + } + eventHandler(message.params); + } catch (error) { + if (error.message) { + logger.error(`Notification handler '${message.method}' failed with message: ${error.message}`); + } else { + logger.error(`Notification handler '${message.method}' failed unexpectedly.`); + } + } + } else { + unhandledNotificationEmitter.fire(message); + } + } + + function handleInvalidMessage(message: Message) { + if (!message) { + logger.error('Received empty message.'); + return; + } + logger.error(`Received message which is neither a response nor a notification message:\n${JSON.stringify(message, null, 4)}`); + // Test whether we find an id to reject the promise + let responseMessage: ResponseMessage = message as ResponseMessage; + if (is.string(responseMessage.id) || is.number(responseMessage.id)) { + let key = String(responseMessage.id); + let responseHandler = responsePromises[key]; + if (responseHandler) { + responseHandler.reject(new Error('The received response has neither a result nor an error property.')); + } + } + } + + function traceRequest(message: RequestMessage): void { + let data: string = undefined; + if (trace === Trace.Verbose && message.params) { + data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; + } + tracer.log(`Sending request '${message.method} - (${message.id})'.`, data); + } + + function traceSendNotification(message: NotificationMessage): void { + let data: string = undefined; + if (trace === Trace.Verbose) { + if (message.params) { + data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; + } else { + data = 'No parameters provided.\n\n'; + } + } + tracer.log(`Sending notification '${message.method}'.`, data); + } + + function traceReceivedNotification(message: NotificationMessage): void { + if (message.method === LogTraceNotification.type.method) { + return; + } + let data: string = undefined; + if (trace === Trace.Verbose) { + if (message.params) { + data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; + } else { + data = 'No parameters provided.\n\n'; + } + } + tracer.log(`Received notification '${message.method}'.`, data); + } + + function traceResponse(message: ResponseMessage, responsePromise: ResponsePromise): void { + let data: string = undefined; + if (trace === Trace.Verbose) { + if (message.error && message.error.data) { + data = `Error data: ${JSON.stringify(message.error.data, null, 4)}\n\n`; + } else { + if (message.result) { + data = `Result: ${JSON.stringify(message.result, null, 4)}\n\n`; + } else if (is.undefined(message.error)) { + data = 'No result returned.\n\n'; + } + } + } + if (responsePromise) { + let error = message.error ? ` Request failed: ${message.error.message} (${message.error.code}).` : ''; + tracer.log(`Received response '${responsePromise.method} - (${message.id})' in ${Date.now() - responsePromise.timerStart}ms.${error}`, data); + } else { + tracer.log(`Received response ${message.id} without active response promise.`, data); + } + } + + let callback: DataCallback = (message) => { + if (isRequestMessage(message)) { + handleRequest(message); + } else if (isReponseMessage(message)) { + handleResponse(message) + } else if (isNotificationMessage(message)) { + handleNotification(message); + } else { + handleInvalidMessage(message); + } + }; + + function throwIfClosedOrDisposed() { + if (isClosed()) { + throw new Error('Connection is closed.'); + } + if (isDisposed()) { + throw new Error('Connection is disposed.'); + } + } + + function throwIfListening() { + if (isListening()) { + throw new Error('Connection is already listening'); + } + } + + let connection: MessageConnection = { + sendNotification:

(type: NotificationType

, params): void => { + throwIfClosedOrDisposed(); + + let notificatioMessage: NotificationMessage = { + jsonrpc: version, + method: type.method, + params: params + } + if (trace != Trace.Off && tracer) { + traceSendNotification(notificatioMessage); + } + messageWriter.write(notificatioMessage); + }, + onNotification:

(type: NotificationType

, handler: NotificationHandler

) => { + throwIfClosedOrDisposed(); + + eventHandlers[type.method] = handler; + }, + sendRequest: (type: RequestType, params: P, token?: CancellationToken) => { + throwIfClosedOrDisposed(); + + let id = sequenceNumber++; + let result = new Promise>((resolve, reject) => { + let requestMessage: RequestMessage = { + jsonrpc: version, + id: id, + method: type.method, + params: params + } + let responsePromise: ResponsePromise = { method: type.method, timerStart: Date.now(), resolve, reject }; + if (trace != Trace.Off && tracer) { + traceRequest(requestMessage); + } + try { + messageWriter.write(requestMessage); + } catch (e) { + // Writing the message failed. So we need to reject the promise. + responsePromise.reject(new ResponseError(ErrorCodes.MessageWriteError, e.message ? e.message : 'Unknown reason')); + responsePromise = null; + } + if (responsePromise) { + responsePromises[String(id)] = responsePromise; + } + }); + if (token) { + token.onCancellationRequested((event) => { + connection.sendNotification(CancelNotification.type, { id }); + }); + } + return result; + }, + onRequest: (type: RequestType, handler: RequestHandler) => { + throwIfClosedOrDisposed(); + + requestHandlers[type.method] = handler; + }, + trace: (_value: Trace, _tracer: Tracer, sendNotification: boolean = false) => { + trace = _value; + if (trace === Trace.Off) { + tracer = null; + } else { + tracer = _tracer; + } + if (sendNotification && !isClosed() && !isDisposed()) { + connection.sendNotification(SetTraceNotification.type, { value: Trace.toString(_value) }); + } + }, + onError: errorEmitter.event, + onClose: closeEmitter.event, + onUnhandledNotification: unhandledNotificationEmitter.event, + onDispose: disposeEmitter.event, + dispose: () => { + if (isDisposed()) { + return; + } + state = ConnectionState.Disposed; + disposeEmitter.fire(undefined); + let error = new Error('Connection got disposed.'); + Object.keys(responsePromises).forEach((key) => { + responsePromises[key].reject(error); + }); + responsePromises = Object.create(null); + requestTokens = Object.create(null); + }, + listen: () => { + throwIfClosedOrDisposed(); + throwIfListening(); + + state = ConnectionState.Listening; + messageReader.listen(callback); + } + }; + + connection.onNotification(LogTraceNotification.type, (params) => { + if (trace === Trace.Off) { + return; + } + tracer.log(params.message, trace === Trace.Verbose ? params.verbose : undefined); + }); + return connection as T; +} + +function isMessageReader(value: any): value is MessageReader { + return is.defined(value.listen) && is.undefined(value.read); +} + +function isMessageWriter(value: any): value is MessageWriter { + return is.defined(value.write) && is.undefined(value.end); +} + +export function createServerMessageConnection(reader: MessageReader, writer: MessageWriter, logger: Logger): ServerMessageConnection; +export function createServerMessageConnection(inputStream: NodeJS.ReadableStream, outputStream: NodeJS.WritableStream, logger: Logger): ServerMessageConnection; +export function createServerMessageConnection(input: MessageReader | NodeJS.ReadableStream, output: MessageWriter | NodeJS.WritableStream, logger: Logger): ServerMessageConnection { + let reader = isMessageReader(input) ? input : new StreamMessageReader(input); + let writer = isMessageWriter(output) ? output : new StreamMessageWriter(output); + return createMessageConnection(reader, writer, logger); +} + +export function createClientMessageConnection(reader: MessageReader, writer: MessageWriter, logger: Logger): ClientMessageConnection; +export function createClientMessageConnection(inputStream: NodeJS.ReadableStream, outputStream: NodeJS.WritableStream, logger: Logger): ClientMessageConnection; +export function createClientMessageConnection(input: MessageReader | NodeJS.ReadableStream, output: MessageWriter | NodeJS.WritableStream, logger: Logger): ClientMessageConnection { + let reader = isMessageReader(input) ? input : new StreamMessageReader(input); + let writer = isMessageWriter(output) ? output : new StreamMessageWriter(output); + return createMessageConnection(reader, writer, logger, true); +} diff --git a/dataprotocol-node/jsonrpc/src/messageReader.ts b/dataprotocol-node/jsonrpc/src/messageReader.ts new file mode 100644 index 0000000000..2bf18c3620 --- /dev/null +++ b/dataprotocol-node/jsonrpc/src/messageReader.ts @@ -0,0 +1,265 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import { ChildProcess } from 'child_process'; + +import { Message } from './messages'; +import { Event, Emitter } from './events'; +import * as is from './is'; + +let DefaultSize: number = 8192; +let CR: number = new Buffer('\r', 'ascii')[0]; +let LF: number = new Buffer('\n', 'ascii')[0]; +let CRLF: string = '\r\n'; + +class MessageBuffer { + + private encoding: string; + private index: number; + private buffer: Buffer; + + constructor(encoding: string = 'utf-8') { + this.encoding = encoding; + this.index = 0; + this.buffer = new Buffer(DefaultSize); + } + + public append(chunk: Buffer | String): void { + var toAppend: Buffer = chunk; + if (typeof (chunk) == 'string') { + var str = chunk; + toAppend = new Buffer(str.length); + toAppend.write(str, 0, str.length, this.encoding); + } + if (this.buffer.length - this.index >= toAppend.length) { + toAppend.copy(this.buffer, this.index, 0, toAppend.length); + } else { + var newSize = (Math.ceil((this.index + toAppend.length) / DefaultSize) + 1) * DefaultSize; + if (this.index === 0) { + this.buffer = new Buffer(newSize); + toAppend.copy(this.buffer, 0, 0, toAppend.length); + } else { + this.buffer = Buffer.concat([this.buffer.slice(0, this.index), toAppend], newSize); + } + } + this.index += toAppend.length; + } + + public tryReadHeaders(): { [key: string]: string; } { + let result: { [key: string]: string; } = undefined; + let current = 0; + while (current + 3 < this.index && (this.buffer[current] !== CR || this.buffer[current + 1] !== LF || this.buffer[current + 2] !== CR || this.buffer[current + 3] !== LF)) { + current++; + } + // No header / body separator found (e.g CRLFCRLF) + if (current + 3 >= this.index) { + return result; + } + result = Object.create(null); + let headers = this.buffer.toString('ascii', 0, current).split(CRLF); + headers.forEach((header) => { + let index: number = header.indexOf(':'); + if (index === -1) { + throw new Error('Message header must separate key and value using :'); + } + let key = header.substr(0, index); + let value = header.substr(index + 1).trim(); + result[key] = value; + }) + + let nextStart = current + 4; + this.buffer = this.buffer.slice(nextStart); + this.index = this.index - nextStart; + return result; + } + + public tryReadContent(length: number): string { + if (this.index < length) { + return null; + } + let result = this.buffer.toString(this.encoding, 0, length); + let nextStart = length; + this.buffer.copy(this.buffer, 0, nextStart); + this.index = this.index - nextStart; + return result; + } + + public get numberOfBytes(): number { + return this.index; + } +} + +export interface DataCallback { + (data: Message): void; +} + +export interface PartialMessageInfo { + messageToken: number; + waitingTime: number; +} + +export interface MessageReader { + onError: Event; + onClose: Event; + onPartialMessage: Event; + listen(callback: DataCallback): void; +} + +export abstract class AbstractMessageReader { + + private errorEmitter: Emitter; + private closeEmitter: Emitter; + + private partialMessageEmitter: Emitter; + + constructor() { + this.errorEmitter = new Emitter(); + this.closeEmitter = new Emitter(); + this.partialMessageEmitter = new Emitter(); + } + + public get onError(): Event { + return this.errorEmitter.event; + } + + protected fireError(error: any): void { + this.errorEmitter.fire(this.asError(error)); + } + + public get onClose(): Event { + return this.closeEmitter.event; + } + + protected fireClose(): void { + this.closeEmitter.fire(undefined); + } + + public get onPartialMessage(): Event { + return this.partialMessageEmitter.event; + } + + protected firePartialMessage(info: PartialMessageInfo): void { + this.partialMessageEmitter.fire(info); + } + + private asError(error: any): Error { + if (error instanceof Error) { + return error; + } else { + return new Error(`Reader recevied error. Reason: ${is.string(error.message) ? error.message : 'unknown'}`); + } + } +} + +export class StreamMessageReader extends AbstractMessageReader implements MessageReader { + + private readable: NodeJS.ReadableStream; + private callback: DataCallback; + private buffer: MessageBuffer; + private nextMessageLength: number; + private messageToken: number; + private partialMessageTimer: NodeJS.Timer; + private _partialMessageTimeout: number; + + public constructor(readable: NodeJS.ReadableStream, encoding: string = 'utf-8') { + super(); + this.readable = readable; + this.buffer = new MessageBuffer(encoding); + this._partialMessageTimeout = 10000; + } + + public set partialMessageTimeout(timeout: number) { + this._partialMessageTimeout = timeout; + } + + public get partialMessageTimeout(): number { + return this._partialMessageTimeout; + } + + public listen(callback: DataCallback): void { + this.nextMessageLength = -1; + this.messageToken = 0; + this.partialMessageTimer = undefined; + this.callback = callback; + this.readable.on('data', (data: Buffer) => { + this.onData(data); + }); + this.readable.on('error', (error: any) => this.fireError(error)); + this.readable.on('close', () => this.fireClose()); + } + + private onData(data: Buffer | String): void { + this.buffer.append(data); + while (true) { + if (this.nextMessageLength === -1) { + let headers = this.buffer.tryReadHeaders(); + if (!headers) { + return; + } + let contentLength = headers['Content-Length']; + if (!contentLength) { + throw new Error('Header must provide a Content-Length property.'); + } + let length = parseInt(contentLength); + if (isNaN(length)) { + throw new Error('Content-Length value must be a number.'); + } + this.nextMessageLength = length; + } + var msg = this.buffer.tryReadContent(this.nextMessageLength); + if (msg === null) { + /** We haven't recevied the full message yet. */ + this.setPartialMessageTimer(); + return; + } + this.clearPartialMessageTimer(); + this.nextMessageLength = -1; + this.messageToken++; + var json = JSON.parse(msg); + this.callback(json); + } + } + + private clearPartialMessageTimer(): void { + if (this.partialMessageTimer) { + clearTimeout(this.partialMessageTimer); + this.partialMessageTimer = undefined; + } + } + + private setPartialMessageTimer(): void { + this.clearPartialMessageTimer(); + if (this._partialMessageTimeout <= 0) { + return; + } + this.partialMessageTimer = setTimeout((token, timeout) => { + this.partialMessageTimer = undefined; + if (token === this.messageToken) { + this.firePartialMessage({ messageToken: token, waitingTime: timeout }); + this.setPartialMessageTimer(); + } + }, this._partialMessageTimeout, this.messageToken, this._partialMessageTimeout); + } +} + +export class IPCMessageReader extends AbstractMessageReader implements MessageReader { + + private process: NodeJS.Process | ChildProcess; + + public constructor(process: NodeJS.Process | ChildProcess) { + super(); + this.process = process; + + let eventEmitter: NodeJS.EventEmitter = this.process; + eventEmitter.on('error', (error: any) => this.fireError(error)); + eventEmitter.on('close', () => this.fireClose()); + } + + public listen(callback: DataCallback): void { + let eventEmitter: NodeJS.EventEmitter = this.process; + eventEmitter.on('message', callback); + } +} \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/src/messageWriter.ts b/dataprotocol-node/jsonrpc/src/messageWriter.ts new file mode 100644 index 0000000000..3076364de0 --- /dev/null +++ b/dataprotocol-node/jsonrpc/src/messageWriter.ts @@ -0,0 +1,118 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import { ChildProcess } from 'child_process'; + +import { Message } from './messages'; +import { Event, Emitter } from './events'; +import * as is from './is'; + +let ContentLength: string = 'Content-Length: '; +let CRLF = '\r\n'; + +export interface MessageWriter { + onError: Event<[Error, Message, number]>; + onClose: Event; + write(msg: Message): void; +} + +export abstract class AbstractMessageWriter { + + private errorEmitter: Emitter<[Error, Message, number]>; + private closeEmitter: Emitter; + + constructor() { + this.errorEmitter = new Emitter<[Error, Message, number]>(); + this.closeEmitter = new Emitter(); + } + + public get onError(): Event<[Error, Message, number]> { + return this.errorEmitter.event; + } + + protected fireError(error: any, message?: Message, count?: number): void { + this.errorEmitter.fire([this.asError(error), message, count]); + } + + public get onClose(): Event { + return this.closeEmitter.event; + } + + protected fireClose(): void { + this.closeEmitter.fire(undefined); + } + + private asError(error: any): Error { + if (error instanceof Error) { + return error; + } else { + return new Error(`Writer recevied error. Reason: ${is.string(error.message) ? error.message : 'unknown'}`); + } + } +} + +export class StreamMessageWriter extends AbstractMessageWriter implements MessageWriter { + + private writable: NodeJS.WritableStream; + private encoding: string; + private errorCount: number; + + public constructor(writable: NodeJS.WritableStream, encoding: string = 'utf8') { + super(); + this.writable = writable; + this.encoding = encoding; + this.errorCount = 0; + this.writable.on('error', (error) => this.fireError(error)); + this.writable.on('close', () => this.fireClose()); + } + + public write(msg: Message): void { + let json = JSON.stringify(msg); + let contentLength = Buffer.byteLength(json, this.encoding); + + let headers: string[] = [ + ContentLength, contentLength.toString(), CRLF, + CRLF + ]; + try { + // Header must be written in ASCII encoding + this.writable.write(headers.join(''), 'ascii'); + + // Now write the content. This can be written in any encoding + this.writable.write(json, this.encoding); + this.errorCount = 0; + } catch (error) { + this.errorCount++; + this.fireError(error, msg, this.errorCount); + } + } +} + +export class IPCMessageWriter extends AbstractMessageWriter implements MessageWriter { + + private process: NodeJS.Process | ChildProcess; + private errorCount: number; + + public constructor(process: NodeJS.Process | ChildProcess) { + super(); + this.process = process; + this.errorCount = 0; + + let eventEmitter: NodeJS.EventEmitter = this.process; + eventEmitter.on('error', (error) => this.fireError(error)); + eventEmitter.on('close', () => this.fireClose); + } + + public write(msg: Message): void { + try { + (this.process.send as Function)(msg); + this.errorCount = 0; + } catch (error) { + this.errorCount++; + this.fireError(error, msg, this.errorCount); + } + } +} \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/src/messages.ts b/dataprotocol-node/jsonrpc/src/messages.ts new file mode 100644 index 0000000000..6dbf5cb07b --- /dev/null +++ b/dataprotocol-node/jsonrpc/src/messages.ts @@ -0,0 +1,175 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import * as is from './is'; + +/** + * A language server message + */ +export interface Message { + jsonrpc: string; +} + +/** + * Request message + */ +export interface RequestMessage extends Message { + + /** + * The request id. + */ + id: number | string; + + /** + * The method to be invoked. + */ + method: string; + + /** + * The method's params. + */ + params?: any +} + +/** + * Predefined error codes. + */ +export namespace ErrorCodes { + // Defined by JSON RPC + export const ParseError: number = -32700; + export const InvalidRequest: number = -32600; + export const MethodNotFound: number = -32601; + export const InvalidParams: number = -32602; + export const InternalError: number = -32603; + export const serverErrorStart: number = -32099 + export const serverErrorEnd: number = -32000; + + // Defined by VSCode. + export const MessageWriteError: number = 1; + export const MessageReadError: number = 2; +} + +export interface ResponseErrorLiteral { + /** + * A number indicating the error type that occured. + */ + code: number; + + /** + * A string providing a short decription of the error. + */ + message: string; + + /** + * A Primitive or Structured value that contains additional + * information about the error. Can be omitted. + */ + data?: D; +} + +/** + * A error object return in a response in case a request + * has failed. + */ +export class ResponseError extends Error { + + public code: number; + + public message: string; + + public data: D; + + constructor(code: number, message: string, data?: D) { + super(message); + this.code = code; + this.message = message; + if (is.defined(data)) { + this.data = data; + } + } + + public toJson(): ResponseErrorLiteral { + let result: ResponseErrorLiteral = { + code: this.code, + message: this.message + }; + if (is.defined(this.data)) { + result.data = this.data + }; + return result; + } +} + +/** + * A response message. + */ +export interface ResponseMessage extends Message { + /** + * The request id. + */ + id: number | string; + + /** + * The result of a request. This can be omitted in + * the case of an error. + */ + result?: any; + + /** + * The error object in case a request fails. + */ + error?: ResponseErrorLiteral; +} + +/** + * A interface to type the request parameter / response pair + */ +export interface RequestType { + method: string; +} + +/** + * Notification Message + */ +export interface NotificationMessage extends Message { + /** + * The method to be invoked. + */ + method: string; + + /** + * The notification's params. + */ + params?: any +} + +export interface NotificationType

{ + method: string; +} + +/** + * Tests if the given message is a request message + */ +export function isRequestMessage(message: Message): message is RequestMessage { + let candidate = message; + return candidate && is.string(candidate.method) && (is.string(candidate.id) || is.number(candidate.id)); +} + +/** + * Tests if the given message is a notification message + */ +export function isNotificationMessage(message: Message): message is NotificationMessage { + let candidate = message; + return candidate && is.string(candidate.method) && is.undefined((message).id); +} + +/** + * Tests if the given message is a response message + */ +export function isReponseMessage(message: Message): message is ResponseMessage { + let candidate = message; + return candidate && (is.defined(candidate.result) || is.defined(candidate.error)) && (is.string(candidate.id) || is.number(candidate.id)); +} \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/src/tsconfig.json b/dataprotocol-node/jsonrpc/src/tsconfig.json new file mode 100644 index 0000000000..6744afdba5 --- /dev/null +++ b/dataprotocol-node/jsonrpc/src/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "ES5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "declaration": true, + "stripInternal": true, + "outDir": "../lib" + } +} \ No newline at end of file diff --git a/dataprotocol-node/jsonrpc/src/typings/promise.d.ts b/dataprotocol-node/jsonrpc/src/typings/promise.d.ts new file mode 100644 index 0000000000..925c943df5 --- /dev/null +++ b/dataprotocol-node/jsonrpc/src/typings/promise.d.ts @@ -0,0 +1,112 @@ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + +/** + * The Thenable (E.g. PromiseLike) and Promise declarions are taken from TypeScript's + * lib.core.es6.d.ts file. See above Copyright notice. + */ + +/** + * Thenable is a common denominator between ES6 promises, Q, jquery.Deferred, WinJS.Promise, + * and others. This API makes no assumption about what promise libary is being used which + * enables reusing existing code without migrating to a specific promise implementation. Still, + * we recommand the use of native promises which are available in VS Code. + */ +interface Thenable { + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: (value: R) => TResult | Thenable, onrejected?: (reason: any) => TResult | Thenable): Thenable; + then(onfulfilled?: (value: R) => TResult | Thenable, onrejected?: (reason: any) => void): Thenable; +} + +/** + * Represents the completion of an asynchronous operation + */ +interface Promise extends Thenable { + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => TResult | Thenable): Promise; + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => void): Promise; + + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: (reason: any) => T | Thenable): Promise; +} + +interface PromiseConstructor { + /** + * Creates a new Promise. + * @param executor A callback used to initialize the promise. This callback is passed two arguments: + * a resolve callback used resolve the promise with a value or the result of another promise, + * and a reject callback used to reject the promise with a provided reason or error. + */ + new (executor: (resolve: (value?: T | Thenable) => void, reject: (reason?: any) => void) => void): Promise; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: Array>): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: Array>): Promise; + + /** + * Creates a new rejected promise for the provided reason. + * @param reason The reason the promise was rejected. + * @returns A new rejected Promise. + */ + reject(reason: any): Promise; + + /** + * Creates a new rejected promise for the provided reason. + * @param reason The reason the promise was rejected. + * @returns A new rejected Promise. + */ + reject(reason: any): Promise; + + /** + * Creates a new resolved promise for the provided value. + * @param value A promise. + * @returns A promise whose internal state matches the provided promise. + */ + resolve(value: T | Thenable): Promise; + + /** + * Creates a new resolved promise . + * @returns A resolved promise. + */ + resolve(): Promise; +} + +declare var Promise: PromiseConstructor; diff --git a/dataprotocol-node/jsonrpc/thirdpartynotices.txt b/dataprotocol-node/jsonrpc/thirdpartynotices.txt new file mode 100644 index 0000000000..4a6720c560 --- /dev/null +++ b/dataprotocol-node/jsonrpc/thirdpartynotices.txt @@ -0,0 +1,31 @@ +THIRD-PARTY SOFTWARE NOTICES AND INFORMATION +For Microsoft vscode-jsonrpc + +This project incorporates material from the project(s) listed below (collectively, “Third Party Code”). +Microsoft is not the original author of the Third Party Code. The original copyright notice and license +under which Microsoft received such Third Party Code are set out below. This Third Party Code is licensed +to you under their original license terms set forth below. Microsoft reserves all other rights not expressly +granted, whether by implication, estoppel or otherwise. + +1. DefinitelyTyped version 0.0.1 (https://github.com/borisyankov/DefinitelyTyped) + +This project is licensed under the MIT license. +Copyrights are respective of each contributor listed at the beginning of each definition file. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/dataprotocol-node/types/.eslintrc b/dataprotocol-node/types/.eslintrc new file mode 100644 index 0000000000..306df0be07 --- /dev/null +++ b/dataprotocol-node/types/.eslintrc @@ -0,0 +1,24 @@ +{ + "rules": { + "indent": [ + 2, + "tab" + ], + "quotes": [ + 2, + "single" + ], + "linebreak-style": [ + 2, + "windows" + ], + "semi": [ + 2, + "always" + ] + }, + "env": { + "node": true + }, + "extends": "eslint:recommended" +} \ No newline at end of file diff --git a/dataprotocol-node/types/.gitignore b/dataprotocol-node/types/.gitignore new file mode 100644 index 0000000000..08eb0a07a6 --- /dev/null +++ b/dataprotocol-node/types/.gitignore @@ -0,0 +1 @@ +!bin/ \ No newline at end of file diff --git a/dataprotocol-node/types/.npmignore b/dataprotocol-node/types/.npmignore new file mode 100644 index 0000000000..2b1e5b19e1 --- /dev/null +++ b/dataprotocol-node/types/.npmignore @@ -0,0 +1,9 @@ +.vscode/ +lib/test/ +lib/*.map +src/ +test/ +.eslintrc +.gitignore +gulpfile.js +tsd.json \ No newline at end of file diff --git a/dataprotocol-node/types/.vscode/settings.json b/dataprotocol-node/types/.vscode/settings.json new file mode 100644 index 0000000000..0c0c4bcd8e --- /dev/null +++ b/dataprotocol-node/types/.vscode/settings.json @@ -0,0 +1,9 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "javascript.validate.enable": false, + "files.trimTrailingWhitespace": true, + "eslint.enable": false, + "editor.insertSpaces": false, + "editor.tabSize": 4, + "typescript.tsdk": "./node_modules/typescript/lib" +} \ No newline at end of file diff --git a/dataprotocol-node/types/.vscode/tasks.json b/dataprotocol-node/types/.vscode/tasks.json new file mode 100644 index 0000000000..0ed84877c1 --- /dev/null +++ b/dataprotocol-node/types/.vscode/tasks.json @@ -0,0 +1,9 @@ +{ + "version": "0.1.0", + "command": "npm", + "isShellCommand": true, + "args": ["run", "watch"], + "showOutput": "silent", + "isWatching": true, + "problemMatcher": "$tsc-watch" +} \ No newline at end of file diff --git a/dataprotocol-node/types/README.md b/dataprotocol-node/types/README.md new file mode 100644 index 0000000000..cdfdf7fbf9 --- /dev/null +++ b/dataprotocol-node/types/README.md @@ -0,0 +1,4 @@ +# Microsoft Data Management Protocol - Node + +## License +[MIT](https://github.com/Microsoft/carbon/blob/dev/license.txt) \ No newline at end of file diff --git a/dataprotocol-node/types/package.json b/dataprotocol-node/types/package.json new file mode 100644 index 0000000000..e8dcaf1e07 --- /dev/null +++ b/dataprotocol-node/types/package.json @@ -0,0 +1,26 @@ +{ + "name": "dataprotocol-languageserver-types", + "description": "Types used by the Language server for node", + "version": "1.0.4", + "author": "Microsoft Corporation", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/Microsoft/vscode-languageserver-node.git" + }, + "bugs": { + "url": "https://github.com/Microsoft/vscode-languageserver-node/issues" + }, + "main": "./lib/main.js", + "typings": "./lib/main", + "devDependencies": { + "mocha": "^2.4.5", + "typescript": "2.0.3" + }, + "scripts": { + "prepublish": "tsc -p ./src", + "compile": "tsc -p ./src", + "watch": "tsc -w -p ./src", + "test": "mocha" + } +} diff --git a/dataprotocol-node/types/src/main.ts b/dataprotocol-node/types/src/main.ts new file mode 100644 index 0000000000..35a0089647 --- /dev/null +++ b/dataprotocol-node/types/src/main.ts @@ -0,0 +1,2541 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +export interface CreateSessionResponse { + sessionId: string; +} + +export interface SessionCreatedParameters { + success: boolean; + sessionId: string; + rootNode: NodeInfo; + errorMessage: string; +} + +export interface ExpandResponse { + nodePath: string; + sessionId: string; + nodes: NodeInfo[]; + errorMessage: string; +} + +export interface NodeInfo { + nodePath: string; + nodeType: string; + nodeSubType: string; + nodeStatus: string; + label: string; + isLeaf: boolean; + metadata: ObjectMetadata; + errorMessage: string; +} + +export interface ExpandParams { + sessionId: string; + nodePath: string; +} + +export interface CloseSessionParams { + sessionId: string; +} + +export interface CloseSessionResponse { + success: boolean; + sessionId: string; +} + +export interface CategoryValue { + displayName: string; + + name: string; +} + +export interface ServiceOption { + name: string; + + displayName: string; + + description: string; + + groupName: string; + + valueType: string; + + defaultValue: string; + + objectType: string; + + categoryValues: CategoryValue[]; + + isRequired: boolean; + + isArray: boolean; +} + +export interface ConnectionOption { + name: string; + + displayName: string; + + description: string; + + groupName: string; + + valueType: string; + + defaultValue: string; + + objectType: string; + + categoryValues: CategoryValue[]; + + specialValueType: string; + + isIdentity: boolean; + + isRequired: boolean; + + isArray: boolean; +} + +export interface ConnectionProviderOptions { + options: ConnectionOption[]; +} + +export interface AdminServicesProviderOptions { + databaseInfoOptions: ServiceOption[]; + + databaseFileInfoOptions: ServiceOption[]; + + fileGroupInfoOptions: ServiceOption[]; +} + +export interface FeatureMetadataProvider { + enabled: boolean; + featureName: string; + optionsMetadata: ServiceOption[]; +} + +export interface DataProtocolServerCapabilities { + protocolVersion: string; + + providerName: string; + + providerDisplayName: string; + + connectionProvider: ConnectionProviderOptions; + + adminServicesProvider: AdminServicesProviderOptions; + + features: FeatureMetadataProvider[]; +} + +/** + * Parameters to initialize a connection to a database + */ +export interface ConnectionDetails { + + /** + * connection options + */ + options: {}; +} + +/** + * Summary that identifies a unique database connection. + */ +export class ConnectionSummary { + /** + * server name + */ + public serverName: string; + + /** + * database name + */ + public databaseName: string; + + /** + * user name + */ + public userName: string; +} + +/** + * Connection response format. + */ +export class ConnectionCompleteParams { + /** + * URI identifying the owner of the connection + */ + public ownerUri: string; + + /** + * connection id returned from service host. + */ + public connectionId: string; + + /** + * any diagnostic messages return from the service host. + */ + public messages: string; + + /** + * Error message returned from the engine, if any. + */ + public errorMessage: string; + + /** + * Error number returned from the engine, if any. + */ + public errorNumber: number; + + /** + * Information about the connected server. + */ + public serverInfo: ServerInfo; + + /** + * information about the actual connection established + */ + public connectionSummary: ConnectionSummary; +} + +/** + * Update event parameters + */ +export class IntelliSenseReadyParams { + /** + * URI identifying the text document + */ + public ownerUri: string; +} + +/** + * Information about a SQL Server instance. + */ +export class ServerInfo { + /** + * The major version of the SQL Server instance. + */ + public serverMajorVersion: number; + + /** + * The minor version of the SQL Server instance. + */ + public serverMinorVersion: number; + + /** + * The build of the SQL Server instance. + */ + public serverReleaseVersion: number; + + /** + * The ID of the engine edition of the SQL Server instance. + */ + public engineEditionId: number; + + /** + * String containing the full server version text. + */ + public serverVersion: string; + + /** + * String describing the product level of the server. + */ + public serverLevel: string; + + /** + * The edition of the SQL Server instance. + */ + public serverEdition: string; + + /** + * Whether the SQL Server instance is running in the cloud (Azure) or not. + */ + public isCloud: boolean; + + /** + * The version of Azure that the SQL Server instance is running on, if applicable. + */ + public azureVersion: number; + + /** + * The Operating System version string of the machine running the SQL Server instance. + */ + public osVersion: string; +} + +export class CapabiltiesDiscoveryResult { + public capabilities: DataProtocolServerCapabilities; +} + +// Task Services types + +export enum TaskStatus { + notStarted = 0, + inProgress = 1, + succeeded = 2, + succeededWithWarning = 3, + failed = 4, + canceled = 5 +} + +export enum TaskExecutionMode { + execute = 0, + script = 1, + executeAndScript = 2, +} + +export interface TaskInfo { + taskId: string; + status: TaskStatus; + taskExecutionMode: TaskExecutionMode; + serverName: string; + databaseName: string; + name: string; + description: string; + providerName: string; + isCancelable: boolean; +} + +export interface ListTasksParams { + + listActiveTasksOnly: boolean; +} + +export interface ListTasksResponse { + tasks: TaskInfo[]; +} + +export interface CancelTaskParams { + taskId: string; +} + +export interface TaskProgressInfo { + taskId: string; + status: TaskStatus; + message: string; + script: string; + duration: number; +} + +// Admin Services types + +export interface DatabaseInfo { + /** + * database options + */ + options: {}; +} + +export interface BackupConfigInfo { + recoveryModel: string; + defaultBackupFolder: string; + backupEncryptors: {}; +} + +export interface LoginInfo { + name: string; +} + +export interface CreateDatabaseParams { + ownerUri: string; + + databaseInfo: DatabaseInfo; +} + +export interface CreateDatabaseResponse { + result: boolean; + taskId: number; +} + +export interface DefaultDatabaseInfoParams { + ownerUri: string; +} + +export interface DefaultDatabaseInfoResponse { + defaultDatabaseInfo: DatabaseInfo; +} + +export interface GetDatabaseInfoResponse { + databaseInfo: DatabaseInfo; +} + +export interface GetDatabaseInfoParams { + ownerUri: string; +} + +export interface BackupConfigInfoResponse { + backupConfigInfo: BackupConfigInfo; +} + +export interface CreateLoginParams { + ownerUri: string; + + loginInfo: LoginInfo; +} + +export interface CreateLoginResponse { + result: boolean; + taskId: number; +} + +// Disaster Recovery types + +export interface BackupInfo { + ownerUri: string; + + databaseName: string; + + backupType: number; + + backupComponent: number; + + backupDeviceType: number; + + selectedFiles: string; + + backupsetName: string; + + selectedFileGroup: { [path: string]: string }; + + // List of {key: backup path, value: device type} + backupPathDevices: { [path: string]: number }; + + backupPathList: [string]; + + isCopyOnly: boolean; + + formatMedia: boolean; + + initialize: boolean; + + skipTapeHeader: boolean; + + mediaName: string; + + mediaDescription: string; + + checksum: boolean; + + continueAfterError: boolean; + + logTruncation: boolean; + + tailLogBackup: boolean; + + retainDays: number; + + compressionOption: number; + + verifyBackupRequired: boolean; + + encryptionAlgorithm: number; + + encryptorType: number; + + encryptorName: string; +} + +export interface BackupParams { + ownerUri: string; + + backupInfo: BackupInfo; + + taskExecutionMode: TaskExecutionMode; +} + +export interface BackupResponse { + result: boolean; + taskId: number; +} + +export interface RestoreParams { + ownerUri: string; + options: {}; + taskExecutionMode: TaskExecutionMode; +} + +export interface RestoreConfigInfoRequestParams { + ownerUri: string; +} + +export interface RestoreConfigInfoResponse { + configInfo: { [key: string]: any }; +} + +export interface RestoreDatabaseFileInfo { + fileType: string; + + logicalFileName: string; + + originalFileName: string; + + restoreAsFileName: string; +} + +export interface FileBrowserOpenParams { + ownerUri: string; + expandPath: string; + fileFilters: string[]; + changeFilter: boolean; +} + +export interface FileTreeNode { + children: FileTreeNode[]; + isExpanded: boolean; + isFile: boolean; + name: string; + fullPath: string; +} + +export interface FileTree { + rootNode: FileTreeNode; + selectedNode: FileTreeNode; +} + +export interface FileBrowserOpenedParams { + ownerUri: string; + fileTree: FileTree; + succeeded: boolean; + message: string; +} + +export interface FileBrowserExpandParams { + ownerUri: string; + expandPath: string; +} + +export interface FileBrowserExpandedParams { + ownerUri: string; + expandPath: string; + children: FileTreeNode[]; + succeeded: boolean; + message: string; +} + +export interface FileBrowserValidateParams { + ownerUri: string; + serviceType: string; + selectedFiles: string[]; +} + +export interface FileBrowserValidatedParams { + succeeded: boolean; + message: string; +} + +export interface FileBrowserCloseParams { + ownerUri: string; +} + +export interface FileBrowserCloseResponse { + succeeded: boolean; + message: string; +} + +export interface DatabaseFileInfo { + properties: LocalizedPropertyInfo[]; + id: string; + isSelected: boolean; +} + +export interface LocalizedPropertyInfo { + propertyName: string; + propertyValue: string; + propertyDisplayName: string; + propertyValueDisplayName: string; +} + +export interface RestorePlanDetailInfo { + name: string; + currentValue: any; + isReadOnly: boolean; + isVisible: boolean; + defaultValue: any; + +} + +export interface RestorePlanResponse { + sessionId: string; + backupSetsToRestore: DatabaseFileInfo[]; + canRestore: boolean; + errorMessage: string; + dbFiles: RestoreDatabaseFileInfo[]; + databaseNamesFromBackupSets: string[]; + planDetails: { [key: string]: RestorePlanDetailInfo }; +} + +export interface RestoreResponse { + result: boolean; + taskId: string; + errorMessage: string; +} + +// Query Execution types +export interface ResultSetSummary { + id: number; + batchId: number; + rowCount: number; + columnInfo: IDbColumn[]; +} + +export interface BatchSummary { + hasError: boolean; + id: number; + selection: ISelectionData; + resultSetSummaries: ResultSetSummary[]; + executionElapsed: string; + executionEnd: string; + executionStart: string; +} + +export interface IDbColumn { + allowDBNull?: boolean; + baseCatalogName: string; + baseColumnName: string; + baseSchemaName: string; + baseServerName: string; + baseTableName: string; + columnName: string; + columnOrdinal?: number; + columnSize?: number; + isAliased?: boolean; + isAutoIncrement?: boolean; + isExpression?: boolean; + isHidden?: boolean; + isIdentity?: boolean; + isKey?: boolean; + isBytes?: boolean; + isChars?: boolean; + isSqlVariant?: boolean; + isUdt?: boolean; + dataType: string; + isXml?: boolean; + isJson?: boolean; + isLong?: boolean; + isReadOnly?: boolean; + isUnique?: boolean; + numericPrecision?: number; + numericScale?: number; + udtAssemblyQualifiedName: string; + dataTypeName: string; +} + +export interface IGridResultSet { + columns: IDbColumn[]; + rowsUri: string; + numberOfRows: number; +} + +export interface IResultMessage { + batchId?: number; + isError: boolean; + time: string; + message: string; +} + +export interface ISelectionData { + startLine: number; + startColumn: number; + endLine: number; + endColumn: number; +} + +export interface QueryExecuteBatchNotificationParams { + batchSummary: BatchSummary; + ownerUri: string; +} + +export interface DbCellValue { + displayValue: string; + isNull: boolean; +} + +export enum EditRowState { + clean = 0, + dirtyInsert = 1, + dirtyDelete = 2, + dirtyUpdate = 3 +} + +export interface EditRow { + cells: DbCellValue[]; + id: number; + isDirty: boolean; + state: EditRowState; +} + +export interface EditCell extends DbCellValue { + isDirty: boolean; +} + +export interface EditCell extends DbCellValue { + +} + +export class MetadataQueryParams { + /** + * Owner URI of the connection that changed. + */ + public ownerUri: string; +} + +export enum MetadataType { + Table = 0, + View = 1, + SProc = 2, + Function = 3 +} + +export class ObjectMetadata { + metadataType: MetadataType; + + metadataTypeName: string; + + urn: string; + + name: string; + + schema: string; +} + +export class MetadataQueryResult { + public metadata: ObjectMetadata[]; +} + +export interface ScriptingParamDetails { + filePath: string; + scriptCompatibilityOption: string; + targetDatabaseEngineEdition: string; + targetDatabaseEngineType: string; +} + +export enum ScriptOperation { + Select = 0, + Create = 1, + Insert = 2, + Update = 3, + Delete = 4, + Execute = 5, + Alter = 6 +} + +export interface ScriptOptions { + /** + * Generate ANSI padding statements + */ + scriptANSIPadding?: boolean; + + /** + * Append the generated script to a file + */ + appendToFile?: boolean; + + /** + * Continue to script if an error occurs. Otherwise, stop. + */ + continueScriptingOnError?: boolean; + + /** + * Convert user-defined data types to base types. + */ + convertUDDTToBaseType?: boolean; + + /** + * Generate script for dependent objects for each object scripted. + */ + generateScriptForDependentObjects?: boolean; + + /** + * Include descriptive headers for each object generated. + */ + includeDescriptiveHeaders?: boolean; + + /** + * Check that an object with the given name exists before dropping or altering or that an object with the given name does not exist before creating. + */ + includeIfNotExists?: boolean; + + /** + * Script options to set vardecimal storage format. + */ + includeVarDecimal?: boolean; + + /** + * Include system generated constraint names to enforce declarative referential integrity. + */ + scriptDRIIncludeSystemNames?: boolean; + + /** + * Include statements in the script that are not supported on the specified SQL Server database engine type. + */ + includeUnsupportedStatements?: boolean; + + /** + * Prefix object names with the object schema. + */ + schemaQualify?: boolean; + + /** + * Script options to set bindings option. + */ + bindings?: boolean; + + /** + * Script the objects that use collation. + */ + collation?: boolean; + + /** + * Script the default values. + */ + default?: boolean; + + /** + * Script Object CREATE/DROP statements. + */ + scriptCreateDrop: string; + + /** + * Script the Extended Properties for each object scripted. + */ + scriptExtendedProperties?: boolean; + + /** + * Script only features compatible with the specified version of SQL Server. + */ + scriptCompatibilityOption: string; + + /** + * Script only features compatible with the specified SQL Server database engine type. + */ + targetDatabaseEngineType: string; + + /** + * Script only features compatible with the specified SQL Server database engine edition. + */ + targetDatabaseEngineEdition: string; + + /** + * Script all logins available on the server. Passwords will not be scripted. + */ + scriptLogins?: boolean; + + /** + * Generate object-level permissions. + */ + scriptObjectLevelPermissions?: boolean; + + /** + * Script owner for the objects. + */ + scriptOwner?: boolean; + + /** + * Script statistics, and optionally include histograms, for each selected table or view. + */ + scriptStatistics: string; + + /** + * Generate USE DATABASE statement. + */ + scripUseDatabase?: boolean; + + /** + * Generate script that contains schema only or schema and data. + */ + typeOfDataToScript: string; + + /** + * Scripts the change tracking information. + */ + scriptChangeTracking?: boolean; + + /** + * Script the check constraints for each table or view scripted. + */ + scriptCheckConstraints?: boolean; + + /** + * Scripts the data compression information. + */ + scriptDataCompressionOptions?: boolean; + + /** + * Script the foreign keys for each table scripted. + */ + scriptForeignKeys?: boolean; + + /** + * Script the full-text indexes for each table or indexed view scripted. + */ + scriptFullTextIndexes?: boolean; + + /** + * Script the indexes (including XML and clustered indexes) for each table or indexed view scripted. + */ + scriptIndexes?: boolean; + + /** + * Script the primary keys for each table or view scripted + */ + scriptPrimaryKeys?: boolean; + + /** + * Script the triggers for each table or view scripted + */ + scriptTriggers?: boolean; + + /** + * Script the unique keys for each table or view scripted. + */ + uniqueKeys?: boolean; +} + +export interface ScriptingObject { + /** + * The database object type + */ + type: string; + + /** + * The schema of the database object + */ + schema: string; + + /** + * The database object name + */ + name: string; +} + +export interface ScriptingParams { + /** + * File path used when writing out the script. + */ + filePath: string; + + /** + * Whether scripting to a single file or file per object. + */ + scriptDestination: string; + + /** + * Connection string of the target database the scripting operation will run against. + */ + connectionString: string; + + /** + * A list of scripting objects to script + */ + scriptingObjects: ScriptingObject[]; + + /** + * A list of scripting object which specify the include criteria of objects to script. + */ + includeObjectCriteria: ScriptingObject[]; + + /** + * A list of scripting object which specify the exclude criteria of objects to not script. + */ + excludeObjectCriteria: ScriptingObject[]; + + /** + * A list of schema name of objects to script. + */ + includeSchemas: string[]; + + /** + * A list of schema name of objects to not script. + */ + excludeSchemas: string[]; + + /** + * A list of type name of objects to script. + */ + includeTypes: string[]; + + /** + * A list of type name of objects to not script. + */ + excludeTypes: string[]; + + /** + * Scripting options for the ScriptingParams + */ + scriptOptions: ScriptOptions; + + /** + * Connection details for the ScriptingParams + */ + connectionDetails: ConnectionDetails; + + /** + * Owner URI of the connection + */ + ownerURI: string; + + /** + * Whether the scripting operation is for + * select script statements + */ + selectScript: boolean; + + /** + * Operation associated with the script request + */ + operation: ScriptOperation; +} + +export interface ScriptingResult { + + operationId: string; + script: string; +} + +export interface ScriptingCompleteParams { + /** + * The error details for an error that occurred during the scripting operation. + */ + errorDetails: string; + + /** + * The error message for an error that occurred during the scripting operation. + */ + errorMessage: string; + + /** + * A value to indicate an error occurred during the scripting operation. + */ + hasError: boolean; + + /** + * A value to indicate the scripting operation was canceled. + */ + canceled: boolean; + + /** + * A value to indicate the scripting operation successfully completed. + */ + success: boolean; +} + +export class ColumnMetadata { + + hasExtendedProperties: boolean; + + defaultValue: string; + + ///

+ /// Escaped identifier for the name of the column + /// + escapedName: string; + + /// + /// Whether or not the column is computed + /// + isComputed: boolean; + + /// + /// Whether or not the column is deterministically computed + /// + isDeterministic: boolean; + + /// + /// Whether or not the column is an identity column + /// + isIdentity: boolean; + + /// + /// The ordinal ID of the column + /// + ordinal: number; + + /// + /// Whether or not the column is calculated on the server side. This could be a computed + /// column or a identity column. + /// + isCalculated: boolean; + + /// + /// Whether or not the column is used in a key to uniquely identify a row + /// + isKey: boolean; + + /// + /// Whether or not the column can be trusted for uniqueness + /// + isTrustworthyForUniqueness: boolean; + +} + +export class TableMetadata { + + columns: ColumnMetadata[]; + +} + +/** + * Parameters to start a profiler session + */ +export interface StartProfilingParams { + /** + * Session Owner URI + */ + ownerUri: string; + + /** + * Session options + */ + options: {}; +} + +export interface StartProfilingResponse { + succeeded: string; + errorMessage: string; +} + +/** + * Parameters to start a profiler session + */ +export interface StopProfilingParams { + /** + * Session Owner URI + */ + ownerUri: string; +} + +export interface StopProfilingResponse { + succeeded: string; + errorMessage: string; +} + +/** + * Profiler Event + */ +export interface ProfilerEvent { + /** + * Event class name + */ + name: string; + + /** + * Event timestamp + */ + timestamp: string; + + /** + * Event values + */ + values: {}; +} + +/** + * Profiler events available notification parameters + */ +export interface ProfilerEventsAvailableParams +{ + /** + * Session owner URI + */ + ownerUri: string; + + /** + * New profiler events available + */ + events: ProfilerEvent[]; +} + +/** + * Position in a text document expressed as zero-based line and character offset. + */ +export interface Position { + /** + * Line position in a document (zero-based). + */ + line: number; + + /** + * Character offset on a line in a document (zero-based). + */ + character: number; +} + +/** + * The Position namespace provides helper functions to work with + * [Position](#Position) literals. + */ +export namespace Position { + /** + * Creates a new Position literal from the given line and character. + * @param line The position's line. + * @param character The position's character. + */ + export function create(line: number, character: number): Position { + return { line, character }; + } + /** + * Checks whether the given liternal conforms to the [Position](#Position) interface. + */ + export function is(value: any): value is Position { + let candidate = value as Position; + return Is.defined(candidate) && Is.number(candidate.line) && Is.number(candidate.character); + } +} + +/** + * A range in a text document expressed as (zero-based) start and end positions. + */ +export interface Range { + /** + * The range's start position + */ + start: Position; + + /** + * The range's end position + */ + end: Position; +} + +/** + * The Range namespace provides helper functions to work with + * [Range](#Range) literals. + */ +export namespace Range { + /** + * Create a new Range liternal. + * @param start The range's start position. + * @param end The range's end position. + */ + export function create(start: Position, end: Position): Range; + /** + * Create a new Range liternal. + * @param startLine The start line number. + * @param startCharacter The start character. + * @param endLine The end line number. + * @param endCharacter The end character. + */ + export function create(startLine: number, startCharacter: number, endLine: number, endCharacter: number): Range; + export function create(one: Position | number, two: Position | number, three?: number, four?: number): Range { + if (Is.number(one) && Is.number(two) && Is.number(three) && Is.number(four)) { + return { start: Position.create(one, two), end: Position.create(three, four) }; + } else if (Position.is(one) && Position.is(two)) { + return { start: one, end: two }; + } else { + throw new Error(`Range#create called with invalid arguments[${one}, ${two}, ${three}, ${four}]`); + } + } + /** + * Checks whether the given literal conforms to the [Range](#Range) interface. + */ + export function is(value: any): value is Range { + let candidate = value as Range; + return Is.defined(candidate) && Position.is(candidate.start) && Position.is(candidate.end); + } +} + +/** + * Represents a location inside a resource, such as a line + * inside a text file. + */ +export interface Location { + uri: string; + range: Range; +} + +/** + * The Location namespace provides helper functions to work with + * [Location](#Location) literals. + */ +export namespace Location { + /** + * Creates a Location literal. + * @param uri The location's uri. + * @param range The location's range. + */ + export function create(uri: string, range: Range): Location { + return { uri, range }; + } + /** + * Checks whether the given literal conforms to the [Location](#Location) interface. + */ + export function is(value: any): value is Location { + let candidate = value as Location; + return Is.defined(candidate) && Range.is(candidate.range) && (Is.string(candidate.uri) || Is.undefined(candidate.uri)); + } +} + +/** + * The diagnostic's serverity. + */ +export const enum DiagnosticSeverity { + /** + * Reports an error. + */ + Error = 1, + /** + * Reports a warning. + */ + Warning = 2, + /** + * Reports an information. + */ + Information = 3, + /** + * Reports a hint. + */ + Hint = 4 +} + +/** + * Represents a diagnostic, such as a compiler error or warning. Diagnostic objects + * are only valid in the scope of a resource. + */ +export interface Diagnostic { + /** + * The range at which the message applies + */ + range: Range; + + /** + * The diagnostic's severity. Can be omitted. If omitted it is up to the + * client to interpret diagnostics as error, warning, info or hint. + */ + severity?: number; + + /** + * The diagnostic's code. Can be omitted. + */ + code?: number | string; + + /** + * A human-readable string describing the source of this + * diagnostic, e.g. 'typescript' or 'super lint'. + */ + source?: string; + + /** + * The diagnostic's message. + */ + message: string; +} + +/** + * The Diagnostic namespace provides helper functions to work with + * [Diagnostic](#Diagnostic) literals. + */ +export namespace Diagnostic { + /** + * Creates a new Diagnostic literal. + */ + export function create(range: Range, message: string, severity?: number, code?: number | string, source?: string): Diagnostic { + let result: Diagnostic = { range, message }; + if (Is.defined(severity)) { + result.severity = severity; + } + if (Is.defined(code)) { + result.code = code; + } + if (Is.defined(source)) { + result.source = source; + } + return result; + } + /** + * Checks whether the given literal conforms to the [Diagnostic](#Diagnostic) interface. + */ + export function is(value: any): value is Diagnostic { + let candidate = value as Diagnostic; + return Is.defined(candidate) + && Range.is(candidate.range) + && Is.string(candidate.message) + && (Is.number(candidate.severity) || Is.undefined(candidate.severity)) + && (Is.number(candidate.code) || Is.string(candidate.code) || Is.undefined(candidate.code)) + && (Is.string(candidate.source) || Is.undefined(candidate.source)); + } +} + + +/** + * Represents a reference to a command. Provides a title which + * will be used to represent a command in the UI and, optionally, + * an array of arguments which will be passed to the command handler + * function when invoked. + */ +export interface Command { + /** + * Title of the command, like `save`. + */ + title: string; + /** + * The identifier of the actual command handler. + */ + command: string; + /** + * Arguments that the command handler should be + * invoked with. + */ + arguments?: any[]; +} + + +/** + * The Command namespace provides helper functions to work with + * [Command](#Command) literals. + */ +export namespace Command { + /** + * Creates a new Command literal. + */ + export function create(title: string, command: string, ...args: any[]): Command { + let result: Command = { title, command }; + if (Is.defined(args) && args.length > 0) { + result.arguments = args; + } + return result; + } + /** + * Checks whether the given literal conforms to the [Command](#Command) interface. + */ + export function is(value: any): value is Command { + let candidate = value as Command; + return Is.defined(candidate) && Is.string(candidate.title) && Is.string(candidate.title); + } +} + +/** + * A text edit applicable to a text document. + */ +export interface TextEdit { + /** + * The range of the text document to be manipulated. To insert + * text into a document create a range where start === end. + */ + range: Range; + + /** + * The string to be inserted. For delete operations use an + * empty string. + */ + newText: string; +} + +/** + * The TextEdit namespace provides helper function to create replace, + * insert and delete edits more easily. + */ +export namespace TextEdit { + /** + * Creates a replace text edit. + * @param range The range of text to be replaced. + * @param newText The new text. + */ + export function replace(range: Range, newText: string): TextEdit { + return { range, newText }; + } + /** + * Creates a insert text edit. + * @param psotion The position to insert the text at. + * @param newText The text to be inserted. + */ + export function insert(position: Position, newText: string): TextEdit { + return { range: { start: position, end: position }, newText }; + } + /** + * Creates a delete text edit. + * @param range The range of text to be deleted. + */ + export function del(range: Range): TextEdit { + return { range, newText: '' }; + } +} + +/** + * A workspace edit represents changes to many resources managed + * in the workspace. + */ +export interface WorkspaceEdit { + // creates: { [uri: string]: string; }; + /** + * Holds changes to existing resources. + */ + changes: { [uri: string]: TextEdit[]; }; + // deletes: string[]; +} + +/** + * A change to capture text edits for existing resources. + */ +export interface TextEditChange { + /** + * Gets all text edits for this change. + * + * @return An array of text edits. + */ + all(): TextEdit[]; + + /** + * Clears the edits for this change. + */ + clear(): void; + + /** + * Insert the given text at the given position. + * + * @param position A position. + * @param newText A string. + */ + insert(position: Position, newText: string): void; + + /** + * Replace the given range with given text for the given resource. + * + * @param range A range. + * @param newText A string. + */ + replace(range: Range, newText: string): void; + + /** + * Delete the text at the given range. + * + * @param range A range. + */ + delete(range: Range): void; +} + +/** + * A workspace change helps constructing changes to a workspace. + */ +export class WorkspaceChange { + private workspaceEdit: WorkspaceEdit; + private textEditChanges: { [uri: string]: TextEditChange }; + + constructor() { + this.workspaceEdit = { + changes: Object.create(null) + }; + this.textEditChanges = Object.create(null); + } + + /** + * Returns the underlying [WorkspaceEdit](#WorkspaceEdit) literal + * use to be returned from a workspace edit operation like rename. + */ + public get edit(): WorkspaceEdit { + return this.workspaceEdit; + } + + /** + * Returns the [TextEditChange](#TextEditChange) to manage text edits + * for resources. + */ + public getTextEditChange(uri: string): TextEditChange { + class TextEditChangeImpl implements TextEditChange { + private edits: TextEdit[]; + constructor(edits: TextEdit[]) { + this.edits = edits; + } + insert(position: Position, newText: string): void { + this.edits.push(TextEdit.insert(position, newText)); + } + replace(range: Range, newText: string): void { + this.edits.push(TextEdit.replace(range, newText)); + } + delete(range: Range): void { + this.edits.push(TextEdit.del(range)); + } + all(): TextEdit[] { + return this.edits; + } + clear(): void { + this.edits.splice(0, this.edits.length); + } + } + let result = this.textEditChanges[uri]; + if (!result) { + let edits: TextEdit[] = []; + this.workspaceEdit.changes[uri] = edits; + result = new TextEditChangeImpl(edits); + this.textEditChanges[uri] = result; + } + return result; + } +} + +/** + * A literal to identify a text document in the client. + */ +export interface TextDocumentIdentifier { + /** + * The text document's uri. + */ + uri: string; +} + +/** + * The TextDocumentIdentifier namespace provides helper functions to work with + * [TextDocumentIdentifier](#TextDocumentIdentifier) literals. + */ +export namespace TextDocumentIdentifier { + /** + * Creates a new TextDocumentIdentifier literal. + * @param uri The document's uri. + */ + export function create(uri: string): TextDocumentIdentifier { + return { uri }; + } + /** + * Checks whether the given literal conforms to the [TextDocumentIdentifier](#TextDocumentIdentifier) interface. + */ + export function is(value: any): value is TextDocumentIdentifier { + let candidate = value as TextDocumentIdentifier; + return Is.defined(candidate) && Is.string(candidate.uri); + } +} + +/** + * An identifier to denote a specific version of a text document. + */ +export interface VersionedTextDocumentIdentifier extends TextDocumentIdentifier { + /** + * The version number of this document. + */ + version: number; +} + +/** + * The VersionedTextDocumentIdentifier namespace provides helper functions to work with + * [VersionedTextDocumentIdentifier](#VersionedTextDocumentIdentifier) literals. + */ +export namespace VersionedTextDocumentIdentifier { + /** + * Creates a new VersionedTextDocumentIdentifier literal. + * @param uri The document's uri. + * @param uri The document's text. + */ + export function create(uri: string, version: number): VersionedTextDocumentIdentifier { + return { uri, version }; + } + + /** + * Checks whether the given literal conforms to the [VersionedTextDocumentIdentifier](#VersionedTextDocumentIdentifier) interface. + */ + export function is(value: any): value is VersionedTextDocumentIdentifier { + let candidate = value as VersionedTextDocumentIdentifier; + return Is.defined(candidate) && Is.string(candidate.uri) && Is.number(candidate.version); + } +} + + +/** + * An item to transfer a text document from the client to the + * server. + */ +export interface TextDocumentItem { + /** + * The text document's uri. + */ + uri: string; + + /** + * The text document's language identifier + */ + languageId: string; + + /** + * The version number of this document (it will strictly increase after each + * change, including undo/redo). + */ + version: number; + + /** + * The content of the opened text document. + */ + text: string; +} + +/** + * The TextDocumentItem namespace provides helper functions to work with + * [TextDocumentItem](#TextDocumentItem) literals. + */ +export namespace TextDocumentItem { + /** + * Creates a new TextDocumentItem literal. + * @param uri The document's uri. + * @param uri The document's language identifier. + * @param uri The document's version number. + * @param uri The document's text. + */ + export function create(uri: string, languageId: string, version: number, text: string): TextDocumentItem { + return { uri, languageId, version, text }; + } + + /** + * Checks whether the given literal conforms to the [TextDocumentItem](#TextDocumentItem) interface. + */ + export function is(value: any): value is TextDocumentItem { + let candidate = value as TextDocumentItem; + return Is.defined(candidate) && Is.string(candidate.uri) && Is.string(candidate.languageId) && Is.number(candidate.version) && Is.string(candidate.text); + } +} + +/** + * The kind of a completion entry. + */ +export const enum CompletionItemKind { + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18 +} + +/** + * A completion item represents a text snippet that is + * proposed to complete text that is being typed. + */ +export interface CompletionItem { + /** + * The label of this completion item. By default + * also the text that is inserted when selecting + * this completion. + */ + label: string; + + /** + * The kind of this completion item. Based of the kind + * an icon is chosen by the editor. + */ + kind?: number; + + /** + * A human-readable string with additional information + * about this item, like type or symbol information. + */ + detail?: string; + + /** + * A human-readable string that represents a doc-comment. + */ + documentation?: string; + + /** + * A string that shoud be used when comparing this item + * with other items. When `falsy` the [label](#CompletionItem.label) + * is used. + */ + sortText?: string; + + /** + * A string that should be used when filtering a set of + * completion items. When `falsy` the [label](#CompletionItem.label) + * is used. + */ + filterText?: string; + + /** + * A string that should be inserted a document when selecting + * this completion. When `falsy` the [label](#CompletionItem.label) + * is used. + */ + insertText?: string; + + /** + * An [edit](#TextEdit) which is applied to a document when selecting + * this completion. When an edit is provided the value of + * [insertText](#CompletionItem.insertText) is ignored. + */ + textEdit?: TextEdit; + + /** + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this completion. Edits must not overlap with the main [edit](#CompletionItem.textEdit) + * nor with themselves. + */ + additionalTextEdits?: TextEdit[]; + + /** + * An optional [command](#Command) that is executed *after* inserting this completion. *Note* that + * additional modifications to the current document should be described with the + * [additionalTextEdits](#CompletionItem.additionalTextEdits)-property. + */ + command?: Command; + + /** + * An data entry field that is preserved on a completion item between + * a [CompletionRequest](#CompletionRequest) and a [CompletionResolveRequest] + * (#CompletionResolveRequest) + */ + data?: any +} + +/** + * The CompletionItem namespace provides functions to deal with + * completion items. + */ +export namespace CompletionItem { + /** + * Create a completion item and seed it with a label. + * @param label The completion item's label + */ + export function create(label: string): CompletionItem { + return { label }; + } +} + +/** + * Represents a collection of [completion items](#CompletionItem) to be presented + * in the editor. + */ +export interface CompletionList { + /** + * This list it not complete. Further typing should result in recomputing + * this list. + */ + isIncomplete: boolean; + + /** + * The completion items. + */ + items: CompletionItem[]; +} + +/** + * The CompletionList namespace provides functions to deal with + * completion lists. + */ +export namespace CompletionList { + /** + * Creates a new completion list. + * + * @param items The completion items. + * @param isIncomplete The list is not complete. + */ + export function create(items?: CompletionItem[], isIncomplete?: boolean): CompletionList { + return { items: items ? items : [], isIncomplete: !!isIncomplete }; + } +} + +/** + * MarkedString can be used to render human readable text. It is either a markdown string + * or a code-block that provides a language and a code snippet. Note that + * markdown strings will be sanitized - that means html will be escaped. + */ +export type MarkedString = string | { language: string; value: string }; + +export namespace MarkedString { + /** + * Creates a marked string from plain text. + * + * @param plainText The plain text. + */ + export function fromPlainText(plainText: string): MarkedString { + return plainText.replace(/[\\`*_{}[\]()#+\-.!]/g, "\\$&"); // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash + } +} + +/** + * The result of a hove request. + */ +export interface Hover { + /** + * The hover's content + */ + contents: MarkedString | MarkedString[]; + + /** + * An optional range + */ + range?: Range; +} + +/** + * Represents a parameter of a callable-signature. A parameter can + * have a label and a doc-comment. + */ +export interface ParameterInformation { + /** + * The label of this signature. Will be shown in + * the UI. + */ + label: string; + + /** + * The human-readable doc-comment of this signature. Will be shown + * in the UI but can be omitted. + */ + documentation?: string; +} + +/** + * The ParameterInformation namespace provides helper functions to work with + * [ParameterInformation](#ParameterInformation) literals. + */ +export namespace ParameterInformation { + /** + * Creates a new parameter information literal. + * + * @param label A label string. + * @param documentation A doc string. + */ + export function create(label: string, documentation?: string): ParameterInformation { + return documentation ? { label, documentation } : { label }; + }; +} + +/** + * Represents the signature of something callable. A signature + * can have a label, like a function-name, a doc-comment, and + * a set of parameters. + */ +export interface SignatureInformation { + /** + * The label of this signature. Will be shown in + * the UI. + */ + label: string; + + /** + * The human-readable doc-comment of this signature. Will be shown + * in the UI but can be omitted. + */ + documentation?: string; + + /** + * The parameters of this signature. + */ + parameters?: ParameterInformation[]; +} + +/** + * The SignatureInformation namespace provides helper functions to work with + * [SignatureInformation](#SignatureInformation) literals. + */ +export namespace SignatureInformation { + export function create(label: string, documentation?: string, ...parameters: ParameterInformation[]): SignatureInformation { + let result: SignatureInformation = { label }; + if (Is.defined(documentation)) { + result.documentation = documentation; + } + if (Is.defined(parameters)) { + result.parameters = parameters; + } else { + result.parameters = []; + } + return result; + } +} + +/** + * Signature help represents the signature of something + * callable. There can be multiple signature but only one + * active and only one active parameter. + */ +export interface SignatureHelp { + /** + * One or more signatures. + */ + signatures: SignatureInformation[]; + + /** + * The active signature. + */ + activeSignature?: number; + + /** + * The active parameter of the active signature. + */ + activeParameter?: number; +} + +/** + * The definition of a symbol represented as one or many [locations](#Location). + * For most programming languages there is only one location at which a symbol is + * defined. + */ +export type Definition = Location | Location[]; + +/** + * Value-object that contains additional information when + * requesting references. + */ +export interface ReferenceContext { + /** + * Include the declaration of the current symbol. + */ + includeDeclaration: boolean; +} + + +/** + * A document highlight kind. + */ +export const enum DocumentHighlightKind { + /** + * A textual occurrance. + */ + Text = 1, + + /** + * Read-access of a symbol, like reading a variable. + */ + Read = 2, + + /** + * Write-access of a symbol, like writing to a variable. + */ + Write = 3 +} + +/** + * A document highlight is a range inside a text document which deserves + * special attention. Usually a document highlight is visualized by changing + * the background color of its range. + */ +export interface DocumentHighlight { + /** + * The range this highlight applies to. + */ + range: Range; + + /** + * The highlight kind, default is [text](#DocumentHighlightKind.Text). + */ + kind?: number; +} + +/** + * DocumentHighlight namespace to provide helper functions to work with + * [DocumentHighlight](#DocumentHighlight) literals. + */ +export namespace DocumentHighlight { + /** + * Create a DocumentHighlight object. + * @param range The range the highlight applies to. + */ + export function create(range: Range, kind?: number): DocumentHighlight { + let result: DocumentHighlight = { range }; + if (Is.number(kind)) { + result.kind = kind; + } + return result; + } +} + +/** + * A symbol kind. + */ +export const enum SymbolKind { + File = 1, + Module = 2, + Namespace = 3, + Package = 4, + Class = 5, + Method = 6, + Property = 7, + Field = 8, + Constructor = 9, + Enum = 10, + Interface = 11, + Function = 12, + Variable = 13, + Constant = 14, + String = 15, + Number = 16, + Boolean = 17, + Array = 18, +} + +/** + * Represents information about programming constructs like variables, classes, + * interfaces etc. + */ +export interface SymbolInformation { + /** + * The name of this symbol. + */ + name: string; + + /** + * The kind of this symbol. + */ + kind: number; + + /** + * The location of this symbol. + */ + location: Location; + + /** + * The name of the symbol containing this symbol. + */ + containerName?: string; +} + +export namespace SymbolInformation { + /** + * Creates a new symbol information literal. + * + * @param name The name of the symbol. + * @param kind The kind of the symbol. + * @param range The range of the location of the symbol. + * @param uri The resource of the location of symbol, defaults to the current document. + * @param containerName The name of the symbol containg the symbol. + */ + export function create(name: string, kind: SymbolKind, range: Range, uri?: string, containerName?: string): SymbolInformation { + let result: SymbolInformation = { + name, + kind, + location: { uri, range } + } + if (containerName) { + result.containerName = containerName; + } + return result; + } +} + +/** + * Parameters for a [DocumentSymbolRequest](#DocumentSymbolRequest). + */ +export interface DocumentSymbolParams { + /** + * The text document. + */ + textDocument: TextDocumentIdentifier; +} + +/** + * The parameters of a [WorkspaceSymbolRequest](#WorkspaceSymbolRequest). + */ +export interface WorkspaceSymbolParams { + /** + * A non-empty query string + */ + query: string; +} + +/** + * Contains additional diagnostic information about the context in which + * a [code action](#CodeActionProvider.provideCodeActions) is run. + */ +export interface CodeActionContext { + /** + * An array of diagnostics. + */ + diagnostics: Diagnostic[]; +} + +/** + * The CodeActionContext namespace provides helper functions to work with + * [CodeActionContext](#CodeActionContext) literals. + */ +export namespace CodeActionContext { + /** + * Creates a new CodeActionContext literal. + */ + export function create(diagnostics: Diagnostic[]): CodeActionContext { + return { diagnostics }; + } + /** + * Checks whether the given literal conforms to the [CodeActionContext](#CodeActionContext) interface. + */ + export function is(value: any): value is CodeActionContext { + let candidate = value as CodeActionContext; + return Is.defined(candidate) && Is.typedArray(candidate.diagnostics, Diagnostic.is); + } +} + +/** + * A code lens represents a [command](#Command) that should be shown along with + * source text, like the number of references, a way to run tests, etc. + * + * A code lens is _unresolved_ when no command is associated to it. For performance + * reasons the creation of a code lens and resolving should be done to two stages. + */ +export interface CodeLens { + /** + * The range in which this code lens is valid. Should only span a single line. + */ + range: Range; + + /** + * The command this code lens represents. + */ + command?: Command; + + /** + * An data entry field that is preserved on a code lens item between + * a [CodeLensRequest](#CodeLensRequest) and a [CodeLensResolveRequest] + * (#CodeLensResolveRequest) + */ + data?: any +} + +/** + * The CodeLens namespace provides helper functions to work with + * [CodeLens](#CodeLens) literals. + */ +export namespace CodeLens { + /** + * Creates a new CodeLens literal. + */ + export function create(range: Range, data?: any): CodeLens { + let result: CodeLens = { range }; + if (Is.defined(data)) result.data = data; + return result; + } + /** + * Checks whether the given literal conforms to the [CodeLens](#CodeLens) interface. + */ + export function is(value: any): value is CodeLens { + let candidate = value as CodeLens; + return Is.defined(candidate) && Range.is(candidate.range) && (Is.undefined(candidate.command) || Command.is(candidate.command)); + } +} + +/** + * Value-object describing what options formatting should use. + */ +export interface FormattingOptions { + /** + * Size of a tab in spaces. + */ + tabSize: number; + + /** + * Prefer spaces over tabs. + */ + insertSpaces: boolean; + + /** + * Signature for further properties. + */ + [key: string]: boolean | number | string; +} + +/** + * The FormattingOptions namespace provides helper functions to work with + * [FormattingOptions](#FormattingOptions) literals. + */ +export namespace FormattingOptions { + /** + * Creates a new FormattingOptions literal. + */ + export function create(tabSize: number, insertSpaces: boolean): FormattingOptions { + return { tabSize, insertSpaces }; + } + /** + * Checks whether the given literal conforms to the [FormattingOptions](#FormattingOptions) interface. + */ + export function is(value: any): value is FormattingOptions { + let candidate = value as FormattingOptions; + return Is.defined(candidate) && Is.number(candidate.tabSize) && Is.boolean(candidate.insertSpaces); + } +} + +/** + * A document link is a range in a text document that links to an internal or external resource, like another + * text document or a web site. + */ +export class DocumentLink { + + /** + * The range this link applies to. + */ + range: Range; + + /** + * The uri this link points to. + */ + target: string; +} + +/** + * The DocumentLink namespace provides helper functions to work with + * [DocumentLink](#DocumentLink) literals. + */ +export namespace DocumentLink { + /** + * Creates a new DocumentLink literal. + */ + export function create(range: Range, target?: string): DocumentLink { + return { range, target }; + } + + /** + * Checks whether the given literal conforms to the [DocumentLink](#DocumentLink) interface. + */ + export function is(value: any): value is DocumentLink { + let candidate = value as DocumentLink; + return Is.defined(candidate) && Range.is(candidate.range) && (Is.undefined(candidate.target) || Is.string(candidate.target)); + } +} + +/** + * A simple text document. Not to be implemenented. + */ +export interface TextDocument { + + /** + * The associated URI for this document. Most documents have the __file__-scheme, indicating that they + * represent files on disk. However, some documents may have other schemes indicating that they are not + * available on disk. + * + * @readonly + */ + uri: string; + + /** + * The identifier of the language associated with this document. + * + * @readonly + */ + languageId: string; + + /** + * The version number of this document (it will strictly increase after each + * change, including undo/redo). + * + * @readonly + */ + version: number; + + /** + * Get the text of this document. + * + * @return The text of this document. + */ + getText(): string; + + /** + * Converts a zero-based offset to a position. + * + * @param offset A zero-based offset. + * @return A valid [position](#Position). + */ + positionAt(offset: number): Position; + + /** + * Converts the position to a zero-based offset. + * + * The position will be [adjusted](#TextDocument.validatePosition). + * + * @param position A position. + * @return A valid zero-based offset. + */ + offsetAt(position: Position): number; + + /** + * The number of lines in this document. + * + * @readonly + */ + lineCount: number; +} + +export namespace TextDocument { + /** + * Creates a new ITextDocument literal from the given uri and content. + * @param uri The document's uri. + * @param languageId The document's language Id. + * @param content The document's content. + */ + export function create(uri: string, languageId: string, version: number, content: string): TextDocument { + return new FullTextDocument(uri, languageId, version, content); + } + /** + * Checks whether the given literal conforms to the [ITextDocument](#ITextDocument) interface. + */ + export function is(value: any): value is TextDocument { + let candidate = value as TextDocument; + return Is.defined(candidate) && Is.string(candidate.uri) && (Is.undefined(candidate.languageId) || Is.string(candidate.languageId)) && Is.number(candidate.lineCount) + && Is.func(candidate.getText) && Is.func(candidate.positionAt) && Is.func(candidate.offsetAt) ? true : false; + } +} + +/** + * Event to signal changes to a simple text document. + */ +export interface TextDocumentChangeEvent { + /** + * The document that has changed. + */ + document: TextDocument; +} + +/** + * An event describing a change to a text document. If range and rangeLength are omitted + * the new text is considered to be the full content of the document. + */ +export interface TextDocumentContentChangeEvent { + /** + * The range of the document that changed. + */ + range?: Range; + + /** + * The length of the range that got replaced. + */ + rangeLength?: number; + + /** + * The new text of the document. + */ + text: string; +} + +class FullTextDocument implements TextDocument { + + private _uri: string; + private _languageId: string; + private _version: number; + private _content: string; + private _lineOffsets: number[]; + + public constructor(uri: string, languageId: string, version: number, content: string) { + this._uri = uri; + this._languageId = languageId; + this._version = version; + this._content = content; + this._lineOffsets = null; + } + + public get uri(): string { + return this._uri; + } + + public get languageId(): string { + return this._languageId; + } + + public get version(): number { + return this._version; + } + + public getText(): string { + return this._content; + } + + public update(event: TextDocumentContentChangeEvent, version: number): void { + this._content = event.text; + this._version = version; + this._lineOffsets = null; + } + + private getLineOffsets(): number[] { + if (this._lineOffsets === null) { + let lineOffsets: number[] = []; + let text = this._content; + let isLineStart = true; + for (let i = 0; i < text.length; i++) { + if (isLineStart) { + lineOffsets.push(i); + isLineStart = false; + } + let ch = text.charAt(i); + isLineStart = (ch === '\r' || ch === '\n'); + if (ch === '\r' && i + 1 < text.length && text.charAt(i + 1) === '\n') { + i++; + } + } + if (isLineStart && text.length > 0) { + lineOffsets.push(text.length); + } + this._lineOffsets = lineOffsets; + } + return this._lineOffsets; + } + + public positionAt(offset: number) { + offset = Math.max(Math.min(offset, this._content.length), 0); + + let lineOffsets = this.getLineOffsets(); + let low = 0, high = lineOffsets.length; + if (high === 0) { + return Position.create(0, offset); + } + while (low < high) { + let mid = Math.floor((low + high) / 2); + if (lineOffsets[mid] > offset) { + high = mid; + } else { + low = mid + 1; + } + } + // low is the least x for which the line offset is larger than the current offset + // or array.length if no line offset is larger than the current offset + let line = low - 1; + return Position.create(line, offset - lineOffsets[line]); + } + + public offsetAt(position: Position) { + let lineOffsets = this.getLineOffsets(); + if (position.line >= lineOffsets.length) { + return this._content.length; + } else if (position.line < 0) { + return 0; + } + let lineOffset = lineOffsets[position.line]; + let nextLineOffset = (position.line + 1 < lineOffsets.length) ? lineOffsets[position.line + 1] : this._content.length; + return Math.max(Math.min(lineOffset + position.character, nextLineOffset), lineOffset); + } + + public get lineCount() { + return this.getLineOffsets().length; + } +} + +namespace Is { + + const toString = Object.prototype.toString; + + export function defined(value: any): boolean { + return typeof value !== 'undefined'; + } + + export function undefined(value: any): boolean { + return typeof value === 'undefined'; + } + + export function boolean(value: any): value is boolean { + return value === true || value === false; + } + + export function string(value: any): value is string { + return toString.call(value) === '[object String]'; + } + + export function number(value: any): value is number { + return toString.call(value) === '[object Number]'; + } + + export function func(value: any): value is Function { + return toString.call(value) === '[object Function]'; + } + + export function typedArray(value: any, check: (value: any) => boolean): value is T[] { + return Array.isArray(value) && (value).every(check); + } + +} diff --git a/dataprotocol-node/types/src/tsconfig.json b/dataprotocol-node/types/src/tsconfig.json new file mode 100644 index 0000000000..c8c604f238 --- /dev/null +++ b/dataprotocol-node/types/src/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "ES5", + "module": "umd", + "sourceMap": false, + "declaration": true, + "stripInternal": true, + "outDir": "../lib" + } +} \ No newline at end of file diff --git a/dataprotocol-node/types/src/typings/promise.d.ts b/dataprotocol-node/types/src/typings/promise.d.ts new file mode 100644 index 0000000000..925c943df5 --- /dev/null +++ b/dataprotocol-node/types/src/typings/promise.d.ts @@ -0,0 +1,112 @@ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + +/** + * The Thenable (E.g. PromiseLike) and Promise declarions are taken from TypeScript's + * lib.core.es6.d.ts file. See above Copyright notice. + */ + +/** + * Thenable is a common denominator between ES6 promises, Q, jquery.Deferred, WinJS.Promise, + * and others. This API makes no assumption about what promise libary is being used which + * enables reusing existing code without migrating to a specific promise implementation. Still, + * we recommand the use of native promises which are available in VS Code. + */ +interface Thenable { + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: (value: R) => TResult | Thenable, onrejected?: (reason: any) => TResult | Thenable): Thenable; + then(onfulfilled?: (value: R) => TResult | Thenable, onrejected?: (reason: any) => void): Thenable; +} + +/** + * Represents the completion of an asynchronous operation + */ +interface Promise extends Thenable { + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => TResult | Thenable): Promise; + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => void): Promise; + + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: (reason: any) => T | Thenable): Promise; +} + +interface PromiseConstructor { + /** + * Creates a new Promise. + * @param executor A callback used to initialize the promise. This callback is passed two arguments: + * a resolve callback used resolve the promise with a value or the result of another promise, + * and a reject callback used to reject the promise with a provided reason or error. + */ + new (executor: (resolve: (value?: T | Thenable) => void, reject: (reason?: any) => void) => void): Promise; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: Array>): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: Array>): Promise; + + /** + * Creates a new rejected promise for the provided reason. + * @param reason The reason the promise was rejected. + * @returns A new rejected Promise. + */ + reject(reason: any): Promise; + + /** + * Creates a new rejected promise for the provided reason. + * @param reason The reason the promise was rejected. + * @returns A new rejected Promise. + */ + reject(reason: any): Promise; + + /** + * Creates a new resolved promise for the provided value. + * @param value A promise. + * @returns A promise whose internal state matches the provided promise. + */ + resolve(value: T | Thenable): Promise; + + /** + * Creates a new resolved promise . + * @returns A resolved promise. + */ + resolve(): Promise; +} + +declare var Promise: PromiseConstructor; diff --git a/extensions-modules/package.json b/extensions-modules/package.json index ebe8d53cad..e77b8cad8b 100644 --- a/extensions-modules/package.json +++ b/extensions-modules/package.json @@ -3,15 +3,14 @@ "version": "0.1.0", "description": "Shared modules for Carbon extensions", "dependencies": { - "dataprotocol-client": "file:./../dataprotocol-client", + "dataprotocol-client": "file:../dataprotocol-node/client", "decompress": "^4.2.0", "fs-extra-promise": "^1.0.1", "http-proxy-agent": "^2.0.0", "https-proxy-agent": "^2.1.0", "opener": "^1.4.3", "tmp": "0.0.33", - "vscode-extension-telemetry": "0.0.8", - "vscode-languageclient": "^3.5.0" + "vscode-extension-telemetry": "0.0.8" }, "devDependencies": { "@types/node": "^6.0.61", diff --git a/extensions-modules/src/languageservice/serviceClient.ts b/extensions-modules/src/languageservice/serviceClient.ts index b43821e7cd..01fcac59c8 100644 --- a/extensions-modules/src/languageservice/serviceClient.ts +++ b/extensions-modules/src/languageservice/serviceClient.ts @@ -5,8 +5,11 @@ 'use strict'; import { ExtensionContext, workspace, window, OutputChannel, languages } from 'vscode'; -import { SqlOpsDataClient, LanguageClientOptions } from 'dataprotocol-client'; -import { CloseAction, ErrorAction, ServerOptions, NotificationHandler, NotificationType, RequestType, TransportKind } from 'vscode-languageclient'; +import { + LanguageClient, LanguageClientOptions, ServerOptions, + TransportKind, RequestType, NotificationType, NotificationHandler, + ErrorAction, CloseAction +} from 'dataprotocol-client'; import { VscodeWrapper } from '../controllers/vscodeWrapper'; import { Telemetry } from '../models/telemetry'; @@ -132,14 +135,14 @@ export class SqlToolsServiceClient { } // VS Code Language Client - private _client: SqlOpsDataClient = undefined; + private _client: LanguageClient = undefined; // getter method for the Language Client - private get client(): SqlOpsDataClient { + private get client(): LanguageClient { return this._client; } - private set client(client: SqlOpsDataClient) { + private set client(client: LanguageClient) { this._client = client; } @@ -230,7 +233,6 @@ export class SqlToolsServiceClient { } this._logger.appendLine(); - this._server.getServerPath(platformInfo.runtimeId).then(serverPath => { if (serverPath === undefined) { // Check if the service already installed and if not open the output channel to show the logs @@ -317,9 +319,9 @@ export class SqlToolsServiceClient { } } - public createClient(context: ExtensionContext, runtimeId: Runtime, languageClientHelper: LanguageServiceContracts.ILanguageClientHelper, executableFiles: string[]): Promise { - return new Promise((resolve, reject) => { - let client: SqlOpsDataClient; + public createClient(context: ExtensionContext, runtimeId: Runtime, languageClientHelper: LanguageServiceContracts.ILanguageClientHelper, executableFiles: string[]): Promise { + return new Promise((resolve, reject) => { + let client: LanguageClient; this._server.findServerPath(this.installDirectory, executableFiles).then(serverPath => { if (serverPath === undefined) { reject(new Error(SqlToolsServiceClient._constants.invalidServiceFilePath)); @@ -340,7 +342,7 @@ export class SqlToolsServiceClient { }; this._serviceStatus.showServiceLoading(); // cache the client instance for later use - client = new SqlOpsDataClient(SqlToolsServiceClient._constants.serviceName, serverOptions, clientOptions); + client = new LanguageClient(SqlToolsServiceClient._constants.serviceName, serverOptions, clientOptions); if (context !== undefined) { // Create the language client and start the client. @@ -387,7 +389,7 @@ export class SqlToolsServiceClient { return serverOptions; } - private createLanguageClient(serverOptions: ServerOptions): SqlOpsDataClient { + private createLanguageClient(serverOptions: ServerOptions): LanguageClient { // Options to control the language client let clientOptions: LanguageClientOptions = { documentSelector: [SqlToolsServiceClient._constants.languageId], @@ -401,7 +403,7 @@ export class SqlToolsServiceClient { this._serviceStatus.showServiceLoading(); // cache the client instance for later use - let client = new SqlOpsDataClient(SqlToolsServiceClient._constants.serviceName, serverOptions, clientOptions); + let client = new LanguageClient(SqlToolsServiceClient._constants.serviceName, serverOptions, clientOptions); client.onReady().then(() => { this.checkServiceCompatibility(); this._serviceStatus.showServiceLoaded(); @@ -447,7 +449,7 @@ export class SqlToolsServiceClient { * @param params The params to pass with the request * @returns A thenable object for when the request receives a response */ - public sendRequest(type: RequestType, params?: P, client: SqlOpsDataClient = undefined): Thenable { + public sendRequest(type: RequestType, params?: P, client: LanguageClient = undefined): Thenable { if (client === undefined) { client = this._client; } @@ -461,7 +463,7 @@ export class SqlToolsServiceClient { * @param type The notification type to register the handler for * @param handler The handler to register */ - public onNotification(type: NotificationType, handler: NotificationHandler

, client: SqlOpsDataClient = undefined): void { + public onNotification

(type: NotificationType

, handler: NotificationHandler

, client: LanguageClient = undefined): void { if (client === undefined) { client = this._client; } diff --git a/extensions-modules/src/models/contracts/contracts.ts b/extensions-modules/src/models/contracts/contracts.ts index ae5140b28a..a96185b7e5 100644 --- a/extensions-modules/src/models/contracts/contracts.ts +++ b/extensions-modules/src/models/contracts/contracts.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { RequestType } from 'vscode-languageclient'; +import { RequestType } from 'dataprotocol-client'; import { Runtime, LinuxDistribution } from '../platform'; // --------------------------------- < Version Request > ------------------------------------------------- // Version request message callback declaration export namespace VersionRequest { - export const type = new RequestType('version'); + export const type: RequestType = { get method(): string { return 'version'; } }; } // Version response format diff --git a/extensions-modules/src/models/contracts/languageService.ts b/extensions-modules/src/models/contracts/languageService.ts index 1113338349..78d4821c2e 100644 --- a/extensions-modules/src/models/contracts/languageService.ts +++ b/extensions-modules/src/models/contracts/languageService.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { NotificationType, ServerOptions } from 'vscode-languageclient'; +import { NotificationType, ServerOptions } from 'dataprotocol-client'; import { ITelemetryEventProperties, ITelemetryEventMeasures } from '../telemetry'; import { Runtime } from '../platform'; @@ -12,7 +12,7 @@ import { Runtime } from '../platform'; * Event sent when the language service send a telemetry event */ export namespace TelemetryNotification { - export const type = new NotificationType('telemetry/sqlevent'); + export const type: NotificationType = { get method(): string { return 'telemetry/sqlevent'; } }; } /** @@ -34,7 +34,7 @@ export class TelemetryParams { * Event sent when the language service send a status change event */ export namespace StatusChangedNotification { - export const type = new NotificationType('textDocument/statusChanged'); + export const type: NotificationType = { get method(): string { return 'textDocument/statusChanged'; } }; } /** diff --git a/extensions/mssql/client/src/models/contracts.ts b/extensions/mssql/client/src/models/contracts.ts index 4f387acfc2..5292118e58 100644 --- a/extensions/mssql/client/src/models/contracts.ts +++ b/extensions/mssql/client/src/models/contracts.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { RequestType } from 'vscode-languageclient'; +import { RequestType } from 'dataprotocol-client'; import * as data from 'data'; // DEV-NOTE: Still finalizing what we'll need as part of this interface @@ -22,14 +22,14 @@ export class SaveResultsInfo { } export namespace SaveAsRequest { - export const type = new RequestType('query/saveAs'); + export const type: RequestType = { get method(): string { return 'query/saveAs'; } }; } // --------------------------------- < Read Credential Request > ------------------------------------------------- // Read Credential request message callback declaration export namespace ReadCredentialRequest { - export const type = new RequestType('credential/read'); + export const type: RequestType = { get method(): string { return 'credential/read'; } }; } /** @@ -53,7 +53,7 @@ export class Credential { // Save Credential request message callback declaration export namespace SaveCredentialRequest { - export const type = new RequestType('credential/save'); + export const type: RequestType = { get method(): string { return 'credential/save'; } }; } // --------------------------------- ------------------------------------------------- @@ -62,17 +62,17 @@ export namespace SaveCredentialRequest { // Delete Credential request message callback declaration export namespace DeleteCredentialRequest { - export const type = new RequestType('credential/delete'); + export const type: RequestType = { get method(): string { return 'credential/delete'; } }; } // --------------------------------- ------------------------------------------------- // ------------------------------- < Resource Events > ------------------------------------ export namespace CreateFirewallRuleRequest { - export const type = new RequestType('resource/createFirewallRule'); + export const type: RequestType = { get method(): string { return 'resource/createFirewallRule'; } }; } export namespace HandleFirewallRuleRequest { - export const type = new RequestType('resource/handleFirewallRule'); + export const type: RequestType = { get method(): string { return 'resource/handleFirewallRule'; } }; } // Firewall rule interfaces diff --git a/extensions/mssql/npm-shrinkwrap.json b/extensions/mssql/npm-shrinkwrap.json index 65619d0d70..855401593d 100644 --- a/extensions/mssql/npm-shrinkwrap.json +++ b/extensions/mssql/npm-shrinkwrap.json @@ -1,4 +1,21 @@ { "name": "mssql", - "version": "0.1.0" -} \ No newline at end of file + "version": "0.1.0", + "dependencies": { + "dataprotocol-client": { + "version": "2.6.3", + "from": "..\\..\\dataprotocol-node\\client", + "resolved": "file:..\\..\\dataprotocol-node\\client" + }, + "dataprotocol-jsonrpc": { + "version": "2.4.0", + "from": "..\\..\\dataprotocol-node\\jsonrpc", + "resolved": "file:..\\..\\dataprotocol-node\\jsonrpc" + }, + "dataprotocol-languageserver-types": { + "version": "1.0.4", + "from": "..\\..\\dataprotocol-node\\types", + "resolved": "file:..\\..\\dataprotocol-node\\types" + } + } +} diff --git a/extensions/mssql/package.json b/extensions/mssql/package.json index 4e58d6f4e5..300cb6acd9 100644 --- a/extensions/mssql/package.json +++ b/extensions/mssql/package.json @@ -16,7 +16,7 @@ "scripts": { "compile": "gulp compile-extension:mssql-client", "postinstall": "node ./node_modules/vscode/bin/install", - "update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-mssql syntaxes/SQL.plist ./syntaxes/sql.tmLanguage.json" + "update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-mssql syntaxes/SQL.plist ./syntaxes/sql.tmLanguage.json" }, "contributes": { "languages": [ @@ -191,6 +191,9 @@ ] } }, + "dependencies": { + "dataprotocol-client": "file:../../dataprotocol-node/client" + }, "devDependencies": { "vscode": "1.0.1" } diff --git a/src/sql/base/browser/ui/modal/optionsDialog.ts b/src/sql/base/browser/ui/modal/optionsDialog.ts index 93754a5f13..b8714b1882 100644 --- a/src/sql/base/browser/ui/modal/optionsDialog.ts +++ b/src/sql/base/browser/ui/modal/optionsDialog.ts @@ -29,7 +29,6 @@ import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import { SplitView, CollapsibleState } from 'sql/base/browser/ui/splitview/splitview'; import { Builder, $ } from 'vs/base/browser/builder'; import { Widget } from 'vs/base/browser/ui/widget'; -import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes'; export class CategoryView extends FixedCollapsibleView { private _treecontainer: HTMLElement; @@ -168,13 +167,13 @@ export class OptionsDialog extends Modal { var widget: Widget = this._optionElements[optionName].optionWidget; var option = this._optionElements[optionName].option; switch (option.valueType) { - case ServiceOptionType.category: - case ServiceOptionType.boolean: + case OptionsDialogHelper.ServiceOptionType.category: + case OptionsDialogHelper.ServiceOptionType.boolean: this._register(styler.attachSelectBoxStyler(widget, this._themeService)); break; - case ServiceOptionType.string: - case ServiceOptionType.password: - case ServiceOptionType.number: + case OptionsDialogHelper.ServiceOptionType.string: + case OptionsDialogHelper.ServiceOptionType.password: + case OptionsDialogHelper.ServiceOptionType.number: this._register(styler.attachInputBoxStyler(widget, this._themeService)); } } diff --git a/src/sql/base/browser/ui/modal/optionsDialogHelper.ts b/src/sql/base/browser/ui/modal/optionsDialogHelper.ts index 394eedf341..8b057709dd 100644 --- a/src/sql/base/browser/ui/modal/optionsDialogHelper.ts +++ b/src/sql/base/browser/ui/modal/optionsDialogHelper.ts @@ -14,7 +14,6 @@ import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox'; import * as types from 'vs/base/common/types'; import data = require('data'); import { localize } from 'vs/nls'; -import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes'; export interface IOptionElement { optionWidget: any; @@ -22,6 +21,15 @@ export interface IOptionElement { optionValue: any; } +export enum ServiceOptionType { + string = 0, + multistring = 1, + password = 2, + number = 3, + category = 4, + boolean = 5 +} + export function createOptionElement(option: data.ServiceOption, rowContainer: Builder, options: { [name: string]: any }, optionsMap: { [optionName: string]: IOptionElement }, contextViewService: IContextViewService, onFocus: (name) => void): void { let possibleInputs: string[] = []; diff --git a/src/sql/data.d.ts b/src/sql/data.d.ts index 7763227a2f..2a13c5a7dc 100644 --- a/src/sql/data.d.ts +++ b/src/sql/data.d.ts @@ -11,29 +11,7 @@ declare module 'data' { * Namespace for Data Management Protocol global methods */ export namespace dataprotocol { - export function registerConnectionProvider(provider: ConnectionProvider): vscode.Disposable; - - export function registerBackupProvider(provider: BackupProvider): vscode.Disposable; - - export function registerRestoreProvider(provider: RestoreProvider): vscode.Disposable; - - export function registerScriptingProvider(provider: ScriptingProvider): vscode.Disposable; - - export function registerObjectExplorerProvider(provider: ObjectExplorerProvider): vscode.Disposable; - - export function registerTaskServicesProvider(provider: TaskServicesProvider): vscode.Disposable; - - export function registerFileBrowserProvider(provider: FileBrowserProvider): vscode.Disposable; - - export function registerProfilerProvider(provider: ProfilerProvider): vscode.Disposable; - - export function registerMetadataProvider(provider: MetadataProvider): vscode.Disposable; - - export function registerQueryProvider(provider: QueryProvider): vscode.Disposable; - - export function registerAdminServicesProvider(provider: AdminServicesProvider): vscode.Disposable; - - export function registerCapabilitiesServiceProvider(provider: CapabilitiesProvider): vscode.Disposable; + export function registerProvider(provider: DataProtocolProvider): vscode.Disposable; /** * An [event](#Event) which fires when the specific flavor of a language used in DMP @@ -177,12 +155,8 @@ declare module 'data' { osVersion: string; } - export interface DataProvider { - handle?: number; - readonly providerId: string; - } - - export interface ConnectionProvider extends DataProvider { + export interface ConnectionProvider { + handle: number; connect(connectionUri: string, connectionInfo: ConnectionInfo): Thenable; @@ -196,11 +170,11 @@ declare module 'data' { rebuildIntelliSenseCache(connectionUri: string): Thenable; - registerOnConnectionComplete(handler: (connSummary: ConnectionInfoSummary) => any): void; + registerOnConnectionComplete(handler: (connSummary: ConnectionInfoSummary) => any); - registerOnIntelliSenseCacheComplete(handler: (connectionUri: string) => any): void; + registerOnIntelliSenseCacheComplete(handler: (connectionUri: string) => any); - registerOnConnectionChanged(handler: (changedConnInfo: ChangedConnectionInfo) => any): void; + registerOnConnectionChanged(handler: (changedConnInfo: ChangedConnectionInfo) => any); } export enum ServiceOptionType { @@ -214,12 +188,12 @@ declare module 'data' { } export enum ConnectionOptionSpecialType { - serverName = 'serverName', - databaseName = 'databaseName', - authType = 'authType', - userName = 'userName', - password = 'password', - appName = 'appName' + serverName = 0, + databaseName = 1, + authType = 2, + userName = 3, + password = 4, + appName = 5 } export interface CategoryValue { @@ -332,7 +306,7 @@ declare module 'data' { hostVersion: string; } - export interface CapabilitiesProvider extends DataProvider { + export interface CapabilitiesProvider { getServerCapabilities(client: DataProtocolClientCapabilities): Thenable; } @@ -413,7 +387,7 @@ declare module 'data' { objectMetadata: ObjectMetadata[]; } - export interface MetadataProvider extends DataProvider { + export interface MetadataProvider { getMetadata(connectionUri: string): Thenable; getDatabases(connectionUri: string): Thenable; @@ -445,7 +419,7 @@ declare module 'data' { targetDatabaseEngineType: string; } - export interface ScriptingProvider extends DataProvider { + export interface ScriptingProvider { scriptAsOperation(connectionUri: string, operation: ScriptOperation, metadata: ObjectMetadata, paramDetails: ScriptingParamDetails): Thenable; @@ -465,6 +439,38 @@ declare module 'data' { operationId: string; } + /** + * Data Management Protocol main provider class that DMP extensions should implement. + * This provider interface contains references to providers for the various capabilitiesProvider + * that an extension can implement. + */ + export interface DataProtocolProvider { + handle: number; + + providerId: string; + + capabilitiesProvider: CapabilitiesProvider; + + connectionProvider: ConnectionProvider; + + queryProvider: QueryProvider; + + metadataProvider: MetadataProvider; + + scriptingProvider: ScriptingProvider; + + objectExplorerProvider: ObjectExplorerProvider; + + adminServicesProvider: AdminServicesProvider; + + disasterRecoveryProvider: DisasterRecoveryProvider; + + taskServicesProvider: TaskServicesProvider; + + fileBrowserProvider: FileBrowserProvider; + + profilerProvider: ProfilerProvider; + } /** * Parameters to initialize a connection to a database @@ -503,7 +509,10 @@ declare module 'data' { flavor: string; } - export interface QueryProvider extends DataProvider { + export interface QueryProvider { + handle: number; + // TODO replace this temporary queryType field with a standard definition for supported platform + queryType: string; cancelQuery(ownerUri: string): Thenable; runQuery(ownerUri: string, selection: ISelectionData, runOptions?: ExecutionPlanOptions): Thenable; runQueryStatement(ownerUri: string, line: number, column: number): Thenable; @@ -664,7 +673,6 @@ declare module 'data' { export interface QueryExecuteParams { ownerUri: string; querySelection: ISelectionData; - executionPlanOptions?: ExecutionPlanOptions; } export interface QueryExecuteSubsetParams { @@ -686,7 +694,6 @@ declare module 'data' { } export interface QueryExecuteSubsetResult { - message: string; resultSubset: ResultSetSubset; } @@ -753,15 +760,12 @@ declare module 'data' { export interface EditInitializeFiltering { LimitResults?: number; } - export interface EditInitializeParams extends IEditSessionOperationParams { filters: EditInitializeFiltering; objectName: string; - schemaName: string; objectType: string; } - export interface EditInitializeResult { } // edit/revertCell ---------------------------------------------------------------------------- @@ -845,7 +849,7 @@ declare module 'data' { success: boolean; } - export interface ObjectExplorerProvider extends DataProvider { + export interface ObjectExplorerProvider { createNewSession(connInfo: ConnectionInfo): Thenable; expandNode(nodeInfo: ExpandNodeInfo): Thenable; @@ -879,7 +883,7 @@ declare module 'data' { taskId: number; } - export interface AdminServicesProvider extends DataProvider { + export interface AdminServicesProvider { createDatabase(connectionUri: string, database: DatabaseInfo): Thenable; createLogin(connectionUri: string, login: LoginInfo): Thenable; @@ -937,7 +941,7 @@ declare module 'data' { duration: number; } - export interface TaskServicesProvider extends DataProvider { + export interface TaskServicesProvider { getAllTasks(listTasksParams: ListTasksParams): Thenable; cancelTask(cancelTaskParams: CancelTaskParams): Thenable; @@ -960,12 +964,9 @@ declare module 'data' { taskId: number; } - export interface BackupProvider extends DataProvider { + export interface DisasterRecoveryProvider { backup(connectionUri: string, backupInfo: { [key: string]: any }, taskExecutionMode: TaskExecutionMode): Thenable; getBackupConfigInfo(connectionUri: string): Thenable; - } - - export interface RestoreProvider extends DataProvider { getRestorePlan(connectionUri: string, restoreInfo: RestoreInfo): Thenable; cancelRestorePlan(connectionUri: string, restoreInfo: RestoreInfo): Thenable; restore(connectionUri: string, restoreInfo: RestoreInfo): Thenable; @@ -1028,7 +1029,7 @@ declare module 'data' { errorMessage: string; } - export interface ProfilerProvider extends DataProvider { + export interface ProfilerProvider { startSession(sessionId: string): Thenable; stopSession(sessionId: string): Thenable; pauseSession(sessionId: string): Thenable; @@ -1080,7 +1081,7 @@ declare module 'data' { // File browser interfaces ----------------------------------------------------------------------- - export interface FileBrowserProvider extends DataProvider { + export interface FileBrowserProvider { openFileBrowser(ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean): Thenable; registerOnFileBrowserOpened(handler: (response: FileBrowserOpenedParams) => any); expandFolderNode(ownerUri: string, expandPath: string): Thenable; diff --git a/src/sql/parts/connection/common/connectionManagement.ts b/src/sql/parts/connection/common/connectionManagement.ts index 8b880b6e2c..fbe7242abe 100644 --- a/src/sql/parts/connection/common/connectionManagement.ts +++ b/src/sql/parts/connection/common/connectionManagement.ts @@ -136,7 +136,7 @@ export interface IConnectionManagementService { clearRecentConnectionsList(): void; - clearRecentConnection(connectionProfile: IConnectionProfile): void; + clearRecentConnection(connectionProfile: IConnectionProfile) : void; getActiveConnections(): ConnectionProfile[]; @@ -278,6 +278,24 @@ export interface IErrorMessageService { showDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string, actions?: IAction[]): void; } +export enum ServiceOptionType { + string = 0, + multistring = 1, + password = 2, + number = 3, + category = 4, + boolean = 5 +} + +export enum ConnectionOptionSpecialType { + serverName = 0, + databaseName = 1, + authType = 2, + userName = 3, + password = 4, + appName = 5 +} + export enum RunQueryOnConnectionMode { none = 0, executeQuery = 1, diff --git a/src/sql/parts/connection/common/connectionStore.ts b/src/sql/parts/connection/common/connectionStore.ts index 74b6f1a5ea..fa96c71847 100644 --- a/src/sql/parts/connection/common/connectionStore.ts +++ b/src/sql/parts/connection/common/connectionStore.ts @@ -52,11 +52,6 @@ export class ConnectionStore { this._connectionConfig = new ConnectionConfig(this._configurationEditService, this._workspaceConfigurationService, this._capabilitiesService, cachedServerCapabilities); } - if (_capabilitiesService) { - _capabilitiesService.onProviderRegisteredEvent(e => { - this.saveCachedServerCapabilities(); - }); - } } public static get CRED_PREFIX(): string { return 'Microsoft.SqlTools'; } diff --git a/src/sql/parts/connection/common/providerConnectionInfo.ts b/src/sql/parts/connection/common/providerConnectionInfo.ts index 72c7a3d40f..2b91a84ada 100644 --- a/src/sql/parts/connection/common/providerConnectionInfo.ts +++ b/src/sql/parts/connection/common/providerConnectionInfo.ts @@ -7,7 +7,7 @@ import data = require('data'); import * as interfaces from 'sql/parts/connection/common/interfaces'; -import { ConnectionOptionSpecialType, ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes'; +import { ConnectionOptionSpecialType, ServiceOptionType } from 'sql/parts/connection/common/connectionManagement'; import * as Constants from 'sql/parts/connection/common/constants'; export class ProviderConnectionInfo implements data.ConnectionInfo { @@ -114,7 +114,7 @@ export class ProviderConnectionInfo implements data.ConnectionInfo { return isPasswordRequired; } - private getSpecialTypeOptionValue(type: string): string { + private getSpecialTypeOptionValue(type: number): string { let name = this.getSpecialTypeOptionName(type); if (name) { return this.options[name]; @@ -172,7 +172,7 @@ export class ProviderConnectionInfo implements data.ConnectionInfo { return providerId; } - public getSpecialTypeOptionName(type: string): string { + public getSpecialTypeOptionName(type: number): string { if (this._serverCapabilities) { let optionMetadata = this._serverCapabilities.connectionProvider.options.find(o => o.specialValueType === type); return !!optionMetadata ? optionMetadata.name : undefined; @@ -181,7 +181,7 @@ export class ProviderConnectionInfo implements data.ConnectionInfo { } } - public setSpecialTypeOptionName(type: string, value: string): void { + public setSpecialTypeOptionName(type: number, value: string): void { let name = this.getSpecialTypeOptionName(type); if (!!name) { this.options[name] = value; @@ -238,3 +238,4 @@ export class ProviderConnectionInfo implements data.ConnectionInfo { return parts; } } + diff --git a/src/sql/parts/connection/connectionDialog/connectionController.ts b/src/sql/parts/connection/connectionDialog/connectionController.ts index 566de37170..62fd27ad21 100644 --- a/src/sql/parts/connection/connectionDialog/connectionController.ts +++ b/src/sql/parts/connection/connectionDialog/connectionController.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement'; +import { IConnectionManagementService, ConnectionOptionSpecialType } from 'sql/parts/connection/common/connectionManagement'; import { IConnectionComponentCallbacks, IConnectionComponentController, IConnectionValidateResult } from 'sql/parts/connection/connectionDialog/connectionDialogService'; import { ConnectionWidget } from 'sql/parts/connection/connectionDialog/connectionWidget'; import { AdvancedPropertiesController } from 'sql/parts/connection/connectionDialog/advancedPropertiesController'; @@ -15,7 +15,6 @@ import * as Constants from 'sql/parts/connection/common/constants'; import data = require('data'); import * as Utils from 'sql/parts/connection/common/utils'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; export class ConnectionController implements IConnectionComponentController { private _container: HTMLElement; diff --git a/src/sql/parts/connection/connectionDialog/connectionDialogWidget.ts b/src/sql/parts/connection/connectionDialog/connectionDialogWidget.ts index 6d2296e26c..e413f9dd95 100644 --- a/src/sql/parts/connection/connectionDialog/connectionDialogWidget.ts +++ b/src/sql/parts/connection/connectionDialog/connectionDialogWidget.ts @@ -291,7 +291,8 @@ export class ConnectionDialogWidget extends Modal { this.onConnectionClick({ payload: { origin: origin, originalEvent: eventish } }, element); } }; - let actionProvider = this._instantiationService.createInstance(RecentConnectionActionsProvider); + let actionProvider = this._instantiationService.createInstance(RecentConnectionActionsProvider, this._instantiationService, this._connectionManagementService, + this._messageService); let controller = new RecentConnectionTreeController(leftClick, actionProvider, this._connectionManagementService, this._contextMenuService); actionProvider.onRecentConnectionRemoved(() => { this.open(this._connectionManagementService.getRecentConnections().length > 0); diff --git a/src/sql/parts/connection/connectionDialog/connectionWidget.ts b/src/sql/parts/connection/connectionDialog/connectionWidget.ts index a87b97140f..baf79d5944 100644 --- a/src/sql/parts/connection/connectionDialog/connectionWidget.ts +++ b/src/sql/parts/connection/connectionDialog/connectionWidget.ts @@ -16,7 +16,7 @@ import * as DialogHelper from 'sql/base/browser/ui/modal/dialogHelper'; import { IConnectionComponentCallbacks } from 'sql/parts/connection/connectionDialog/connectionDialogService'; import * as lifecycle from 'vs/base/common/lifecycle'; import { IConnectionProfile } from 'sql/parts/connection/common/interfaces'; -import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; +import { ConnectionOptionSpecialType } from 'sql/parts/connection/common/connectionManagement'; import * as Constants from 'sql/parts/connection/common/constants'; import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -87,7 +87,7 @@ export class ConnectionWidget { } var authTypeOption = this._optionsMaps[ConnectionOptionSpecialType.authType]; - if (authTypeOption) { + if(authTypeOption) { if (OS === OperatingSystem.Windows) { authTypeOption.defaultValue = this.getAuthTypeDisplayName(Constants.integrated); } else { @@ -250,11 +250,11 @@ export class ConnectionWidget { } } - private setConnectButton(): void { + private setConnectButton() : void { let authDisplayName: string = this.getAuthTypeDisplayName(this.authenticationType); let authType: AuthenticationType = this.getMatchingAuthType(authDisplayName); let showUsernameAndPassword: boolean = true; - if (authType) { + if(authType) { showUsernameAndPassword = authType.showUsernameAndPassword; } showUsernameAndPassword ? this._callbacks.onSetConnectButton(!!this.serverName && !!this.userName) : @@ -366,7 +366,7 @@ export class ConnectionWidget { var displayName: string; var authTypeOption = this._optionsMaps[ConnectionOptionSpecialType.authType]; - if (authTypeOption) { + if(authTypeOption) { authTypeOption.categoryValues.forEach(c => { if (c.name === authTypeName) { displayName = c.displayName; diff --git a/src/sql/parts/disasterRecovery/backup/backup.component.ts b/src/sql/parts/disasterRecovery/backup/backup.component.ts index ea7dc808b5..7fa3b4fa1d 100644 --- a/src/sql/parts/disasterRecovery/backup/backup.component.ts +++ b/src/sql/parts/disasterRecovery/backup/backup.component.ts @@ -17,7 +17,7 @@ import { SplitView } from 'sql/base/browser/ui/splitview/splitview'; import { attachButtonStyler, attachListBoxStyler, attachInputBoxStyler, attachSelectBoxStyler } from 'sql/common/theme/styler'; import { IConnectionProfile } from 'sql/parts/connection/common/interfaces'; import * as BackupConstants from 'sql/parts/disasterRecovery/backup/constants'; -import { IBackupService, IBackupUiService, TaskExecutionMode } from 'sql/parts/disasterRecovery/backup/common/backupService'; +import { IDisasterRecoveryService, IDisasterRecoveryUiService, TaskExecutionMode } from 'sql/parts/disasterRecovery/common/interfaces'; import FileValidationConstants = require('sql/parts/fileBrowser/common/fileValidationServiceConstants'); import { DashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams'; import { IBootstrapService, BOOTSTRAP_SERVICE_ID } from 'sql/services/bootstrap/bootstrapService'; @@ -140,8 +140,8 @@ export class BackupComponent { // tslint:enable:no-unused-variable - private _backupService: IBackupService; - private _backupUiService: IBackupUiService; + private _disasterRecoveryService: IDisasterRecoveryService; + private _disasterRecoveryUiService: IDisasterRecoveryUiService; private _uri: string; private _toDispose: lifecycle.IDisposable[] = []; private _advancedHeaderSize = 32; @@ -198,9 +198,9 @@ export class BackupComponent { @Inject(forwardRef(() => ChangeDetectorRef)) private _changeDetectorRef: ChangeDetectorRef, @Inject(BOOTSTRAP_SERVICE_ID) private _bootstrapService: IBootstrapService, ) { - this._backupService = _bootstrapService.backupService; - this._backupUiService = _bootstrapService.backupUiService; - this._backupUiService.onShowBackupEvent((param) => this.onGetBackupConfigInfo(param)); + this._disasterRecoveryService = _bootstrapService.disasterRecoveryService; + this._disasterRecoveryUiService = _bootstrapService.disasterRecoveryUiService; + this._disasterRecoveryUiService.onShowBackupEvent((param) => this.onGetBackupConfigInfo(param)); } ngOnInit() { @@ -315,12 +315,12 @@ export class BackupComponent { ngAfterViewInit() { // Set category view for advanced options. This should be defined in ngAfterViewInit so that it correctly calculates the text height after data binding. var splitview = new SplitView(this.advancedOptionElement.nativeElement); - var advancedBodySize = DOM.getTotalHeight(this.advancedOptionBodyElement.nativeElement); + var advancedBodySize = DOM.getTotalHeight(this.advancedOptionBodyElement.nativeElement); var categoryView = new CategoryView(this.advancedConfigurationLabel, this.advancedOptionBodyElement.nativeElement, true, advancedBodySize, this._advancedHeaderSize); splitview.addView(categoryView); splitview.layout(advancedBodySize + this._advancedHeaderSize); - this._backupUiService.onShowBackupDialog(); + this._disasterRecoveryUiService.onShowBackupDialog(); } private onGetBackupConfigInfo(param: DashboardComponentParams) { @@ -336,7 +336,7 @@ export class BackupComponent { this._uri = param.ownerUri; // Get backup configuration info - this._backupService.getBackupConfigInfo(this._uri).then(configInfo => { + this._disasterRecoveryService.getBackupConfigInfo(this._uri).then(configInfo => { if (configInfo) { this.defaultNewBackupFolder = configInfo.defaultBackupFolder; this.recoveryModel = configInfo.recoveryModel; @@ -546,12 +546,12 @@ export class BackupComponent { * UI event handlers */ private onScript(): void { - this._backupService.backup(this._uri, this.createBackupInfo(), TaskExecutionMode.script); + this._disasterRecoveryService.backup(this._uri, this.createBackupInfo(), TaskExecutionMode.script); this.close(); } private onOk(): void { - this._backupService.backup(this._uri, this.createBackupInfo(), TaskExecutionMode.executeAndScript); + this._disasterRecoveryService.backup(this._uri, this.createBackupInfo(), TaskExecutionMode.executeAndScript); this.close(); } @@ -561,7 +561,7 @@ export class BackupComponent { } private close(): void { - this._backupUiService.closeBackup(); + this._disasterRecoveryUiService.closeBackup(); this.resetDialog(); } diff --git a/src/sql/parts/disasterRecovery/common/disasterRecoveryService.ts b/src/sql/parts/disasterRecovery/common/disasterRecoveryService.ts new file mode 100644 index 0000000000..7314d7e092 --- /dev/null +++ b/src/sql/parts/disasterRecovery/common/disasterRecoveryService.ts @@ -0,0 +1,149 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; +import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement'; +import data = require('data'); +import { IDisasterRecoveryService, TaskExecutionMode } from 'sql/parts/disasterRecovery/common/interfaces'; +import * as Constants from 'sql/common/constants'; +import * as TelemetryKeys from 'sql/common/telemetryKeys'; +import * as TelemetryUtils from 'sql/common/telemetryUtilities'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; + +export class DisasterRecoveryService implements IDisasterRecoveryService { + + public _serviceBrand: any; + private _providers: { [handle: string]: data.DisasterRecoveryProvider; } = Object.create(null); + + constructor( + @IConnectionManagementService private _connectionService: IConnectionManagementService, + @ITelemetryService private _telemetryService: ITelemetryService + ) { + } + + /** + * Get database metadata needed to populate backup UI + */ + public getBackupConfigInfo(connectionUri: string): Thenable { + let providerId: string = this._connectionService.getProviderIdFromUri(connectionUri); + if (providerId) { + let provider = this._providers[providerId]; + if (provider) { + return provider.getBackupConfigInfo(connectionUri); + } + } + return Promise.resolve(undefined); + } + + /** + * Backup a data source using the provided connection + */ + public backup(connectionUri: string, backupInfo: { [key: string]: any }, taskExecutionMode: TaskExecutionMode): Thenable { + return new Promise((resolve, reject) => { + let providerResult = this.getProvider(connectionUri); + if (providerResult) { + TelemetryUtils.addTelemetry(this._telemetryService, TelemetryKeys.BackupCreated, { provider: providerResult.providerName }); + providerResult.provider.backup(connectionUri, backupInfo, taskExecutionMode).then(result => { + resolve(result); + }, error => { + reject(error); + }); + } else { + reject(Constants.InvalidProvider); + } + }); + } + + /** + * Gets restore config Info + */ + getRestoreConfigInfo(connectionUri: string): Thenable { + return new Promise((resolve, reject) => { + let providerResult = this.getProvider(connectionUri); + if (providerResult) { + providerResult.provider.getRestoreConfigInfo(connectionUri).then(result => { + resolve(result); + }, error => { + reject(error); + }); + } else { + reject(Constants.InvalidProvider); + } + }); + } + + /** + * Restore a data source using a backup file or database + */ + restore(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { + return new Promise((resolve, reject) => { + let providerResult = this.getProvider(connectionUri); + if (providerResult) { + TelemetryUtils.addTelemetry(this._telemetryService, TelemetryKeys.RestoreRequested, { provider: providerResult.providerName }); + providerResult.provider.restore(connectionUri, restoreInfo).then(result => { + resolve(result); + }, error => { + reject(error); + }); + } else { + reject(Constants.InvalidProvider); + } + }); + } + + private getProvider(connectionUri: string): { provider: data.DisasterRecoveryProvider, providerName: string } { + let providerId: string = this._connectionService.getProviderIdFromUri(connectionUri); + if (providerId) { + return { provider: this._providers[providerId], providerName: providerId }; + } else { + return undefined; + } + } + + /** + * Gets restore plan to do the restore operation on a database + */ + getRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { + return new Promise((resolve, reject) => { + let providerResult = this.getProvider(connectionUri); + if (providerResult) { + providerResult.provider.getRestorePlan(connectionUri, restoreInfo).then(result => { + resolve(result); + }, error => { + reject(error); + }); + } else { + reject(Constants.InvalidProvider); + + } + }); + } + + /** + * Cancels a restore plan + */ + cancelRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { + return new Promise((resolve, reject) => { + let providerResult = this.getProvider(connectionUri); + if (providerResult) { + providerResult.provider.cancelRestorePlan(connectionUri, restoreInfo).then(result => { + resolve(result); + }, error => { + reject(error); + }); + } else { + reject(Constants.InvalidProvider); + + } + }); + } + + /** + * Register a disaster recovery provider + */ + public registerProvider(providerId: string, provider: data.DisasterRecoveryProvider): void { + this._providers[providerId] = provider; + } +} diff --git a/src/sql/parts/disasterRecovery/backup/common/backupServiceImp.ts b/src/sql/parts/disasterRecovery/common/disasterRecoveryUiService.ts similarity index 62% rename from src/sql/parts/disasterRecovery/backup/common/backupServiceImp.ts rename to src/sql/parts/disasterRecovery/common/disasterRecoveryUiService.ts index f7d3c2ece1..227cc14a74 100644 --- a/src/sql/parts/disasterRecovery/backup/common/backupServiceImp.ts +++ b/src/sql/parts/disasterRecovery/common/disasterRecoveryUiService.ts @@ -4,87 +4,25 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement'; -import * as data from 'data'; -import * as Constants from 'sql/common/constants'; -import * as TelemetryKeys from 'sql/common/telemetryKeys'; -import * as TelemetryUtils from 'sql/common/telemetryUtilities'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IBackupService, TaskExecutionMode, IBackupUiService } from 'sql/parts/disasterRecovery/backup/common/backupService'; -import { BackupDialog } from 'sql/parts/disasterRecovery/backup/backupDialog'; -import { OptionsDialog } from 'sql/base/browser/ui/modal/optionsDialog'; + +import { TPromise } from 'vs/base/common/winjs.base'; import Event, { Emitter } from 'vs/base/common/event'; -import { DashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IPartService } from 'vs/workbench/services/part/common/partService'; +import * as data from 'data'; + import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService'; import { IConnectionProfile } from 'sql/parts/connection/common/interfaces'; -import { TPromise } from 'vs/base/common/winjs.base'; -import * as ConnectionUtils from 'sql/parts/connection/common/utils'; +import { OptionsDialog } from 'sql/base/browser/ui/modal/optionsDialog'; +import { BackupDialog } from 'sql/parts/disasterRecovery/backup/backupDialog'; +import { IDisasterRecoveryService, IDisasterRecoveryUiService, TaskExecutionMode } from 'sql/parts/disasterRecovery/common/interfaces'; +import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement'; +import ConnectionUtils = require('sql/parts/connection/common/utils'); import { ProviderConnectionInfo } from 'sql/parts/connection/common/providerConnectionInfo'; +import { DashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams'; +import * as Utils from 'sql/parts/connection/common/utils'; -export class BackupService implements IBackupService { - - public _serviceBrand: any; - private _providers: { [handle: string]: data.BackupProvider; } = Object.create(null); - - constructor( - @IConnectionManagementService private _connectionService: IConnectionManagementService, - @ITelemetryService private _telemetryService: ITelemetryService - ) { - } - - /** - * Get database metadata needed to populate backup UI - */ - public getBackupConfigInfo(connectionUri: string): Thenable { - let providerId: string = this._connectionService.getProviderIdFromUri(connectionUri); - if (providerId) { - let provider = this._providers[providerId]; - if (provider) { - return provider.getBackupConfigInfo(connectionUri); - } - } - return Promise.resolve(undefined); - } - - /** - * Backup a data source using the provided connection - */ - public backup(connectionUri: string, backupInfo: { [key: string]: any }, taskExecutionMode: TaskExecutionMode): Thenable { - return new Promise((resolve, reject) => { - let providerResult = this.getProvider(connectionUri); - if (providerResult) { - TelemetryUtils.addTelemetry(this._telemetryService, TelemetryKeys.BackupCreated, { provider: providerResult.providerName }); - providerResult.provider.backup(connectionUri, backupInfo, taskExecutionMode).then(result => { - resolve(result); - }, error => { - reject(error); - }); - } else { - reject(Constants.InvalidProvider); - } - }); - } - - private getProvider(connectionUri: string): { provider: data.BackupProvider, providerName: string } { - let providerId: string = this._connectionService.getProviderIdFromUri(connectionUri); - if (providerId) { - return { provider: this._providers[providerId], providerName: providerId }; - } else { - return undefined; - } - } - - /** - * Register a disaster recovery provider - */ - public registerProvider(providerId: string, provider: data.BackupProvider): void { - this._providers[providerId] = provider; - } -} - -export class BackupUiService implements IBackupUiService { +export class DisasterRecoveryUiService implements IDisasterRecoveryUiService { public _serviceBrand: any; private _backupDialogs: { [providerName: string]: BackupDialog | OptionsDialog } = {}; private _currentProvider: string; @@ -99,10 +37,10 @@ export class BackupUiService implements IBackupUiService { constructor( @IInstantiationService private _instantiationService: IInstantiationService, @IPartService private _partService: IPartService, @ICapabilitiesService private _capabilitiesService: ICapabilitiesService, - @IBackupService private _disasterRecoveryService: IBackupService, + @IDisasterRecoveryService private _disasterRecoveryService: IDisasterRecoveryService, @IConnectionManagementService private _connectionManagementService: IConnectionManagementService) { - this._onShowBackupEvent = new Emitter(); - } + this._onShowBackupEvent = new Emitter(); + } public showBackup(connection: IConnectionProfile): Promise { let self = this; @@ -148,16 +86,16 @@ export class BackupUiService implements IBackupUiService { } else { let uri = this._connectionManagementService.getConnectionId(connection) + ProviderConnectionInfo.idSeparator - + ConnectionUtils.ConnectionUriBackupIdAttributeName + + Utils.ConnectionUriBackupIdAttributeName + ProviderConnectionInfo.nameValueSeparator - + BackupUiService._connectionUniqueId; + + DisasterRecoveryUiService._connectionUniqueId; - BackupUiService._connectionUniqueId++; + DisasterRecoveryUiService._connectionUniqueId++; // Create connection if needed if (!this._connectionManagementService.isConnected(uri)) { this._connectionManagementService.connect(connection, uri).then(() => { - this._onShowBackupEvent.fire({ connection: connection, ownerUri: uri }); + this._onShowBackupEvent.fire({connection: connection, ownerUri: uri}); }); } (backupDialog as BackupDialog).open(connection); diff --git a/src/sql/parts/disasterRecovery/backup/common/backupService.ts b/src/sql/parts/disasterRecovery/common/interfaces.ts similarity index 52% rename from src/sql/parts/disasterRecovery/backup/common/backupService.ts rename to src/sql/parts/disasterRecovery/common/interfaces.ts index 963596f746..078120d0cb 100644 --- a/src/sql/parts/disasterRecovery/backup/common/backupService.ts +++ b/src/sql/parts/disasterRecovery/common/interfaces.ts @@ -5,6 +5,7 @@ 'use strict'; +import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; import data = require('data'); @@ -19,12 +20,12 @@ export enum TaskExecutionMode { executeAndScript = 2, } -export const SERVICE_ID = 'backupService'; -export const UI_SERVICE_ID = 'backupUiService'; +export const SERVICE_ID = 'disasterRecoveryService'; +export const UI_SERVICE_ID = 'disasterRecoveryUiService'; -export const IBackupUiService = createDecorator(UI_SERVICE_ID); +export const IDisasterRecoveryUiService = createDecorator(UI_SERVICE_ID); -export interface IBackupUiService { +export interface IDisasterRecoveryUiService { _serviceBrand: any; /** @@ -48,9 +49,9 @@ export interface IBackupUiService { onShowBackupDialog(); } -export const IBackupService = createDecorator(SERVICE_ID); +export const IDisasterRecoveryService = createDecorator(SERVICE_ID); -export interface IBackupService { +export interface IDisasterRecoveryService { _serviceBrand: any; getBackupConfigInfo(connectionUri: string): Thenable; @@ -63,5 +64,31 @@ export interface IBackupService { /** * Register a disaster recovery provider */ - registerProvider(providerId: string, provider: data.BackupProvider): void; + registerProvider(providerId: string, provider: data.DisasterRecoveryProvider): void; + + /** + * Restore a data source using a backup file or database + */ + restore(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable; + + /** + * Gets restore plan to do the restore operation on a database + */ + getRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable; + + /** + * Gets restore config Info + */ + getRestoreConfigInfo(connectionUri: string): Thenable; + + /** + * Cancel restore plan + */ + cancelRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable; } + +export const IRestoreDialogController = createDecorator('restoreDialogService'); +export interface IRestoreDialogController { + _serviceBrand: any; + showDialog(connection: IConnectionProfile): TPromise; +} \ No newline at end of file diff --git a/src/sql/parts/disasterRecovery/restore/common/restoreService.ts b/src/sql/parts/disasterRecovery/restore/common/restoreService.ts deleted file mode 100644 index d2bc84a509..0000000000 --- a/src/sql/parts/disasterRecovery/restore/common/restoreService.ts +++ /dev/null @@ -1,51 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -import { TPromise } from 'vs/base/common/winjs.base'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import * as data from 'data'; - -import { IConnectionProfile } from 'sql/parts/connection/common/interfaces'; - -export const SERVICE_ID = 'restoreService'; -export const IRestoreService = createDecorator(SERVICE_ID); -export { TaskExecutionMode } from 'sql/parts/disasterRecovery/backup/common/backupService'; - -export interface IRestoreService { - _serviceBrand: any; - - /** - * Register a disaster recovery provider - */ - registerProvider(providerId: string, provider: data.RestoreProvider): void; - - /** - * Restore a data source using a backup file or database - */ - restore(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable; - - /** - * Gets restore plan to do the restore operation on a database - */ - getRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable; - - /** - * Gets restore config Info - */ - getRestoreConfigInfo(connectionUri: string): Thenable; - - /** - * Cancel restore plan - */ - cancelRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable; -} - -export const IRestoreDialogController = createDecorator('restoreDialogService'); -export interface IRestoreDialogController { - _serviceBrand: any; - showDialog(connection: IConnectionProfile): TPromise; -} diff --git a/src/sql/parts/disasterRecovery/restore/restoreDialog.ts b/src/sql/parts/disasterRecovery/restore/restoreDialog.ts index 00dcd5c188..ff8a2c63d5 100644 --- a/src/sql/parts/disasterRecovery/restore/restoreDialog.ts +++ b/src/sql/parts/disasterRecovery/restore/restoreDialog.ts @@ -30,6 +30,7 @@ import * as DialogHelper from 'sql/base/browser/ui/modal/dialogHelper'; import { Modal } from 'sql/base/browser/ui/modal/modal'; import { attachButtonStyler, attachModalDialogStyler, attachTableStyler, attachInputBoxStyler, attachSelectBoxStyler, attachEditableDropdownStyler } from 'sql/common/theme/styler'; import * as TelemetryKeys from 'sql/common/telemetryKeys'; +import { ServiceOptionType } from 'sql/parts/connection/common/connectionManagement'; import * as BackupConstants from 'sql/parts/disasterRecovery/backup/constants'; import { RestoreViewModel, RestoreOptionParam, SouceDatabaseNamesParam } from 'sql/parts/disasterRecovery/restore/restoreViewModel'; import * as FileValidationConstants from 'sql/parts/fileBrowser/common/fileValidationServiceConstants'; @@ -39,7 +40,6 @@ import { TabbedPanel, PanelTabIdentifier } from 'sql/base/browser/ui/panel/panel import * as DOM from 'vs/base/browser/dom'; import * as data from 'data'; import * as strings from 'vs/base/common/strings'; -import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes'; interface FileListElement { logicalFileName: string; diff --git a/src/sql/parts/disasterRecovery/restore/common/restoreServiceImpl.ts b/src/sql/parts/disasterRecovery/restore/restoreDialogController.ts similarity index 69% rename from src/sql/parts/disasterRecovery/restore/common/restoreServiceImpl.ts rename to src/sql/parts/disasterRecovery/restore/restoreDialogController.ts index 7814460bc1..e3ab169b07 100644 --- a/src/sql/parts/disasterRecovery/restore/common/restoreServiceImpl.ts +++ b/src/sql/parts/disasterRecovery/restore/restoreDialogController.ts @@ -4,128 +4,21 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement'; -import * as data from 'data'; import { TPromise } from 'vs/base/common/winjs.base'; -import * as Constants from 'sql/common/constants'; -import * as TelemetryKeys from 'sql/common/telemetryKeys'; -import * as TelemetryUtils from 'sql/common/telemetryUtilities'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import * as types from 'vs/base/common/types'; -import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService'; -import { IRestoreService, IRestoreDialogController, TaskExecutionMode } from 'sql/parts/disasterRecovery/restore/common/restoreService'; + import { OptionsDialog } from 'sql/base/browser/ui/modal/optionsDialog'; -import { RestoreDialog } from 'sql/parts/disasterRecovery/restore/restoreDialog'; -import * as ConnectionConstants from 'sql/parts/connection/common/constants'; -import { MssqlRestoreInfo } from 'sql/parts/disasterRecovery/restore/mssqlRestoreInfo'; import { IConnectionProfile } from 'sql/parts/connection/common/interfaces'; +import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement'; +import * as ConnectionConstants from 'sql/parts/connection/common/constants'; import { ProviderConnectionInfo } from 'sql/parts/connection/common/providerConnectionInfo'; +import { IDisasterRecoveryService, IRestoreDialogController, TaskExecutionMode } from 'sql/parts/disasterRecovery/common/interfaces'; +import { MssqlRestoreInfo } from 'sql/parts/disasterRecovery/restore/mssqlRestoreInfo'; +import { RestoreDialog } from 'sql/parts/disasterRecovery/restore/restoreDialog'; +import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService'; import * as Utils from 'sql/parts/connection/common/utils'; - -export class RestoreService implements IRestoreService { - - public _serviceBrand: any; - private _providers: { [handle: string]: data.RestoreProvider; } = Object.create(null); - - constructor( - @IConnectionManagementService private _connectionService: IConnectionManagementService, - @ITelemetryService private _telemetryService: ITelemetryService - ) { - } - - /** - * Gets restore config Info - */ - getRestoreConfigInfo(connectionUri: string): Thenable { - return new Promise((resolve, reject) => { - let providerResult = this.getProvider(connectionUri); - if (providerResult) { - providerResult.provider.getRestoreConfigInfo(connectionUri).then(result => { - resolve(result); - }, error => { - reject(error); - }); - } else { - reject(Constants.InvalidProvider); - } - }); - } - - /** - * Restore a data source using a backup file or database - */ - restore(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { - return new Promise((resolve, reject) => { - let providerResult = this.getProvider(connectionUri); - if (providerResult) { - TelemetryUtils.addTelemetry(this._telemetryService, TelemetryKeys.RestoreRequested, { provider: providerResult.providerName }); - providerResult.provider.restore(connectionUri, restoreInfo).then(result => { - resolve(result); - }, error => { - reject(error); - }); - } else { - reject(Constants.InvalidProvider); - } - }); - } - - private getProvider(connectionUri: string): { provider: data.RestoreProvider, providerName: string } { - let providerId: string = this._connectionService.getProviderIdFromUri(connectionUri); - if (providerId) { - return { provider: this._providers[providerId], providerName: providerId }; - } else { - return undefined; - } - } - - /** - * Gets restore plan to do the restore operation on a database - */ - getRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { - return new Promise((resolve, reject) => { - let providerResult = this.getProvider(connectionUri); - if (providerResult) { - providerResult.provider.getRestorePlan(connectionUri, restoreInfo).then(result => { - resolve(result); - }, error => { - reject(error); - }); - } else { - reject(Constants.InvalidProvider); - - } - }); - } - - /** - * Cancels a restore plan - */ - cancelRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { - return new Promise((resolve, reject) => { - let providerResult = this.getProvider(connectionUri); - if (providerResult) { - providerResult.provider.cancelRestorePlan(connectionUri, restoreInfo).then(result => { - resolve(result); - }, error => { - reject(error); - }); - } else { - reject(Constants.InvalidProvider); - - } - }); - } - - /** - * Register a disaster recovery provider - */ - public registerProvider(providerId: string, provider: data.RestoreProvider): void { - this._providers[providerId] = provider; - } -} - +import * as data from 'data'; export class RestoreDialogController implements IRestoreDialogController { _serviceBrand: any; @@ -139,7 +32,7 @@ export class RestoreDialogController implements IRestoreDialogController { constructor( @IInstantiationService private _instantiationService: IInstantiationService, - @IRestoreService private _restoreService: IRestoreService, + @IDisasterRecoveryService private _disasterRecoveryService: IDisasterRecoveryService, @IConnectionManagementService private _connectionService: IConnectionManagementService, @ICapabilitiesService private _capabilitiesService: ICapabilitiesService ) { @@ -153,14 +46,14 @@ export class RestoreDialogController implements IRestoreDialogController { restoreOption.taskExecutionMode = TaskExecutionMode.executeAndScript; } - this._restoreService.restore(this._ownerUri, restoreOption); + this._disasterRecoveryService.restore(this._ownerUri, restoreOption); let restoreDialog = this._restoreDialogs[this._currentProvider]; restoreDialog.close(); } private handleMssqlOnValidateFile(overwriteTargetDatabase: boolean = false): void { let restoreDialog = this._restoreDialogs[this._currentProvider] as RestoreDialog; - this._restoreService.getRestorePlan(this._ownerUri, this.setRestoreOption(overwriteTargetDatabase)).then(restorePlanResponse => { + this._disasterRecoveryService.getRestorePlan(this._ownerUri, this.setRestoreOption(overwriteTargetDatabase)).then(restorePlanResponse => { this._sessionId = restorePlanResponse.sessionId; if (restorePlanResponse.errorMessage) { @@ -195,7 +88,7 @@ export class RestoreDialogController implements IRestoreDialogController { private getMssqlRestoreConfigInfo(): Promise { return new Promise((resolve, reject) => { let restoreDialog = this._restoreDialogs[this._currentProvider] as RestoreDialog; - this._restoreService.getRestoreConfigInfo(this._ownerUri).then(restoreConfigInfo => { + this._disasterRecoveryService.getRestoreConfigInfo(this._ownerUri).then(restoreConfigInfo => { restoreDialog.viewModel.updateOptionWithConfigInfo(restoreConfigInfo.configInfo); resolve(); }, error => { @@ -257,7 +150,7 @@ export class RestoreDialogController implements IRestoreDialogController { private handleOnCancel(): void { let restoreInfo = new MssqlRestoreInfo(); restoreInfo.sessionId = this._sessionId; - this._restoreService.cancelRestorePlan(this._ownerUri, restoreInfo).then(() => { + this._disasterRecoveryService.cancelRestorePlan(this._ownerUri, restoreInfo).then(() => { this._connectionService.disconnect(this._ownerUri); }); } diff --git a/src/sql/parts/disasterRecovery/restore/restoreViewModel.ts b/src/sql/parts/disasterRecovery/restore/restoreViewModel.ts index e70c4226b0..c0a77e9d64 100644 --- a/src/sql/parts/disasterRecovery/restore/restoreViewModel.ts +++ b/src/sql/parts/disasterRecovery/restore/restoreViewModel.ts @@ -5,11 +5,11 @@ 'use strict'; import * as data from 'data'; +import { ServiceOptionType } from 'sql/parts/connection/common/connectionManagement'; import * as DialogHelper from 'sql/base/browser/ui/modal/dialogHelper'; import * as types from 'vs/base/common/types'; import Event, { Emitter } from 'vs/base/common/event'; -import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes'; export interface RestoreOptionsElement { optionMetadata: data.ServiceOption; diff --git a/src/sql/parts/profiler/service/profilerTestBackend.ts b/src/sql/parts/profiler/service/profilerTestBackend.ts index bb366b5ea7..a2ea0dd3f4 100644 --- a/src/sql/parts/profiler/service/profilerTestBackend.ts +++ b/src/sql/parts/profiler/service/profilerTestBackend.ts @@ -31,7 +31,6 @@ const columns = [ ]; export class ProfilerTestBackend implements data.ProfilerProvider { - public readonly providerId = 'MSSQL'; private index = 0; private timeOutMap = new Map(); private testData: Array> = new Array>(); diff --git a/src/sql/services/bootstrap/bootstrapService.ts b/src/sql/services/bootstrap/bootstrapService.ts index b8e1cdce7a..4e8d94e3d9 100644 --- a/src/sql/services/bootstrap/bootstrapService.ts +++ b/src/sql/services/bootstrap/bootstrapService.ts @@ -15,8 +15,7 @@ import { IScriptingService } from 'sql/services/scripting/scriptingService'; import { IQueryModelService } from 'sql/parts/query/execution/queryModel'; import { IQueryManagementService } from 'sql/parts/query/common/queryManagement'; import { IAdminService } from 'sql/parts/admin/common/adminService'; -import { IRestoreDialogController, IRestoreService } from 'sql/parts/disasterRecovery/restore/common/restoreService'; -import { IBackupService, IBackupUiService } from 'sql/parts/disasterRecovery/backup/common/backupService'; +import { IDisasterRecoveryService, IDisasterRecoveryUiService, IRestoreDialogController } from 'sql/parts/disasterRecovery/common/interfaces'; import { IInsightsDialogService } from 'sql/parts/insights/common/interfaces'; import { ISqlOAuthService } from 'sql/common/sqlOAuthService'; import { IFileBrowserService, IFileBrowserDialogController } from 'sql/parts/fileBrowser/common/interfaces'; @@ -58,9 +57,8 @@ export interface IBootstrapService { connectionDialogService: IConnectionDialogService; queryModelService: IQueryModelService; adminService: IAdminService; - backupService: IBackupService; - backupUiService: IBackupUiService; - restoreService: IRestoreService; + disasterRecoveryService: IDisasterRecoveryService; + disasterRecoveryUiService: IDisasterRecoveryUiService; keybindingService: IKeybindingService; contextKeyService: IContextKeyService; contextMenuService: IContextMenuService; diff --git a/src/sql/services/bootstrap/bootstrapServiceImpl.ts b/src/sql/services/bootstrap/bootstrapServiceImpl.ts index ea3ee9ff3f..3fb14951ee 100644 --- a/src/sql/services/bootstrap/bootstrapServiceImpl.ts +++ b/src/sql/services/bootstrap/bootstrapServiceImpl.ts @@ -16,8 +16,7 @@ import { IScriptingService } from 'sql/services/scripting/scriptingService'; import { IQueryManagementService } from 'sql/parts/query/common/queryManagement'; import { IQueryModelService } from 'sql/parts/query/execution/queryModel'; import { IAdminService } from 'sql/parts/admin/common/adminService'; -import { IRestoreDialogController, IRestoreService } from 'sql/parts/disasterRecovery/restore/common/restoreService'; -import { IBackupService, IBackupUiService } from 'sql/parts/disasterRecovery/backup/common/backupService'; +import { IDisasterRecoveryService, IDisasterRecoveryUiService, IRestoreDialogController } from 'sql/parts/disasterRecovery/common/interfaces'; import { IAngularEventingService } from 'sql/services/angularEventing/angularEventingService'; import { IInsightsDialogService } from 'sql/parts/insights/common/interfaces'; import { ISqlOAuthService } from 'sql/common/sqlOAuthService'; @@ -68,10 +67,9 @@ export class BootstrapService implements IBootstrapService { @IAdminService public adminService: IAdminService, @IWorkbenchThemeService public themeService: IWorkbenchThemeService, @IWorkbenchEditorService public editorService: IWorkbenchEditorService, - @IBackupService public backupService: IBackupService, - @IBackupUiService public backupUiService: IBackupUiService, + @IDisasterRecoveryService public disasterRecoveryService: IDisasterRecoveryService, + @IDisasterRecoveryUiService public disasterRecoveryUiService: IDisasterRecoveryUiService, @IRestoreDialogController public restoreDialogService: IRestoreDialogController, - @IRestoreService public restoreService: IRestoreService, @IConnectionDialogService public connectionDialogService: IConnectionDialogService, @IQueryModelService public queryModelService: IQueryModelService, @IKeybindingService public keybindingService: IKeybindingService, diff --git a/src/sql/workbench/api/node/extHostDataProtocol.ts b/src/sql/workbench/api/node/extHostDataProtocol.ts index 5d9e6ff005..dd5f0853d4 100644 --- a/src/sql/workbench/api/node/extHostDataProtocol.ts +++ b/src/sql/workbench/api/node/extHostDataProtocol.ts @@ -20,7 +20,7 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { private _proxy: MainThreadDataProtocolShape; private static _handlePool: number = 0; - private _adapter = new Map(); + private _adapter = new Map(); constructor( threadService: IThreadService @@ -40,121 +40,71 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { return ExtHostDataProtocol._handlePool++; } - private _resolveProvider

(handle: number): P { - let provider = this._adapter.get(handle) as P; - if (provider) { - return provider; - } else { - throw new Error(`Unfound provider ${handle}`); - } + private _runWithProvider(handle: number, action: (p: data.DataProtocolProvider) => Thenable): Thenable { + let provider = this._adapter.get(handle); + return provider !== undefined + ? action(provider) + : undefined; } - private registerProvider(provider: data.DataProvider): vscode.Disposable { + + $registerProvider(provider: data.DataProtocolProvider): vscode.Disposable { provider.handle = this._nextHandle(); this._adapter.set(provider.handle, provider); + + this._proxy.$registerProvider(provider.providerId, provider.handle); return this._createDisposable(provider.handle); - }; - - $registerConnectionProvider(provider: data.ConnectionProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerConnectionProvider(provider.providerId, provider.handle); - return rt; - } - - $registerBackupProvider(provider: data.BackupProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerBackupProvider(provider.providerId, provider.handle); - return rt; - } - - $registerRestoreProvider(provider: data.RestoreProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerRestoreProvider(provider.providerId, provider.handle); - return rt; - } - - $registerScriptingProvider(provider: data.ScriptingProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerScriptingProvider(provider.providerId, provider.handle); - return rt; - } - - $registerQueryProvider(provider: data.QueryProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerQueryProvider(provider.providerId, provider.handle); - return rt; - } - - $registerMetadataProvider(provider: data.MetadataProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerMetadataProvider(provider.providerId, provider.handle); - return rt; - } - - $registerTaskServicesProvider(provider: data.TaskServicesProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerTaskServicesProvider(provider.providerId, provider.handle); - return rt; - } - - $registerFileBrowserProvider(provider: data.FileBrowserProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerFileBrowserProvider(provider.providerId, provider.handle); - return rt; - } - - $registerObjectExplorerProvider(provider: data.ObjectExplorerProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerObjectExplorerProvider(provider.providerId, provider.handle); - return rt; - } - - $registerProfilerProvider(provider: data.ProfilerProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerProfilerProvider(provider.providerId, provider.handle); - return rt; - } - - $registerAdminServicesProvider(provider: data.AdminServicesProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerAdminServicesProvider(provider.providerId, provider.handle); - return rt; - } - - $registerCapabilitiesServiceProvider(provider: data.CapabilitiesProvider): vscode.Disposable { - let rt = this.registerProvider(provider); - this._proxy.$registerCapabilitiesServiceProvider(provider.providerId, provider.handle); - return rt; } // Capabilities Discovery handlers $getServerCapabilities(handle: number, client: data.DataProtocolClientCapabilities): Thenable { - return this._resolveProvider(handle).getServerCapabilities(client); + return this._runWithProvider(handle, provider => { + return provider.capabilitiesProvider ? provider.capabilitiesProvider.getServerCapabilities(client) + : undefined; + }); } // Connection Management handlers $connect(handle: number, connectionUri: string, connection: data.ConnectionInfo): Thenable { - return this._resolveProvider(handle).connect(connectionUri, connection); + return this._runWithProvider(handle, provider => { + return provider.connectionProvider ? provider.connectionProvider.connect(connectionUri, connection) + : undefined; + }); } $disconnect(handle: number, connectionUri: string): Thenable { - return this._resolveProvider(handle).disconnect(connectionUri); + return this._runWithProvider(handle, provider => { + return provider.connectionProvider ? provider.connectionProvider.disconnect(connectionUri) + : undefined; + }); } $cancelConnect(handle: number, connectionUri: string): Thenable { - return this._resolveProvider(handle).cancelConnect(connectionUri); + return this._runWithProvider(handle, provider => { + return provider.connectionProvider ? provider.connectionProvider.cancelConnect(connectionUri) + : undefined; + }); } $changeDatabase(handle: number, connectionUri: string, newDatabase: string): Thenable { - return this._resolveProvider(handle).changeDatabase(connectionUri, newDatabase); + return this._runWithProvider(handle, provider => { + return provider.connectionProvider ? provider.connectionProvider.changeDatabase(connectionUri, newDatabase) + : undefined; + }); } $listDatabases(handle: number, connectionUri: string): Thenable { - return this._resolveProvider(handle).listDatabases(connectionUri); + return this._runWithProvider(handle, provider => { + return provider.connectionProvider ? provider.connectionProvider.listDatabases(connectionUri) + : undefined; + }); } $rebuildIntelliSenseCache(handle: number, connectionUri: string): Thenable { - return this._resolveProvider(handle).rebuildIntelliSenseCache(connectionUri); + return this._runWithProvider(handle, provider => { + return provider.connectionProvider ? provider.connectionProvider.rebuildIntelliSenseCache(connectionUri) + : undefined; + }); } $onConnectComplete(handle: number, connectionInfoSummary: data.ConnectionInfoSummary): void { @@ -177,31 +127,45 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { // Query Management handlers $cancelQuery(handle: number, ownerUri: string): Thenable { - return this._resolveProvider(handle).cancelQuery(ownerUri); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.cancelQuery(ownerUri); + }); } $runQuery(handle: number, ownerUri: string, selection: data.ISelectionData, runOptions?: data.ExecutionPlanOptions): Thenable { - return this._resolveProvider(handle).runQuery(ownerUri, selection, runOptions); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.runQuery(ownerUri, selection, runOptions); + }); } $runQueryStatement(handle: number, ownerUri: string, line: number, column: number): Thenable { - return this._resolveProvider(handle).runQueryStatement(ownerUri, line, column); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.runQueryStatement(ownerUri, line, column); + }); } $runQueryString(handle: number, ownerUri: string, queryString: string): Thenable { - return this._resolveProvider(handle).runQueryString(ownerUri, queryString); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.runQueryString(ownerUri, queryString); + }); } $runQueryAndReturn(handle: number, ownerUri: string, queryString: string): Thenable { - return this._resolveProvider(handle).runQueryAndReturn(ownerUri, queryString); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.runQueryAndReturn(ownerUri, queryString); + }); } $getQueryRows(handle: number, rowData: data.QueryExecuteSubsetParams): Thenable { - return this._resolveProvider(handle).getQueryRows(rowData); + return this._runWithProvider(handle, (provider) => { + return provider.queryProvider.getQueryRows(rowData); + }); } $disposeQuery(handle: number, ownerUri: string): Thenable { - return this._resolveProvider(handle).disposeQuery(ownerUri); + return this._runWithProvider(handle, (provider) => { + return provider.queryProvider.disposeQuery(ownerUri); + }); } $onQueryComplete(handle: number, result: data.QueryExecuteCompleteNotificationResult): void { @@ -221,44 +185,64 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { } $saveResults(handle: number, requestParams: data.SaveResultsRequestParams): Thenable { - return this._resolveProvider(handle).saveResults(requestParams); + return this._runWithProvider(handle, (provider) => { + return provider.queryProvider.saveResults(requestParams); + }); } // Edit Data handlers $commitEdit(handle: number, ownerUri: string): Thenable { - return this._resolveProvider(handle).commitEdit(ownerUri); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.commitEdit(ownerUri); + }); } $createRow(handle: number, ownerUri: string): Thenable { - return this._resolveProvider(handle).createRow(ownerUri); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.createRow(ownerUri); + }); } $deleteRow(handle: number, ownerUri: string, rowId: number): Thenable { - return this._resolveProvider(handle).deleteRow(ownerUri, rowId); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.deleteRow(ownerUri, rowId); + }); } $disposeEdit(handle: number, ownerUri: string): Thenable { - return this._resolveProvider(handle).disposeEdit(ownerUri); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.disposeEdit(ownerUri); + }); } $initializeEdit(handle: number, ownerUri: string, schemaName: string, objectName: string, objectType: string, rowLimit: number): Thenable { - return this._resolveProvider(handle).initializeEdit(ownerUri, schemaName, objectName, objectType, rowLimit); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.initializeEdit(ownerUri, schemaName, objectName, objectType, rowLimit); + }); } $revertCell(handle: number, ownerUri: string, rowId: number, columnId: number): Thenable { - return this._resolveProvider(handle).revertCell(ownerUri, rowId, columnId); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.revertCell(ownerUri, rowId, columnId); + }); } $revertRow(handle: number, ownerUri: string, rowId: number): Thenable { - return this._resolveProvider(handle).revertRow(ownerUri, rowId); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.revertRow(ownerUri, rowId); + }); } $updateCell(handle: number, ownerUri: string, rowId: number, columnId: number, newValue: string): Thenable { - return this._resolveProvider(handle).updateCell(ownerUri, rowId, columnId, newValue); + return this._runWithProvider(handle, provider => { + return provider.queryProvider.updateCell(ownerUri, rowId, columnId, newValue); + }); } $getEditRows(handle: number, rowData: data.EditSubsetParams): Thenable { - return this._resolveProvider(handle).getEditRows(rowData); + return this._runWithProvider(handle, (provider) => { + return provider.queryProvider.getEditRows(rowData); + }); } $onEditSessionReady(handle: number, ownerUri: string, success: boolean, message: string): void { @@ -267,36 +251,39 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { // Metadata handlers public $getMetadata(handle: number, connectionUri: string): Thenable { - return this._resolveProvider(handle).getMetadata(connectionUri); - } - - public $getDatabases(handle: number, connectionUri: string): Thenable { - return this._resolveProvider(handle).getDatabases(connectionUri); - } - - public $getTableInfo(handle: number, connectionUri: string, metadata: data.ObjectMetadata): Thenable { - return this._resolveProvider(handle).getTableInfo(connectionUri, metadata); - } - - public $getViewInfo(handle: number, connectionUri: string, metadata: data.ObjectMetadata): Thenable { - return this._resolveProvider(handle).getViewInfo(connectionUri, metadata); + return this._runWithProvider(handle, provider => { + return provider.metadataProvider ? provider.metadataProvider.getMetadata(connectionUri) + : Promise.resolve(undefined); + }); } // Object Explorer Service public $createObjectExplorerSession(handle: number, connInfo: data.ConnectionInfo): Thenable { - return this._resolveProvider(handle).createNewSession(connInfo); + return this._runWithProvider(handle, provider => { + return provider.objectExplorerProvider ? provider.objectExplorerProvider.createNewSession(connInfo) + : Promise.resolve(undefined); + }); } public $expandObjectExplorerNode(handle: number, nodeInfo: data.ExpandNodeInfo): Thenable { - return this._resolveProvider(handle).expandNode(nodeInfo); + return this._runWithProvider(handle, provider => { + return provider.objectExplorerProvider ? provider.objectExplorerProvider.expandNode(nodeInfo) + : Promise.resolve(undefined); + }); } public $refreshObjectExplorerNode(handle: number, nodeInfo: data.ExpandNodeInfo): Thenable { - return this._resolveProvider(handle).refreshNode(nodeInfo); + return this._runWithProvider(handle, provider => { + return provider.objectExplorerProvider ? provider.objectExplorerProvider.refreshNode(nodeInfo) + : Promise.resolve(undefined); + }); } public $closeObjectExplorerSession(handle: number, closeSessionInfo: data.ObjectExplorerCloseSessionInfo): Thenable { - return this._resolveProvider(handle).closeSession(closeSessionInfo); + return this._runWithProvider(handle, provider => { + return provider.objectExplorerProvider ? provider.objectExplorerProvider.closeSession(closeSessionInfo) + : Promise.resolve(undefined); + }); } public $onObjectExplorerSessionCreated(handle: number, response: data.ObjectExplorerSession): void { @@ -309,11 +296,17 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { // Task Service public $getAllTasks(handle: number, listTasksParams: data.ListTasksParams): Thenable { - return this._resolveProvider(handle).getAllTasks(listTasksParams); + return this._runWithProvider(handle, provider => { + return provider.taskServicesProvider ? provider.taskServicesProvider.getAllTasks(listTasksParams) + : Promise.resolve(undefined); + }); } public $cancelTask(handle: number, cancelTaskParams: data.CancelTaskParams): Thenable { - return this._resolveProvider(handle).cancelTask(cancelTaskParams); + return this._runWithProvider(handle, provider => { + return provider.taskServicesProvider ? provider.taskServicesProvider.cancelTask(cancelTaskParams) + : Promise.resolve(undefined); + }); } public $onTaskStatusChanged(handle: number, response: data.TaskProgressInfo): void { @@ -324,10 +317,34 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { this._proxy.$onTaskCreated(handle, response); } + public $getDatabases(handle: number, connectionUri: string): Thenable { + return this._runWithProvider(handle, provider => { + return provider.metadataProvider ? provider.metadataProvider.getDatabases(connectionUri) + : Promise.resolve(undefined); + }); + } + + public $getTableInfo(handle: number, connectionUri: string, metadata: data.ObjectMetadata): Thenable { + return this._runWithProvider(handle, provider => { + return provider.metadataProvider ? provider.metadataProvider.getTableInfo(connectionUri, metadata) + : Promise.resolve(undefined); + }); + } + + public $getViewInfo(handle: number, connectionUri: string, metadata: data.ObjectMetadata): Thenable { + return this._runWithProvider(handle, provider => { + return provider.metadataProvider ? provider.metadataProvider.getViewInfo(connectionUri, metadata) + : Promise.resolve(undefined); + }); + } + // Scripting handlers public $scriptAsOperation(handle: number, connectionUri: string, operation: data.ScriptOperation, metadata: data.ObjectMetadata, paramDetails: data.ScriptingParamDetails): Thenable { - return this._resolveProvider(handle).scriptAsOperation(connectionUri, operation, metadata, paramDetails); + return this._runWithProvider(handle, provider => { + return provider.scriptingProvider ? provider.scriptingProvider.scriptAsOperation(connectionUri, operation, metadata, paramDetails) + : Promise.resolve(undefined); + }); } public $onScriptingComplete(handle: number, scriptingCompleteResult: data.ScriptingCompleteResult): void { @@ -338,77 +355,110 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { * Create a new database on the provided connection */ public $createDatabase(handle: number, connectionUri: string, database: data.DatabaseInfo): Thenable { - return this._resolveProvider(handle).createDatabase(connectionUri, database); + return this._runWithProvider(handle, provider => { + return provider.adminServicesProvider ? provider.adminServicesProvider.createDatabase(connectionUri, database) + : Promise.resolve(undefined); + }); } /** * Create a new database on the provided connection */ public $getDefaultDatabaseInfo(handle: number, connectionUri: string): Thenable { - return this._resolveProvider(handle).getDefaultDatabaseInfo(connectionUri); + return this._runWithProvider(handle, provider => { + return provider.adminServicesProvider ? provider.adminServicesProvider.getDefaultDatabaseInfo(connectionUri) + : Promise.resolve(undefined); + }); } /** * Get the info on a database */ public $getDatabaseInfo(handle: number, connectionUri: string): Thenable { - return this._resolveProvider(handle).getDatabaseInfo(connectionUri); + return this._runWithProvider(handle, provider => { + return provider.adminServicesProvider ? provider.adminServicesProvider.getDatabaseInfo(connectionUri) + : Promise.resolve(undefined); + }); } /** * Create a new login on the provided connection */ public $createLogin(handle: number, connectionUri: string, login: data.LoginInfo): Thenable { - return this._resolveProvider(handle).createLogin(connectionUri, login); + return this._runWithProvider(handle, provider => { + return provider.adminServicesProvider ? provider.adminServicesProvider.createLogin(connectionUri, login) + : Promise.resolve(undefined); + }); } /** * Backup a database */ public $backup(handle: number, connectionUri: string, backupInfo: { [key: string]: any }, taskExecutionMode: data.TaskExecutionMode): Thenable { - return this._resolveProvider(handle).backup(connectionUri, backupInfo, taskExecutionMode); + return this._runWithProvider(handle, provider => { + return provider.disasterRecoveryProvider ? provider.disasterRecoveryProvider.backup(connectionUri, backupInfo, taskExecutionMode) + : Promise.resolve(undefined); + }); } /** * Create a new database on the provided connection */ public $getBackupConfigInfo(handle: number, connectionUri: string): Thenable { - return this._resolveProvider(handle).getBackupConfigInfo(connectionUri); + return this._runWithProvider(handle, provider => { + return provider.disasterRecoveryProvider ? provider.disasterRecoveryProvider.getBackupConfigInfo(connectionUri) + : Promise.resolve(undefined); + }); } /** * Restores a database */ public $restore(handle: number, connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { - return this._resolveProvider(handle).restore(connectionUri, restoreInfo); + return this._runWithProvider(handle, provider => { + return provider.disasterRecoveryProvider ? provider.disasterRecoveryProvider.restore(connectionUri, restoreInfo) + : Promise.resolve(undefined); + }); } /** * Gets a plan for restoring a database */ public $getRestorePlan(handle: number, connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { - return this._resolveProvider(handle).getRestorePlan(connectionUri, restoreInfo); + return this._runWithProvider(handle, provider => { + return provider.disasterRecoveryProvider ? provider.disasterRecoveryProvider.getRestorePlan(connectionUri, restoreInfo) + : Promise.resolve(undefined); + }); } /** * cancels a restore plan */ public $cancelRestorePlan(handle: number, connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { - return this._resolveProvider(handle).cancelRestorePlan(connectionUri, restoreInfo); + return this._runWithProvider(handle, provider => { + return provider.disasterRecoveryProvider ? provider.disasterRecoveryProvider.cancelRestorePlan(connectionUri, restoreInfo) + : Promise.resolve(undefined); + }); } /** * Gets restore config Info */ public $getRestoreConfigInfo(handle: number, connectionUri: string): Thenable { - return this._resolveProvider(handle).getRestoreConfigInfo(connectionUri); + return this._runWithProvider(handle, provider => { + return provider.disasterRecoveryProvider ? provider.disasterRecoveryProvider.getRestoreConfigInfo(connectionUri) + : Promise.resolve(undefined); + }); } /** * Open a file browser */ public $openFileBrowser(handle: number, ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean): Thenable { - return this._resolveProvider(handle).openFileBrowser(ownerUri, expandPath, fileFilters, changeFilter); + return this._runWithProvider(handle, provider => { + return provider.fileBrowserProvider ? provider.fileBrowserProvider.openFileBrowser(ownerUri, expandPath, fileFilters, changeFilter) + : Promise.resolve(undefined); + }); } /** @@ -422,7 +472,10 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { * Expand a folder node */ public $expandFolderNode(handle: number, ownerUri: string, expandPath: string): Thenable { - return this._resolveProvider(handle).expandFolderNode(ownerUri, expandPath); + return this._runWithProvider(handle, provider => { + return provider.fileBrowserProvider ? provider.fileBrowserProvider.expandFolderNode(ownerUri, expandPath) + : Promise.resolve(undefined); + }); } /** @@ -436,7 +489,10 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { * Validate selected file path */ public $validateFilePaths(handle: number, ownerUri: string, serviceType: string, selectedFiles: string[]): Thenable { - return this._resolveProvider(handle).validateFilePaths(ownerUri, serviceType, selectedFiles); + return this._runWithProvider(handle, provider => { + return provider.fileBrowserProvider ? provider.fileBrowserProvider.validateFilePaths(ownerUri, serviceType, selectedFiles) + : Promise.resolve(undefined); + }); } /** @@ -450,7 +506,10 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { * Close file browser */ public $closeFileBrowser(handle: number, ownerUri: string): Thenable { - return this._resolveProvider(handle).closeFileBrowser(ownerUri); + return this._runWithProvider(handle, provider => { + return provider.fileBrowserProvider ? provider.fileBrowserProvider.closeFileBrowser(ownerUri) + : Promise.resolve(undefined); + }); } /** @@ -460,15 +519,21 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { /** * Start a profiler session */ - public $startSession(handle: number, sessionId: string): Thenable { - return this._resolveProvider(handle).startSession(sessionId); + public $startSession(handle: number, sessionId: string): Thenable { + return this._runWithProvider(handle, provider => { + return provider.profilerProvider ? provider.profilerProvider.startSession(sessionId) + : Promise.resolve(undefined); + }); } /** * Stop a profiler session */ - public $stopSession(handle: number, sessionId: string): Thenable { - return this._resolveProvider(handle).stopSession(sessionId); + public $stopSession(handle: number, sessionId: string): Thenable { + return this._runWithProvider(handle, provider => { + return provider.profilerProvider ? provider.profilerProvider.stopSession(sessionId) + : Promise.resolve(undefined); + }); } /** diff --git a/src/sql/workbench/api/node/mainThreadDataProtocol.ts b/src/sql/workbench/api/node/mainThreadDataProtocol.ts index 546f0a749c..eb83323d7f 100644 --- a/src/sql/workbench/api/node/mainThreadDataProtocol.ts +++ b/src/sql/workbench/api/node/mainThreadDataProtocol.ts @@ -18,8 +18,7 @@ import { IMetadataService } from 'sql/services/metadata/metadataService'; import { IObjectExplorerService } from 'sql/parts/registeredServer/common/objectExplorerService'; import { IScriptingService } from 'sql/services/scripting/scriptingService'; import { IAdminService } from 'sql/parts/admin/common/adminService'; -import { IBackupService } from 'sql/parts/disasterRecovery/backup/common/backupService'; -import { IRestoreService } from 'sql/parts/disasterRecovery/restore/common/restoreService'; +import { IDisasterRecoveryService } from 'sql/parts/disasterRecovery/common/interfaces'; import { ITaskService } from 'sql/parts/taskHistory/common/taskService'; import { IProfilerService } from 'sql/parts/profiler/service/interfaces'; import { ISerializationService } from 'sql/services/serialization/serializationService'; @@ -48,8 +47,7 @@ export class MainThreadDataProtocol extends MainThreadDataProtocolShape { @IObjectExplorerService private _objectExplorerService: IObjectExplorerService, @IScriptingService private _scriptingService: IScriptingService, @IAdminService private _adminService: IAdminService, - @IBackupService private _backupService: IBackupService, - @IRestoreService private _restoreService: IRestoreService, + @IDisasterRecoveryService private _disasterRecoveryService: IDisasterRecoveryService, @ITaskService private _taskService: ITaskService, @IProfilerService private _profilerService: IProfilerService, @ISerializationService private _serializationService: ISerializationService, @@ -68,8 +66,10 @@ export class MainThreadDataProtocol extends MainThreadDataProtocolShape { this._toDispose = dispose(this._toDispose); } - public $registerConnectionProvider(providerId: string, handle: number): TPromise { - const self = this; + public $registerProvider(providerId: string, handle: number): TPromise { + let self = this; + + // register connection management provider this._connectionManagementService.registerProvider(providerId, { connect(connectionUri: string, connectionInfo: data.ConnectionInfo): Thenable { return self._proxy.$connect(handle, connectionUri, connectionInfo); @@ -91,11 +91,13 @@ export class MainThreadDataProtocol extends MainThreadDataProtocolShape { } }); - return undefined; - } + this._capabilitiesService.registerProvider({ + getServerCapabilities(client: data.DataProtocolClientCapabilities): Thenable { + return self._proxy.$getServerCapabilities(handle, client); + } + }); - public $registerQueryProvider(providerId: string, handle: number): TPromise { - const self = this; + // register query provider this._queryManagementService.addQueryRequestHandler(providerId, { cancelQuery(ownerUri: string): Thenable { return self._proxy.$cancelQuery(handle, ownerUri); @@ -159,45 +161,6 @@ export class MainThreadDataProtocol extends MainThreadDataProtocolShape { } }); - return undefined; - } - - public $registerBackupProvider(providerId: string, handle: number): TPromise { - const self = this; - this._backupService.registerProvider(providerId, { - backup(connectionUri: string, backupInfo: { [key: string]: any }, taskExecutionMode: data.TaskExecutionMode): Thenable { - return self._proxy.$backup(handle, connectionUri, backupInfo, taskExecutionMode); - }, - getBackupConfigInfo(connectionUri: string): Thenable { - return self._proxy.$getBackupConfigInfo(handle, connectionUri); - } - }); - - return undefined; - } - - public $registerRestoreProvider(providerId: string, handle: number): TPromise { - const self = this; - this._restoreService.registerProvider(providerId, { - getRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { - return self._proxy.$getRestorePlan(handle, connectionUri, restoreInfo); - }, - cancelRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { - return self._proxy.$cancelRestorePlan(handle, connectionUri, restoreInfo); - }, - restore(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { - return self._proxy.$restore(handle, connectionUri, restoreInfo); - }, - getRestoreConfigInfo(connectionUri: string): Thenable { - return self._proxy.$getRestoreConfigInfo(handle, connectionUri); - } - }); - - return undefined; - } - - public $registerMetadataProvider(providerId: string, handle: number): TPromise { - const self = this; this._metadataService.registerProvider(providerId, { getMetadata(connectionUri: string): Thenable { return self._proxy.$getMetadata(handle, connectionUri); @@ -213,11 +176,6 @@ export class MainThreadDataProtocol extends MainThreadDataProtocolShape { } }); - return undefined; - } - - public $registerObjectExplorerProvider(providerId: string, handle: number): TPromise { - const self = this; this._objectExplorerService.registerProvider(providerId, { createNewSession(connection: data.ConnectionInfo): Thenable { return self._proxy.$createObjectExplorerSession(handle, connection); @@ -233,11 +191,6 @@ export class MainThreadDataProtocol extends MainThreadDataProtocolShape { } }); - return undefined; - } - - public $registerTaskServicesProvider(providerId: string, handle: number): TPromise { - const self = this; this._taskService.registerProvider(providerId, { getAllTasks(listTasksParams: data.ListTasksParams): Thenable { return self._proxy.$getAllTasks(handle, listTasksParams); @@ -247,65 +200,12 @@ export class MainThreadDataProtocol extends MainThreadDataProtocolShape { } }); - return undefined; - } - - public $registerScriptingProvider(providerId: string, handle: number): TPromise { - const self = this; this._scriptingService.registerProvider(providerId, { scriptAsOperation(connectionUri: string, operation: data.ScriptOperation, metadata: data.ObjectMetadata, paramDetails: data.ScriptingParamDetails): Thenable { return self._proxy.$scriptAsOperation(handle, connectionUri, operation, metadata, paramDetails); } }); - return undefined; - } - - public $registerFileBrowserProvider(providerId: string, handle: number): TPromise { - const self = this; - this._fileBrowserService.registerProvider(providerId, { - openFileBrowser(ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean): Thenable { - return self._proxy.$openFileBrowser(handle, ownerUri, expandPath, fileFilters, changeFilter); - }, - expandFolderNode(ownerUri: string, expandPath: string): Thenable { - return self._proxy.$expandFolderNode(handle, ownerUri, expandPath); - }, - validateFilePaths(ownerUri: string, serviceType: string, selectedFiles: string[]): Thenable { - return self._proxy.$validateFilePaths(handle, ownerUri, serviceType, selectedFiles); - }, - closeFileBrowser(ownerUri: string): Thenable { - return self._proxy.$closeFileBrowser(handle, ownerUri); - } - }); - - return undefined; - } - - public $registerProfilerProvider(providerId: string, handle: number): TPromise { - const self = this; - this._profilerService.registerProvider(providerId, { - startSession(sessionId: string): Thenable { - return self._proxy.$startSession(handle, sessionId); - }, - stopSession(sessionId: string): Thenable { - return self._proxy.$stopSession(handle, sessionId); - }, - pauseSession(sessionId: string): Thenable { - return TPromise.as(true); - }, - connectSession(sessionId: string): Thenable { - return TPromise.as(true); - }, - disconnectSession(sessionId: string): Thenable { - return TPromise.as(true); - } - }); - - return undefined; - } - - public $registerAdminServicesProvider(providerId: string, handle: number): TPromise { - const self = this; this._adminService.registerProvider(providerId, { createDatabase(connectionUri: string, database: data.DatabaseInfo): Thenable { return self._proxy.$createDatabase(handle, connectionUri, database); @@ -321,14 +221,57 @@ export class MainThreadDataProtocol extends MainThreadDataProtocolShape { } }); - return undefined; - } + this._disasterRecoveryService.registerProvider(providerId, { + backup(connectionUri: string, backupInfo: { [key: string]: any }, taskExecutionMode: data.TaskExecutionMode): Thenable { + return self._proxy.$backup(handle, connectionUri, backupInfo, taskExecutionMode); + }, + getBackupConfigInfo(connectionUri: string): Thenable { + return self._proxy.$getBackupConfigInfo(handle, connectionUri); + }, + getRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { + return self._proxy.$getRestorePlan(handle, connectionUri, restoreInfo); + }, + cancelRestorePlan(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { + return self._proxy.$cancelRestorePlan(handle, connectionUri, restoreInfo); + }, + restore(connectionUri: string, restoreInfo: data.RestoreInfo): Thenable { + return self._proxy.$restore(handle, connectionUri, restoreInfo); + }, + getRestoreConfigInfo(connectionUri: string): Thenable { + return self._proxy.$getRestoreConfigInfo(handle, connectionUri); + } + }); - public $registerCapabilitiesServiceProvider(providerId: string, handle: number): TPromise { - const self = this; - this._capabilitiesService.registerProvider({ - getServerCapabilities(client: data.DataProtocolClientCapabilities): Thenable { - return self._proxy.$getServerCapabilities(handle, client); + this._fileBrowserService.registerProvider(providerId, { + openFileBrowser(ownerUri: string, expandPath: string, fileFilters: string[], changeFilter: boolean): Thenable { + return self._proxy.$openFileBrowser(handle, ownerUri, expandPath, fileFilters, changeFilter); + }, + expandFolderNode(ownerUri: string, expandPath: string): Thenable { + return self._proxy.$expandFolderNode(handle, ownerUri, expandPath); + }, + validateFilePaths(ownerUri: string, serviceType: string, selectedFiles: string[]): Thenable { + return self._proxy.$validateFilePaths(handle, ownerUri, serviceType, selectedFiles); + }, + closeFileBrowser(ownerUri: string): Thenable { + return self._proxy.$closeFileBrowser(handle, ownerUri); + } + }); + + this._profilerService.registerProvider(providerId, { + startSession(sessionId: string): Thenable { + return self._proxy.$startSession(handle, sessionId); + }, + stopSession(sessionId: string): Thenable { + return self._proxy.$stopSession(handle, sessionId); + }, + pauseSession(sessionId: string): Thenable { + return TPromise.as(true); + }, + connectSession(sessionId: string): Thenable { + return TPromise.as(true); + }, + disconnectSession(sessionId: string): Thenable { + return TPromise.as(true); } }); diff --git a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts index 280178a7b2..a50116e329 100644 --- a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts +++ b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts @@ -22,7 +22,7 @@ import { ExtHostDataProtocol } from 'sql/workbench/api/node/extHostDataProtocol' import { ExtHostSerializationProvider } from 'sql/workbench/api/node/extHostSerializationProvider'; import { ExtHostResourceProvider } from 'sql/workbench/api/node/extHostResourceProvider'; import { ExtHostThreadService } from 'vs/workbench/services/thread/node/extHostThreadService'; -import * as sqlExtHostTypes from 'sql/workbench/api/common/sqlExtHostTypes'; +import * as sqlExtHostTypes from 'sql/workbench/api/node/sqlExtHostTypes'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; @@ -95,141 +95,92 @@ export function createApiFactory( } }; - let registerConnectionProvider = (provider: data.ConnectionProvider): vscode.Disposable => { - // Connection callbacks - provider.registerOnConnectionComplete((connSummary: data.ConnectionInfoSummary) => { - extHostDataProvider.$onConnectComplete(provider.handle, connSummary); - }); - - provider.registerOnIntelliSenseCacheComplete((connectionUri: string) => { - extHostDataProvider.$onIntelliSenseCacheComplete(provider.handle, connectionUri); - }); - - provider.registerOnConnectionChanged((changedConnInfo: data.ChangedConnectionInfo) => { - extHostDataProvider.$onConnectionChanged(provider.handle, changedConnInfo); - }); - - return extHostDataProvider.$registerConnectionProvider(provider); - }; - - let registerQueryProvider = (provider: data.QueryProvider): vscode.Disposable => { - provider.registerOnQueryComplete((result: data.QueryExecuteCompleteNotificationResult) => { - extHostDataProvider.$onQueryComplete(provider.handle, result); - }); - - provider.registerOnBatchStart((batchInfo: data.QueryExecuteBatchNotificationParams) => { - extHostDataProvider.$onBatchStart(provider.handle, batchInfo); - }); - - provider.registerOnBatchComplete((batchInfo: data.QueryExecuteBatchNotificationParams) => { - extHostDataProvider.$onBatchComplete(provider.handle, batchInfo); - }); - - provider.registerOnResultSetComplete((resultSetInfo: data.QueryExecuteResultSetCompleteNotificationParams) => { - extHostDataProvider.$onResultSetComplete(provider.handle, resultSetInfo); - }); - - provider.registerOnMessage((message: data.QueryExecuteMessageParams) => { - extHostDataProvider.$onQueryMessage(provider.handle, message); - }); - - provider.registerOnEditSessionReady((ownerUri: string, success: boolean, message: string) => { - extHostDataProvider.$onEditSessionReady(provider.handle, ownerUri, success, message); - }); - - return extHostDataProvider.$registerQueryProvider(provider); - }; - - let registerObjectExplorerProvider = (provider: data.ObjectExplorerProvider): vscode.Disposable => { - provider.registerOnSessionCreated((response: data.ObjectExplorerSession) => { - extHostDataProvider.$onObjectExplorerSessionCreated(provider.handle, response); - }); - - provider.registerOnExpandCompleted((response: data.ObjectExplorerExpandInfo) => { - extHostDataProvider.$onObjectExplorerNodeExpanded(provider.handle, response); - }); - - return extHostDataProvider.$registerObjectExplorerProvider(provider); - }; - - let registerTaskServicesProvider = (provider: data.TaskServicesProvider): vscode.Disposable => { - provider.registerOnTaskCreated((response: data.TaskInfo) => { - extHostDataProvider.$onTaskCreated(provider.handle, response); - }); - - provider.registerOnTaskStatusChanged((response: data.TaskProgressInfo) => { - extHostDataProvider.$onTaskStatusChanged(provider.handle, response); - }); - - return extHostDataProvider.$registerTaskServicesProvider(provider); - }; - - let registerFileBrowserProvider = (provider: data.FileBrowserProvider): vscode.Disposable => { - provider.registerOnFileBrowserOpened((response: data.FileBrowserOpenedParams) => { - extHostDataProvider.$onFileBrowserOpened(provider.handle, response); - }); - - provider.registerOnFolderNodeExpanded((response: data.FileBrowserExpandedParams) => { - extHostDataProvider.$onFolderNodeExpanded(provider.handle, response); - }); - - provider.registerOnFilePathsValidated((response: data.FileBrowserValidatedParams) => { - extHostDataProvider.$onFilePathsValidated(provider.handle, response); - }); - - return extHostDataProvider.$registerFileBrowserProvider(provider); - }; - - let registerScriptingProvider = (provider: data.ScriptingProvider): vscode.Disposable => { - provider.registerOnScriptingComplete((response: data.ScriptingCompleteResult) => { - extHostDataProvider.$onScriptingComplete(provider.handle, response); - }); - - return extHostDataProvider.$registerScriptingProvider(provider); - }; - - let registerProfilerProvider = (provider: data.ProfilerProvider): vscode.Disposable => { - provider.registerOnSessionEventsAvailable((response: data.ProfilerSessionEvents) => { - extHostDataProvider.$onSessionEventsAvailable(provider.handle, response); - }); - - return extHostDataProvider.$registerProfilerProvider(provider); - }; - - let registerBackupProvider = (provider: data.BackupProvider): vscode.Disposable => { - return extHostDataProvider.$registerBackupProvider(provider); - }; - - let registerRestoreProvider = (provider: data.RestoreProvider): vscode.Disposable => { - return extHostDataProvider.$registerRestoreProvider(provider); - }; - - let registerMetadataProvider = (provider: data.MetadataProvider): vscode.Disposable => { - return extHostDataProvider.$registerMetadataProvider(provider); - }; - - let registerCapabilitiesServiceProvider = (provider: data.CapabilitiesProvider): vscode.Disposable => { - return extHostDataProvider.$registerCapabilitiesServiceProvider(provider); - }; - - let registerAdminServicesProvider = (provider: data.AdminServicesProvider): vscode.Disposable => { - return extHostDataProvider.$registerAdminServicesProvider(provider); - }; - // namespace: dataprotocol const dataprotocol: typeof data.dataprotocol = { - registerBackupProvider, - registerConnectionProvider, - registerFileBrowserProvider, - registerMetadataProvider, - registerObjectExplorerProvider, - registerProfilerProvider, - registerRestoreProvider, - registerScriptingProvider, - registerTaskServicesProvider, - registerQueryProvider, - registerAdminServicesProvider, - registerCapabilitiesServiceProvider, + registerProvider(provider: data.DataProtocolProvider): vscode.Disposable { + // Connection callbacks + provider.connectionProvider.registerOnConnectionComplete((connSummary: data.ConnectionInfoSummary) => { + extHostDataProvider.$onConnectComplete(provider.handle, connSummary); + }); + + provider.connectionProvider.registerOnIntelliSenseCacheComplete((connectionUri: string) => { + extHostDataProvider.$onIntelliSenseCacheComplete(provider.handle, connectionUri); + }); + + provider.connectionProvider.registerOnConnectionChanged((changedConnInfo: data.ChangedConnectionInfo) => { + extHostDataProvider.$onConnectionChanged(provider.handle, changedConnInfo); + }); + + // Query callbacks + provider.queryProvider.registerOnQueryComplete((result: data.QueryExecuteCompleteNotificationResult) => { + extHostDataProvider.$onQueryComplete(provider.handle, result); + }); + + provider.queryProvider.registerOnBatchStart((batchInfo: data.QueryExecuteBatchNotificationParams) => { + extHostDataProvider.$onBatchStart(provider.handle, batchInfo); + }); + + provider.queryProvider.registerOnBatchComplete((batchInfo: data.QueryExecuteBatchNotificationParams) => { + extHostDataProvider.$onBatchComplete(provider.handle, batchInfo); + }); + + provider.queryProvider.registerOnResultSetComplete((resultSetInfo: data.QueryExecuteResultSetCompleteNotificationParams) => { + extHostDataProvider.$onResultSetComplete(provider.handle, resultSetInfo); + }); + + provider.queryProvider.registerOnMessage((message: data.QueryExecuteMessageParams) => { + extHostDataProvider.$onQueryMessage(provider.handle, message); + }); + + //OE callbacks + provider.objectExplorerProvider.registerOnSessionCreated((response: data.ObjectExplorerSession) => { + extHostDataProvider.$onObjectExplorerSessionCreated(provider.handle, response); + }); + + provider.objectExplorerProvider.registerOnExpandCompleted((response: data.ObjectExplorerExpandInfo) => { + extHostDataProvider.$onObjectExplorerNodeExpanded(provider.handle, response); + }); + + //Tasks callbacks + provider.taskServicesProvider.registerOnTaskCreated((response: data.TaskInfo) => { + extHostDataProvider.$onTaskCreated(provider.handle, response); + }); + + provider.taskServicesProvider.registerOnTaskStatusChanged((response: data.TaskProgressInfo) => { + extHostDataProvider.$onTaskStatusChanged(provider.handle, response); + }); + + // Edit Data callbacks + provider.queryProvider.registerOnEditSessionReady((ownerUri: string, success: boolean, message: string) => { + extHostDataProvider.$onEditSessionReady(provider.handle, ownerUri, success, message); + }); + + // File browser callbacks + provider.fileBrowserProvider.registerOnFileBrowserOpened((response: data.FileBrowserOpenedParams) => { + extHostDataProvider.$onFileBrowserOpened(provider.handle, response); + }); + + provider.fileBrowserProvider.registerOnFolderNodeExpanded((response: data.FileBrowserExpandedParams) => { + extHostDataProvider.$onFolderNodeExpanded(provider.handle, response); + }); + + provider.fileBrowserProvider.registerOnFilePathsValidated((response: data.FileBrowserValidatedParams) => { + extHostDataProvider.$onFilePathsValidated(provider.handle, response); + }); + + // Scripting callbacks + provider.scriptingProvider.registerOnScriptingComplete((response: data.ScriptingCompleteResult) => { + extHostDataProvider.$onScriptingComplete(provider.handle, response); + }); + + // Profiler callbacks + provider.profilerProvider.registerOnSessionEventsAvailable((response: data.ProfilerSessionEvents) => { + extHostDataProvider.$onSessionEventsAvailable(provider.handle, response); + }); + + // Complete registration + return extHostDataProvider.$registerProvider(provider); + }, onDidChangeLanguageFlavor(listener: (e: data.DidChangeLanguageFlavorParams) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) { return extHostDataProvider.onDidChangeLanguageFlavor(listener, thisArgs, disposables); } diff --git a/src/sql/workbench/api/node/sqlExtHost.protocol.ts b/src/sql/workbench/api/node/sqlExtHost.protocol.ts index 597ef9c5b2..f64ed59a81 100644 --- a/src/sql/workbench/api/node/sqlExtHost.protocol.ts +++ b/src/sql/workbench/api/node/sqlExtHost.protocol.ts @@ -352,18 +352,7 @@ export abstract class MainThreadResourceProviderShape { } export abstract class MainThreadDataProtocolShape { - $registerConnectionProvider(providerId: string, handle: number): TPromise { throw ni(); } - $registerBackupProvider(providerId: string, handle: number): TPromise { throw ni(); } - $registerRestoreProvider(providerId: string, handle: number): TPromise { throw ni(); } - $registerScriptingProvider(providerId: string, handle: number): TPromise { throw ni(); } - $registerQueryProvider(providerId: string, handle: number): TPromise { throw ni(); } - $registerProfilerProvider(providerId: string, handle: number): TPromise { throw ni(); } - $registerObjectExplorerProvider(providerId: string, handle: number): TPromise { throw ni(); } - $registerMetadataProvider(providerId: string, handle: number): TPromise { throw ni(); } - $registerTaskServicesProvider(providerId: string, handle: number): TPromise { throw ni(); } - $registerFileBrowserProvider(providerId: string, handle: number): TPromise { throw ni(); } - $registerCapabilitiesServiceProvider(providerId: string, handle: number): TPromise { throw ni(); } - $registerAdminServicesProvider(providerId: string, handle: number): TPromise { throw ni(); } + $registerProvider(providerId: string, handle: number): TPromise { throw ni(); } $unregisterProvider(handle: number): TPromise { throw ni(); } $onConnectionComplete(handle: number, connectionInfoSummary: data.ConnectionInfoSummary): void { throw ni(); } $onIntelliSenseCacheComplete(handle: number, connectionUri: string): void { throw ni(); } diff --git a/src/sql/workbench/api/common/sqlExtHostTypes.ts b/src/sql/workbench/api/node/sqlExtHostTypes.ts similarity index 87% rename from src/sql/workbench/api/common/sqlExtHostTypes.ts rename to src/sql/workbench/api/node/sqlExtHostTypes.ts index 89beaad413..dec9766292 100644 --- a/src/sql/workbench/api/common/sqlExtHostTypes.ts +++ b/src/sql/workbench/api/node/sqlExtHostTypes.ts @@ -16,14 +16,15 @@ export enum ServiceOptionType { } export enum ConnectionOptionSpecialType { - serverName = 'serverName', - databaseName = 'databaseName', - authType = 'authType', - userName = 'userName', - password = 'password', - appName = 'appName' + serverName = 0, + databaseName = 1, + authType = 2, + userName = 3, + password = 4, + appName = 5 } + export enum MetadataType { Table = 0, View = 1, @@ -38,6 +39,7 @@ export enum EditRowState { dirtyUpdate = 3 } + export enum TaskStatus { notStarted = 0, inProgress = 1, @@ -61,4 +63,4 @@ export enum ScriptOperation { Delete = 4, Execute = 5, Alter = 6 -} +} \ No newline at end of file diff --git a/src/sql/workbench/common/actions.ts b/src/sql/workbench/common/actions.ts index 952f7b0b90..a64563079d 100644 --- a/src/sql/workbench/common/actions.ts +++ b/src/sql/workbench/common/actions.ts @@ -9,8 +9,7 @@ import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService'; import { IConnectionProfile } from 'sql/parts/connection/common/interfaces'; import { IInsightsConfig } from 'sql/parts/dashboard/widgets/insights/interfaces'; import { IScriptingService } from 'sql/services/scripting/scriptingService'; -import { IRestoreDialogController } from 'sql/parts/disasterRecovery/restore/common/restoreService'; -import { IBackupUiService } from 'sql/parts/disasterRecovery/backup/common/backupService'; +import { IDisasterRecoveryUiService, IRestoreDialogController } from 'sql/parts/disasterRecovery/common/interfaces'; import { IAngularEventingService, AngularEventType } from 'sql/services/angularEventing/angularEventingService'; import { IInsightsDialogService } from 'sql/parts/insights/common/interfaces'; import { IAdminService } from 'sql/parts/admin/common/adminService'; @@ -285,7 +284,7 @@ export class BackupAction extends TaskAction { constructor( id: string, label: string, icon: string, - @IBackupUiService protected _backupUiService: IBackupUiService + @IDisasterRecoveryUiService protected _disasterRecoveryService: IDisasterRecoveryUiService ) { super(id, label, icon); } @@ -294,7 +293,7 @@ export class BackupAction extends TaskAction { return new TPromise((resolve, reject) => { TaskUtilities.showBackup( actionContext.profile, - this._backupUiService, + this._disasterRecoveryService, ).then( result => { resolve(true); diff --git a/src/sql/workbench/common/taskUtilities.ts b/src/sql/workbench/common/taskUtilities.ts index 1d620b46b5..e33e69e2b4 100644 --- a/src/sql/workbench/common/taskUtilities.ts +++ b/src/sql/workbench/common/taskUtilities.ts @@ -14,8 +14,7 @@ import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService'; import { IScriptingService } from 'sql/services/scripting/scriptingService'; import { EditDataInput } from 'sql/parts/editData/common/editDataInput'; import { IAdminService } from 'sql/parts/admin/common/adminService'; -import { IRestoreDialogController } from 'sql/parts/disasterRecovery/restore/common/restoreService'; -import { IBackupUiService } from 'sql/parts/disasterRecovery/backup/common/backupService'; +import { IDisasterRecoveryUiService, IRestoreDialogController } from 'sql/parts/disasterRecovery/common/interfaces'; import { IInsightsConfig } from 'sql/parts/dashboard/widgets/insights/interfaces'; import { IInsightsDialogService } from 'sql/parts/insights/common/interfaces'; import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo'; @@ -315,9 +314,9 @@ export function showCreateLogin(uri: string, connection: IConnectionProfile, adm }); } -export function showBackup(connection: IConnectionProfile, backupUiService: IBackupUiService): Promise { +export function showBackup(connection: IConnectionProfile, disasterRecoveryUiService: IDisasterRecoveryUiService): Promise { return new Promise((resolve) => { - backupUiService.showBackup(connection); + disasterRecoveryUiService.showBackup(connection); }); } diff --git a/src/sqltest/parts/common/optionsDialogHelper.test.ts b/src/sqltest/parts/common/optionsDialogHelper.test.ts index 2bcf763e3a..e5c42c181f 100644 --- a/src/sqltest/parts/common/optionsDialogHelper.test.ts +++ b/src/sqltest/parts/common/optionsDialogHelper.test.ts @@ -5,12 +5,12 @@ 'use strict'; import * as OptionsDialogHelper from 'sql/base/browser/ui/modal/optionsDialogHelper'; +import { ServiceOptionType } from 'sql/parts/connection/common/connectionManagement'; import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import data = require('data'); import { Builder, $ } from 'vs/base/browser/builder'; import * as TypeMoq from 'typemoq'; import * as assert from 'assert'; -import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes'; suite('Advanced options helper tests', () => { var possibleInputs: string[]; diff --git a/src/sqltest/parts/connection/connectionProfile.test.ts b/src/sqltest/parts/connection/connectionProfile.test.ts index f81be9142f..74752999c0 100644 --- a/src/sqltest/parts/connection/connectionProfile.test.ts +++ b/src/sqltest/parts/connection/connectionProfile.test.ts @@ -10,7 +10,6 @@ import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile import { IConnectionProfile, IConnectionProfileStore } from 'sql/parts/connection/common/interfaces'; import data = require('data'); import * as assert from 'assert'; -import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; suite('SQL ConnectionProfileInfo tests', () => { let msSQLCapabilities: data.DataProtocolServerCapabilities; @@ -59,7 +58,7 @@ suite('SQL ConnectionProfileInfo tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.serverName, + specialValueType: 0, valueType: 0 }, { @@ -71,7 +70,7 @@ suite('SQL ConnectionProfileInfo tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.databaseName, + specialValueType: 1, valueType: 0 }, { @@ -83,7 +82,7 @@ suite('SQL ConnectionProfileInfo tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.userName, + specialValueType: 3, valueType: 0 }, { @@ -95,7 +94,7 @@ suite('SQL ConnectionProfileInfo tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.authType, + specialValueType: 2, valueType: 0 }, { @@ -107,7 +106,7 @@ suite('SQL ConnectionProfileInfo tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.password, + specialValueType: 4, valueType: 0 } ] diff --git a/src/sqltest/parts/connection/connectionStore.test.ts b/src/sqltest/parts/connection/connectionStore.test.ts index 07325562a5..2be21c4876 100644 --- a/src/sqltest/parts/connection/connectionStore.test.ts +++ b/src/sqltest/parts/connection/connectionStore.test.ts @@ -19,7 +19,6 @@ import * as data from 'data'; import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile'; import { Emitter } from 'vs/base/common/event'; import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup'; -import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; suite('SQL ConnectionStore tests', () => { let defaultNamedProfile: IConnectionProfile; @@ -109,7 +108,7 @@ suite('SQL ConnectionStore tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.serverName, + specialValueType: 0, valueType: 0 }, { @@ -121,7 +120,7 @@ suite('SQL ConnectionStore tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.databaseName, + specialValueType: 1, valueType: 0 }, { @@ -133,7 +132,7 @@ suite('SQL ConnectionStore tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.userName, + specialValueType: 3, valueType: 0 }, { @@ -145,7 +144,7 @@ suite('SQL ConnectionStore tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.authType, + specialValueType: 2, valueType: 0 }, { @@ -157,7 +156,7 @@ suite('SQL ConnectionStore tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.password, + specialValueType: 4, valueType: 0 } ] diff --git a/src/sqltest/parts/connection/objectExplorerService.test.ts b/src/sqltest/parts/connection/objectExplorerService.test.ts index 2881f5100a..fb1083f894 100644 --- a/src/sqltest/parts/connection/objectExplorerService.test.ts +++ b/src/sqltest/parts/connection/objectExplorerService.test.ts @@ -16,7 +16,6 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as data from 'data'; import * as TypeMoq from 'typemoq'; import * as assert from 'assert'; -import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; suite('SQL Object Explorer Service tests', () => { var sqlOEProvider: TypeMoq.Mock; @@ -136,7 +135,7 @@ suite('SQL Object Explorer Service tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.serverName, + specialValueType: 0, valueType: 0 }, { @@ -148,7 +147,7 @@ suite('SQL Object Explorer Service tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.databaseName, + specialValueType: 1, valueType: 0 }, { @@ -160,7 +159,7 @@ suite('SQL Object Explorer Service tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.userName, + specialValueType: 3, valueType: 0 }, { @@ -172,7 +171,7 @@ suite('SQL Object Explorer Service tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.authType, + specialValueType: 2, valueType: 0 }, { @@ -184,7 +183,7 @@ suite('SQL Object Explorer Service tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.password, + specialValueType: 4, valueType: 0 }, { diff --git a/src/sqltest/parts/connection/providerConnectionInfo.test.ts b/src/sqltest/parts/connection/providerConnectionInfo.test.ts index c03093f2ea..ac86b961bd 100644 --- a/src/sqltest/parts/connection/providerConnectionInfo.test.ts +++ b/src/sqltest/parts/connection/providerConnectionInfo.test.ts @@ -10,7 +10,6 @@ import { ProviderConnectionInfo } from 'sql/parts/connection/common/providerConn import { IConnectionProfile } from 'sql/parts/connection/common/interfaces'; import data = require('data'); import * as assert from 'assert'; -import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; suite('SQL ProviderConnectionInfo tests', () => { let msSQLCapabilities: data.DataProtocolServerCapabilities; @@ -45,7 +44,7 @@ suite('SQL ProviderConnectionInfo tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.serverName, + specialValueType: 0, valueType: 0 }, { @@ -57,7 +56,7 @@ suite('SQL ProviderConnectionInfo tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.databaseName, + specialValueType: 1, valueType: 0 }, { @@ -69,7 +68,7 @@ suite('SQL ProviderConnectionInfo tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.userName, + specialValueType: 3, valueType: 0 }, { @@ -81,7 +80,7 @@ suite('SQL ProviderConnectionInfo tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.authType, + specialValueType: 2, valueType: 0 }, { @@ -93,7 +92,7 @@ suite('SQL ProviderConnectionInfo tests', () => { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.password, + specialValueType: 4, valueType: 0 }, { diff --git a/src/sqltest/parts/disasterRecovery/restoreViewModel.test.ts b/src/sqltest/parts/disasterRecovery/restoreViewModel.test.ts index 2851a0c5ca..a166703b8a 100644 --- a/src/sqltest/parts/disasterRecovery/restoreViewModel.test.ts +++ b/src/sqltest/parts/disasterRecovery/restoreViewModel.test.ts @@ -6,8 +6,8 @@ 'use strict'; import data = require('data'); import * as assert from 'assert'; +import { ServiceOptionType } from 'sql/parts/connection/common/connectionManagement'; import { RestoreViewModel } from 'sql/parts/disasterRecovery/restore/restoreViewModel'; -import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes'; suite('Restore Dialog view model tests', () => { let option1String = 'option1'; diff --git a/src/sqltest/stubs/capabilitiesTestService.ts b/src/sqltest/stubs/capabilitiesTestService.ts index e8f31fd4ba..08957319ac 100644 --- a/src/sqltest/stubs/capabilitiesTestService.ts +++ b/src/sqltest/stubs/capabilitiesTestService.ts @@ -9,7 +9,6 @@ import { ConnectionManagementInfo } from 'sql/parts/connection/common/connection import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService'; import Event from 'vs/base/common/event'; import { Action } from 'vs/base/common/actions'; -import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes'; export class CapabilitiesTestService implements ICapabilitiesService { @@ -34,7 +33,7 @@ export class CapabilitiesTestService implements ICapabilitiesService { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.serverName, + specialValueType: 0, valueType: 0 }, { @@ -46,7 +45,7 @@ export class CapabilitiesTestService implements ICapabilitiesService { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.databaseName, + specialValueType: 1, valueType: 0 }, { @@ -58,7 +57,7 @@ export class CapabilitiesTestService implements ICapabilitiesService { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.userName, + specialValueType: 3, valueType: 0 }, { @@ -70,7 +69,7 @@ export class CapabilitiesTestService implements ICapabilitiesService { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.authType, + specialValueType: 2, valueType: 0 }, { @@ -82,7 +81,7 @@ export class CapabilitiesTestService implements ICapabilitiesService { defaultValue: undefined, isIdentity: true, isRequired: true, - specialValueType: ConnectionOptionSpecialType.password, + specialValueType: 4, valueType: 0 } ] diff --git a/src/sqltest/stubs/connectionProviderStub.ts b/src/sqltest/stubs/connectionProviderStub.ts index 4aa88f00db..3258ac11cc 100644 --- a/src/sqltest/stubs/connectionProviderStub.ts +++ b/src/sqltest/stubs/connectionProviderStub.ts @@ -3,10 +3,10 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as data from 'data'; +import data = require('data'); export class ConnectionProviderStub implements data.ConnectionProvider { - public readonly providerId = 'MSSQL'; + handle: number = 1; connect(connectionUri: string, connectionInfo: data.ConnectionInfo): Thenable { return undefined; diff --git a/src/sqltest/stubs/objectExplorerProviderTestService.ts b/src/sqltest/stubs/objectExplorerProviderTestService.ts index b62e8a5607..ddabd70f8b 100644 --- a/src/sqltest/stubs/objectExplorerProviderTestService.ts +++ b/src/sqltest/stubs/objectExplorerProviderTestService.ts @@ -8,8 +8,6 @@ import data = require('data'); export class ObjectExplorerProviderTestService implements data.ObjectExplorerProvider { - public readonly providerId = 'MSSQL'; - public createNewSession(connInfo: data.ConnectionInfo): Thenable { return Promise.resolve(undefined); } diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index c42a534fe4..c48f290fd3 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -123,10 +123,10 @@ import { IQueryManagementService, QueryManagementService } from 'sql/parts/query import { IEditorDescriptorService, EditorDescriptorService } from 'sql/parts/query/editor/editorDescriptorService'; import { IScriptingService, ScriptingService } from 'sql/services/scripting/scriptingService'; import { IAdminService, AdminService } from 'sql/parts/admin/common/adminService'; -import { IBackupService, IBackupUiService } from 'sql/parts/disasterRecovery/backup/common/backupService'; -import { BackupService, BackupUiService } from 'sql/parts/disasterRecovery/backup/common/backupServiceImp'; -import { IRestoreDialogController, IRestoreService } from 'sql/parts/disasterRecovery/restore/common/restoreService'; -import { RestoreService, RestoreDialogController } from 'sql/parts/disasterRecovery/restore/common/restoreServiceImpl'; +import { DisasterRecoveryService } from 'sql/parts/disasterRecovery/common/disasterRecoveryService'; +import { DisasterRecoveryUiService } from 'sql/parts/disasterRecovery/common/disasterRecoveryUiService'; +import { RestoreDialogController } from 'sql/parts/disasterRecovery/restore/restoreDialogController'; +import { IDisasterRecoveryService, IDisasterRecoveryUiService, IRestoreDialogController } from 'sql/parts/disasterRecovery/common/interfaces'; import { IFileBrowserService, IFileBrowserDialogController } from 'sql/parts/fileBrowser/common/interfaces'; import { FileBrowserService } from 'sql/parts/fileBrowser/common/fileBrowserService'; import { FileBrowserDialogController } from 'sql/parts/fileBrowser/fileBrowserDialogController'; @@ -681,9 +681,8 @@ export class Workbench implements IPartService { serviceCollection.set(IObjectExplorerService, this.instantiationService.createInstance(ObjectExplorerService)); serviceCollection.set(IScriptingService, this.instantiationService.createInstance(ScriptingService)); serviceCollection.set(IAdminService, this.instantiationService.createInstance(AdminService)); - serviceCollection.set(IBackupService, this.instantiationService.createInstance(BackupService)); - serviceCollection.set(IBackupUiService, this.instantiationService.createInstance(BackupUiService)); - serviceCollection.set(IRestoreService, this.instantiationService.createInstance(RestoreService)); + serviceCollection.set(IDisasterRecoveryService, this.instantiationService.createInstance(DisasterRecoveryService)); + serviceCollection.set(IDisasterRecoveryUiService, this.instantiationService.createInstance(DisasterRecoveryUiService)); serviceCollection.set(IRestoreDialogController, this.instantiationService.createInstance(RestoreDialogController)); serviceCollection.set(IFileBrowserService, this.instantiationService.createInstance(FileBrowserService)); serviceCollection.set(IFileBrowserDialogController, this.instantiationService.createInstance(FileBrowserDialogController));