diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..7d6cf97e1 --- /dev/null +++ b/.clang-format @@ -0,0 +1,3 @@ +Language: JavaScript +BasedOnStyle: Google +ColumnLimit: 80 \ No newline at end of file diff --git a/.jsdoc.js b/.jsdoc.js index 5f2af4d08..e09418fc3 100644 --- a/.jsdoc.js +++ b/.jsdoc.js @@ -31,7 +31,7 @@ module.exports = { source: { excludePattern: '(^|\\/|\\\\)[._]', include: [ - 'src' + 'build/src' ], includePattern: '\\.js$' }, diff --git a/package.json b/package.json index 830e04d5f..5ff40ccc1 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,10 @@ "node": ">=6.0.0" }, "repository": "googleapis/nodejs-pubsub", - "main": "./src/index.js", + "main": "./build/src/index.js", "files": [ "protos", - "src", + "build/src", "AUTHORS", "CONTRIBUTORS", "LICENSE" @@ -62,16 +62,20 @@ "renovate[bot] " ], "scripts": { - "system-test": "mocha system-test/ --timeout 600000", - "cover": "nyc --reporter=lcov mocha test/ && nyc report", + "presystem-test": "npm run compile", + "system-test": "mocha build/system-test --timeout 600000", + "cover": "nyc --reporter=lcov mocha build/test && nyc report", "samples-test": "cd samples/ && npm link ../ && npm test && cd ../", - "test-no-cover": "mocha test/*.js", + "test-no-cover": "mocha build/test", "test": "npm run cover", - "lint": "eslint '**/*.js'", - "prettier": "prettier --write src/*.js src/*/*.js samples/*.js samples/*/*.js test/*.js test/*/*.js system-test/*.js system-test/*/*.js smoke-test/*.js", + "lint": "eslint 'samples/*.js' 'samples/**/*.js'", "docs": "jsdoc -c .jsdoc.js", - "fix": "eslint --fix '**/*.js' && npm run prettier", - "generate-scaffolding": "repo-tools generate all && repo-tools generate lib_samples_readme -l samples/ --config ../.cloud-repo-tools.json" + "fix": "eslint --fix 'samples/*.js' 'samples/**/*.js'", + "generate-scaffolding": "repo-tools generate all && repo-tools generate lib_samples_readme -l samples/ --config ../.cloud-repo-tools.json", + "clean": "gts clean", + "compile": "tsc -p . && cp -r src/v1/ build/src/v1/ && cp -r protos build/", + "prepare": "npm run compile", + "pretest": "npm run compile" }, "dependencies": { "@google-cloud/paginator": "^0.1.0", @@ -95,12 +99,21 @@ }, "devDependencies": { "@google-cloud/nodejs-repo-tools": "^2.3.3", + "@types/arrify": "^1.0.4", + "@types/extend": "^3.0.0", + "@types/is": "0.0.20", + "@types/mocha": "^5.2.5", + "@types/proxyquire": "^1.3.28", + "@types/sinon": "^5.0.5", + "@types/through2": "^2.0.34", + "@types/uuid": "^3.4.4", "async": "^2.6.0", "codecov": "^3.0.0", "eslint": "^5.0.0", "eslint-config-prettier": "^3.0.0", "eslint-plugin-node": "^8.0.0", "eslint-plugin-prettier": "^3.0.0", + "gts": "^0.8.0", "ink-docstrap": "^1.3.2", "intelli-espower-loader": "^1.0.1", "jsdoc": "^3.5.5", @@ -108,6 +121,14 @@ "nyc": "^13.0.0", "power-assert": "^1.4.4", "prettier": "^1.9.1", - "proxyquire": "^2.0.0" + "proxyquire": "^2.0.0", + "sinon": "^7.1.1", + "source-map-support": "^0.5.9", + "typescript": "~3.1.5" + }, + "nyc": { + "exclude": [ + "build/test" + ] } } diff --git a/smoke-test/publisher_smoke_test.js b/smoke-test/publisher_smoke_test.ts similarity index 100% rename from smoke-test/publisher_smoke_test.js rename to smoke-test/publisher_smoke_test.ts diff --git a/src/connection-pool.js b/src/connection-pool.ts similarity index 95% rename from src/connection-pool.js rename to src/connection-pool.ts index 1ffb85a8f..b840ea26d 100644 --- a/src/connection-pool.js +++ b/src/connection-pool.ts @@ -14,16 +14,14 @@ * limitations under the License. */ -'use strict'; - -const {replaceProjectIdToken} = require('@google-cloud/projectify'); +import {replaceProjectIdToken} from '@google-cloud/projectify'; const duplexify = require('duplexify'); const each = require('async-each'); -const {EventEmitter} = require('events'); -const is = require('is'); -const through = require('through2'); -const uuid = require('uuid'); -const util = require('./util'); +import {EventEmitter} from 'events'; +import * as is from 'is'; +import * as through from 'through2'; +import * as uuid from 'uuid'; +import * as util from './util'; const CHANNEL_READY_EVENT = 'channel.ready'; const CHANNEL_ERROR_EVENT = 'channel.error'; @@ -64,6 +62,18 @@ const RETRY_CODES = [ * creating a connection. */ class ConnectionPool extends EventEmitter { + subscription; + pubsub; + connections; + isPaused; + isOpen; + isGettingChannelState; + failedConnectionAttempts; + noConnectionsTime; + settings; + queue; + keepAliveHandle; + client; constructor(subscription) { super(); this.subscription = subscription; @@ -223,7 +233,7 @@ class ConnectionPool extends EventEmitter { this.queueConnection(); } else if (this.isOpen && !this.connections.size) { const error = new Error(status.details); - error.code = status.code; + (error as any).code = status.code; this.emit('error', error); } }; @@ -272,13 +282,13 @@ class ConnectionPool extends EventEmitter { get length() { return originalDataLength; }, - }; - message.ack = () => { - this.subscription.ack_(message); - }; - message.nack = () => { - this.subscription.nack_(message); - }; + ack: () => { + this.subscription.ack_(message); + }, + nack: () => { + this.subscription.nack_(message); + } + } return message; } /*! diff --git a/src/histogram.js b/src/histogram.ts similarity index 97% rename from src/histogram.js rename to src/histogram.ts index d386fc35e..c1c1cfa95 100644 --- a/src/histogram.js +++ b/src/histogram.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -'use strict'; - -const extend = require('extend'); +import * as extend from 'extend'; /*! * The Histogram class is used to capture the lifespan of messages within the @@ -27,6 +25,9 @@ const extend = require('extend'); * @class */ class Histogram { + options; + data; + length; constructor(options) { this.options = extend( { diff --git a/src/iam.js b/src/iam.ts similarity index 98% rename from src/iam.js rename to src/iam.ts index 502c04dff..a8ef8342b 100644 --- a/src/iam.js +++ b/src/iam.ts @@ -20,9 +20,9 @@ 'use strict'; -const arrify = require('arrify'); -const {promisifyAll} = require('@google-cloud/promisify'); -const is = require('is'); +import * as arrify from 'arrify'; +import {promisifyAll} from '@google-cloud/promisify'; +import * as is from 'is'; /** * [IAM (Identity and Access Management)](https://cloud.google.com/pubsub/access_control) @@ -63,6 +63,10 @@ const is = require('is'); * // subscription.iam */ class IAM { + Promise; + pubsub; + request; + id; constructor(pubsub, id) { if (pubsub.Promise) { this.Promise = pubsub.Promise; diff --git a/src/index.js b/src/index.ts similarity index 97% rename from src/index.js rename to src/index.ts index ac360f9cb..925c859be 100644 --- a/src/index.js +++ b/src/index.ts @@ -16,16 +16,16 @@ 'use strict'; -const {replaceProjectIdToken} = require('@google-cloud/projectify'); -const {paginator} = require('@google-cloud/paginator'); -const {promisifyAll} = require('@google-cloud/promisify'); -const extend = require('extend'); -const {GoogleAuth} = require('google-auth-library'); +import {replaceProjectIdToken} from '@google-cloud/projectify'; +import {paginator} from '@google-cloud/paginator'; +import {promisifyAll} from '@google-cloud/promisify'; +import * as extend from 'extend'; +import {GoogleAuth} from 'google-auth-library'; const gax = require('google-gax'); const {grpc} = new gax.GrpcClient(); -const is = require('is'); +import * as is from 'is'; -const PKG = require('../package.json'); +const PKG = require('../../package.json'); const v1 = require('./v1'); const Snapshot = require('./snapshot'); @@ -94,6 +94,12 @@ const PROJECT_ID_PLACEHOLDER = '{{projectId}}'; * Full quickstart example: */ class PubSub { + options; + isEmulator; + api; + auth; + projectId; + Promise; constructor(options) { options = options || {}; // Determine what scopes are needed. @@ -728,7 +734,7 @@ class PubSub { * // message.publishTime = Timestamp when Pub/Sub received the message. * }); */ - subscription(name, options) { + subscription(name, options?) { if (!name) { throw new Error('A name must be specified for a subscription.'); } @@ -748,7 +754,7 @@ class PubSub { * * const topic = pubsub.topic('my-topic'); */ - topic(name, options) { + topic(name, options?) { if (!name) { throw new Error('A name must be specified for a topic.'); } @@ -786,7 +792,7 @@ class PubSub { * this.end(); * }); */ -PubSub.prototype.getSnapshotsStream = paginator.streamify('getSnapshots'); +(PubSub.prototype as any).getSnapshotsStream = paginator.streamify('getSnapshots'); /** * Get a list of the {@link Subscription} objects registered to all of @@ -819,7 +825,7 @@ PubSub.prototype.getSnapshotsStream = paginator.streamify('getSnapshots'); * this.end(); * }); */ -PubSub.prototype.getSubscriptionsStream = paginator.streamify( +(PubSub.prototype as any).getSubscriptionsStream = paginator.streamify( 'getSubscriptions' ); @@ -854,7 +860,7 @@ PubSub.prototype.getSubscriptionsStream = paginator.streamify( * this.end(); * }); */ -PubSub.prototype.getTopicsStream = paginator.streamify('getTopics'); +(PubSub.prototype as any).getTopicsStream = paginator.streamify('getTopics'); /*! Developer Documentation * diff --git a/src/publisher.js b/src/publisher.ts similarity index 97% rename from src/publisher.js rename to src/publisher.ts index 1ba9e9fde..39c66e40e 100644 --- a/src/publisher.js +++ b/src/publisher.ts @@ -16,11 +16,11 @@ 'use strict'; -const arrify = require('arrify'); -const {promisifyAll} = require('@google-cloud/promisify'); +import * as arrify from 'arrify'; +import {promisifyAll} from '@google-cloud/promisify'; const each = require('async-each'); -const extend = require('extend'); -const is = require('is'); +import * as extend from 'extend'; +import * as is from 'is'; /** * A Publisher object allows you to publish messages to a specific topic. @@ -49,6 +49,11 @@ const is = require('is'); * const publisher = topic.publisher(); */ class Publisher { + Promise; + topic; + inventory_; + settings; + timeoutHandle_; constructor(topic, options) { if (topic.Promise) { this.Promise = topic.Promise; diff --git a/src/snapshot.js b/src/snapshot.ts similarity index 97% rename from src/snapshot.js rename to src/snapshot.ts index 64bc4710c..6b7fc88ff 100644 --- a/src/snapshot.js +++ b/src/snapshot.ts @@ -16,9 +16,9 @@ 'use strict'; -const util = require('./util'); -const {promisifyAll} = require('@google-cloud/promisify'); -const is = require('is'); +import * as util from './util'; +import {promisifyAll} from '@google-cloud/promisify'; +import * as is from 'is'; /** * A Snapshot object will give you access to your Cloud Pub/Sub snapshot. @@ -85,6 +85,11 @@ const is = require('is'); * }); */ class Snapshot { + parent; + name; + Promise; + create; + seek; constructor(parent, name) { if (parent.Promise) { this.Promise = parent.Promise; diff --git a/src/subscriber.js b/src/subscriber.ts similarity index 94% rename from src/subscriber.js rename to src/subscriber.ts index 7f018fc42..4ab422d1a 100644 --- a/src/subscriber.js +++ b/src/subscriber.ts @@ -16,15 +16,15 @@ 'use strict'; -const arrify = require('arrify'); +import * as arrify from 'arrify'; const chunk = require('lodash.chunk'); -const util = require('./util'); -const {promisify, promisifyAll} = require('@google-cloud/promisify'); +import * as util from './util'; +import {promisify, promisifyAll} from '@google-cloud/promisify'; const delay = require('delay'); -const {EventEmitter} = require('events'); -const extend = require('extend'); -const is = require('is'); -const os = require('os'); +import {EventEmitter} from 'events'; +import * as extend from 'extend'; +import * as is from 'is'; +import * as os from 'os'; const ConnectionPool = require('./connection-pool'); const Histogram = require('./histogram'); @@ -45,6 +45,23 @@ const MAX_ACK_IDS_PER_REQUEST = 3000; * @param {object} options Configuration object. */ class Subscriber extends EventEmitter { + histogram; + latency_; + connectionPool; + ackDeadline; + maxConnections; + inventory_; + flowControl; + batching; + flushTimeoutHandle_; + leaseTimeoutHandle_; + userClosed_; + isOpen; + messageListeners; + writeToStreams_; + request; + name; + constructor(options) { super(); options = options || {}; @@ -111,7 +128,7 @@ class Subscriber extends EventEmitter { * @param {string} [connId] Connection ID to send request on. * @return {Promise} */ - acknowledge_(ackIds, connId) { + acknowledge_(ackIds: string|string[], connId?: string): Promise { ackIds = arrify(ackIds); const promises = chunk(ackIds, MAX_ACK_IDS_PER_REQUEST).map(ackIdChunk => { if (this.writeToStreams_ && this.isConnected_()) { @@ -195,7 +212,7 @@ class Subscriber extends EventEmitter { * @param {function} [callback] The callback function. * @param {?error} err An error returned from this request. */ - closeConnection_(callback) { + closeConnection_(callback?) { this.isOpen = false; if (this.connectionPool) { this.connectionPool.close(callback || util.noop); @@ -215,7 +232,7 @@ class Subscriber extends EventEmitter { * * @private */ - flushQueues_() { + flushQueues_(): Promise { if (this.flushTimeoutHandle_) { this.flushTimeoutHandle_.clear(); this.flushTimeoutHandle_ = null; @@ -225,7 +242,7 @@ class Subscriber extends EventEmitter { if (!acks.length && !nacks.length) { return Promise.resolve(); } - const requests = []; + const requests: Promise[] = []; if (acks.length) { requests.push( this.acknowledge_(acks).then(() => { @@ -325,7 +342,7 @@ class Subscriber extends EventEmitter { * @param {string=} connId Connection ID to send request on. * @return {Promise} */ - modifyAckDeadline_(ackIds, deadline, connId) { + modifyAckDeadline_(ackIds: string|string[], deadline: number, connId?: string) { ackIds = arrify(ackIds); const promises = chunk(ackIds, MAX_ACK_IDS_PER_REQUEST).map(ackIdChunk => { if (this.writeToStreams_ && this.isConnected_()) { diff --git a/src/subscription.js b/src/subscription.ts similarity index 99% rename from src/subscription.js rename to src/subscription.ts index 823933a97..e2778ae16 100644 --- a/src/subscription.js +++ b/src/subscription.ts @@ -16,10 +16,10 @@ 'use strict'; -const util = require('./util'); -const {promisifyAll} = require('@google-cloud/promisify'); -const extend = require('extend'); -const is = require('is'); +import * as util from './util'; +import {promisifyAll} from '@google-cloud/promisify'; +import * as extend from 'extend'; +import * as is from 'is'; const snakeCase = require('lodash.snakecase'); const IAM = require('./iam'); @@ -458,7 +458,7 @@ class Subscription extends Subscriber { * const apiResponse = data[0]; * }); */ - getMetadata(gaxOpts, callback) { + getMetadata(gaxOpts, callback?) { if (is.fn(gaxOpts)) { callback = gaxOpts; gaxOpts = {}; @@ -589,7 +589,7 @@ class Subscription extends Subscriber { callback = gaxOpts; gaxOpts = {}; } - const reqOpts = { + const reqOpts: any = { subscription: this.name, }; if (is.string(snapshot)) { diff --git a/src/topic.js b/src/topic.ts similarity index 97% rename from src/topic.js rename to src/topic.ts index 99c7e0803..81fca0c61 100644 --- a/src/topic.js +++ b/src/topic.ts @@ -16,11 +16,11 @@ 'use strict'; -const util = require('./util'); -const {promisifyAll} = require('@google-cloud/promisify'); -const {paginator} = require('@google-cloud/paginator'); -const extend = require('extend'); -const is = require('is'); +import * as util from './util'; +import {promisifyAll} from '@google-cloud/promisify'; +import {paginator} from '@google-cloud/paginator'; +import * as extend from 'extend'; +import * as is from 'is'; const IAM = require('./iam'); const Publisher = require('./publisher'); @@ -39,6 +39,13 @@ const Publisher = require('./publisher'); * const topic = pubsub.topic('my-topic'); */ class Topic { + Promise; + name; + parent; + pubsub; + request; + iam; + metadata; constructor(pubsub, name) { if (pubsub.Promise) { this.Promise = pubsub.Promise; @@ -354,7 +361,7 @@ class Topic { * const apiResponse = data[0]; * }); */ - getMetadata(gaxOpts, callback) { + getMetadata(gaxOpts, callback?) { if (is.fn(gaxOpts)) { callback = gaxOpts; gaxOpts = {}; @@ -520,7 +527,7 @@ class Topic { * // message.publishTime = Timestamp when Pub/Sub received the message. * }); */ - subscription(name, options) { + subscription(name, options?) { options = options || {}; options.topic = this; return this.pubsub.subscription(name, options); @@ -575,7 +582,7 @@ class Topic { * this.end(); * }); */ -Topic.prototype.getSubscriptionsStream = paginator.streamify( +(Topic.prototype as any).getSubscriptionsStream = paginator.streamify( 'getSubscriptions' ); diff --git a/src/util.js b/src/util.ts similarity index 88% rename from src/util.js rename to src/util.ts index 8607c40fb..189d0a7a1 100644 --- a/src/util.js +++ b/src/util.ts @@ -14,10 +14,4 @@ * limitations under the License. */ -'use strict'; - -const util = { - noop: function() {}, -}; - -module.exports = util; +export function noop() {}; diff --git a/src/v1/publisher_client.js b/src/v1/publisher_client.js index 345d08cda..174146ae3 100644 --- a/src/v1/publisher_client.js +++ b/src/v1/publisher_client.js @@ -20,7 +20,7 @@ const merge = require('lodash.merge'); const path = require('path'); const protobuf = require('protobufjs'); -const VERSION = require('../../package.json').version; +const VERSION = require('../../../package.json').version; /** * The service that an application uses to manipulate topics, and to send diff --git a/src/v1/subscriber_client.js b/src/v1/subscriber_client.js index 8cf34a1fb..010017acd 100644 --- a/src/v1/subscriber_client.js +++ b/src/v1/subscriber_client.js @@ -19,7 +19,7 @@ const gax = require('google-gax'); const merge = require('lodash.merge'); const path = require('path'); -const VERSION = require('../../package.json').version; +const VERSION = require('../../../package.json').version; /** * The service that an application uses to manipulate subscriptions and to diff --git a/synth.py b/synth.py index 183411448..4a00aefa4 100644 --- a/synth.py +++ b/synth.py @@ -18,10 +18,9 @@ library, excludes=['package.json', 'README.md', 'src/index.js']) -templates = common_templates.node_library(package_name="@google-cloud/pubsub") +templates = common_templates.node_library(source_location='build/src') s.copy(templates) - # https://github.com/googleapis/gapic-generator/issues/2127 s.replace("src/v1/subscriber_client.js", " }\n\s*/\*\*\n\s+\* The DNS address for this API service.", @@ -34,7 +33,10 @@ " };\n" "\g<0>") +# Update path discovery due to build/ dir and TypeScript conversion. +s.replace("src/v1/publisher_client.js", "../../package.json", "../../../package.json") +s.replace("src/v1/subscriber_client.js", "../../package.json", "../../../package.json") + # Node.js specific cleanup subprocess.run(['npm', 'install']) -subprocess.run(['npm', 'run', 'prettier']) -subprocess.run(['npm', 'run', 'lint']) +subprocess.run(['npm', 'run', 'fix']) diff --git a/system-test/pubsub.js b/system-test/pubsub.ts similarity index 98% rename from system-test/pubsub.js rename to system-test/pubsub.ts index cacc2e3f2..89439fd9a 100644 --- a/system-test/pubsub.js +++ b/system-test/pubsub.ts @@ -16,12 +16,12 @@ 'use strict'; -const assert = require('assert'); +import * as assert from 'assert'; const async = require('async'); const Subscription = require('../src/subscription.js'); -const uuid = require('uuid'); +import * as uuid from 'uuid'; -const PubSub = require('../'); +const PubSub = require('../src'); const pubsub = new PubSub(); describe('pubsub', function() { @@ -135,7 +135,7 @@ describe('pubsub', function() { }); it('should list topics in a stream', function(done) { - const topicsEmitted = []; + const topicsEmitted: any[] = []; pubsub .getTopicsStream() @@ -162,7 +162,7 @@ describe('pubsub', function() { }, function(err, topics) { assert.ifError(err); - assert(topics.length, TOPIC_NAMES.length - 1); + assert.strictEqual(topics.length, TOPIC_NAMES.length - 1); done(); } ); @@ -330,7 +330,7 @@ describe('pubsub', function() { }); it('should list all topic subscriptions as a stream', function(done) { - const subscriptionsEmitted = []; + const subscriptionsEmitted: {}[] = []; topic .getSubscriptionsStream() @@ -650,7 +650,7 @@ describe('pubsub', function() { }); it('should get a list of snapshots as a stream', function(done) { - const snapshots = []; + const snapshots: any[] = []; pubsub .getSnapshotsStream() diff --git a/test/connection-pool.js b/test/connection-pool.ts similarity index 95% rename from test/connection-pool.js rename to test/connection-pool.ts index 4556397f4..6d450e8cd 100644 --- a/test/connection-pool.js +++ b/test/connection-pool.ts @@ -14,21 +14,31 @@ * limitations under the License. */ -'use strict'; - -const assert = require('assert'); -const util = require('../src/util'); +import * as assert from 'assert'; +import * as util from '../src/util'; const duplexify = require('duplexify'); -const {EventEmitter} = require('events'); -const extend = require('extend'); -const proxyquire = require('proxyquire'); -const uuid = require('uuid'); -const pjy = require('@google-cloud/projectify'); +import {EventEmitter} from 'events'; +import * as extend from 'extend'; +import * as proxyquire from 'proxyquire'; +import * as uuid from 'uuid'; +import * as pjy from '@google-cloud/projectify'; +import * as sinon from 'sinon'; + +let noopOverride: Function|null = null; +const fakeUtil = { + noop: (...args) => { + (noopOverride || util.noop).apply(null, args); + } +}; -const fakeUtil = extend({}, util); const fakeUuid = extend({}, uuid); class FakeConnection extends EventEmitter { + isConnected; + isPaused; + ended; + canceled; + written; constructor() { super(); this.isConnected = false; @@ -66,7 +76,7 @@ class FakeConnection extends EventEmitter { } } -let duplexifyOverride = null; +let duplexifyOverride: Function|null = null; function fakeDuplexify() { const args = [].slice.call(arguments); return (duplexifyOverride || duplexify).apply(null, args); @@ -78,22 +88,23 @@ describe('ConnectionPool', function() { let fakeConnection; let fakeChannel; let fakeClient; + let sandbox: sinon.SinonSandbox; const FAKE_PUBSUB_OPTIONS = {}; const PROJECT_ID = 'grapce-spacheship-123'; - const PUBSUB = { + const PUBSUB: any = { auth: { - getAuthClient: fakeUtil.noop, + getAuthClient: util.noop, }, options: FAKE_PUBSUB_OPTIONS, }; const SUB_NAME = 'test-subscription'; - const SUBSCRIPTION = { + const SUBSCRIPTION: any = { name: SUB_NAME, pubsub: PUBSUB, - request: fakeUtil.noop, + request: util.noop, }; let pjyOverride; @@ -113,6 +124,7 @@ describe('ConnectionPool', function() { }); beforeEach(function() { + sandbox = sinon.createSandbox(); fakeConnection = new FakeConnection(); duplexifyOverride = null; @@ -132,8 +144,8 @@ describe('ConnectionPool', function() { waitForReady: function() {}, }; - SUBSCRIPTION.request = fakeUtil.noop; - PUBSUB.auth.getAuthClient = fakeUtil.noop; + SUBSCRIPTION.request = util.noop; + PUBSUB.auth.getAuthClient = util.noop; PUBSUB.getClient_ = function(config, callback) { callback(null, fakeClient); }; @@ -147,15 +159,14 @@ describe('ConnectionPool', function() { if (pool.isOpen) { pool.close(); } + noopOverride = null; + sandbox.restore(); }); describe('initialization', function() { it('should initialize internally used properties', function() { - const open = ConnectionPool.prototype.open; - ConnectionPool.prototype.open = fakeUtil.noop; - + sandbox.stub(ConnectionPool.prototype, 'open').returns(undefined); const pool = new ConnectionPool(SUBSCRIPTION); - assert.strictEqual(pool.subscription, SUBSCRIPTION); assert.strictEqual(pool.pubsub, SUBSCRIPTION.pubsub); assert(pool.connections instanceof Map); @@ -167,8 +178,6 @@ describe('ConnectionPool', function() { assert.strictEqual(pool.settings.maxConnections, 5); assert.strictEqual(pool.settings.ackDeadline, 10000); assert.deepStrictEqual(pool.queue, []); - - ConnectionPool.prototype.open = open; }); it('should respect user specified settings', function() { @@ -275,7 +284,7 @@ describe('ConnectionPool', function() { }); beforeEach(function() { - global.clearTimeout = global.clearInterval = fakeUtil.noop; + global.clearTimeout = global.clearInterval = util.noop; }); afterEach(function() { @@ -394,10 +403,7 @@ describe('ConnectionPool', function() { }); it('should use noop when callback is omitted', function(done) { - fakeUtil.noop = function() { - fakeUtil.noop = function() {}; - done(); - }; + noopOverride = done; pool.close(); }); }); @@ -426,7 +432,7 @@ describe('ConnectionPool', function() { }, }; - fakeClient.waitForReady = fakeUtil.noop; + fakeClient.waitForReady = util.noop; pool.getClient = function(callback) { pool.pubsub = { @@ -565,7 +571,7 @@ describe('ConnectionPool', function() { it('should unpack the recieved messages', function(done) { const fakeDuplex = new FakeConnection(); - const pipedMessages = []; + const pipedMessages: {}[] = []; const fakeResp = { receivedMessages: [{}, {}, {}, {}, null], }; @@ -826,7 +832,7 @@ describe('ConnectionPool', function() { it('should capture the message data', function() { const expectedPublishTime = new Date( - parseInt(PT.seconds, 10) * 1000 + parseInt(PT.nanos, 10) / 1e6 + Math.floor(PT.seconds) * 1000 + Math.floor(PT.nanos) / 1e6 ); assert.strictEqual(message.ackId, RESP.ackId); @@ -871,9 +877,9 @@ describe('ConnectionPool', function() { let fakeChannelState; let dateNow; let fakeTimestamp; - const fakeChannel = {}; + const fakeChannel: any = {}; - const fakeClient = { + const fakeClient: any = { getChannel: function() { return fakeChannel; }, @@ -889,7 +895,7 @@ describe('ConnectionPool', function() { }; fakeChannelState = 0; - fakeClient.waitForReady = fakeUtil.noop; + fakeClient.waitForReady = util.noop; pool.getClient = function(callback) { callback(null, fakeClient); @@ -961,7 +967,7 @@ describe('ConnectionPool', function() { }); pool.getAndEmitChannelState(); - fakeClient.waitForReady = fakeUtil.noop; + fakeClient.waitForReady = util.noop; }); it('should wait for the channel to be ready', function(done) { @@ -1107,7 +1113,7 @@ describe('ConnectionPool', function() { describe('open', function() { beforeEach(function() { - pool.queueConnection = fakeUtil.noop; + pool.queueConnection = util.noop; clearInterval(pool.keepAliveHandle); }); @@ -1188,7 +1194,7 @@ describe('ConnectionPool', function() { pool.subscription = {writeToStreams_: false}; pool.sendKeepAlives = done; - global.setInterval = function(fn, interval) { + (global as any).setInterval = function(fn, interval) { global.setInterval = _setInterval; assert.strictEqual(interval, 30000); @@ -1237,7 +1243,7 @@ describe('ConnectionPool', function() { _open = ConnectionPool.prototype.open; // prevent open from calling queueConnection - ConnectionPool.prototype.open = fakeUtil.noop; + ConnectionPool.prototype.open = util.noop; }); beforeEach(function() { @@ -1245,13 +1251,13 @@ describe('ConnectionPool', function() { return 1; }; - global.setTimeout = function(cb) { + (global as any).setTimeout = function(cb) { cb(); return fakeTimeoutHandle; }; pool.failedConnectionAttempts = 0; - pool.createConnection = fakeUtil.noop; + pool.createConnection = util.noop; }); after(function() { @@ -1263,7 +1269,7 @@ describe('ConnectionPool', function() { it('should set a timeout to create the connection', function(done) { pool.createConnection = done; - global.setTimeout = function(cb, delay) { + (global as any).setTimeout = function(cb, delay) { assert.strictEqual(delay, 0); cb(); // should call the done fn }; @@ -1275,7 +1281,7 @@ describe('ConnectionPool', function() { pool.createConnection = done; pool.failedConnectionAttempts = 3; - global.setTimeout = function(cb, delay) { + (global as any).setTimeout = function(cb, delay) { assert.strictEqual(delay, 9000); cb(); // should call the done fn }; diff --git a/test/gapic-v1.js b/test/gapic-v1.ts similarity index 99% rename from test/gapic-v1.js rename to test/gapic-v1.ts index e5a2b357e..513fd15c4 100644 --- a/test/gapic-v1.js +++ b/test/gapic-v1.ts @@ -14,14 +14,14 @@ 'use strict'; -const assert = require('assert'); +import * as assert from 'assert'; const through2 = require('through2'); const pubsubModule = require('../src'); const FAKE_STATUS_CODE = 1; const error = new Error(); -error.code = FAKE_STATUS_CODE; +(error as any).code = FAKE_STATUS_CODE; describe('PublisherClient', () => { describe('createTopic', () => { @@ -1872,7 +1872,7 @@ describe('SubscriberClient', () => { }); }); -function mockSimpleGrpcMethod(expectedRequest, response, error) { +function mockSimpleGrpcMethod(expectedRequest, response?, error?) { return function(actualRequest, options, callback) { assert.deepStrictEqual(actualRequest, expectedRequest); if (error) { @@ -1885,7 +1885,7 @@ function mockSimpleGrpcMethod(expectedRequest, response, error) { }; } -function mockBidiStreamingGrpcMethod(expectedRequest, response, error) { +function mockBidiStreamingGrpcMethod(expectedRequest, response, error?) { return () => { const mockStream = through2.obj((chunk, enc, callback) => { assert.deepStrictEqual(chunk, expectedRequest); diff --git a/test/histogram.js b/test/histogram.ts similarity index 98% rename from test/histogram.js rename to test/histogram.ts index ccac664c7..11e48ba29 100644 --- a/test/histogram.js +++ b/test/histogram.ts @@ -16,7 +16,7 @@ 'use strict'; -const assert = require('assert'); +import * as assert from 'assert'; const Histogram = require('../src/histogram.js'); @@ -105,7 +105,7 @@ describe('Histogram', function() { describe('percentile', function() { function range(a, b) { - const result = []; + const result: number[] = []; for (; a < b; a++) { result.push(a); diff --git a/test/iam.js b/test/iam.ts similarity index 98% rename from test/iam.js rename to test/iam.ts index 3589e1b9e..8d69a9aba 100644 --- a/test/iam.js +++ b/test/iam.ts @@ -16,10 +16,10 @@ 'use strict'; -const assert = require('assert'); -const extend = require('extend'); +import * as assert from 'assert'; +import * as extend from 'extend'; const proxyquire = require('proxyquire'); -const util = require('../src/util'); +import * as util from '../src/util'; const promisify = require('@google-cloud/promisify'); let promisified = false; diff --git a/test/index.js b/test/index.ts similarity index 97% rename from test/index.js rename to test/index.ts index ba1d00f7b..10da3385f 100644 --- a/test/index.js +++ b/test/index.ts @@ -16,16 +16,16 @@ 'use strict'; -const arrify = require('arrify'); -const assert = require('assert'); -const extend = require('extend'); -const gax = require('google-gax'); -const proxyquire = require('proxyquire'); -const util = require('../src/util'); -const pjy = require('@google-cloud/projectify'); -const promisify = require('@google-cloud/promisify'); +import * as arrify from 'arrify'; +import * as assert from 'assert'; +import * as extend from 'extend'; +import * as gax from 'google-gax'; +import * as proxyquire from 'proxyquire'; +import * as util from '../src/util'; +import * as pjy from '@google-cloud/projectify'; +import * as promisify from '@google-cloud/promisify'; -const PKG = require('../package.json'); +const PKG = require('../../package.json'); const fakeCreds = {}; const fakeGoogleGax = { @@ -38,12 +38,12 @@ const fakeGoogleGax = { return fakeCreds; }, }, - }; + } as gax.GrpcModule; } }, }; -const SubscriptionCached = require('../src/subscription.js'); +const SubscriptionCached = require('../src/subscription'); let SubscriptionOverride; function Subscription(a, b, c) { @@ -109,7 +109,7 @@ function fakeGoogleAuth() { } const v1Override = {}; -let v1ClientOverrides = {}; +let v1ClientOverrides: any = {}; function defineOverridableClient(clientName) { function DefaultClient() {} @@ -139,7 +139,7 @@ describe('PubSub', function() { before(function() { delete process.env.PUBSUB_EMULATOR_HOST; - PubSub = proxyquire('../', { + PubSub = proxyquire('../src', { '@google-cloud/paginator': { paginator: fakePaginator, }, @@ -297,7 +297,7 @@ describe('PubSub', function() { }; beforeEach(function() { - Subscription.formatMetadata_ = function(metadata) { + (Subscription as any).formatMetadata_ = function(metadata) { return extend({}, metadata); }; }); @@ -458,7 +458,7 @@ describe('PubSub', function() { a: 'a', }; - Subscription.formatMetadata_ = function(metadata) { + (Subscription as any).formatMetadata_ = function(metadata) { assert.strictEqual(metadata, fakeMetadata); return formatted; }; @@ -1028,7 +1028,7 @@ describe('PubSub', function() { it('should call client method with correct options', function(done) { const fakeClient = {}; - fakeClient.fakeMethod = function(reqOpts, gaxOpts) { + (fakeClient as any).fakeMethod = function(reqOpts, gaxOpts) { assert.deepStrictEqual(CONFIG.reqOpts, reqOpts); assert.deepStrictEqual(CONFIG.gaxOpts, gaxOpts); done(); @@ -1050,7 +1050,7 @@ describe('PubSub', function() { }); describe('getClient_', function() { - const FAKE_CLIENT_INSTANCE = util.noop; + const FAKE_CLIENT_INSTANCE = class {}; const CONFIG = { client: 'FakeClient', }; diff --git a/test/mocha.opts b/test/mocha.opts index 8751e7bae..48bf1c3df 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1,3 +1,4 @@ +--require source-map-support/register --require intelli-espower-loader --timeout 10000 --throw-deprecation diff --git a/test/publisher.js b/test/publisher.ts similarity index 97% rename from test/publisher.js rename to test/publisher.ts index a63e4e50c..16d0e8b60 100644 --- a/test/publisher.js +++ b/test/publisher.ts @@ -16,10 +16,10 @@ 'use strict'; -const assert = require('assert'); -const util = require('../src/util'); +import * as assert from 'assert'; +import * as util from '../src/util'; const pfy = require('@google-cloud/promisify'); -const extend = require('extend'); +import * as extend from 'extend'; const proxyquire = require('proxyquire'); let promisified = false; @@ -38,7 +38,7 @@ describe('Publisher', function() { let batchOpts; const TOPIC_NAME = 'test-topic'; - const TOPIC = { + const TOPIC: any = { name: TOPIC_NAME, Promise: {}, request: util.noop, @@ -143,7 +143,7 @@ describe('Publisher', function() { beforeEach(function() { publisher.publish_ = util.noop; - global.setTimeout = util.noop; + (global as any).setTimeout = util.noop; }); after(function() { @@ -211,7 +211,7 @@ All attributes must be in the form of a string. }); it('should not attempt to publish empty payload if data puts payload above size cap', function(done) { - const pushRequests = []; + const pushRequests: {}[] = []; publisher.settings.batching.maxBytes = 2; publisher.inventory_.bytes = 0; @@ -266,7 +266,7 @@ All attributes must be in the form of a string. const globalSetTimeout = global.setTimeout; const fakeTimeoutHandle = 12345; - global.setTimeout = function(callback, duration) { + (global as any).setTimeout = function(callback, duration) { assert.strictEqual(duration, batchOpts.maxMilliseconds); global.setTimeout = globalSetTimeout; setImmediate(callback); diff --git a/test/snapshot.js b/test/snapshot.ts similarity index 93% rename from test/snapshot.js rename to test/snapshot.ts index ecdd45c67..50ad5064d 100644 --- a/test/snapshot.js +++ b/test/snapshot.ts @@ -16,11 +16,12 @@ 'use strict'; -const assert = require('assert'); -const util = require('../src/util'); -const extend = require('extend'); -const proxyquire = require('proxyquire'); -const pfy = require('@google-cloud/promisify'); +import * as assert from 'assert'; +import * as util from '../src/util'; +import * as extend from 'extend'; +import * as proxyquire from 'proxyquire'; +import * as pfy from '@google-cloud/promisify'; +import * as sinon from 'sinon'; let promisified = false; const fakePromisify = extend({}, pfy, { @@ -42,7 +43,7 @@ describe('Snapshot', function() { projectId: PROJECT_ID, }; - const SUBSCRIPTION = { + const SUBSCRIPTION: any = { Promise: {}, projectId: PROJECT_ID, pubsub: PUBSUB, @@ -57,10 +58,11 @@ describe('Snapshot', function() { }); }); + const sandbox = sinon.createSandbox(); beforeEach(function() { - util.noop = function() {}; snapshot = new Snapshot(SUBSCRIPTION, SNAPSHOT_NAME); }); + afterEach(() => sandbox.restore()); describe('initialization', function() { const FULL_SNAPSHOT_NAME = 'a/b/c/d'; @@ -179,12 +181,10 @@ describe('Snapshot', function() { }); it('should optionally accept a callback', function(done) { - util.noop = done; - + sandbox.stub(util, 'noop').callsFake(done); snapshot.parent.request = function(config, callback) { callback(); // the done fn }; - snapshot.delete(); }); }); diff --git a/test/subscriber.js b/test/subscriber.ts similarity index 98% rename from test/subscriber.js rename to test/subscriber.ts index edb8def8e..03be3fdde 100644 --- a/test/subscriber.js +++ b/test/subscriber.ts @@ -16,13 +16,13 @@ 'use strict'; -const assert = require('assert'); +import * as assert from 'assert'; const delay = require('delay'); -const {EventEmitter} = require('events'); -const extend = require('extend'); -const is = require('is'); +import {EventEmitter} from 'events'; +import * as extend from 'extend'; +import * as is from 'is'; const proxyquire = require('proxyquire'); -const util = require('../src/util'); +import * as util from '../src/util'; const pfy = require('@google-cloud/promisify'); const fakeUtil = extend({}, util); @@ -33,8 +33,8 @@ function fakePromisify() { } let promisified = false; -function fakePromisifyAll(Class) { - if (Class.name === 'Subscriber') { +function fakePromisifyAll(klass) { + if (klass.name === 'Subscriber') { promisified = true; } } @@ -47,6 +47,7 @@ const fakeOs = { }; class FakeConnectionPool extends EventEmitter { + calledWith_: IArguments; constructor() { super(); this.calledWith_ = [].slice.call(arguments); @@ -57,7 +58,7 @@ function FakeHistogram() { this.calledWith_ = [].slice.call(arguments); } -let delayOverride = null; +let delayOverride: any = null; function fakeDelay(timeout) { return (delayOverride || delay)(timeout); @@ -1337,7 +1338,7 @@ describe('Subscriber', function() { return fakeRandom; }; - global.setTimeout = function(callback, duration) { + (global as any).setTimeout = function(callback, duration) { assert.strictEqual(duration, fakeRandom * ackDeadline * 0.9); setImmediate(callback); // the done fn return fakeTimeoutHandle; @@ -1362,7 +1363,7 @@ describe('Subscriber', function() { return fakeRandom; }; - global.setTimeout = function(callback, duration) { + (global as any).setTimeout = function(callback, duration) { assert.strictEqual(duration, fakeRandom * ackDeadline * 0.9 - latency); done(); }; @@ -1407,7 +1408,7 @@ describe('Subscriber', function() { describe('writeTo_', function() { const CONNECTION_ID = 'abc'; - const CONNECTION = {}; + const CONNECTION: any = {}; beforeEach(function() { subscriber.connectionPool = { diff --git a/test/subscription.js b/test/subscription.ts similarity index 95% rename from test/subscription.js rename to test/subscription.ts index a1b7e66ee..37b5d082c 100644 --- a/test/subscription.js +++ b/test/subscription.ts @@ -16,19 +16,19 @@ 'use strict'; -const assert = require('assert'); -const util = require('../src/util'); -const extend = require('extend'); -const proxyquire = require('proxyquire'); -const pfy = require('@google-cloud/promisify'); +import * as assert from 'assert'; +import * as util from '../src/util'; +import * as extend from 'extend'; +import * as proxyquire from 'proxyquire'; +import * as pfy from '@google-cloud/promisify'; +import * as sinon from 'sinon'; let promisified = false; const fakePromisify = extend({}, pfy, { - promisifyAll: function(Class, options) { - if (Class.name !== 'Subscription') { + promisifyAll: (klass, options) => { + if (klass.name !== 'Subscription') { return; } - promisified = true; assert.deepStrictEqual(options.exclude, ['snapshot']); }, @@ -38,8 +38,12 @@ function FakeIAM() { this.calledWith_ = [].slice.call(arguments); } -function FakeSnapshot() { - this.calledWith_ = [].slice.call(arguments); +class FakeSnapshot { + calledWith_: IArguments; + static formatName_?: Function; + constructor() { + this.calledWith_ = [].slice.call(arguments); + } } function FakeSubscriber() { @@ -47,14 +51,17 @@ function FakeSubscriber() { } describe('Subscription', function() { - let Subscription; - let subscription; + // tslint:disable-next-line no-any variable-name + let Subscription: any; + // tslint:disable-next-line no-any + let subscription: any; const PROJECT_ID = 'test-project'; const SUB_NAME = 'test-subscription'; const SUB_FULL_NAME = 'projects/' + PROJECT_ID + '/subscriptions/' + SUB_NAME; - const PUBSUB = { + // tslint:disable-next-line no-any + const PUBSUB: any = { projectId: PROJECT_ID, Promise: {}, request: util.noop, @@ -69,11 +76,14 @@ describe('Subscription', function() { }); }); + const sandbox = sinon.createSandbox(); beforeEach(function() { - PUBSUB.request = util.noop = function() {}; + PUBSUB.request = util.noop; subscription = new Subscription(PUBSUB, SUB_NAME); }); + afterEach(() => sandbox.restore()); + describe('initialization', function() { it('should promisify all the things', function() { assert(promisified); @@ -147,7 +157,7 @@ describe('Subscription', function() { const subscription = new Subscription(PUBSUB, SUB_NAME, options); assert(subscription instanceof FakeSubscriber); - assert(subscription.calledWith_[0], options); + assert.strictEqual(subscription.calledWith_[0], options); }); }); @@ -324,12 +334,11 @@ describe('Subscription', function() { }); it('should optionally accept a callback', function(done) { - util.noop = function(err, resp) { + sandbox.stub(util, 'noop').callsFake((err, resp) => { assert.ifError(err); assert.strictEqual(resp, apiResponse); done(); - }; - + }); subscription.delete(); }); diff --git a/test/topic.js b/test/topic.ts similarity index 95% rename from test/topic.js rename to test/topic.ts index f523e8214..652d06224 100644 --- a/test/topic.js +++ b/test/topic.ts @@ -16,16 +16,17 @@ 'use strict'; -const assert = require('assert'); -const extend = require('extend'); -const proxyquire = require('proxyquire'); -const util = require('../src/util'); -const pfy = require('@google-cloud/promisify'); +import * as assert from 'assert'; +import * as extend from 'extend'; +import * as proxyquire from 'proxyquire'; +import * as util from '../src/util'; +import * as pfy from '@google-cloud/promisify'; +import * as sinon from 'sinon'; let promisified = false; const fakePromisify = extend({}, pfy, { - promisifyAll: function(Class, options) { - if (Class.name !== 'Topic') { + promisifyAll: (klass, options) => { + if (klass.name !== 'Topic') { return; } promisified = true; @@ -57,14 +58,17 @@ const fakePaginator = { }; describe('Topic', function() { - let Topic; - let topic; + // tslint:disable-next-line no-any variable-name + let Topic: any; + // tslint:disable-next-line no-any + let topic: any; const PROJECT_ID = 'test-project'; const TOPIC_NAME = 'projects/' + PROJECT_ID + '/topics/test-topic'; const TOPIC_UNFORMATTED_NAME = TOPIC_NAME.split('/').pop(); - const PUBSUB = { + // tslint:disable-next-line no-any + const PUBSUB: any = { Promise: {}, projectId: PROJECT_ID, createTopic: util.noop, @@ -82,10 +86,12 @@ describe('Topic', function() { }); }); + const sandbox = sinon.createSandbox(); beforeEach(function() { topic = new Topic(PUBSUB, TOPIC_NAME); topic.parent = PUBSUB; }); + afterEach(() => sandbox.restore()); describe('initialization', function() { it('should extend the correct methods', function() { @@ -209,12 +215,10 @@ describe('Topic', function() { }); it('should optionally accept a callback', function(done) { - util.noop = done; - + sandbox.stub(util, 'noop').callsFake(done); topic.request = function(config, callback) { callback(); // the done fn }; - topic.delete(); }); }); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..2f66e4d86 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "./node_modules/gts/tsconfig-google.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "build", + "noImplicitAny": false, + "noImplicitThis": false + }, + "include": [ + "src/*.ts", + "test/*.ts", + "system-test/*.ts", + "smoke-test/*.ts" + ] +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 000000000..617dc975b --- /dev/null +++ b/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "gts/tslint.json" +}