diff --git a/client-ts/FunctionalTests/package.json b/client-ts/FunctionalTests/package.json index e326b646a5..439929a594 100644 --- a/client-ts/FunctionalTests/package.json +++ b/client-ts/FunctionalTests/package.json @@ -10,7 +10,8 @@ }, "scripts": { "clean": "node ../node_modules/rimraf/bin.js ./wwwroot/dist", - "build": "npm run build:tsc && npm run build:rollup", + "build": "npm run build:lint && npm run build:tsc && npm run build:rollup", + "build:lint": "node ../node_modules/tslint/bin/tslint -c ../tslint.json -p ./tsconfig.json", "build:tsc": "node ../node_modules/typescript/bin/tsc --project ./tsconfig.json", "build:rollup": "node ../node_modules/rollup/bin/rollup -c" }, diff --git a/client-ts/FunctionalTests/ts/Common.ts b/client-ts/FunctionalTests/ts/Common.ts index 8b05be212d..a7adf1ef01 100644 --- a/client-ts/FunctionalTests/ts/Common.ts +++ b/client-ts/FunctionalTests/ts/Common.ts @@ -1,13 +1,13 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { TransportType, IHubProtocol, JsonHubProtocol } from "@aspnet/signalr" -import { MessagePackHubProtocol } from "@aspnet/signalr-protocol-msgpack" +import { IHubProtocol, JsonHubProtocol, TransportType } from "@aspnet/signalr"; +import { MessagePackHubProtocol } from "@aspnet/signalr-protocol-msgpack"; export const ECHOENDPOINT_URL = "http://" + document.location.host + "/echo"; export function getTransportTypes(): TransportType[] { - var transportTypes = []; + const transportTypes = []; if (typeof WebSocket !== "undefined") { transportTypes.push(TransportType.WebSockets); } @@ -20,13 +20,13 @@ export function getTransportTypes(): TransportType[] { } export function eachTransport(action: (transport: TransportType) => void) { - getTransportTypes().forEach(function (t) { + getTransportTypes().forEach((t) => { return action(t); }); } export function eachTransportAndProtocol(action: (transport: TransportType, protocol: IHubProtocol) => void) { - var protocols : IHubProtocol[] = [new JsonHubProtocol()]; + const protocols: IHubProtocol[] = [new JsonHubProtocol()]; // IE9 does not support XmlHttpRequest advanced features so disable for now // This can be enabled if we fix: https://github.com/aspnet/SignalR/issues/742 if (typeof new XMLHttpRequest().responseType === "string") { @@ -35,9 +35,9 @@ export function eachTransportAndProtocol(action: (transport: TransportType, prot // Everything works fine in the module protocols.push(new MessagePackHubProtocol()); } - getTransportTypes().forEach(function (t) { - return protocols.forEach(function (p) { + getTransportTypes().forEach((t) => { + return protocols.forEach((p) => { return action(t, p); }); }); -} \ No newline at end of file +} diff --git a/client-ts/FunctionalTests/ts/ConnectionTests.ts b/client-ts/FunctionalTests/ts/ConnectionTests.ts index f32bda5e87..ed7f6ca1aa 100644 --- a/client-ts/FunctionalTests/ts/ConnectionTests.ts +++ b/client-ts/FunctionalTests/ts/ConnectionTests.ts @@ -1,63 +1,63 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { HttpConnection, LogLevel, TransportType } from "@aspnet/signalr" -import { eachTransport, ECHOENDPOINT_URL } from "./Common" +import { HttpConnection, LogLevel, TransportType } from "@aspnet/signalr"; +import { eachTransport, ECHOENDPOINT_URL } from "./Common"; -describe('connection', function () { - if (typeof WebSocket !== 'undefined') { - it("can connect to the server without specifying transport explicitly", function (done) { - var message = "Hello World!"; - var connection = new HttpConnection(ECHOENDPOINT_URL); +describe("connection", () => { + if (typeof WebSocket !== "undefined") { + it("can connect to the server without specifying transport explicitly", (done) => { + const message = "Hello World!"; + const connection = new HttpConnection(ECHOENDPOINT_URL); - var received = ""; - connection.onreceive = function (data) { + let received = ""; + connection.onreceive = (data) => { received += data; - if (data == message) { + if (data === message) { connection.stop(); } }; - connection.onclose = function (error) { + connection.onclose = (error) => { expect(error).toBeUndefined(); done(); }; - connection.start().then(function () { + connection.start().then(() => { connection.send(message); - }).catch(function (e) { + }).catch((e) => { fail(); done(); }); }); } - eachTransport(function (transportType) { - it("over " + TransportType[transportType] + " can send and receive messages", function (done) { - var message = "Hello World!"; + eachTransport((transportType) => { + it("over " + TransportType[transportType] + " can send and receive messages", (done) => { + const message = "Hello World!"; // the url should be resolved relative to the document.location.host // and the leading '/' should be automatically added to the url - var connection = new HttpConnection("echo", { + const connection = new HttpConnection("echo", { + logger: LogLevel.Trace, transport: transportType, - logger: LogLevel.Trace }); - var received = ""; - connection.onreceive = function (data) { + let received = ""; + connection.onreceive = (data) => { received += data; - if (data == message) { + if (data === message) { connection.stop(); } }; - connection.onclose = function (error) { + connection.onclose = (error) => { expect(error).toBeUndefined(); done(); }; - connection.start().then(function () { + connection.start().then(() => { connection.send(message); - }).catch(function (e) { + }).catch((e) => { fail(); done(); }); diff --git a/client-ts/FunctionalTests/ts/HubConnectionTests.ts b/client-ts/FunctionalTests/ts/HubConnectionTests.ts index 91a0c9718e..b048f69ff9 100644 --- a/client-ts/FunctionalTests/ts/HubConnectionTests.ts +++ b/client-ts/FunctionalTests/ts/HubConnectionTests.ts @@ -1,394 +1,394 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { TransportType, HubConnection, LogLevel } from "@aspnet/signalr"; +import { HubConnection, LogLevel, TransportType } from "@aspnet/signalr"; -import { eachTransportAndProtocol, eachTransport } from "./Common"; +import { eachTransport, eachTransportAndProtocol } from "./Common"; -var TESTHUBENDPOINT_URL = '/testhub'; +const TESTHUBENDPOINT_URL = "/testhub"; -describe('hubConnection', function () { - eachTransportAndProtocol(function (transportType, protocol) { - describe(protocol.name + ' over ' + TransportType[transportType] + ' transport', function () { - it('can invoke server method and receive result', function (done) { - var message = '你好,世界!'; +describe("hubConnection", () => { + eachTransportAndProtocol((transportType, protocol) => { + describe(protocol.name + " over " + TransportType[transportType] + " transport", () => { + it("can invoke server method and receive result", (done) => { + const message = "你好,世界!"; - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - hubConnection.onclose(function (error) { + hubConnection.onclose((error) => { expect(error).toBe(undefined); done(); }); - hubConnection.start().then(function () { - hubConnection.invoke('Echo', message).then(function (result) { + hubConnection.start().then(() => { + hubConnection.invoke("Echo", message).then((result) => { expect(result).toBe(message); - }).catch(function (e) { + }).catch((e) => { fail(e); - }).then(function () { + }).then(() => { hubConnection.stop(); }); - }).catch(function (e) { + }).catch((e) => { fail(e); done(); }); }); - it('can invoke server method non-blocking and not receive result', function (done) { - var message = '你好,世界!'; + it("can invoke server method non-blocking and not receive result", (done) => { + const message = "你好,世界!"; - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - hubConnection.onclose(function (error) { + hubConnection.onclose((error) => { expect(error).toBe(undefined); done(); }); - hubConnection.start().then(function () { - hubConnection.send('Echo', message).catch(function (e) { + hubConnection.start().then(() => { + hubConnection.send("Echo", message).catch((e) => { fail(e); - }).then(function () { + }).then(() => { hubConnection.stop(); }); - }).catch(function (e) { + }).catch((e) => { fail(e); done(); }); }); - it('can invoke server method structural object and receive structural result', function (done) { - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + it("can invoke server method structural object and receive structural result", (done) => { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - hubConnection.on('CustomObject', function (customObject) { - expect(customObject.Name).toBe('test'); + hubConnection.on("CustomObject", (customObject) => { + expect(customObject.Name).toBe("test"); expect(customObject.Value).toBe(42); hubConnection.stop(); }); - hubConnection.onclose(function (error) { + hubConnection.onclose((error) => { expect(error).toBe(undefined); done(); }); - hubConnection.start().then(function () { - hubConnection.send('SendCustomObject', { Name: 'test', Value: 42 }); - }).catch(function (e) { + hubConnection.start().then(() => { + hubConnection.send("SendCustomObject", { Name: "test", Value: 42 }); + }).catch((e) => { fail(e); done(); }); }); - it('can stream server method and receive result', function (done) { - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + it("can stream server method and receive result", (done) => { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - hubConnection.onclose(function (error) { + hubConnection.onclose((error) => { expect(error).toBe(undefined); done(); }); - var received = []; - hubConnection.start().then(function () { - hubConnection.stream('Stream').subscribe({ - next: function next(item) { - received.push(item); + const received = []; + hubConnection.start().then(() => { + hubConnection.stream("Stream").subscribe({ + complete: function complete() { + expect(received).toEqual(["a", "b", "c"]); + hubConnection.stop(); }, error: function error(err) { fail(err); hubConnection.stop(); }, - complete: function complete() { - expect(received).toEqual(['a', 'b', 'c']); - hubConnection.stop(); - } + next: function next(item) { + received.push(item); + }, }); - }).catch(function (e) { + }).catch((e) => { fail(e); done(); }); }); - it('rethrows an exception from the server when invoking', function (done) { - var errorMessage = 'An error occurred.'; - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + it("rethrows an exception from the server when invoking", (done) => { + const errorMessage = "An error occurred."; + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - hubConnection.start().then(function () { - hubConnection.invoke('ThrowException', errorMessage).then(function () { + hubConnection.start().then(() => { + hubConnection.invoke("ThrowException", errorMessage).then(() => { // exception expected but none thrown fail(); - }).catch(function (e) { + }).catch((e) => { expect(e.message).toBe(errorMessage); - }).then(function () { + }).then(() => { return hubConnection.stop(); - }).then(function () { + }).then(() => { done(); }); - }).catch(function (e) { + }).catch((e) => { fail(e); done(); }); }); - it('throws an exception when invoking streaming method with invoke', function (done) { - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + it("throws an exception when invoking streaming method with invoke", (done) => { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - hubConnection.start().then(function () { - hubConnection.invoke('EmptyStream').then(function () { + hubConnection.start().then(() => { + hubConnection.invoke("EmptyStream").then(() => { // exception expected but none thrown fail(); - }).catch(function (e) { - expect(e.message).toBe('The client attempted to invoke the streaming \'EmptyStream\' method in a non-streaming fashion.'); - }).then(function () { + }).catch((e) => { + expect(e.message).toBe("The client attempted to invoke the streaming 'EmptyStream' method in a non-streaming fashion."); + }).then(() => { return hubConnection.stop(); - }).then(function () { + }).then(() => { done(); }); - }).catch(function (e) { + }).catch((e) => { fail(e); done(); }); }); - it('throws an exception when receiving a streaming result for method called with invoke', function (done) { - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + it("throws an exception when receiving a streaming result for method called with invoke", (done) => { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - hubConnection.start().then(function () { - hubConnection.invoke('Stream').then(function () { + hubConnection.start().then(() => { + hubConnection.invoke("Stream").then(() => { // exception expected but none thrown fail(); - }).catch(function (e) { - expect(e.message).toBe('The client attempted to invoke the streaming \'Stream\' method in a non-streaming fashion.'); - }).then(function () { + }).catch((e) => { + expect(e.message).toBe("The client attempted to invoke the streaming 'Stream' method in a non-streaming fashion."); + }).then(() => { return hubConnection.stop(); - }).then(function () { + }).then(() => { done(); }); - }).catch(function (e) { + }).catch((e) => { fail(e); done(); }); }); - it('rethrows an exception from the server when streaming', function (done) { - var errorMessage = 'An error occurred.'; - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + it("rethrows an exception from the server when streaming", (done) => { + const errorMessage = "An error occurred."; + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - hubConnection.start().then(function () { - hubConnection.stream('StreamThrowException', errorMessage).subscribe({ - next: function next(item) { + hubConnection.start().then(() => { + hubConnection.stream("StreamThrowException", errorMessage).subscribe({ + complete: function complete() { hubConnection.stop(); fail(); }, error: function error(err) { - expect(err.message).toEqual('An error occurred.'); + expect(err.message).toEqual("An error occurred."); hubConnection.stop(); done(); }, - complete: function complete() { - hubConnection.stop(); - fail(); - } - }); - }).catch(function (e) { - fail(e); - done(); - }); - }); - - it('throws an exception when invoking hub method with stream', function (done) { - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { - transport: transportType, - protocol: protocol, - logger: LogLevel.Trace - }); - - hubConnection.start().then(function () { - hubConnection.stream('Echo', '42').subscribe({ next: function next(item) { hubConnection.stop(); fail(); }, - error: function error(err) { - expect(err.message).toEqual('The client attempted to invoke the non-streaming \'Echo\' method in a streaming fashion.'); - hubConnection.stop(); - done(); - }, - complete: function complete() { - hubConnection.stop(); - fail(); - } }); - }).catch(function (e) { + }).catch((e) => { fail(e); done(); }); }); - it('can receive server calls', function (done) { - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + it("throws an exception when invoking hub method with stream", (done) => { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - var message = '你好 SignalR!'; + hubConnection.start().then(() => { + hubConnection.stream("Echo", "42").subscribe({ + complete: function complete() { + hubConnection.stop(); + fail(); + }, + error: function error(err) { + expect(err.message).toEqual("The client attempted to invoke the non-streaming 'Echo' method in a streaming fashion."); + hubConnection.stop(); + done(); + }, + next: function next(item) { + hubConnection.stop(); + fail(); + }, + }); + }).catch((e) => { + fail(e); + done(); + }); + }); + + it("can receive server calls", (done) => { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, + transport: transportType, + }); + + const message = "你好 SignalR!"; // client side method names are case insensitive - var methodName = 'message'; - var idx = Math.floor(Math.random() * (methodName.length - 1)); + let methodName = "message"; + const idx = Math.floor(Math.random() * (methodName.length - 1)); methodName = methodName.substr(0, idx) + methodName[idx].toUpperCase() + methodName.substr(idx + 1); - hubConnection.on(methodName, function (msg) { + hubConnection.on(methodName, (msg) => { expect(msg).toBe(message); done(); }); hubConnection.start() - .then(function () { - return hubConnection.invoke('InvokeWithString', message); + .then(() => { + return hubConnection.invoke("InvokeWithString", message); }) - .then(function () { + .then(() => { return hubConnection.stop(); }) - .catch(function (e) { + .catch((e) => { fail(e); done(); }); }); - it('can receive server calls without rebinding handler when restarted', function (done) { - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + it("can receive server calls without rebinding handler when restarted", (done) => { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - var message = '你好 SignalR!'; + const message = "你好 SignalR!"; // client side method names are case insensitive - var methodName = 'message'; - var idx = Math.floor(Math.random() * (methodName.length - 1)); + let methodName = "message"; + const idx = Math.floor(Math.random() * (methodName.length - 1)); methodName = methodName.substr(0, idx) + methodName[idx].toUpperCase() + methodName.substr(idx + 1); let closeCount = 0; let invocationCount = 0; - hubConnection.onclose(function (e) { + hubConnection.onclose((e) => { expect(e).toBeUndefined(); closeCount += 1; if (closeCount === 1) { // Reconnect hubConnection.start() - .then(function () { - return hubConnection.invoke('InvokeWithString', message); + .then(() => { + return hubConnection.invoke("InvokeWithString", message); }) - .then(function () { + .then(() => { return hubConnection.stop(); }) - .catch(function (e) { - fail(e); + .catch((error) => { + fail(error); done(); }); } else { expect(invocationCount).toBe(2); done(); } - }) + }); - hubConnection.on(methodName, function (msg) { + hubConnection.on(methodName, (msg) => { expect(msg).toBe(message); invocationCount += 1; }); hubConnection.start() - .then(function () { - return hubConnection.invoke('InvokeWithString', message); + .then(() => { + return hubConnection.invoke("InvokeWithString", message); }) - .then(function () { + .then(() => { return hubConnection.stop(); }) - .catch(function (e) { + .catch((e) => { fail(e); done(); }); }); - it('closed with error if hub cannot be created', function (done) { - var errorRegex = { - WebSockets: '1011|1005', // Message is browser specific (e.g. 'Websocket closed with status code: 1011'), Edge and IE report 1005 even though the server sent 1011 - LongPolling: 'Internal Server Error', - ServerSentEvents: 'Error occurred' + it("closed with error if hub cannot be created", (done) => { + const errorRegex = { + LongPolling: "Internal Server Error", + ServerSentEvents: "Error occurred", + WebSockets: "1011|1005", // Message is browser specific (e.g. 'Websocket closed with status code: 1011'), Edge and IE report 1005 even though the server sent 1011 }; - var hubConnection = new HubConnection('http://' + document.location.host + '/uncreatable', { + const hubConnection = new HubConnection("http://" + document.location.host + "/uncreatable", { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - hubConnection.onclose(function (error) { + hubConnection.onclose((error) => { expect(error.message).toMatch(errorRegex[TransportType[transportType]]); done(); }); hubConnection.start(); }); - it('can handle different types', function (done) { - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + it("can handle different types", (done) => { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); - hubConnection.onclose(function (error) { + hubConnection.onclose((error) => { expect(error).toBe(undefined); done(); }); - var complexObject = { - String: 'Hello, World!', - IntArray: [0x01, 0x02, 0x03, 0xff], + const complexObject = { ByteArray: protocol.name === "json" ? "aGVsbG8=" : new Uint8Array([0x68, 0x65, 0x6c, 0x6c, 0x6f]), GUID: protocol.name === "json" ? "00010203-0405-0607-0706-050403020100" - : new Uint8Array([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00]) + : new Uint8Array([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00]), + IntArray: [0x01, 0x02, 0x03, 0xff], + String: "Hello, World!", }; hubConnection.start() - .then(function () { - return hubConnection.invoke('EchoComplexObject', complexObject); + .then(() => { + return hubConnection.invoke("EchoComplexObject", complexObject); }) - .then(function (value) { + .then((value) => { if (protocol.name === "messagepack") { // msgpack creates a Buffer for byte arrays and jasmine fails to compare a Buffer // and a Uint8Array even though Buffer instances are also Uint8Array instances @@ -398,7 +398,7 @@ describe('hubConnection', function () { // be extracted. Note that with msgpack5 the original bytes will be encoded with utf8 // and needs to be decoded. To not go into utf8 encoding intricacies the test uses values // less than 0x80. - let guidBytes = []; + const guidBytes = []; for (let i = 0; i < value.GUID.length; i++) { guidBytes.push(value.GUID.charCodeAt(i)); } @@ -406,40 +406,40 @@ describe('hubConnection', function () { } expect(value).toEqual(complexObject); }) - .then(function () { + .then(() => { hubConnection.stop(); }) - .catch(function (e) { + .catch((e) => { fail(e); done(); }); }); - it('can be restarted', function (done) { - var message = '你好,世界!'; + it("can be restarted", (done) => { + const message = "你好,世界!"; - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { + logger: LogLevel.Trace, + protocol, transport: transportType, - protocol: protocol, - logger: LogLevel.Trace }); let closeCount = 0; - hubConnection.onclose(function (error) { + hubConnection.onclose((error) => { expect(error).toBe(undefined); // Start and invoke again if (closeCount === 0) { closeCount += 1; - hubConnection.start().then(function () { - hubConnection.invoke('Echo', message).then(function (result) { + hubConnection.start().then(() => { + hubConnection.invoke("Echo", message).then((result) => { expect(result).toBe(message); - }).catch(function (e) { + }).catch((e) => { fail(e); - }).then(function () { - hubConnection.stop() + }).then(() => { + hubConnection.stop(); }); - }).catch(function (e) { + }).catch((e) => { fail(e); done(); }); @@ -448,15 +448,15 @@ describe('hubConnection', function () { } }); - hubConnection.start().then(function () { - hubConnection.invoke('Echo', message).then(function (result) { + hubConnection.start().then(() => { + hubConnection.invoke("Echo", message).then((result) => { expect(result).toBe(message); - }).catch(function (e) { + }).catch((e) => { fail(e); - }).then(function () { - hubConnection.stop() + }).then(() => { + hubConnection.stop(); }); - }).catch(function (e) { + }).catch((e) => { fail(e); done(); }); @@ -464,53 +464,53 @@ describe('hubConnection', function () { }); }); - eachTransport(function (transportType) { - describe(' over ' + TransportType[transportType] + ' transport', function () { + eachTransport((transportType) => { + describe(" over " + TransportType[transportType] + " transport", () => { - it('can connect to hub with authorization', async function (done) { - var message = '你好,世界!'; + it("can connect to hub with authorization", async (done) => { + const message = "你好,世界!"; - var hubConnection; - getJwtToken('http://' + document.location.host + '/generateJwtToken') - .then(jwtToken => { - hubConnection = new HubConnection('/authorizedhub', { - transport: transportType, + let hubConnection; + getJwtToken("http://" + document.location.host + "/generateJwtToken") + .then((jwtToken) => { + hubConnection = new HubConnection("/authorizedhub", { + accessTokenFactory: () => jwtToken, logger: LogLevel.Trace, - accessTokenFactory: () => jwtToken + transport: transportType, }); - hubConnection.onclose(function (error) { + hubConnection.onclose((error) => { expect(error).toBe(undefined); done(); }); return hubConnection.start(); }) .then(() => { - return hubConnection.invoke('Echo', message) + return hubConnection.invoke("Echo", message); }) - .then(response => { + .then((response) => { expect(response).toEqual(message); done(); }) - .catch(err => { + .catch((err) => { fail(err); done(); }); }); - if (transportType != TransportType.LongPolling) { - it("terminates if no messages received within timeout interval", function (done) { - var hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { - transport: transportType, + if (transportType !== TransportType.LongPolling) { + it("terminates if no messages received within timeout interval", (done) => { + const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, { logger: LogLevel.Trace, - timeoutInMilliseconds: 100 + timeoutInMilliseconds: 100, + transport: transportType, }); - var timeout = setTimeout(200, function () { + const timeout = setTimeout(200, () => { fail("Server timeout did not fire within expected interval"); }); - hubConnection.start().then(function () { - hubConnection.onclose(function (error) { + hubConnection.start().then(() => { + hubConnection.onclose((error) => { clearTimeout(timeout); expect(error).toEqual(new Error("Server timeout elapsed without receiving a message from the server.")); done(); @@ -521,25 +521,24 @@ describe('hubConnection', function () { }); }); - function getJwtToken(url) : Promise { + function getJwtToken(url): Promise { return new Promise((resolve, reject) => { - let xhr = new XMLHttpRequest(); + const xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); + xhr.open("GET", url, true); + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhr.send(); xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.response || xhr.responseText); - } - else { + } else { reject(new Error(xhr.statusText)); } }; xhr.onerror = () => { reject(new Error(xhr.statusText)); - } + }; }); } }); diff --git a/client-ts/FunctionalTests/ts/WebSocketTests.ts b/client-ts/FunctionalTests/ts/WebSocketTests.ts index 6c6783c782..a9aac5643d 100644 --- a/client-ts/FunctionalTests/ts/WebSocketTests.ts +++ b/client-ts/FunctionalTests/ts/WebSocketTests.ts @@ -3,26 +3,26 @@ import { ECHOENDPOINT_URL } from "./Common"; -if (typeof WebSocket !== 'undefined') { - describe('WebSockets', function () { - it('can be used to connect to SignalR', function (done) { - var message = "message"; +if (typeof WebSocket !== "undefined") { + describe("WebSockets", () => { + it("can be used to connect to SignalR", (done) => { + const message = "message"; - var webSocket = new WebSocket(ECHOENDPOINT_URL.replace(/^http/, "ws")); + const webSocket = new WebSocket(ECHOENDPOINT_URL.replace(/^http/, "ws")); - webSocket.onopen = function () { + webSocket.onopen = () => { webSocket.send(message); }; - var received = ""; - webSocket.onmessage = function (event) { + let received = ""; + webSocket.onmessage = (event) => { received += event.data; if (received === message) { webSocket.close(); } }; - webSocket.onclose = function (event) { + webSocket.onclose = (event) => { if (!event.wasClean) { fail("connection closed with unexpected status code: " + event.code + " " + event.reason); } diff --git a/client-ts/FunctionalTests/ts/index.ts b/client-ts/FunctionalTests/ts/index.ts index 1db64aa16e..812865d851 100644 --- a/client-ts/FunctionalTests/ts/index.ts +++ b/client-ts/FunctionalTests/ts/index.ts @@ -1,8 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import 'es6-promise/dist/es6-promise.auto.js'; +import "es6-promise/dist/es6-promise.auto.js"; -import './ConnectionTests' -import './HubConnectionTests' -import './WebSocketTests' \ No newline at end of file +import "./ConnectionTests"; +import "./HubConnectionTests"; +import "./WebSocketTests"; diff --git a/client-ts/package-lock.json b/client-ts/package-lock.json index 5bcdbf914e..89e7825cb3 100644 --- a/client-ts/package-lock.json +++ b/client-ts/package-lock.json @@ -16,6 +16,27 @@ "integrity": "sha512-KA4GKOpgXnrqEH2eCVhiv2CsxgXGQJgV1X0vsGlh+WCnxbeAE1GT44ZsTU1IN5dEeV/gDupKa7gWo08V5IxWVQ==", "dev": true }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, "arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", @@ -43,6 +64,32 @@ "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=", "dev": true }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + } + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -76,6 +123,58 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.0.tgz", + "integrity": "sha512-okPpdvdJr6mUGi2XzupC+irQxzwGLVaBzacFC14hjLv8NColXEsxsU+QaeuSSXpQUak5g2K0vQ7WjA1e8svczg==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -88,12 +187,36 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "diff": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", + "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, "estree-walker": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.3.1.tgz", "integrity": "sha1-5rGlHPcpJSTnI3wxLl/mZgwc4ao=", "dev": true }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -200,6 +323,21 @@ "is-glob": "2.0.1" } }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -317,6 +455,22 @@ "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", "dev": true }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + } + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -579,6 +733,12 @@ "micromatch": "2.3.11" } }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, "source-map-resolve": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", @@ -598,6 +758,62 @@ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "tslib": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", + "dev": true + }, + "tslint": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz", + "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "builtin-modules": "1.1.1", + "chalk": "2.3.0", + "commander": "2.14.0", + "diff": "3.4.0", + "glob": "7.1.2", + "js-yaml": "3.10.0", + "minimatch": "3.0.4", + "resolve": "1.5.0", + "semver": "5.5.0", + "tslib": "1.9.0", + "tsutils": "2.21.0" + } + }, + "tsutils": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.21.0.tgz", + "integrity": "sha512-zlOHTYtTwvTiKxUyAU8wiKzPpAgwZrGjb7AY18VUlxuCgBiTMVorIl5HjrCT8V64Hm34RI1BZITJMVQpBLMxVg==", + "dev": true, + "requires": { + "tslib": "1.9.0" + } + }, "typescript": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.1.tgz", diff --git a/client-ts/package.json b/client-ts/package.json index 19a69b205f..e54a316e59 100644 --- a/client-ts/package.json +++ b/client-ts/package.json @@ -18,6 +18,7 @@ "rollup-plugin-commonjs": "^8.2.6", "rollup-plugin-node-resolve": "^3.0.2", "rollup-plugin-sourcemaps": "^0.4.2", + "tslint": "^5.9.1", "typescript": "^2.7.1", "uglify-js": "^3.3.5" } diff --git a/client-ts/signalr-protocol-msgpack/package-lock.json b/client-ts/signalr-protocol-msgpack/package-lock.json index 4167e7a3cf..532a81cc67 100644 --- a/client-ts/signalr-protocol-msgpack/package-lock.json +++ b/client-ts/signalr-protocol-msgpack/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aspnet/signalr-protocol-msgpack", - "version": "1.0.0-preview1-t000", + "version": "1.0.0-preview2-t000", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/client-ts/signalr-protocol-msgpack/package.json b/client-ts/signalr-protocol-msgpack/package.json index bac8cd06b0..53788f99f6 100644 --- a/client-ts/signalr-protocol-msgpack/package.json +++ b/client-ts/signalr-protocol-msgpack/package.json @@ -12,7 +12,8 @@ }, "scripts": { "clean": "node ../node_modules/rimraf/bin.js ./dist", - "build": "npm run clean && npm run build:esm && npm run build:cjs && npm run build:browser && npm run build:uglify", + "build": "npm run clean && npm run build:lint && npm run build:esm && npm run build:cjs && npm run build:browser && npm run build:uglify", + "build:lint": "node ../node_modules/tslint/bin/tslint -c ../tslint.json -p ./tsconfig.json", "build:esm": "node ../node_modules/typescript/bin/tsc --project ./tsconfig.json --module es2015 --outDir ./dist/esm --target ES2015 -d", "build:cjs": "node ../node_modules/typescript/bin/tsc --project ./tsconfig.json --module commonjs --outDir ./dist/cjs --target ES5", "build:browser": "node ../node_modules/rollup/bin/rollup -c", diff --git a/client-ts/signalr-protocol-msgpack/src/BinaryMessageFormat.ts b/client-ts/signalr-protocol-msgpack/src/BinaryMessageFormat.ts index 672e7acf57..3f40b9e7c9 100644 --- a/client-ts/signalr-protocol-msgpack/src/BinaryMessageFormat.ts +++ b/client-ts/signalr-protocol-msgpack/src/BinaryMessageFormat.ts @@ -6,13 +6,12 @@ export class BinaryMessageFormat { // The length prefix of binary messages is encoded as VarInt. Read the comment in // the BinaryMessageParser.TryParseMessage for details. - static write(output: Uint8Array): ArrayBuffer { + public static write(output: Uint8Array): ArrayBuffer { // msgpack5 uses returns Buffer instead of Uint8Array on IE10 and some other browser // in which case .byteLength does will be undefined let size = output.byteLength || output.length; - let lenBuffer = []; - do - { + const lenBuffer = []; + do { let sizePart = size & 0x7f; size = size >> 7; if (size > 0) { @@ -26,15 +25,15 @@ export class BinaryMessageFormat { // in which case .byteLength does will be undefined size = output.byteLength || output.length; - let buffer = new Uint8Array(lenBuffer.length + size); + const buffer = new Uint8Array(lenBuffer.length + size); buffer.set(lenBuffer, 0); buffer.set(output, lenBuffer.length); return buffer.buffer; } - static parse(input: ArrayBuffer): Uint8Array[] { - let result: Uint8Array[] = []; - let uint8Array = new Uint8Array(input); + public static parse(input: ArrayBuffer): Uint8Array[] { + const result: Uint8Array[] = []; + const uint8Array = new Uint8Array(input); const maxLengthPrefixSize = 5; const numBitsToShift = [0, 7, 14, 21, 28 ]; @@ -42,13 +41,12 @@ export class BinaryMessageFormat { let numBytes = 0; let size = 0; let byteRead; - do - { + do { byteRead = uint8Array[offset + numBytes]; size = size | ((byteRead & 0x7f) << (numBitsToShift[numBytes])); numBytes++; } - while (numBytes < Math.min(maxLengthPrefixSize, input.byteLength - offset) && (byteRead & 0x80) != 0); + while (numBytes < Math.min(maxLengthPrefixSize, input.byteLength - offset) && (byteRead & 0x80) !== 0); if ((byteRead & 0x80) !== 0 && numBytes < maxLengthPrefixSize) { throw new Error("Cannot read message size."); @@ -63,8 +61,7 @@ export class BinaryMessageFormat { result.push(uint8Array.slice ? uint8Array.slice(offset + numBytes, offset + numBytes + size) : uint8Array.subarray(offset + numBytes, offset + numBytes + size)); - } - else { + } else { throw new Error("Incomplete message."); } @@ -73,4 +70,4 @@ export class BinaryMessageFormat { return result; } -} \ No newline at end of file +} diff --git a/client-ts/signalr-protocol-msgpack/src/MessagePackHubProtocol.ts b/client-ts/signalr-protocol-msgpack/src/MessagePackHubProtocol.ts index 3e59381c2d..4e0b6ec18d 100644 --- a/client-ts/signalr-protocol-msgpack/src/MessagePackHubProtocol.ts +++ b/client-ts/signalr-protocol-msgpack/src/MessagePackHubProtocol.ts @@ -1,33 +1,33 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { IHubProtocol, ProtocolType, MessageType, HubMessage, InvocationMessage, StreamItemMessage, CompletionMessage, StreamInvocationMessage, MessageHeaders } from "@aspnet/signalr"; -import { BinaryMessageFormat } from "./BinaryMessageFormat" -import { Buffer } from 'buffer'; +import { CompletionMessage, HubMessage, IHubProtocol, InvocationMessage, MessageHeaders, MessageType, ProtocolType, StreamInvocationMessage, StreamItemMessage } from "@aspnet/signalr"; +import { Buffer } from "buffer"; import * as msgpack5 from "msgpack5"; +import { BinaryMessageFormat } from "./BinaryMessageFormat"; export class MessagePackHubProtocol implements IHubProtocol { - readonly name: string = "messagepack"; + public readonly name: string = "messagepack"; - readonly type: ProtocolType = ProtocolType.Binary; + public readonly type: ProtocolType = ProtocolType.Binary; - parseMessages(input: ArrayBuffer): HubMessage[] { - return BinaryMessageFormat.parse(input).map(m => this.parseMessage(m)); + public parseMessages(input: ArrayBuffer): HubMessage[] { + return BinaryMessageFormat.parse(input).map((m) => this.parseMessage(m)); } private parseMessage(input: Uint8Array): HubMessage { - if (input.length == 0) { + if (input.length === 0) { throw new Error("Invalid payload."); } - let msgpack = msgpack5(); - let properties = msgpack.decode(new Buffer(input)); - if (properties.length == 0 || !(properties instanceof Array)) { + const msgpack = msgpack5(); + const properties = msgpack.decode(new Buffer(input)); + if (properties.length === 0 || !(properties instanceof Array)) { throw new Error("Invalid payload."); } - let messageType = properties[0] as MessageType; + const messageType = properties[0] as MessageType; switch (messageType) { case MessageType.Invocation: @@ -44,52 +44,51 @@ export class MessagePackHubProtocol implements IHubProtocol { } private createPingMessage(properties: any[]): HubMessage { - if (properties.length != 1) { + if (properties.length !== 1) { throw new Error("Invalid payload for Ping message."); } return { // Ping messages have no headers. - type: MessageType.Ping + type: MessageType.Ping, } as HubMessage; } private createInvocationMessage(headers: MessageHeaders, properties: any[]): InvocationMessage { - if (properties.length != 5) { + if (properties.length !== 5) { throw new Error("Invalid payload for Invocation message."); } - let invocationId = properties[2] as string; + const invocationId = properties[2] as string; if (invocationId) { return { - headers, - type: MessageType.Invocation, - invocationId: invocationId, - target: properties[3] as string, arguments: properties[4], - }; - } - else { - return { headers, + invocationId, + target: properties[3] as string, type: MessageType.Invocation, + }; + } else { + return { + arguments: properties[4], + headers, target: properties[3], - arguments: properties[4] + type: MessageType.Invocation, }; } } private createStreamItemMessage(headers: MessageHeaders, properties: any[]): StreamItemMessage { - if (properties.length != 4) { + if (properties.length !== 4) { throw new Error("Invalid payload for stream Result message."); } return { headers, - type: MessageType.StreamItem, invocationId: properties[2], - item: properties[3] + item: properties[3], + type: MessageType.StreamItem, } as StreamItemMessage; } @@ -102,19 +101,19 @@ export class MessagePackHubProtocol implements IHubProtocol { const voidResult = 2; const nonVoidResult = 3; - let resultKind = properties[3]; + const resultKind = properties[3]; - if ((resultKind === voidResult && properties.length != 4) || - (resultKind !== voidResult && properties.length != 5)) { + if ((resultKind === voidResult && properties.length !== 4) || + (resultKind !== voidResult && properties.length !== 5)) { throw new Error("Invalid payload for Completion message."); } - let completionMessage = { - headers, - type: MessageType.Completion, - invocationId: properties[2], + const completionMessage = { error: null as string, - result: null as any + headers, + invocationId: properties[2], + result: null as any, + type: MessageType.Completion, }; switch (resultKind) { @@ -129,7 +128,7 @@ export class MessagePackHubProtocol implements IHubProtocol { return completionMessage as CompletionMessage; } - writeMessage(message: HubMessage): ArrayBuffer { + public writeMessage(message: HubMessage): ArrayBuffer { switch (message.type) { case MessageType.Invocation: return this.writeInvocation(message as InvocationMessage); @@ -144,26 +143,26 @@ export class MessagePackHubProtocol implements IHubProtocol { } private writeInvocation(invocationMessage: InvocationMessage): ArrayBuffer { - let msgpack = msgpack5(); - let payload = msgpack.encode([MessageType.Invocation, invocationMessage.headers || {}, invocationMessage.invocationId || null, + const msgpack = msgpack5(); + const payload = msgpack.encode([MessageType.Invocation, invocationMessage.headers || {}, invocationMessage.invocationId || null, invocationMessage.target, invocationMessage.arguments]); return BinaryMessageFormat.write(payload.slice()); } private writeStreamInvocation(streamInvocationMessage: StreamInvocationMessage): ArrayBuffer { - let msgpack = msgpack5(); - let payload = msgpack.encode([MessageType.StreamInvocation, streamInvocationMessage.headers || {}, streamInvocationMessage.invocationId, + const msgpack = msgpack5(); + const payload = msgpack.encode([MessageType.StreamInvocation, streamInvocationMessage.headers || {}, streamInvocationMessage.invocationId, streamInvocationMessage.target, streamInvocationMessage.arguments]); return BinaryMessageFormat.write(payload.slice()); } private readHeaders(properties: any): MessageHeaders { - let headers: MessageHeaders = properties[1] as MessageHeaders; + const headers: MessageHeaders = properties[1] as MessageHeaders; if (typeof headers !== "object") { throw new Error("Invalid headers."); } return headers; } -} \ No newline at end of file +} diff --git a/client-ts/signalr-protocol-msgpack/src/browser-index.ts b/client-ts/signalr-protocol-msgpack/src/browser-index.ts index 6734b09ad6..8dd659258e 100644 --- a/client-ts/signalr-protocol-msgpack/src/browser-index.ts +++ b/client-ts/signalr-protocol-msgpack/src/browser-index.ts @@ -3,4 +3,4 @@ // This is where we add any polyfills we'll need for the browser. It is the entry module for browser-specific builds. -export * from './index' +export * from "./index"; diff --git a/client-ts/signalr-protocol-msgpack/src/index.ts b/client-ts/signalr-protocol-msgpack/src/index.ts index 6c724e137a..eaf3037c3d 100644 --- a/client-ts/signalr-protocol-msgpack/src/index.ts +++ b/client-ts/signalr-protocol-msgpack/src/index.ts @@ -1,4 +1,4 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -export { MessagePackHubProtocol } from "./MessagePackHubProtocol"; \ No newline at end of file +export { MessagePackHubProtocol } from "./MessagePackHubProtocol"; diff --git a/client-ts/signalr/package-lock.json b/client-ts/signalr/package-lock.json index 49d499908f..264748f026 100644 --- a/client-ts/signalr/package-lock.json +++ b/client-ts/signalr/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aspnet/signalr", - "version": "1.0.0-preview1-t000", + "version": "1.0.0-preview2-t000", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/client-ts/signalr/package.json b/client-ts/signalr/package.json index 77e6e9de59..dcb7d731f0 100644 --- a/client-ts/signalr/package.json +++ b/client-ts/signalr/package.json @@ -12,7 +12,8 @@ }, "scripts": { "clean": "node ../node_modules/rimraf/bin.js ./dist ./.rpt2_cache", - "build": "npm run clean && npm run build:esm && npm run build:cjs && npm run build:browser && npm run build:uglify", + "build": "npm run clean && npm run build:lint && npm run build:esm && npm run build:cjs && npm run build:browser && npm run build:uglify", + "build:lint": "node ../node_modules/tslint/bin/tslint -c ../tslint.json -p ./tsconfig.json", "build:esm": "node ../node_modules/typescript/bin/tsc --project ./tsconfig.json --module es2015 --outDir ./dist/esm --target ES2015 -d && node ./build/process-dts.js", "build:cjs": "node ../node_modules/typescript/bin/tsc --project ./tsconfig.json --module commonjs --outDir ./dist/cjs --target ES5", "build:browser": "node ../node_modules/rollup/bin/rollup -c", diff --git a/client-ts/signalr/spec/AbortSignal.spec.ts b/client-ts/signalr/spec/AbortSignal.spec.ts index 1064b7e98b..0752361f41 100644 --- a/client-ts/signalr/spec/AbortSignal.spec.ts +++ b/client-ts/signalr/spec/AbortSignal.spec.ts @@ -1,8 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { asyncit as it } from "./Utils"; import { AbortController } from "../src/AbortController"; +import { asyncit as it } from "./Utils"; describe("AbortSignal", () => { describe("aborted", () => { @@ -11,21 +11,21 @@ describe("AbortSignal", () => { }); it("is true when aborted", () => { - let controller = new AbortController(); - let signal = controller.signal; + const controller = new AbortController(); + const signal = controller.signal; controller.abort(); expect(signal.aborted).toBe(true); - }) + }); }); describe("onabort", () => { it("is called when abort is called", () => { - let controller = new AbortController(); - let signal = controller.signal; + const controller = new AbortController(); + const signal = controller.signal; let abortCalled = false; signal.onabort = () => abortCalled = true; controller.abort(); expect(abortCalled).toBe(true); - }) - }) + }); + }); }); diff --git a/client-ts/signalr/spec/Base64EncodedHubProtocol.spec.ts b/client-ts/signalr/spec/Base64EncodedHubProtocol.spec.ts index 89f91df5e1..14a376bf5a 100644 --- a/client-ts/signalr/spec/Base64EncodedHubProtocol.spec.ts +++ b/client-ts/signalr/spec/Base64EncodedHubProtocol.spec.ts @@ -1,14 +1,14 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { Base64EncodedHubProtocol } from "../src/Base64EncodedHubProtocol" -import { IHubProtocol, HubMessage, ProtocolType } from "../src/IHubProtocol" +import { Base64EncodedHubProtocol } from "../src/Base64EncodedHubProtocol"; +import { HubMessage, IHubProtocol, ProtocolType } from "../src/IHubProtocol"; class FakeHubProtocol implements IHubProtocol { - name: "fakehubprotocol"; - type: ProtocolType; + public name: "fakehubprotocol"; + public type: ProtocolType; - parseMessages(input: any): HubMessage[] { + public parseMessages(input: any): HubMessage[] { let s = ""; new Uint8Array(input).forEach((item: any) => { @@ -18,9 +18,9 @@ class FakeHubProtocol implements IHubProtocol { return JSON.parse(s); } - writeMessage(message: HubMessage): any { - let s = JSON.stringify(message); - let payload = new Uint8Array(s.length); + public writeMessage(message: HubMessage): any { + const s = JSON.stringify(message); + const payload = new Uint8Array(s.length); for (let i = 0; i < payload.length; i++) { payload[i] = s.charCodeAt(i); } @@ -36,9 +36,9 @@ describe("Base64EncodedHubProtocol", () => { ["1.0:A;", new Error("Invalid length: '1.0'")], ["2:A;", new Error("Invalid message size.")], ["2:ABC;", new Error("Invalid message size.")], - ] as [string, Error][]).forEach(([payload, expected_error]) => { + ] as Array<[string, Error]>).forEach(([payload, expectedError]) => { it(`should fail to parse '${payload}'`, () => { - expect(() => new Base64EncodedHubProtocol(new FakeHubProtocol()).parseMessages(payload)).toThrow(expected_error); + expect(() => new Base64EncodedHubProtocol(new FakeHubProtocol()).parseMessages(payload)).toThrow(expectedError); }); }); @@ -47,10 +47,10 @@ describe("Base64EncodedHubProtocol", () => { ] as [[string, any]]).forEach(([payload, message]) => { it(`should be able to parse '${payload}'`, () => { - let globalAny: any = global; - globalAny.atob = function(input: any) { return input }; + const globalAny: any = global; + globalAny.atob = (input: any) => input; - let result = new Base64EncodedHubProtocol(new FakeHubProtocol()).parseMessages(payload); + const result = new Base64EncodedHubProtocol(new FakeHubProtocol()).parseMessages(payload); expect(result).toEqual(message); delete globalAny.atob; @@ -59,13 +59,13 @@ describe("Base64EncodedHubProtocol", () => { ([ [{}, "2:{};"], - ] as [any, string][]).forEach(([message, payload]) => { + ] as Array<[any, string]>).forEach(([message, payload]) => { it(`should be able to write '${JSON.stringify(message)}'`, () => { - let globalAny: any = global; - globalAny.btoa = function(input: any) { return input }; + const globalAny: any = global; + globalAny.btoa = (input: any) => input; - let result = new Base64EncodedHubProtocol(new FakeHubProtocol()).writeMessage(message); + const result = new Base64EncodedHubProtocol(new FakeHubProtocol()).writeMessage(message); expect(result).toEqual(payload); delete globalAny.btoa; diff --git a/client-ts/signalr/spec/Common.ts b/client-ts/signalr/spec/Common.ts index c0a7732bf0..faf74045b8 100644 --- a/client-ts/signalr/spec/Common.ts +++ b/client-ts/signalr/spec/Common.ts @@ -1,23 +1,23 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { ITransport, TransportType } from "../src/Transports" +import { ITransport, TransportType } from "../src/Transports"; export function eachTransport(action: (transport: TransportType) => void) { - let transportTypes = [ + const transportTypes = [ TransportType.WebSockets, TransportType.ServerSentEvents, TransportType.LongPolling ]; - transportTypes.forEach(t => action(t)); -}; + transportTypes.forEach((t) => action(t)); +} export function eachEndpointUrl(action: (givenUrl: string, expectedUrl: string) => void) { - let urls = [ + const urls = [ [ "http://tempuri.org/endpoint/?q=my/Data", "http://tempuri.org/endpoint/negotiate?q=my/Data" ], [ "http://tempuri.org/endpoint?q=my/Data", "http://tempuri.org/endpoint/negotiate?q=my/Data" ], [ "http://tempuri.org/endpoint", "http://tempuri.org/endpoint/negotiate" ], - [ "http://tempuri.org/endpoint/", "http://tempuri.org/endpoint/negotiate" ] + [ "http://tempuri.org/endpoint/", "http://tempuri.org/endpoint/negotiate" ], ]; - urls.forEach(t => action(t[0], t[1])); -} \ No newline at end of file + urls.forEach((t) => action(t[0], t[1])); +} diff --git a/client-ts/signalr/spec/HttpClient.spec.ts b/client-ts/signalr/spec/HttpClient.spec.ts index db941359f3..f4af2473a2 100644 --- a/client-ts/signalr/spec/HttpClient.spec.ts +++ b/client-ts/signalr/spec/HttpClient.spec.ts @@ -1,15 +1,15 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { asyncit as it } from "./Utils" -import { TestHttpClient } from "./TestHttpClient"; import { HttpRequest } from "../src/index"; +import { TestHttpClient } from "./TestHttpClient"; +import { asyncit as it } from "./Utils"; describe("HttpClient", () => { describe("get", () => { it("sets the method and URL appropriately", async () => { let request: HttpRequest; - let testClient = new TestHttpClient().on(r => { + const testClient = new TestHttpClient().on((r) => { request = r; return ""; }); @@ -20,21 +20,21 @@ describe("HttpClient", () => { it("overrides method and url in options", async () => { let request: HttpRequest; - let testClient = new TestHttpClient().on(r => { + const testClient = new TestHttpClient().on((r) => { request = r; return ""; }); await testClient.get("http://localhost", { method: "OPTIONS", - url: "http://wrong" + url: "http://wrong", }); expect(request.method).toEqual("GET"); expect(request.url).toEqual("http://localhost"); - }) + }); it("copies other options", async () => { let request: HttpRequest; - let testClient = new TestHttpClient().on(r => { + const testClient = new TestHttpClient().on((r) => { request = r; return ""; }); @@ -42,13 +42,13 @@ describe("HttpClient", () => { timeout: 42, }); expect(request.timeout).toEqual(42); - }) + }); }); describe("post", () => { it("sets the method and URL appropriately", async () => { let request: HttpRequest; - let testClient = new TestHttpClient().on(r => { + const testClient = new TestHttpClient().on((r) => { request = r; return ""; }); @@ -59,21 +59,21 @@ describe("HttpClient", () => { it("overrides method and url in options", async () => { let request: HttpRequest; - let testClient = new TestHttpClient().on(r => { + const testClient = new TestHttpClient().on((r) => { request = r; return ""; }); await testClient.post("http://localhost", { method: "OPTIONS", - url: "http://wrong" + url: "http://wrong", }); expect(request.method).toEqual("POST"); expect(request.url).toEqual("http://localhost"); - }) + }); it("copies other options", async () => { let request: HttpRequest; - let testClient = new TestHttpClient().on(r => { + const testClient = new TestHttpClient().on((r) => { request = r; return ""; }); @@ -81,6 +81,6 @@ describe("HttpClient", () => { timeout: 42, }); expect(request.timeout).toEqual(42); - }) + }); }); }); diff --git a/client-ts/signalr/spec/HttpConnection.spec.ts b/client-ts/signalr/spec/HttpConnection.spec.ts index bcd6da9bae..2d24100934 100644 --- a/client-ts/signalr/spec/HttpConnection.spec.ts +++ b/client-ts/signalr/spec/HttpConnection.spec.ts @@ -1,16 +1,16 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { TestHttpClient } from "./TestHttpClient" -import { HttpConnection } from "../src/HttpConnection" -import { IHttpConnectionOptions } from "../src/HttpConnection" -import { DataReceived, TransportClosed } from "../src/Common" -import { ITransport, TransportType, TransferMode } from "../src/Transports" -import { eachTransport, eachEndpointUrl } from "./Common"; +import { DataReceived, TransportClosed } from "../src/Common"; +import { HttpConnection } from "../src/HttpConnection"; +import { IHttpConnectionOptions } from "../src/HttpConnection"; import { HttpResponse } from "../src/index"; +import { ITransport, TransferMode, TransportType } from "../src/Transports"; +import { eachEndpointUrl, eachTransport } from "./Common"; +import { TestHttpClient } from "./TestHttpClient"; const commonOptions: IHttpConnectionOptions = { - logger: null + logger: null, }; describe("HttpConnection", () => { @@ -20,38 +20,37 @@ describe("HttpConnection", () => { }); it("cannot be created with relative url if window object is not present", () => { - (global).window = {}; + (global as any).window = {}; expect(() => new HttpConnection("/test", commonOptions)) .toThrow(new Error("Cannot resolve '/test'.")); - delete (global).window; + delete (global as any).window; }); it("starting connection fails if getting id fails", async (done) => { - let options: IHttpConnectionOptions = { + const options: IHttpConnectionOptions = { ...commonOptions, httpClient: new TestHttpClient() - .on("POST", r => Promise.reject("error")) - .on("GET", r => ""), + .on("POST", (r) => Promise.reject("error")) + .on("GET", (r) => ""), } as IHttpConnectionOptions; - let connection = new HttpConnection("http://tempuri.org", options); + const connection = new HttpConnection("http://tempuri.org", options); try { await connection.start(); fail(); done(); - } - catch (e) { + } catch (e) { expect(e).toBe("error"); done(); } }); it("cannot start a running connection", async (done) => { - let options: IHttpConnectionOptions = { + const options: IHttpConnectionOptions = { ...commonOptions, httpClient: new TestHttpClient() - .on("POST", r => { + .on("POST", (r) => { connection.start() .then(() => { fail(); @@ -65,12 +64,11 @@ describe("HttpConnection", () => { }), } as IHttpConnectionOptions; - let connection = new HttpConnection("http://tempuri.org", options); + const connection = new HttpConnection("http://tempuri.org", options); try { await connection.start(); - } - catch (e) { + } catch (e) { // This exception is thrown after the actual verification is completed. // The connection is not setup to be running so just ignore the error. } @@ -78,17 +76,17 @@ describe("HttpConnection", () => { it("can start a stopped connection", async (done) => { let negotiateCalls = 0; - let options: IHttpConnectionOptions = { + const options: IHttpConnectionOptions = { ...commonOptions, httpClient: new TestHttpClient() - .on("POST", r => { + .on("POST", (r) => { negotiateCalls += 1; return Promise.reject("reached negotiate"); }) - .on("GET", r => ""), + .on("GET", (r) => ""), } as IHttpConnectionOptions; - let connection = new HttpConnection("http://tempuri.org", options); + const connection = new HttpConnection("http://tempuri.org", options); try { await connection.start(); @@ -106,40 +104,39 @@ describe("HttpConnection", () => { }); it("can stop a starting connection", async (done) => { - let options: IHttpConnectionOptions = { + const options: IHttpConnectionOptions = { ...commonOptions, httpClient: new TestHttpClient() - .on("POST", r => { + .on("POST", (r) => { connection.stop(); return "{}"; }) - .on("GET", r => { + .on("GET", (r) => { connection.stop(); return ""; }), } as IHttpConnectionOptions; - let connection = new HttpConnection("http://tempuri.org", options); + const connection = new HttpConnection("http://tempuri.org", options); try { await connection.start(); done(); - } - catch (e) { + } catch (e) { fail(); done(); } }); it("can stop a non-started connection", async (done) => { - let connection = new HttpConnection("http://tempuri.org", commonOptions); + const connection = new HttpConnection("http://tempuri.org", commonOptions); await connection.stop(); done(); }); - it("preserves users connection string", async done => { + it("preserves users connection string", async (done) => { let connectUrl: string; - let fakeTransport: ITransport = { + const fakeTransport: ITransport = { connect(url: string): Promise { connectUrl = url; return Promise.reject(TransferMode.Text); @@ -150,27 +147,25 @@ describe("HttpConnection", () => { stop(): Promise { return Promise.resolve(); }, - onreceive: undefined, onclose: undefined, - } + onreceive: undefined, + }; - let options: IHttpConnectionOptions = { + const options: IHttpConnectionOptions = { ...commonOptions, httpClient: new TestHttpClient() - .on("POST", r => "{ \"connectionId\": \"42\" }") - .on("GET", r => ""), + .on("POST", (r) => "{ \"connectionId\": \"42\" }") + .on("GET", (r) => ""), transport: fakeTransport, } as IHttpConnectionOptions; - - let connection = new HttpConnection("http://tempuri.org?q=myData", options); + const connection = new HttpConnection("http://tempuri.org?q=myData", options); try { await connection.start(); fail(); done(); - } - catch (e) { + } catch (e) { } expect(connectUrl).toBe("http://tempuri.org?q=myData&id=42"); @@ -178,18 +173,18 @@ describe("HttpConnection", () => { }); eachEndpointUrl((givenUrl: string, expectedUrl: string) => { - it("negotiate request puts 'negotiate' at the end of the path", async done => { + it("negotiate request puts 'negotiate' at the end of the path", async (done) => { let negotiateUrl: string; let connection: HttpConnection; - let options: IHttpConnectionOptions = { + const options: IHttpConnectionOptions = { ...commonOptions, httpClient: new TestHttpClient() - .on("POST", r => { + .on("POST", (r) => { negotiateUrl = r.url; connection.stop(); return "{}"; }) - .on("GET", r => { + .on("GET", (r) => { connection.stop(); return ""; }), @@ -214,62 +209,59 @@ describe("HttpConnection", () => { if (requestedTransport === TransportType.WebSockets) { return; } - it(`cannot be started if requested ${TransportType[requestedTransport]} transport not available on server`, async done => { - let options: IHttpConnectionOptions = { + it(`cannot be started if requested ${TransportType[requestedTransport]} transport not available on server`, async (done) => { + const options: IHttpConnectionOptions = { ...commonOptions, httpClient: new TestHttpClient() - .on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }") - .on("GET", r => ""), + .on("POST", (r) => "{ \"connectionId\": \"42\", \"availableTransports\": [] }") + .on("GET", (r) => ""), transport: requestedTransport, } as IHttpConnectionOptions; - let connection = new HttpConnection("http://tempuri.org", options); + const connection = new HttpConnection("http://tempuri.org", options); try { await connection.start(); fail(); done(); - } - catch (e) { + } catch (e) { expect(e.message).toBe("No available transports found."); done(); } }); }); - it("cannot be started if no transport available on server and no transport requested", async done => { - let options: IHttpConnectionOptions = { + it("cannot be started if no transport available on server and no transport requested", async (done) => { + const options: IHttpConnectionOptions = { ...commonOptions, httpClient: new TestHttpClient() - .on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }") - .on("GET", r => ""), + .on("POST", (r) => "{ \"connectionId\": \"42\", \"availableTransports\": [] }") + .on("GET", (r) => ""), } as IHttpConnectionOptions; - let connection = new HttpConnection("http://tempuri.org", options); + const connection = new HttpConnection("http://tempuri.org", options); try { await connection.start(); fail(); done(); - } - catch (e) { + } catch (e) { expect(e.message).toBe("No available transports found."); done(); } }); - it('does not send negotiate request if WebSockets transport requested explicitly', async done => { - let options: IHttpConnectionOptions = { + it("does not send negotiate request if WebSockets transport requested explicitly", async (done) => { + const options: IHttpConnectionOptions = { ...commonOptions, httpClient: new TestHttpClient(), transport: TransportType.WebSockets, } as IHttpConnectionOptions; - let connection = new HttpConnection("http://tempuri.org", options); + const connection = new HttpConnection("http://tempuri.org", options); try { await connection.start(); fail(); done(); - } - catch (e) { + } catch (e) { // WebSocket is created when the transport is connecting which happens after // negotiate request would be sent. No better/easier way to test this. expect(e.message).toBe("WebSocket is not defined"); @@ -284,28 +276,28 @@ describe("HttpConnection", () => { [TransferMode.Binary, TransferMode.Binary], ].forEach(([requestedTransferMode, transportTransferMode]) => { it(`connection returns ${transportTransferMode} transfer mode when ${requestedTransferMode} transfer mode is requested`, async () => { - let fakeTransport = { + const fakeTransport = { // mode: TransferMode : TransferMode.Text connect(url: string, requestedTransferMode: TransferMode): Promise { return Promise.resolve(transportTransferMode); }, + mode: transportTransferMode, + onclose: null, + onreceive: null, send(data: any): Promise { return Promise.resolve(); }, stop(): Promise { return Promise.resolve(); }, - onreceive: null, - onclose: null, - mode: transportTransferMode } as ITransport; - let options: IHttpConnectionOptions = { + const options: IHttpConnectionOptions = { ...commonOptions, httpClient: new TestHttpClient() - .on("POST", r => "{ \"connectionId\": \"42\", \"availableTransports\": [] }") - .on("GET", r => ""), + .on("POST", (r) => "{ \"connectionId\": \"42\", \"availableTransports\": [] }") + .on("GET", (r) => ""), transport: fakeTransport, } as IHttpConnectionOptions; - let connection = new HttpConnection("https://tempuri.org", options); + const connection = new HttpConnection("https://tempuri.org", options); connection.features.transferMode = requestedTransferMode; await connection.start(); - let actualTransferMode = connection.features.transferMode; + const actualTransferMode = connection.features.transferMode; expect(actualTransferMode).toBe(transportTransferMode); }); diff --git a/client-ts/signalr/spec/HubConnection.spec.ts b/client-ts/signalr/spec/HubConnection.spec.ts index a77d4551c6..0b2f6789b7 100644 --- a/client-ts/signalr/spec/HubConnection.spec.ts +++ b/client-ts/signalr/spec/HubConnection.spec.ts @@ -1,32 +1,32 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { IConnection } from "../src/IConnection" -import { HubConnection } from "../src/HubConnection" -import { DataReceived, ConnectionClosed } from "../src/Common" -import { TransportType, ITransport, TransferMode } from "../src/Transports" -import { Observer } from "../src/Observable" -import { TextMessageFormat } from "../src/TextMessageFormat" -import { ILogger, LogLevel } from "../src/ILogger" -import { MessageType } from "../src/IHubProtocol" +import { ConnectionClosed, DataReceived } from "../src/Common"; +import { HubConnection } from "../src/HubConnection"; +import { IConnection } from "../src/IConnection"; +import { MessageType } from "../src/IHubProtocol"; +import { ILogger, LogLevel } from "../src/ILogger"; +import { Observer } from "../src/Observable"; +import { TextMessageFormat } from "../src/TextMessageFormat"; +import { ITransport, TransferMode, TransportType } from "../src/Transports"; -import { asyncit as it, captureException, delay, PromiseSource } from './Utils'; import { IHubConnectionOptions } from "../src/HubConnection"; +import { asyncit as it, captureException, delay, PromiseSource } from "./Utils"; const commonOptions: IHubConnectionOptions = { logger: null, -} +}; describe("HubConnection", () => { describe("start", () => { it("sends negotiation message", async () => { - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, commonOptions); await hubConnection.start(); - expect(connection.sentData.length).toBe(1) + expect(connection.sentData.length).toBe(1); expect(JSON.parse(connection.sentData[0])).toEqual({ - protocol: "json" + protocol: "json", }); await hubConnection.stop(); }); @@ -34,21 +34,21 @@ describe("HubConnection", () => { describe("send", () => { it("sends a non blocking invocation", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let invokePromise = hubConnection.send("testMethod", "arg", 42) + const hubConnection = new HubConnection(connection, commonOptions); + const invokePromise = hubConnection.send("testMethod", "arg", 42) .catch((_) => { }); // Suppress exception and unhandled promise rejection warning. // Verify the message is sent expect(connection.sentData.length).toBe(1); expect(JSON.parse(connection.sentData[0])).toEqual({ - type: MessageType.Invocation, - target: "testMethod", arguments: [ "arg", - 42 - ] + 42, + ], + target: "testMethod", + type: MessageType.Invocation, }); // Close the connection @@ -58,22 +58,22 @@ describe("HubConnection", () => { describe("invoke", () => { it("sends an invocation", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let invokePromise = hubConnection.invoke("testMethod", "arg", 42) + const hubConnection = new HubConnection(connection, commonOptions); + const invokePromise = hubConnection.invoke("testMethod", "arg", 42) .catch((_) => { }); // Suppress exception and unhandled promise rejection warning. // Verify the message is sent expect(connection.sentData.length).toBe(1); expect(JSON.parse(connection.sentData[0])).toEqual({ - type: MessageType.Invocation, - invocationId: connection.lastInvocationId, - target: "testMethod", arguments: [ "arg", - 42 - ] + 42, + ], + invocationId: connection.lastInvocationId, + target: "testMethod", + type: MessageType.Invocation, }); // Close the connection @@ -81,22 +81,22 @@ describe("HubConnection", () => { }); it("rejects the promise when an error is received", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let invokePromise = hubConnection.invoke("testMethod", "arg", 42); + const hubConnection = new HubConnection(connection, commonOptions); + const invokePromise = hubConnection.invoke("testMethod", "arg", 42); connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, error: "foo" }); - let ex = await captureException(async () => invokePromise); + const ex = await captureException(async () => invokePromise); expect(ex.message).toBe("foo"); }); it("resolves the promise when a result is received", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let invokePromise = hubConnection.invoke("testMethod", "arg", 42); + const hubConnection = new HubConnection(connection, commonOptions); + const invokePromise = hubConnection.invoke("testMethod", "arg", 42); connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, result: "foo" }); @@ -104,84 +104,84 @@ describe("HubConnection", () => { }); it("completes pending invocations when stopped", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let invokePromise = hubConnection.invoke("testMethod"); + const hubConnection = new HubConnection(connection, commonOptions); + const invokePromise = hubConnection.invoke("testMethod"); hubConnection.stop(); - let ex = await captureException(async () => await invokePromise); + const ex = await captureException(async () => await invokePromise); expect(ex.message).toBe("Invocation canceled due to connection being closed."); }); it("completes pending invocations when connection is lost", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let invokePromise = hubConnection.invoke("testMethod"); + const hubConnection = new HubConnection(connection, commonOptions); + const invokePromise = hubConnection.invoke("testMethod"); // Typically this would be called by the transport connection.onclose(new Error("Connection lost")); - let ex = await captureException(async () => await invokePromise); + const ex = await captureException(async () => await invokePromise); expect(ex.message).toBe("Connection lost"); }); }); describe("on", () => { it("invocations ignored in callbacks not registered", async () => { - let warnings: string[] = []; - let logger = { - log: function (logLevel: LogLevel, message: string) { + const warnings: string[] = []; + const logger = { + log: (logLevel: LogLevel, message: string) => { if (logLevel === LogLevel.Warning) { warnings.push(message); } - } - }; - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, { logger: logger }); + }, + } as ILogger; + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, { logger }); connection.receive({ - type: MessageType.Invocation, - invocationId: 0, - target: "message", arguments: ["test"], - nonblocking: true + invocationId: 0, + nonblocking: true, + target: "message", + type: MessageType.Invocation, }); expect(warnings).toEqual(["No client method with the name 'message' found."]); }); it("callback invoked when servers invokes a method on the client", async () => { - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, commonOptions); let value = ""; - hubConnection.on("message", v => value = v); + hubConnection.on("message", (v) => value = v); connection.receive({ - type: MessageType.Invocation, - invocationId: 0, - target: "message", arguments: ["test"], - nonblocking: true + invocationId: 0, + nonblocking: true, + target: "message", + type: MessageType.Invocation, }); expect(value).toBe("test"); }); it("can have multiple callbacks", async () => { - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, commonOptions); let numInvocations1 = 0; let numInvocations2 = 0; hubConnection.on("message", () => numInvocations1++); hubConnection.on("message", () => numInvocations2++); connection.receive({ - type: MessageType.Invocation, - invocationId: 0, - target: "message", arguments: [], - nonblocking: true + invocationId: 0, + nonblocking: true, + target: "message", + type: MessageType.Invocation, }); expect(numInvocations1).toBe(1); @@ -189,56 +189,56 @@ describe("HubConnection", () => { }); it("can unsubscribe from on", async () => { - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, commonOptions); - var numInvocations = 0; - var callback = () => numInvocations++; + let numInvocations = 0; + const callback = () => numInvocations++; hubConnection.on("message", callback); connection.receive({ - type: MessageType.Invocation, - invocationId: 0, - target: "message", arguments: [], - nonblocking: true + invocationId: 0, + nonblocking: true, + target: "message", + type: MessageType.Invocation, }); hubConnection.off("message", callback); connection.receive({ - type: MessageType.Invocation, - invocationId: 0, - target: "message", arguments: [], - nonblocking: true + invocationId: 0, + nonblocking: true, + target: "message", + type: MessageType.Invocation, }); expect(numInvocations).toBe(1); }); it("unsubscribing from non-existing callbacks no-ops", async () => { - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, commonOptions); hubConnection.off("_", () => { }); - hubConnection.on("message", t => { }); + hubConnection.on("message", (t) => { }); hubConnection.on("message", () => { }); }); it("using null/undefined for methodName or method no-ops", async () => { - let warnings: string[] = []; - let logger = { - log: function (logLevel: LogLevel, message: string) { + const warnings: string[] = []; + const logger = { + log(logLevel: LogLevel, message: string) { if (logLevel === LogLevel.Warning) { warnings.push(message); } - } - }; + }, + } as ILogger; - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, { logger: logger }); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, { logger }); hubConnection.on(null, undefined); hubConnection.on(undefined, null); @@ -249,11 +249,11 @@ describe("HubConnection", () => { // invoke a method to make sure we are not trying to use null/undefined connection.receive({ - type: MessageType.Invocation, - invocationId: 0, - target: "message", arguments: [], - nonblocking: true + invocationId: 0, + nonblocking: true, + target: "message", + type: MessageType.Invocation, }); expect(warnings).toEqual(["No client method with the name 'message' found."]); @@ -269,21 +269,21 @@ describe("HubConnection", () => { describe("stream", () => { it("sends an invocation", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let invokePromise = hubConnection.stream("testStream", "arg", 42); + const hubConnection = new HubConnection(connection, commonOptions); + const invokePromise = hubConnection.stream("testStream", "arg", 42); // Verify the message is sent expect(connection.sentData.length).toBe(1); expect(JSON.parse(connection.sentData[0])).toEqual({ - type: MessageType.StreamInvocation, - invocationId: connection.lastInvocationId, - target: "testStream", arguments: [ "arg", - 42 - ] + 42, + ], + invocationId: connection.lastInvocationId, + target: "testStream", + type: MessageType.StreamInvocation, }); // Close the connection @@ -291,24 +291,24 @@ describe("HubConnection", () => { }); it("completes with an error when an error is yielded", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let observer = new TestObserver(); + const hubConnection = new HubConnection(connection, commonOptions); + const observer = new TestObserver(); hubConnection.stream("testMethod", "arg", 42) .subscribe(observer); connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, error: "foo" }); - let ex = await captureException(async () => await observer.completed); + const ex = await captureException(async () => await observer.completed); expect(ex.message).toEqual("Error: foo"); }); it("completes the observer when a completion is received", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let observer = new TestObserver(); + const hubConnection = new HubConnection(connection, commonOptions); + const observer = new TestObserver(); hubConnection.stream("testMethod", "arg", 42) .subscribe(observer); @@ -318,38 +318,38 @@ describe("HubConnection", () => { }); it("completes pending streams when stopped", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let observer = new TestObserver(); + const hubConnection = new HubConnection(connection, commonOptions); + const observer = new TestObserver(); hubConnection.stream("testMethod") .subscribe(observer); hubConnection.stop(); - let ex = await captureException(async () => await observer.completed); + const ex = await captureException(async () => await observer.completed); expect(ex.message).toEqual("Error: Invocation canceled due to connection being closed."); }); it("completes pending streams when connection is lost", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let observer = new TestObserver(); + const hubConnection = new HubConnection(connection, commonOptions); + const observer = new TestObserver(); hubConnection.stream("testMethod") .subscribe(observer); // Typically this would be called by the transport connection.onclose(new Error("Connection lost")); - let ex = await captureException(async () => await observer.completed); + const ex = await captureException(async () => await observer.completed); expect(ex.message).toEqual("Error: Connection lost"); }); it("yields items as they arrive", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let observer = new TestObserver(); + const hubConnection = new HubConnection(connection, commonOptions); + const observer = new TestObserver(); hubConnection.stream("testMethod") .subscribe(observer); @@ -367,11 +367,11 @@ describe("HubConnection", () => { }); it("does not require error function registered", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let observer = hubConnection.stream("testMethod").subscribe({ - next: val => { } + const hubConnection = new HubConnection(connection, commonOptions); + const observer = hubConnection.stream("testMethod").subscribe({ + next: (val) => { }, }); // Typically this would be called by the transport @@ -380,11 +380,11 @@ describe("HubConnection", () => { }); it("does not require complete function registered", async () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let observer = hubConnection.stream("testMethod").subscribe({ - next: val => { } + const hubConnection = new HubConnection(connection, commonOptions); + const observer = hubConnection.stream("testMethod").subscribe({ + next: (val) => { }, }); // Send completion to trigger observer.complete() @@ -393,11 +393,11 @@ describe("HubConnection", () => { }); it("can be canceled", () => { - let connection = new TestConnection(); + const connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let observer = new TestObserver(); - let subscription = hubConnection.stream("testMethod") + const hubConnection = new HubConnection(connection, commonOptions); + const observer = new TestObserver(); + const subscription = hubConnection.stream("testMethod") .subscribe(observer); connection.receive({ type: MessageType.StreamItem, invocationId: connection.lastInvocationId, item: 1 }); @@ -412,29 +412,29 @@ describe("HubConnection", () => { // Verify the cancel is sent expect(connection.sentData.length).toBe(2); expect(JSON.parse(connection.sentData[1])).toEqual({ + invocationId: connection.lastInvocationId, type: MessageType.CancelInvocation, - invocationId: connection.lastInvocationId }); }); }); describe("onClose", () => { it("can have multiple callbacks", async () => { - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, commonOptions); let invocations = 0; - hubConnection.onclose(e => invocations++); - hubConnection.onclose(e => invocations++); + hubConnection.onclose((e) => invocations++); + hubConnection.onclose((e) => invocations++); // Typically this would be called by the transport connection.onclose(); expect(invocations).toBe(2); }); it("callbacks receive error", async () => { - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, commonOptions); let error: Error; - hubConnection.onclose(e => error = e); + hubConnection.onclose((e) => error = e); // Typically this would be called by the transport connection.onclose(new Error("Test error.")); @@ -442,8 +442,8 @@ describe("HubConnection", () => { }); it("ignores null callbacks", async () => { - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, commonOptions); hubConnection.onclose(null); hubConnection.onclose(undefined); // Typically this would be called by the transport @@ -456,9 +456,9 @@ describe("HubConnection", () => { it("can receive ping messages", async () => { // Receive the ping mid-invocation so we can see that the rest of the flow works fine - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, commonOptions); - let invokePromise = hubConnection.invoke("testMethod", "arg", 42); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, commonOptions); + const invokePromise = hubConnection.invoke("testMethod", "arg", 42); connection.receive({ type: MessageType.Ping }); connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, result: "foo" }); @@ -467,11 +467,11 @@ describe("HubConnection", () => { }); it("does not terminate if messages are received", async () => { - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, { ...commonOptions, timeoutInMilliseconds: 100 }); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, { ...commonOptions, timeoutInMilliseconds: 100 }); - let p = new PromiseSource(); - hubConnection.onclose(error => p.resolve(error)); + const p = new PromiseSource(); + hubConnection.onclose((e) => p.resolve(e)); await hubConnection.start(); @@ -486,69 +486,67 @@ describe("HubConnection", () => { connection.stop(); - let error = await p.promise; + const error = await p.promise; expect(error).toBeUndefined(); }); it("terminates if no messages received within timeout interval", async () => { - let connection = new TestConnection(); - let hubConnection = new HubConnection(connection, { ...commonOptions, timeoutInMilliseconds: 100 }); + const connection = new TestConnection(); + const hubConnection = new HubConnection(connection, { ...commonOptions, timeoutInMilliseconds: 100 }); - let p = new PromiseSource(); - hubConnection.onclose(error => p.resolve(error)); + const p = new PromiseSource(); + hubConnection.onclose((e) => p.resolve(e)); await hubConnection.start(); - let error = await p.promise; + const error = await p.promise; expect(error).toEqual(new Error("Server timeout elapsed without receiving a message from the server.")); }); - }) + }); }); class TestConnection implements IConnection { - readonly features: any = {}; + public readonly features: any = {}; - start(): Promise { + public start(): Promise { return Promise.resolve(); - }; + } - send(data: any): Promise { - let invocation = TextMessageFormat.parse(data)[0]; - let invocationId = JSON.parse(invocation).invocationId; + public send(data: any): Promise { + const invocation = TextMessageFormat.parse(data)[0]; + const invocationId = JSON.parse(invocation).invocationId; if (invocationId) { this.lastInvocationId = invocationId; } if (this.sentData) { this.sentData.push(invocation); - } - else { + } else { this.sentData = [invocation]; } return Promise.resolve(); - }; + } - stop(error?: Error): Promise { + public stop(error?: Error): Promise { if (this.onclose) { this.onclose(error); } return Promise.resolve(); - }; + } - receive(data: any): void { - let payload = JSON.stringify(data); + public receive(data: any): void { + const payload = JSON.stringify(data); this.onreceive(TextMessageFormat.write(payload)); } - onreceive: DataReceived; - onclose: ConnectionClosed; - sentData: any[]; - lastInvocationId: string; -}; + public onreceive: DataReceived; + public onclose: ConnectionClosed; + public sentData: any[]; + public lastInvocationId: string; +} -class TestObserver implements Observer -{ +class TestObserver implements Observer { public itemsReceived: [any]; private itemsSource: PromiseSource<[any]>; @@ -557,19 +555,19 @@ class TestObserver implements Observer } constructor() { - this.itemsReceived = <[any]>[]; + this.itemsReceived = [] as [any]; this.itemsSource = new PromiseSource<[any]>(); } - next(value: any) { + public next(value: any) { this.itemsReceived.push(value); } - error(err: any) { + public error(err: any) { this.itemsSource.reject(new Error(err)); } - complete() { + public complete() { this.itemsSource.resolve(this.itemsReceived); } -}; +} diff --git a/client-ts/signalr/spec/LoggerFactory.spec.ts b/client-ts/signalr/spec/LoggerFactory.spec.ts index 65adf1deab..457cb0c59e 100644 --- a/client-ts/signalr/spec/LoggerFactory.spec.ts +++ b/client-ts/signalr/spec/LoggerFactory.spec.ts @@ -1,8 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { LoggerFactory } from "../src/Loggers" -import { ILogger, LogLevel } from "../src/ILogger" +import { ILogger, LogLevel } from "../src/ILogger"; +import { LoggerFactory } from "../src/Loggers"; describe("LoggerFactory", () => { it("creates ConsoleLogger when no logging specified", () => { @@ -18,7 +18,7 @@ describe("LoggerFactory", () => { }); it("does not create its own logger if the user provides one", () => { - let customLogger : ILogger = { log: LogLevel => {} }; + const customLogger: ILogger = { log: (logLevel) => {} }; expect(LoggerFactory.createLogger(customLogger)).toBe(customLogger); }); -}); \ No newline at end of file +}); diff --git a/client-ts/signalr/spec/TestHttpClient.ts b/client-ts/signalr/spec/TestHttpClient.ts index 90c63393bf..0f879cbde3 100644 --- a/client-ts/signalr/spec/TestHttpClient.ts +++ b/client-ts/signalr/spec/TestHttpClient.ts @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { HttpClient, HttpRequest, HttpResponse } from "../src/HttpClient" +import { HttpClient, HttpRequest, HttpResponse } from "../src/HttpClient"; type TestHttpHandlerResult = HttpResponse | string; export type TestHttpHandler = (request: HttpRequest, next?: (request: HttpRequest) => Promise) => Promise | TestHttpHandlerResult; @@ -16,28 +16,26 @@ export class TestHttpClient extends HttpClient { } - send(request: HttpRequest): Promise { + public send(request: HttpRequest): Promise { return this.handler(request); } - on(handler: TestHttpHandler): TestHttpClient; - on(method: string | RegExp, handler: TestHttpHandler): TestHttpClient; - on(method: string | RegExp, url: string, handler: TestHttpHandler): TestHttpClient; - on(method: string | RegExp, url: RegExp, handler: TestHttpHandler): TestHttpClient; - on(methodOrHandler: string | RegExp | TestHttpHandler, urlOrHandler?: string | RegExp | TestHttpHandler, handler?: TestHttpHandler): TestHttpClient { + public on(handler: TestHttpHandler): TestHttpClient; + public on(method: string | RegExp, handler: TestHttpHandler): TestHttpClient; + public on(method: string | RegExp, url: string, handler: TestHttpHandler): TestHttpClient; + public on(method: string | RegExp, url: RegExp, handler: TestHttpHandler): TestHttpClient; + public on(methodOrHandler: string | RegExp | TestHttpHandler, urlOrHandler?: string | RegExp | TestHttpHandler, handler?: TestHttpHandler): TestHttpClient { let method: string | RegExp; let url: string | RegExp; if ((typeof methodOrHandler === "string") || (methodOrHandler instanceof RegExp)) { method = methodOrHandler; - } - else if (methodOrHandler) { + } else if (methodOrHandler) { handler = methodOrHandler; } if ((typeof urlOrHandler === "string") || (urlOrHandler instanceof RegExp)) { url = urlOrHandler; - } - else if (urlOrHandler) { + } else if (urlOrHandler) { handler = urlOrHandler; } @@ -46,10 +44,10 @@ export class TestHttpClient extends HttpClient { throw new Error("Missing required argument: 'handler'"); } - let oldHandler = this.handler; - let newHandler = async (request: HttpRequest) => { + const oldHandler = this.handler; + const newHandler = async (request: HttpRequest) => { if (matches(method, request.method) && matches(url, request.url)) { - let promise = handler(request, oldHandler); + const promise = handler(request, oldHandler); let val: TestHttpHandlerResult; if (promise instanceof Promise) { @@ -60,12 +58,10 @@ export class TestHttpClient extends HttpClient { if (typeof val === "string") { return new HttpResponse(200, "OK", val); - } - else { + } else { return val; } - } - else { + } else { return await oldHandler(request); } }; @@ -83,8 +79,7 @@ function matches(pattern: string | RegExp, actual: string): boolean { if (typeof pattern === "string") { return actual === pattern; - } - else { + } else { return pattern.test(actual); } } diff --git a/client-ts/signalr/spec/TextMessageFormatter.spec.ts b/client-ts/signalr/spec/TextMessageFormatter.spec.ts index 9201a9c6f7..e4a8eccd45 100644 --- a/client-ts/signalr/spec/TextMessageFormatter.spec.ts +++ b/client-ts/signalr/spec/TextMessageFormatter.spec.ts @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { TextMessageFormat } from "../src/TextMessageFormat" +import { TextMessageFormat } from "../src/TextMessageFormat"; describe("Text Message Formatter", () => { ([ @@ -9,20 +9,20 @@ describe("Text Message Formatter", () => { ["\u001e\u001e", ["", ""]], ["Hello\u001e", ["Hello"]], ["Hello,\u001eWorld!\u001e", ["Hello,", "World!"]], - ] as [string, string[]][]).forEach(([payload, expected_messages]) => { + ] as Array<[string, string[]]>).forEach(([payload, expectedMessages]) => { it(`should parse '${payload}' correctly`, () => { - let messages = TextMessageFormat.parse(payload); - expect(messages).toEqual(expected_messages); - }) + const messages = TextMessageFormat.parse(payload); + expect(messages).toEqual(expectedMessages); + }); }); ([ ["", new Error("Message is incomplete.")], ["ABC", new Error("Message is incomplete.")], ["ABC\u001eXYZ", new Error("Message is incomplete.")], - ] as [string, Error][]).forEach(([payload, expected_error]) => { + ] as Array<[string, Error]>).forEach(([payload, expectedError]) => { it(`should fail to parse '${payload}'`, () => { - expect(() => TextMessageFormat.parse(payload)).toThrow(expected_error); + expect(() => TextMessageFormat.parse(payload)).toThrow(expectedError); }); }); -}); \ No newline at end of file +}); diff --git a/client-ts/signalr/spec/Utils.ts b/client-ts/signalr/spec/Utils.ts index f79e7aa06d..2c856715d5 100644 --- a/client-ts/signalr/spec/Utils.ts +++ b/client-ts/signalr/spec/Utils.ts @@ -4,8 +4,8 @@ export function asyncit(expectation: string, assertion?: () => Promise | void, timeout?: number): void { let testFunction: (done: DoneFn) => void; if (assertion) { - testFunction = done => { - let promise = assertion(); + testFunction = (done) => { + const promise = assertion(); if (promise) { promise.then(() => done()) .catch((err) => { @@ -31,13 +31,13 @@ export async function captureException(fn: () => Promise): Promise { } export function delay(durationInMilliseconds: number): Promise { - let source = new PromiseSource(); + const source = new PromiseSource(); setTimeout(() => source.resolve(), durationInMilliseconds); return source.promise; } export class PromiseSource { - public promise: Promise + public promise: Promise; private resolver: (value?: T | PromiseLike) => void; private rejecter: (reason?: any) => void; @@ -49,11 +49,11 @@ export class PromiseSource { }); } - resolve(value?: T | PromiseLike) { + public resolve(value?: T | PromiseLike) { this.resolver(value); } - reject(reason?: any) { + public reject(reason?: any) { this.rejecter(reason); } } diff --git a/client-ts/signalr/src/AbortController.ts b/client-ts/signalr/src/AbortController.ts index f872be739b..3992ddeb1e 100644 --- a/client-ts/signalr/src/AbortController.ts +++ b/client-ts/signalr/src/AbortController.ts @@ -9,7 +9,7 @@ export class AbortController implements AbortSignal { private isAborted: boolean = false; public onabort: () => void; - abort() { + public abort() { if (!this.isAborted) { this.isAborted = true; if (this.onabort) { diff --git a/client-ts/signalr/src/Base64EncodedHubProtocol.ts b/client-ts/signalr/src/Base64EncodedHubProtocol.ts index 1015fd5609..9cd2d2abc5 100644 --- a/client-ts/signalr/src/Base64EncodedHubProtocol.ts +++ b/client-ts/signalr/src/Base64EncodedHubProtocol.ts @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { IHubProtocol, HubMessage, ProtocolType } from "./IHubProtocol" +import { HubMessage, IHubProtocol, ProtocolType } from "./IHubProtocol"; export class Base64EncodedHubProtocol implements IHubProtocol { private wrappedProtocol: IHubProtocol; @@ -12,49 +12,49 @@ export class Base64EncodedHubProtocol implements IHubProtocol { this.type = ProtocolType.Text; } - readonly name: string; - readonly type: ProtocolType; + public readonly name: string; + public readonly type: ProtocolType; - parseMessages(input: any): HubMessage[] { + public parseMessages(input: any): HubMessage[] { // The format of the message is `size:message;` - let pos = input.indexOf(":"); - if (pos == -1 || input[input.length - 1] != ';') { + const pos = input.indexOf(":"); + if (pos === -1 || input[input.length - 1] !== ";") { throw new Error("Invalid payload."); } - let lenStr = input.substring(0, pos); + const lenStr = input.substring(0, pos); if (!/^[0-9]+$/.test(lenStr)) { throw new Error(`Invalid length: '${lenStr}'`); } - let messageSize = parseInt(lenStr, 10); + const messageSize = parseInt(lenStr, 10); // 2 accounts for ':' after message size and trailing ';' - if (messageSize != input.length - pos - 2) { + if (messageSize !== input.length - pos - 2) { throw new Error("Invalid message size."); } - let encodedMessage = input.substring(pos + 1, input.length - 1); + const encodedMessage = input.substring(pos + 1, input.length - 1); // atob/btoa are browsers APIs but they can be polyfilled. If this becomes problematic we can use // base64-js module - let s = atob(encodedMessage); - let payload = new Uint8Array(s.length); + const s = atob(encodedMessage); + const payload = new Uint8Array(s.length); for (let i = 0; i < payload.length; i++) { payload[i] = s.charCodeAt(i); } return this.wrappedProtocol.parseMessages(payload.buffer); } - writeMessage(message: HubMessage): any { - let payload = new Uint8Array(this.wrappedProtocol.writeMessage(message)); + public writeMessage(message: HubMessage): any { + const payload = new Uint8Array(this.wrappedProtocol.writeMessage(message)); let s = ""; for (let i = 0; i < payload.byteLength; i++) { s += String.fromCharCode(payload[i]); } // atob/btoa are browsers APIs but they can be polyfilled. If this becomes problematic we can use // base64-js module - let encodedMessage = btoa(s); + const encodedMessage = btoa(s); return `${encodedMessage.length.toString()}:${encodedMessage};`; } -} \ No newline at end of file +} diff --git a/client-ts/signalr/src/Errors.ts b/client-ts/signalr/src/Errors.ts index c27ce417c2..94c28d0be3 100644 --- a/client-ts/signalr/src/Errors.ts +++ b/client-ts/signalr/src/Errors.ts @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. export class HttpError extends Error { - statusCode: number; + public statusCode: number; constructor(errorMessage: string, statusCode: number) { super(errorMessage); this.statusCode = statusCode; diff --git a/client-ts/signalr/src/HttpClient.ts b/client-ts/signalr/src/HttpClient.ts index 1ccc040d42..8eb7477b1d 100644 --- a/client-ts/signalr/src/HttpClient.ts +++ b/client-ts/signalr/src/HttpClient.ts @@ -1,17 +1,17 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { TimeoutError, HttpError } from "./Errors"; import { AbortSignal } from "./AbortController"; +import { HttpError, TimeoutError } from "./Errors"; export interface HttpRequest { - method?: string, - url?: string, - content?: string | ArrayBuffer, - headers?: Map, - responseType?: XMLHttpRequestResponseType, - abortSignal?: AbortSignal, - timeout?: number, + method?: string; + url?: string; + content?: string | ArrayBuffer; + headers?: Map; + responseType?: XMLHttpRequestResponseType; + abortSignal?: AbortSignal; + timeout?: number; } export class HttpResponse { @@ -25,33 +25,33 @@ export class HttpResponse { } export abstract class HttpClient { - get(url: string): Promise; - get(url: string, options: HttpRequest): Promise; - get(url: string, options?: HttpRequest): Promise { + public get(url: string): Promise; + public get(url: string, options: HttpRequest): Promise; + public get(url: string, options?: HttpRequest): Promise { return this.send({ ...options, method: "GET", - url: url, + url, }); } - post(url: string): Promise; - post(url: string, options: HttpRequest): Promise; - post(url: string, options?: HttpRequest): Promise { + public post(url: string): Promise; + public post(url: string, options: HttpRequest): Promise; + public post(url: string, options?: HttpRequest): Promise { return this.send({ ...options, method: "POST", - url: url, + url, }); } - abstract send(request: HttpRequest): Promise; + public abstract send(request: HttpRequest): Promise; } export class DefaultHttpClient extends HttpClient { - send(request: HttpRequest): Promise { + public send(request: HttpRequest): Promise { return new Promise((resolve, reject) => { - let xhr = new XMLHttpRequest(); + const xhr = new XMLHttpRequest(); xhr.open(request.method, request.url, true); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); @@ -80,20 +80,19 @@ export class DefaultHttpClient extends HttpClient { } if (xhr.status >= 200 && xhr.status < 300) { - resolve(new HttpResponse(xhr.status, xhr.statusText, xhr.response || xhr.responseText)) - } - else { + resolve(new HttpResponse(xhr.status, xhr.statusText, xhr.response || xhr.responseText)); + } else { reject(new HttpError(xhr.statusText, xhr.status)); } }; xhr.onerror = () => { reject(new HttpError(xhr.statusText, xhr.status)); - } + }; xhr.ontimeout = () => { reject(new TimeoutError()); - } + }; xhr.send(request.content || ""); }); diff --git a/client-ts/signalr/src/HttpConnection.ts b/client-ts/signalr/src/HttpConnection.ts index 101d6816eb..e2f5fd4e43 100644 --- a/client-ts/signalr/src/HttpConnection.ts +++ b/client-ts/signalr/src/HttpConnection.ts @@ -1,12 +1,12 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { DataReceived, ConnectionClosed } from "./Common" -import { IConnection } from "./IConnection" -import { ITransport, TransferMode, TransportType, WebSocketTransport, ServerSentEventsTransport, LongPollingTransport } from "./Transports" -import { HttpClient, DefaultHttpClient } from "./HttpClient" -import { ILogger, LogLevel } from "./ILogger" -import { LoggerFactory } from "./Loggers" +import { ConnectionClosed, DataReceived } from "./Common"; +import { DefaultHttpClient, HttpClient } from "./HttpClient"; +import { IConnection } from "./IConnection"; +import { ILogger, LogLevel } from "./ILogger"; +import { LoggerFactory } from "./Loggers"; +import { ITransport, LongPollingTransport, ServerSentEventsTransport, TransferMode, TransportType, WebSocketTransport } from "./Transports"; export interface IHttpConnectionOptions { httpClient?: HttpClient; @@ -18,12 +18,12 @@ export interface IHttpConnectionOptions { const enum ConnectionState { Connecting, Connected, - Disconnected + Disconnected, } interface INegotiateResponse { - connectionId: string - availableTransports: string[] + connectionId: string; + availableTransports: string[]; } export class HttpConnection implements IConnection { @@ -37,7 +37,7 @@ export class HttpConnection implements IConnection { private connectionId: string; private startPromise: Promise; - readonly features: any = {}; + public readonly features: any = {}; constructor(url: string, options: IHttpConnectionOptions = {}) { this.logger = LoggerFactory.createLogger(options.logger); @@ -51,7 +51,7 @@ export class HttpConnection implements IConnection { this.options = options; } - async start(): Promise { + public async start(): Promise { if (this.connectionState !== ConnectionState.Disconnected) { return Promise.reject(new Error("Cannot start a connection that is not in the 'Disconnected' state.")); } @@ -68,25 +68,24 @@ export class HttpConnection implements IConnection { // No need to add a connection ID in this case this.url = this.baseUrl; this.transport = this.createTransport(this.options.transport, [TransportType[TransportType.WebSockets]]); - } - else { + } else { let headers; - let token = this.options.accessTokenFactory(); + const token = this.options.accessTokenFactory(); if (token) { headers = new Map(); headers.set("Authorization", `Bearer ${token}`); } - let negotiatePayload = await this.httpClient.post(this.resolveNegotiateUrl(this.baseUrl), { + const negotiatePayload = await this.httpClient.post(this.resolveNegotiateUrl(this.baseUrl), { content: "", - headers + headers, }); - let negotiateResponse: INegotiateResponse = JSON.parse(negotiatePayload.content); + const negotiateResponse: INegotiateResponse = JSON.parse(negotiatePayload.content as string); this.connectionId = negotiateResponse.connectionId; // the user tries to stop the the connection when it is being started - if (this.connectionState == ConnectionState.Disconnected) { + if (this.connectionState === ConnectionState.Disconnected) { return; } @@ -97,9 +96,9 @@ export class HttpConnection implements IConnection { } this.transport.onreceive = this.onreceive; - this.transport.onclose = e => this.stopConnection(true, e); + this.transport.onclose = (e) => this.stopConnection(true, e); - let requestedTransferMode = + const requestedTransferMode = this.features.transferMode === TransferMode.Binary ? TransferMode.Binary : TransferMode.Text; @@ -109,13 +108,12 @@ export class HttpConnection implements IConnection { // only change the state if we were connecting to not overwrite // the state if the connection is already marked as Disconnected this.changeState(ConnectionState.Connecting, ConnectionState.Connected); - } - catch (e) { + } catch (e) { this.logger.log(LogLevel.Error, "Failed to start the connection. " + e); this.connectionState = ConnectionState.Disconnected; this.transport = null; throw e; - }; + } } private createTransport(transport: TransportType | ITransport, availableTransports: string[]): ITransport { @@ -143,36 +141,35 @@ export class HttpConnection implements IConnection { return typeof (transport) === "object" && "connect" in transport; } - private changeState(from: ConnectionState, to: ConnectionState): Boolean { - if (this.connectionState == from) { + private changeState(from: ConnectionState, to: ConnectionState): boolean { + if (this.connectionState === from) { this.connectionState = to; return true; } return false; } - send(data: any): Promise { - if (this.connectionState != ConnectionState.Connected) { + public send(data: any): Promise { + if (this.connectionState !== ConnectionState.Connected) { throw new Error("Cannot send data if the connection is not in the 'Connected' State"); } return this.transport.send(data); } - async stop(error?: Error): Promise { - let previousState = this.connectionState; + public async stop(error?: Error): Promise { + const previousState = this.connectionState; this.connectionState = ConnectionState.Disconnected; try { await this.startPromise; - } - catch (e) { + } catch (e) { // this exception is returned to the user as a rejected Promise from the start method } - this.stopConnection(/*raiseClosed*/ previousState == ConnectionState.Connected, error); + this.stopConnection(/*raiseClosed*/ previousState === ConnectionState.Connected, error); } - private stopConnection(raiseClosed: Boolean, error?: Error) { + private stopConnection(raiseClosed: boolean, error?: Error) { if (this.transport) { this.transport.stop(); this.transport = null; @@ -197,28 +194,28 @@ export class HttpConnection implements IConnection { return url; } - if (typeof window === 'undefined' || !window || !window.document) { + if (typeof window === "undefined" || !window || !window.document) { throw new Error(`Cannot resolve '${url}'.`); } - let parser = window.document.createElement("a"); + const parser = window.document.createElement("a"); parser.href = url; - let baseUrl = (!parser.protocol || parser.protocol === ":") + const baseUrl = (!parser.protocol || parser.protocol === ":") ? `${window.document.location.protocol}//${(parser.host || window.document.location.host)}` : `${parser.protocol}//${parser.host}`; - if (!url || url[0] != '/') { - url = '/' + url; + if (!url || url[0] !== "/") { + url = "/" + url; } - let normalizedUrl = baseUrl + url; + const normalizedUrl = baseUrl + url; this.logger.log(LogLevel.Information, `Normalizing '${url}' to '${normalizedUrl}'`); return normalizedUrl; } private resolveNegotiateUrl(url: string): string { - let index = url.indexOf("?"); + const index = url.indexOf("?"); let negotiateUrl = url.substring(0, index === -1 ? url.length : index); if (negotiateUrl[negotiateUrl.length - 1] !== "/") { negotiateUrl += "/"; @@ -228,6 +225,6 @@ export class HttpConnection implements IConnection { return negotiateUrl; } - onreceive: DataReceived; - onclose: ConnectionClosed; + public onreceive: DataReceived; + public onclose: ConnectionClosed; } diff --git a/client-ts/signalr/src/HubConnection.ts b/client-ts/signalr/src/HubConnection.ts index 4669c8b5ae..ab5682f96c 100644 --- a/client-ts/signalr/src/HubConnection.ts +++ b/client-ts/signalr/src/HubConnection.ts @@ -1,19 +1,19 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { ConnectionClosed } from "./Common" -import { IConnection } from "./IConnection" -import { HttpConnection, IHttpConnectionOptions } from "./HttpConnection" -import { TransportType, TransferMode } from "./Transports" -import { Subject, Observable } from "./Observable" -import { IHubProtocol, ProtocolType, MessageType, HubMessage, CompletionMessage, StreamItemMessage, InvocationMessage, StreamInvocationMessage, NegotiationMessage, CancelInvocationMessage } from "./IHubProtocol"; +import { Base64EncodedHubProtocol } from "./Base64EncodedHubProtocol"; +import { ConnectionClosed } from "./Common"; +import { HttpConnection, IHttpConnectionOptions } from "./HttpConnection"; +import { IConnection } from "./IConnection"; +import { CancelInvocationMessage, CompletionMessage, HubMessage, IHubProtocol, InvocationMessage, MessageType, NegotiationMessage, ProtocolType, StreamInvocationMessage, StreamItemMessage } from "./IHubProtocol"; +import { ILogger, LogLevel } from "./ILogger"; import { JsonHubProtocol } from "./JsonHubProtocol"; -import { TextMessageFormat } from "./TextMessageFormat" -import { Base64EncodedHubProtocol } from "./Base64EncodedHubProtocol" -import { ILogger, LogLevel } from "./ILogger" -import { ConsoleLogger, NullLogger, LoggerFactory } from "./Loggers" +import { ConsoleLogger, LoggerFactory, NullLogger } from "./Loggers"; +import { Observable, Subject } from "./Observable"; +import { TextMessageFormat } from "./TextMessageFormat"; +import { TransferMode, TransportType } from "./Transports"; -export { JsonHubProtocol } +export { JsonHubProtocol }; export interface IHubConnectionOptions extends IHttpConnectionOptions { protocol?: IHubProtocol; @@ -27,7 +27,7 @@ export class HubConnection { private readonly logger: ILogger; private protocol: IHubProtocol; private callbacks: Map void>; - private methods: Map void)[]>; + private methods: Map void>>; private id: number; private closedCallbacks: ConnectionClosed[]; private timeoutHandle: NodeJS.Timer; @@ -42,8 +42,7 @@ export class HubConnection { if (typeof urlOrConnection === "string") { this.connection = new HttpConnection(urlOrConnection, options); - } - else { + } else { this.connection = urlOrConnection; } @@ -54,7 +53,7 @@ export class HubConnection { this.connection.onclose = (error?: Error) => this.connectionClosed(error); this.callbacks = new Map void>(); - this.methods = new Map void)[]>(); + this.methods = new Map void>>(); this.closedCallbacks = []; this.id = 0; } @@ -65,18 +64,16 @@ export class HubConnection { } // Parse the messages - let messages = this.protocol.parseMessages(data); - - for (var i = 0; i < messages.length; ++i) { - var message = messages[i]; + const messages = this.protocol.parseMessages(data); + for (const message of messages) { switch (message.type) { case MessageType.Invocation: this.invokeClientMethod(message); break; case MessageType.StreamItem: case MessageType.Completion: - let callback = this.callbacks.get(message.invocationId); + const callback = this.callbacks.get(message.invocationId); if (callback != null) { if (message.type === MessageType.Completion) { this.callbacks.delete(message.invocationId); @@ -110,45 +107,44 @@ export class HubConnection { } private invokeClientMethod(invocationMessage: InvocationMessage) { - let methods = this.methods.get(invocationMessage.target.toLowerCase()); + const methods = this.methods.get(invocationMessage.target.toLowerCase()); if (methods) { - methods.forEach(m => m.apply(this, invocationMessage.arguments)); + methods.forEach((m) => m.apply(this, invocationMessage.arguments)); if (invocationMessage.invocationId) { // This is not supported in v1. So we return an error to avoid blocking the server waiting for the response. - let message = "Server requested a response, which is not supported in this version of the client." + const message = "Server requested a response, which is not supported in this version of the client."; this.logger.log(LogLevel.Error, message); - this.connection.stop(new Error(message)) + this.connection.stop(new Error(message)); } - } - else { + } else { this.logger.log(LogLevel.Warning, `No client method with the name '${invocationMessage.target}' found.`); } } private connectionClosed(error?: Error) { - this.callbacks.forEach(callback => { + this.callbacks.forEach((callback) => { callback(undefined, error ? error : new Error("Invocation canceled due to connection being closed.")); }); this.callbacks.clear(); - this.closedCallbacks.forEach(c => c.apply(this, [error])); + this.closedCallbacks.forEach((c) => c.apply(this, [error])); this.cleanupTimeout(); } - async start(): Promise { - let requestedTransferMode = + public async start(): Promise { + const requestedTransferMode = (this.protocol.type === ProtocolType.Binary) ? TransferMode.Binary : TransferMode.Text; - this.connection.features.transferMode = requestedTransferMode + this.connection.features.transferMode = requestedTransferMode; await this.connection.start(); - var actualTransferMode = this.connection.features.transferMode; + const actualTransferMode = this.connection.features.transferMode; await this.connection.send( TextMessageFormat.write( - JSON.stringify({ protocol: this.protocol.name }))); + JSON.stringify({ protocol: this.protocol.name } as NegotiationMessage))); this.logger.log(LogLevel.Information, `Using HubProtocol '${this.protocol.name}'.`); @@ -159,21 +155,21 @@ export class HubConnection { this.configureTimeout(); } - stop(): Promise { + public stop(): Promise { this.cleanupTimeout(); return this.connection.stop(); } - stream(methodName: string, ...args: any[]): Observable { - let invocationDescriptor = this.createStreamInvocation(methodName, args); + public stream(methodName: string, ...args: any[]): Observable { + const invocationDescriptor = this.createStreamInvocation(methodName, args); - let subject = new Subject(() => { - let cancelInvocation: CancelInvocationMessage = this.createCancelInvocation(invocationDescriptor.invocationId); - let message: any = this.protocol.writeMessage(cancelInvocation); + const subject = new Subject(() => { + const cancelInvocation: CancelInvocationMessage = this.createCancelInvocation(invocationDescriptor.invocationId); + const cancelMessage: any = this.protocol.writeMessage(cancelInvocation); this.callbacks.delete(invocationDescriptor.invocationId); - return this.connection.send(message); + return this.connection.send(cancelMessage); }); this.callbacks.set(invocationDescriptor.invocationId, (invocationEvent: CompletionMessage | StreamItemMessage, error?: Error) => { @@ -185,20 +181,18 @@ export class HubConnection { if (invocationEvent.type === MessageType.Completion) { if (invocationEvent.error) { subject.error(new Error(invocationEvent.error)); - } - else { + } else { subject.complete(); } - } - else { - subject.next((invocationEvent.item)); + } else { + subject.next((invocationEvent.item) as T); } }); - let message = this.protocol.writeMessage(invocationDescriptor); + const message = this.protocol.writeMessage(invocationDescriptor); this.connection.send(message) - .catch(e => { + .catch((e) => { subject.error(e); this.callbacks.delete(invocationDescriptor.invocationId); }); @@ -206,41 +200,39 @@ export class HubConnection { return subject; } - send(methodName: string, ...args: any[]): Promise { - let invocationDescriptor = this.createInvocation(methodName, args, true); + public send(methodName: string, ...args: any[]): Promise { + const invocationDescriptor = this.createInvocation(methodName, args, true); - let message = this.protocol.writeMessage(invocationDescriptor); + const message = this.protocol.writeMessage(invocationDescriptor); return this.connection.send(message); } - invoke(methodName: string, ...args: any[]): Promise { - let invocationDescriptor = this.createInvocation(methodName, args, false); + public invoke(methodName: string, ...args: any[]): Promise { + const invocationDescriptor = this.createInvocation(methodName, args, false); - let p = new Promise((resolve, reject) => { + const p = new Promise((resolve, reject) => { this.callbacks.set(invocationDescriptor.invocationId, (invocationEvent: StreamItemMessage | CompletionMessage, error?: Error) => { if (error) { reject(error); return; } if (invocationEvent.type === MessageType.Completion) { - let completionMessage = invocationEvent; + const completionMessage = invocationEvent as CompletionMessage; if (completionMessage.error) { reject(new Error(completionMessage.error)); - } - else { + } else { resolve(completionMessage.result); } - } - else { + } else { reject(new Error(`Unexpected message type: ${invocationEvent.type}`)); } }); - let message = this.protocol.writeMessage(invocationDescriptor); + const message = this.protocol.writeMessage(invocationDescriptor); this.connection.send(message) - .catch(e => { + .catch((e) => { reject(e); this.callbacks.delete(invocationDescriptor.invocationId); }); @@ -249,7 +241,7 @@ export class HubConnection { return p; } - on(methodName: string, method: (...args: any[]) => void) { + public on(methodName: string, method: (...args: any[]) => void) { if (!methodName || !method) { return; } @@ -262,23 +254,23 @@ export class HubConnection { this.methods.get(methodName).push(method); } - off(methodName: string, method: (...args: any[]) => void) { + public off(methodName: string, method: (...args: any[]) => void) { if (!methodName || !method) { return; } methodName = methodName.toLowerCase(); - let handlers = this.methods.get(methodName); + const handlers = this.methods.get(methodName); if (!handlers) { return; } - var removeIdx = handlers.indexOf(method); - if (removeIdx != -1) { + const removeIdx = handlers.indexOf(method); + if (removeIdx !== -1) { handlers.splice(removeIdx, 1); } } - onclose(callback: ConnectionClosed) { + public onclose(callback: ConnectionClosed) { if (callback) { this.closedCallbacks.push(callback); } @@ -293,40 +285,39 @@ export class HubConnection { private createInvocation(methodName: string, args: any[], nonblocking: boolean): InvocationMessage { if (nonblocking) { return { - type: MessageType.Invocation, - target: methodName, arguments: args, + target: methodName, + type: MessageType.Invocation, }; - } - else { - let id = this.id; + } else { + const id = this.id; this.id++; return { - type: MessageType.Invocation, + arguments: args, invocationId: id.toString(), target: methodName, - arguments: args, + type: MessageType.Invocation, }; } } private createStreamInvocation(methodName: string, args: any[]): StreamInvocationMessage { - let id = this.id; + const id = this.id; this.id++; return { - type: MessageType.StreamInvocation, + arguments: args, invocationId: id.toString(), target: methodName, - arguments: args, + type: MessageType.StreamInvocation, }; } private createCancelInvocation(id: string): CancelInvocationMessage { return { - type: MessageType.CancelInvocation, invocationId: id, + type: MessageType.CancelInvocation, }; } } diff --git a/client-ts/signalr/src/IConnection.ts b/client-ts/signalr/src/IConnection.ts index 2e99ffecb0..f4e62c8c07 100644 --- a/client-ts/signalr/src/IConnection.ts +++ b/client-ts/signalr/src/IConnection.ts @@ -1,8 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { DataReceived, ConnectionClosed } from "./Common" -import { TransportType, TransferMode, ITransport } from "./Transports" +import { ConnectionClosed, DataReceived } from "./Common"; +import { ITransport, TransferMode, TransportType } from "./Transports"; export interface IConnection { readonly features: any; diff --git a/client-ts/signalr/src/IHubProtocol.ts b/client-ts/signalr/src/IHubProtocol.ts index 11d5b7d822..e65e171867 100644 --- a/client-ts/signalr/src/IHubProtocol.ts +++ b/client-ts/signalr/src/IHubProtocol.ts @@ -10,7 +10,7 @@ export const enum MessageType { Ping = 6, } -export type MessageHeaders = { [key: string]: string }; +export interface MessageHeaders { [key: string]: string; } export type HubMessage = InvocationMessage | StreamInvocationMessage | StreamItemMessage | CompletionMessage | CancelInvocationMessage | PingMessage; @@ -26,13 +26,13 @@ export interface HubInvocationMessage extends HubMessageBase { export interface InvocationMessage extends HubInvocationMessage { readonly type: MessageType.Invocation; readonly target: string; - readonly arguments: Array; + readonly arguments: any[]; } export interface StreamInvocationMessage extends HubInvocationMessage { readonly type: MessageType.StreamInvocation; readonly target: string; - readonly arguments: Array + readonly arguments: any[]; } export interface StreamItemMessage extends HubInvocationMessage { @@ -60,7 +60,7 @@ export interface CancelInvocationMessage extends HubInvocationMessage { export const enum ProtocolType { Text = 1, - Binary + Binary, } export interface IHubProtocol { diff --git a/client-ts/signalr/src/ILogger.ts b/client-ts/signalr/src/ILogger.ts index b04154cf92..026542a919 100644 --- a/client-ts/signalr/src/ILogger.ts +++ b/client-ts/signalr/src/ILogger.ts @@ -6,7 +6,7 @@ export enum LogLevel { Information, Warning, Error, - None + None, } export interface ILogger { diff --git a/client-ts/signalr/src/JsonHubProtocol.ts b/client-ts/signalr/src/JsonHubProtocol.ts index 2b232423d9..c2119455c0 100644 --- a/client-ts/signalr/src/JsonHubProtocol.ts +++ b/client-ts/signalr/src/JsonHubProtocol.ts @@ -1,33 +1,33 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +import { HubMessage, IHubProtocol, ProtocolType } from "./IHubProtocol"; import { TextMessageFormat } from "./TextMessageFormat"; -import { IHubProtocol, ProtocolType, HubMessage } from "./IHubProtocol"; export const JSON_HUB_PROTOCOL_NAME: string = "json"; export class JsonHubProtocol implements IHubProtocol { - readonly name: string = JSON_HUB_PROTOCOL_NAME; + public readonly name: string = JSON_HUB_PROTOCOL_NAME; - readonly type: ProtocolType = ProtocolType.Text; + public readonly type: ProtocolType = ProtocolType.Text; - parseMessages(input: string): HubMessage[] { + public parseMessages(input: string): HubMessage[] { if (!input) { return []; } // Parse the messages - let messages = TextMessageFormat.parse(input); - let hubMessages = []; - for (var i = 0; i < messages.length; ++i) { - hubMessages.push(JSON.parse(messages[i])); + const messages = TextMessageFormat.parse(input); + const hubMessages = []; + for (const message of messages) { + hubMessages.push(JSON.parse(message)); } return hubMessages; } - writeMessage(message: HubMessage): string { + public writeMessage(message: HubMessage): string { return TextMessageFormat.write(JSON.stringify(message)); } -} \ No newline at end of file +} diff --git a/client-ts/signalr/src/Loggers.ts b/client-ts/signalr/src/Loggers.ts index 64dc23b4ee..618076911a 100644 --- a/client-ts/signalr/src/Loggers.ts +++ b/client-ts/signalr/src/Loggers.ts @@ -1,10 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { ILogger, LogLevel } from "./ILogger" +import { ILogger, LogLevel } from "./ILogger"; export class NullLogger implements ILogger { - log(logLevel: LogLevel, message: string): void { + public log(logLevel: LogLevel, message: string): void { } } @@ -15,7 +15,7 @@ export class ConsoleLogger implements ILogger { this.minimumLogLevel = minimumLogLevel; } - log(logLevel: LogLevel, message: string): void { + public log(logLevel: LogLevel, message: string): void { if (logLevel >= this.minimumLogLevel) { switch (logLevel) { case LogLevel.Error: @@ -35,8 +35,8 @@ export class ConsoleLogger implements ILogger { } } -export namespace LoggerFactory { - export function createLogger(logging?: ILogger | LogLevel) { +export class LoggerFactory { + public static createLogger(logging?: ILogger | LogLevel) { if (logging === undefined) { return new ConsoleLogger(LogLevel.Information); } @@ -45,10 +45,10 @@ export namespace LoggerFactory { return new NullLogger(); } - if ((logging).log) { - return logging; + if ((logging as ILogger).log) { + return logging as ILogger; } - return new ConsoleLogger(logging); + return new ConsoleLogger(logging as LogLevel); } -} \ No newline at end of file +} diff --git a/client-ts/signalr/src/Observable.ts b/client-ts/signalr/src/Observable.ts index eeaaf0c626..5894837c1e 100644 --- a/client-ts/signalr/src/Observable.ts +++ b/client-ts/signalr/src/Observable.ts @@ -11,8 +11,8 @@ export interface Observer { } export class Subscription { - subject: Subject; - observer: Observer; + private subject: Subject; + private observer: Observer; constructor(subject: Subject, observer: Observer) { this.subject = subject; @@ -20,7 +20,7 @@ export class Subscription { } public dispose(): void { - let index: number = this.subject.observers.indexOf(this.observer); + const index: number = this.subject.observers.indexOf(this.observer); if (index > -1) { this.subject.observers.splice(index, 1); } @@ -36,8 +36,8 @@ export interface Observable { } export class Subject implements Observable { - observers: Observer[]; - cancelCallback: () => Promise; + public observers: Array>; + public cancelCallback: () => Promise; constructor(cancelCallback: () => Promise) { this.observers = []; @@ -45,13 +45,13 @@ export class Subject implements Observable { } public next(item: T): void { - for (let observer of this.observers) { + for (const observer of this.observers) { observer.next(item); } } public error(err: any): void { - for (let observer of this.observers) { + for (const observer of this.observers) { if (observer.error) { observer.error(err); } @@ -59,7 +59,7 @@ export class Subject implements Observable { } public complete(): void { - for (let observer of this.observers) { + for (const observer of this.observers) { if (observer.complete) { observer.complete(); } diff --git a/client-ts/signalr/src/TextMessageFormat.ts b/client-ts/signalr/src/TextMessageFormat.ts index ef15313407..e4ce928f56 100644 --- a/client-ts/signalr/src/TextMessageFormat.ts +++ b/client-ts/signalr/src/TextMessageFormat.ts @@ -2,18 +2,18 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. export class TextMessageFormat { - static RecordSeparator = String.fromCharCode(0x1e); + private static RecordSeparator = String.fromCharCode(0x1e); - static write(output: string): string { + public static write(output: string): string { return `${output}${TextMessageFormat.RecordSeparator}`; } - static parse(input: string): string[] { - if (input[input.length - 1] != TextMessageFormat.RecordSeparator) { + public static parse(input: string): string[] { + if (input[input.length - 1] !== TextMessageFormat.RecordSeparator) { throw new Error("Message is incomplete."); } - let messages = input.split(TextMessageFormat.RecordSeparator); + const messages = input.split(TextMessageFormat.RecordSeparator); messages.pop(); return messages; } diff --git a/client-ts/signalr/src/Transports.ts b/client-ts/signalr/src/Transports.ts index ff5e2b9f0e..34c6571d58 100644 --- a/client-ts/signalr/src/Transports.ts +++ b/client-ts/signalr/src/Transports.ts @@ -1,22 +1,22 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -import { DataReceived, TransportClosed } from "./Common"; -import { HttpClient, HttpRequest } from "./HttpClient"; -import { HttpError, TimeoutError } from "./Errors"; -import { ILogger, LogLevel } from "./ILogger"; -import { IConnection } from "./IConnection"; import { AbortController } from "./AbortController"; +import { DataReceived, TransportClosed } from "./Common"; +import { HttpError, TimeoutError } from "./Errors"; +import { HttpClient, HttpRequest } from "./HttpClient"; +import { IConnection } from "./IConnection"; +import { ILogger, LogLevel } from "./ILogger"; export enum TransportType { WebSockets, ServerSentEvents, - LongPolling + LongPolling, } export const enum TransferMode { Text = 1, - Binary + Binary, } export interface ITransport { @@ -37,17 +37,17 @@ export class WebSocketTransport implements ITransport { this.accessTokenFactory = accessTokenFactory || (() => null); } - connect(url: string, requestedTransferMode: TransferMode, connection: IConnection): Promise { + public connect(url: string, requestedTransferMode: TransferMode, connection: IConnection): Promise { return new Promise((resolve, reject) => { url = url.replace(/^http/, "ws"); - let token = this.accessTokenFactory(); + const token = this.accessTokenFactory(); if (token) { url += (url.indexOf("?") < 0 ? "?" : "&") + `access_token=${encodeURIComponent(token)}`; } - let webSocket = new WebSocket(url); - if (requestedTransferMode == TransferMode.Binary) { + const webSocket = new WebSocket(url); + if (requestedTransferMode === TransferMode.Binary) { webSocket.binaryType = "arraybuffer"; } @@ -66,23 +66,22 @@ export class WebSocketTransport implements ITransport { if (this.onreceive) { this.onreceive(message.data); } - } + }; webSocket.onclose = (event: CloseEvent) => { // webSocket will be null if the transport did not start successfully if (this.onclose && this.webSocket) { if (event.wasClean === false || event.code !== 1000) { this.onclose(new Error(`Websocket closed with status code: ${event.code} (${event.reason})`)); - } - else { + } else { this.onclose(); } } - } + }; }); } - send(data: any): Promise { + public send(data: any): Promise { if (this.webSocket && this.webSocket.readyState === WebSocket.OPEN) { this.webSocket.send(data); return Promise.resolve(); @@ -91,7 +90,7 @@ export class WebSocketTransport implements ITransport { return Promise.reject("WebSocket is not in the OPEN state"); } - stop(): Promise { + public stop(): Promise { if (this.webSocket) { this.webSocket.close(); this.webSocket = null; @@ -99,8 +98,8 @@ export class WebSocketTransport implements ITransport { return Promise.resolve(); } - onreceive: DataReceived; - onclose: TransportClosed; + public onreceive: DataReceived; + public onclose: TransportClosed; } export class ServerSentEventsTransport implements ITransport { @@ -116,19 +115,19 @@ export class ServerSentEventsTransport implements ITransport { this.logger = logger; } - connect(url: string, requestedTransferMode: TransferMode, connection: IConnection): Promise { + public connect(url: string, requestedTransferMode: TransferMode, connection: IConnection): Promise { if (typeof (EventSource) === "undefined") { Promise.reject("EventSource not supported by the browser."); } this.url = url; return new Promise((resolve, reject) => { - let token = this.accessTokenFactory(); + const token = this.accessTokenFactory(); if (token) { url += (url.indexOf("?") < 0 ? "?" : "&") + `access_token=${encodeURIComponent(token)}`; } - let eventSource = new EventSource(url); + const eventSource = new EventSource(url); try { eventSource.onmessage = (e: MessageEvent) => { @@ -152,26 +151,25 @@ export class ServerSentEventsTransport implements ITransport { if (this.eventSource && this.onclose) { this.onclose(new Error(e.message || "Error occurred")); } - } + }; eventSource.onopen = () => { this.logger.log(LogLevel.Information, `SSE connected to ${this.url}`); this.eventSource = eventSource; // SSE is a text protocol resolve(TransferMode.Text); - } - } - catch (e) { + }; + } catch (e) { return Promise.reject(e); } }); } - async send(data: any): Promise { + public async send(data: any): Promise { return send(this.httpClient, this.url, this.accessTokenFactory, data); } - stop(): Promise { + public stop(): Promise { if (this.eventSource) { this.eventSource.close(); this.eventSource = null; @@ -179,8 +177,8 @@ export class ServerSentEventsTransport implements ITransport { return Promise.resolve(); } - onreceive: DataReceived; - onclose: TransportClosed; + public onreceive: DataReceived; + public onclose: TransportClosed; } export class LongPollingTransport implements ITransport { @@ -199,7 +197,7 @@ export class LongPollingTransport implements ITransport { this.pollAbort = new AbortController(); } - connect(url: string, requestedTransferMode: TransferMode, connection: IConnection): Promise { + public connect(url: string, requestedTransferMode: TransferMode, connection: IConnection): Promise { this.url = url; // Set a flag indicating we have inherent keep-alive in this transport. @@ -215,26 +213,26 @@ export class LongPollingTransport implements ITransport { } private async poll(url: string, transferMode: TransferMode): Promise { - let pollOptions: HttpRequest = { - timeout: 120000, + const pollOptions: HttpRequest = { abortSignal: this.pollAbort.signal, headers: new Map(), + timeout: 120000, }; if (transferMode === TransferMode.Binary) { pollOptions.responseType = "arraybuffer"; } - let token = this.accessTokenFactory(); + const token = this.accessTokenFactory(); if (token) { pollOptions.headers.set("Authorization", `Bearer ${token}`); } while (!this.pollAbort.signal.aborted) { try { - let pollUrl = `${url}&_=${Date.now()}`; + const pollUrl = `${url}&_=${Date.now()}`; this.logger.log(LogLevel.Trace, `(LongPolling transport) polling: ${pollUrl}`); - let response = await this.httpClient.get(pollUrl, pollOptions) + const response = await this.httpClient.get(pollUrl, pollOptions); if (response.statusCode === 204) { this.logger.log(LogLevel.Information, "(LongPolling transport) Poll terminated by server"); @@ -243,8 +241,7 @@ export class LongPollingTransport implements ITransport { this.onclose(); } this.pollAbort.abort(); - } - else if (response.statusCode !== 200) { + } else if (response.statusCode !== 200) { this.logger.log(LogLevel.Error, `(LongPolling transport) Unexpected response code: ${response.statusCode}`); // Unexpected status code @@ -252,16 +249,14 @@ export class LongPollingTransport implements ITransport { this.onclose(new HttpError(response.statusText, response.statusCode)); } this.pollAbort.abort(); - } - else { + } else { // Process the response if (response.content) { this.logger.log(LogLevel.Trace, `(LongPolling transport) data received: ${response.content}`); if (this.onreceive) { this.onreceive(response.content); } - } - else { + } else { // This is another way timeout manifest. this.logger.log(LogLevel.Trace, "(LongPolling transport) Poll timed out, reissuing."); } @@ -281,29 +276,29 @@ export class LongPollingTransport implements ITransport { } } - async send(data: any): Promise { + public async send(data: any): Promise { return send(this.httpClient, this.url, this.accessTokenFactory, data); } - stop(): Promise { + public stop(): Promise { this.pollAbort.abort(); return Promise.resolve(); } - onreceive: DataReceived; - onclose: TransportClosed; + public onreceive: DataReceived; + public onclose: TransportClosed; } async function send(httpClient: HttpClient, url: string, accessTokenFactory: () => string, content: string | ArrayBuffer): Promise { let headers; - let token = accessTokenFactory(); + const token = accessTokenFactory(); if (token) { headers = new Map(); - headers.set("Authorization", `Bearer ${accessTokenFactory()}`) + headers.set("Authorization", `Bearer ${accessTokenFactory()}`); } await httpClient.post(url, { content, - headers + headers, }); } diff --git a/client-ts/signalr/src/browser-index.ts b/client-ts/signalr/src/browser-index.ts index f2ce41beeb..6b466ba7fe 100644 --- a/client-ts/signalr/src/browser-index.ts +++ b/client-ts/signalr/src/browser-index.ts @@ -3,6 +3,6 @@ // This is where we add any polyfills we'll need for the browser. It is the entry module for browser-specific builds. -import 'es6-promise/dist/es6-promise.auto.js'; +import "es6-promise/dist/es6-promise.auto.js"; -export * from './index' +export * from "./index"; diff --git a/client-ts/signalr/src/index.ts b/client-ts/signalr/src/index.ts index 7d9548d347..392dd08a62 100644 --- a/client-ts/signalr/src/index.ts +++ b/client-ts/signalr/src/index.ts @@ -2,14 +2,14 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Everything that users need to access must be exported here. Including interfaces. -export * from "./Common" -export * from "./Errors" -export * from "./HttpClient" -export * from "./HttpConnection" -export * from "./HubConnection" -export * from "./IConnection" -export * from "./IHubProtocol" -export * from "./ILogger" -export * from "./Loggers" -export * from "./Transports" -export * from "./Observable" \ No newline at end of file +export * from "./Common"; +export * from "./Errors"; +export * from "./HttpClient"; +export * from "./HttpConnection"; +export * from "./HubConnection"; +export * from "./IConnection"; +export * from "./IHubProtocol"; +export * from "./ILogger"; +export * from "./Loggers"; +export * from "./Transports"; +export * from "./Observable"; diff --git a/client-ts/tslint.json b/client-ts/tslint.json new file mode 100644 index 0000000000..9dc31ff068 --- /dev/null +++ b/client-ts/tslint.json @@ -0,0 +1,13 @@ +{ + "extends": "tslint:recommended", + "rules": { + "max-line-length": { "options": [300] }, + "member-ordering": false, + "interface-name": false, + "unified-signatures": false, + "max-classes-per-file": false, + "no-empty": false, + "no-bitwise": false, + "no-console": false + } +} \ No newline at end of file