From 7e5f66f1ba6051f85a5d9ae8e662ffec61f32ae1 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Tue, 25 Sep 2018 09:27:43 -0700 Subject: [PATCH] fix: improve the types (#114) --- packages/google-cloud-dns/src/change.ts | 10 +- packages/google-cloud-dns/src/index.ts | 13 +- packages/google-cloud-dns/src/record.ts | 38 +- packages/google-cloud-dns/src/zone.ts | 447 +++++++++++-------- packages/google-cloud-dns/system-test/dns.ts | 9 +- 5 files changed, 291 insertions(+), 226 deletions(-) diff --git a/packages/google-cloud-dns/src/change.ts b/packages/google-cloud-dns/src/change.ts index 8a8ef0a8bdc..62ac339ecd2 100644 --- a/packages/google-cloud-dns/src/change.ts +++ b/packages/google-cloud-dns/src/change.ts @@ -30,7 +30,7 @@ export interface CreateChangeRequest extends CreateOptions { export type CreateChangeResponse = [Change, r.Response]; -export interface ChangeCallback { +export interface CreateChangeCallback { (err: Error|null, change?: Change|null, apiResponse?: r.Response): void; } @@ -233,11 +233,11 @@ export class Change extends ServiceObject { * }); */ create(config?: CreateChangeRequest): Promise; - create(config: CreateChangeRequest, callback: ChangeCallback): void; - create(callback: ChangeCallback): void; + create(config: CreateChangeRequest, callback: CreateChangeCallback): void; + create(callback: CreateChangeCallback): void; create( - configOrCallback?: CreateChangeRequest|ChangeCallback, - callback?: ChangeCallback): void|Promise { + configOrCallback?: CreateChangeRequest|CreateChangeCallback, + callback?: CreateChangeCallback): void|Promise { const config = typeof configOrCallback === 'object' ? configOrCallback : {}; callback = typeof configOrCallback === 'function' ? configOrCallback! : callback; diff --git a/packages/google-cloud-dns/src/index.ts b/packages/google-cloud-dns/src/index.ts index 6209c24ac2b..a8a58b1d30a 100644 --- a/packages/google-cloud-dns/src/index.ts +++ b/packages/google-cloud-dns/src/index.ts @@ -24,7 +24,7 @@ import {promisifyAll} from '@google-cloud/promisify'; import * as extend from 'extend'; import {teenyRequest} from 'teeny-request'; import {Zone} from './zone'; -import {Response} from 'request'; +import * as r from 'request'; export {Record, RecordMetadata} from './record'; export interface GetZonesRequest { @@ -41,13 +41,13 @@ export interface DNSConfig extends GoogleAuthOptions { export interface GetZonesCallback { (err: Error|null, zones: Zone[]|null, nextQuery?: GetZonesRequest|null, - apiResponse?: Response): void; + apiResponse?: r.Response): void; } -export type GetZonesResponse = [Zone[], GetZonesRequest | null, Response]; +export type GetZonesResponse = [Zone[], GetZonesRequest | null, r.Response]; export interface GetZoneCallback { - (err: Error|null, zone?: Zone|null, apiResponse?: Response): void; + (err: Error|null, zone?: Zone|null, apiResponse?: r.Response): void; } export interface CreateZoneRequest { @@ -56,7 +56,7 @@ export interface CreateZoneRequest { name?: string; } -export type CreateZoneResponse = [Zone, Response]; +export type CreateZoneResponse = [Zone, r.Response]; /** * @typedef {object} ClientConfig @@ -126,8 +126,7 @@ class DNS extends Service { 'https://www.googleapis.com/auth/cloud-platform', ], packageJson: require('../../package.json'), - // tslint:disable-next-line:no-any - requestModule: teenyRequest as any, + requestModule: teenyRequest as typeof r, }; super(config, options); diff --git a/packages/google-cloud-dns/src/record.ts b/packages/google-cloud-dns/src/record.ts index 7c052450659..cf6957476db 100644 --- a/packages/google-cloud-dns/src/record.ts +++ b/packages/google-cloud-dns/src/record.ts @@ -19,9 +19,10 @@ import * as arrify from 'arrify'; import {promisifyAll} from '@google-cloud/promisify'; import * as extend from 'extend'; -import {ChangeCallback} from './change'; +import {CreateChangeCallback, Change} from './change'; import {Zone} from './zone'; const format = require('string-format-obj'); +import * as r from 'request'; export interface RecordObject { rrdatas?: Array<{}>; @@ -38,6 +39,23 @@ export interface RecordMetadata { signatureRrdatas?: string[]; } +/** + * @typedef {array} DeleteRecordResponse + * @property {Change} 0 A {@link Change} object. + * @property {object} 1 The full API response. + */ +export type DeleteRecordResponse = [Change, r.Response]; + +/** + * @callback DeleteRecordCallback + * @param {?Error} err Request error, if any. + * @param {?Change} change A {@link Change} object. + * @param {object} apiResponse The full API response. + */ +export interface DeleteRecordCallback { + (err: Error|null, change?: Change, apiResponse?: r.Response): void; +} + /** * Create a Resource Record object. * @@ -95,17 +113,7 @@ export class Record implements RecordObject { delete this.rrdatas; } } - /** - * @typedef {array} DeleteRecordResponse - * @property {Change} 0 A {@link Change} object. - * @property {object} 1 The full API response. - */ - /** - * @callback DeleteRecordCallback - * @param {?Error} err Request error, if any. - * @param {?Change} change A {@link Change} object. - * @param {object} apiResponse The full API response. - */ + /** * Delete this record by creating a change on your zone. This is a convenience * method for: @@ -143,8 +151,10 @@ export class Record implements RecordObject { * const apiResponse = data[1]; * }); */ - delete(callback: ChangeCallback) { - this.zone_.deleteRecords(this, callback); + delete(): Promise; + delete(callback: CreateChangeCallback): void; + delete(callback?: CreateChangeCallback): void|Promise { + this.zone_.deleteRecords(this, callback!); } /** * Serialize the record instance to the format the API expects. diff --git a/packages/google-cloud-dns/src/zone.ts b/packages/google-cloud-dns/src/zone.ts index 6c653823e66..4520e5138cf 100644 --- a/packages/google-cloud-dns/src/zone.ts +++ b/packages/google-cloud-dns/src/zone.ts @@ -28,11 +28,108 @@ import * as is from 'is'; import {teenyRequest} from 'teeny-request'; const zonefile = require('dns-zonefile'); -import {Change, ChangeCallback, CreateChangeRequest} from './change'; +import {Change, CreateChangeCallback, CreateChangeRequest} from './change'; import {Record, RecordMetadata, RecordObject} from './record'; import {DNS} from '.'; import * as r from 'request'; +/** + * @typedef {array} ZoneDeleteRecordsResponse + * @property {Change} 0 A {@link Change} object. + * @property {object} 1 The full API response. + */ +export type ZoneDeleteRecordsResponse = [Change, r.Response]; + +/** + * @callback ZoneDeleteRecordsCallback + * @param {?Error} err Request error, if any. + * @param {?Change} change A {@link Change} object. + * @param {object} apiResponse The full API response. + */ +export interface ZoneDeleteRecordsCallback { + (err: Error|null, change?: Change|null, apiResponse?: r.Response): void; +} + +/** + * @typedef {array} ZoneReplaceRecordsResponse + * @property {Change} 0 A {@link Change} object. + * @property {object} 1 The full API response. + */ +export type ZoneReplaceRecordsResponse = [Change, r.Response]; + +/** + * @callback ZoneReplaceRecordsCallback + * @param {?Error} err Request error, if any. + * @param {?Change} change A {@link Change} object. + * @param {object} apiResponse The full API response. + */ +export interface ZoneReplaceRecordsCallback { + (err: Error|null, change?: Change, apiResponse?: r.Response): void; +} + +/** + * @typedef {array} DeleteZoneResponse + * @property {object} 0 The full API response. + */ +export type DeleteZoneResponse = [r.Response]; + +/** + * @callback DeleteZoneCallback + * @param {?Error} err Request error, if any. + * @param {object} apiResponse The full API response. + */ +export interface DeleteZoneCallback { + (err: Error|null, apiResponse?: r.Response): void; +} + +/** + * Config to set for the change. + * + * @typedef {object} CreateChangeRequest + * @property {Record|Record[]} add {@link Record} objects to add to this zone. + * @property {Record|Record[]} delete {@link Record} objects to delete + * from this zone. Be aware that the resource records here must match + * exactly to be deleted. + */ +export interface CreateChangeRequest { + add?: Record|Record[]; + delete?: Record|Record[]; +} + +/** + * @typedef {array} CreateChangeResponse + * @property {Change} 0 A {@link Change} object. + * @property {object} 1 The full API response. + */ +export type CreateChangeResponse = [Change, r.Response]; + +/** + * @callback CreateChangeCallback + * @param {?Error} err Request error, if any. + * @param {?Change} change A {@link Change} object. + * @param {object} apiResponse The full API response. + */ +export interface CreateChangeCallback { + (err: Error|null, change?: Change, apiResponse?: r.Response): void; +} + +/** + * @typedef {array} ZoneAddRecordsResponse + * @property {Change} 0 A {@link Change} object. + * @property {object} 1 The full API response. + */ +export type ZoneAddRecordsResponse = [Change, r.Response]; + +/** + * @callback ZoneAddRecordsCallback + * @param {?Error} err Request error, if any. + * @param {?Change} change A {@link Change} object. + * @param {object} apiResponse The full API response. + */ +export interface ZoneAddRecordsCallback { + (err: Error|null, change?: Change|null, apiResponse?: r.Response): void; +} + export interface DeleteZoneConfig { force?: boolean; } @@ -42,6 +139,8 @@ export interface GetRecordsCallback { apiResponse?: r.Response): void; } +export type GetRecordsResponse = [Record[], r.Response]; + export interface GetRecordsRequest { autoPaginate?: boolean; maxApiCalls?: number; @@ -253,17 +352,7 @@ class Zone extends ServiceObject { */ this.name = name; } - /** - * @typedef {array} ZoneAddRecordsResponse - * @property {Change} 0 A {@link Change} object. - * @property {object} 1 The full API response. - */ - /** - * @callback ZoneAddRecordsCallback - * @param {?Error} err Request error, if any. - * @param {?Change} change A {@link Change} object. - * @param {object} apiResponse The full API response. - */ + /** * Add records to this zone. This is a convenience wrapper around * {@link Zone#createChange}. @@ -274,7 +363,7 @@ class Zone extends ServiceObject { * @param {ZoneAddRecordsCallback} [callback] Callback function. * @returns {Promise} */ - addRecords(records: Record|Record[], callback: ChangeCallback) { + addRecords(records: Record|Record[], callback: ZoneAddRecordsCallback) { this.createChange({add: records}, callback); } /** @@ -292,27 +381,7 @@ class Zone extends ServiceObject { change(id?: string) { return new Change(this, id); } - /** - * Config to set for the change. - * - * @typedef {object} CreateChangeRequest - * @property {Record|Record[]} add {@link Record} objects to add to this - * zone. - * @property {Record|Record[]} delete {@link Record} objects to delete - * from this zone. Be aware that the resource records here must match - * exactly to be deleted. - */ - /** - * @typedef {array} CreateChangeResponse - * @property {Change} 0 A {@link Change} object. - * @property {object} 1 The full API response. - */ - /** - * @callback CreateChangeCallback - * @param {?Error} err Request error, if any. - * @param {?Change} change A {@link Change} object. - * @param {object} apiResponse The full API response. - */ + /** * Create a change of resource record sets for the zone. * @@ -358,7 +427,7 @@ class Zone extends ServiceObject { * const apiResponse = data[1]; * }); */ - createChange(config: CreateChangeRequest, callback: ChangeCallback) { + createChange(config: CreateChangeRequest, callback: CreateChangeCallback) { if (!config || (!config.add && !config.delete)) { throw new Error('Cannot create a change with no additions or deletions.'); } @@ -406,15 +475,7 @@ class Zone extends ServiceObject { callback(null, change, resp); }); } - /** - * @typedef {array} DeleteZoneResponse - * @property {object} 0 The full API response. - */ - /** - * @callback DeleteZoneCallback - * @param {?Error} err Request error, if any. - * @param {object} apiResponse The full API response. - */ + /** * Delete the zone. * @@ -475,17 +536,7 @@ class Zone extends ServiceObject { } super.delete(callback!); } - /** - * @typedef {array} ZoneDeleteRecordsResponse - * @property {Change} 0 A {@link Change} object. - * @property {object} 1 The full API response. - */ - /** - * @callback ZoneDeleteRecordsCallback - * @param {?Error} err Request error, if any. - * @param {?Change} change A {@link Change} object. - * @param {object} apiResponse The full API response. - */ + /** * Delete records from this zone. This is a convenience wrapper around * {@link Zone#createChange}. @@ -564,12 +615,16 @@ class Zone extends ServiceObject { * const apiResponse = data[1]; * }); */ - deleteRecords(callback: ChangeCallback): void; - deleteRecords(records: Record|Record[]|string, callback: ChangeCallback): - void; + deleteRecords(records?: Record|Record[]| + string): Promise; + deleteRecords(callback: ZoneDeleteRecordsCallback): void; + deleteRecords( + records: Record|Record[]|string, + callback: ZoneDeleteRecordsCallback): void; deleteRecords( - recordsOrCallback: Record|Record[]|string|ChangeCallback, - callback?: ChangeCallback): void { + recordsOrCallback?: Record|Record[]|string|ZoneDeleteRecordsCallback, + callback?: ZoneDeleteRecordsCallback): + void|Promise { let records: Array; if (typeof recordsOrCallback === 'function') { callback = recordsOrCallback; @@ -606,7 +661,7 @@ class Zone extends ServiceObject { * @param {ZoneEmptyCallback} [callback] Callback function. * @returns {Promise} */ - empty(callback: ChangeCallback) { + empty(callback: CreateChangeCallback) { this.getRecords((err, records) => { if (err) { callback(err); @@ -862,19 +917,21 @@ class Zone extends ServiceObject { * const records = data[0]; * }); */ + getRecords(query?: GetRecordsRequest|string| + string[]): Promise; getRecords(callback: GetRecordsCallback): void; getRecords( query: GetRecordsRequest|string|string[], callback: GetRecordsCallback): void; getRecords( - queryOrCallback: GetRecordsRequest|GetRecordsCallback|string|string[], - callback?: GetRecordsCallback): void { + queryOrCallback?: GetRecordsRequest|GetRecordsCallback|string|string[], + callback?: GetRecordsCallback): void|Promise { let query: string|string[]|GetRecordsRequest; if (typeof queryOrCallback === 'function') { callback = queryOrCallback; query = []; } else { - query = queryOrCallback; + query = queryOrCallback!; } if (is.string(query) || is.array(query)) { @@ -916,48 +973,47 @@ class Zone extends ServiceObject { callback!(null, records, nextQuery, resp); }); } - /** - * @typedef {array} ZoneImportResponse - * @property {Change} 0 A {@link Change} object. - * @property {object} 1 The full API response. - */ - /** - * @callback ZoneImportCallback - * @param {?Error} err Request error, if any. - * @param {?Change} change A {@link Change} object. - * @param {object} apiResponse The full API response. - */ - /** - * Copy the records from a zone file into this zone. - * - * @see [ManagedZones: create API Documentation]{@link https://cloud.google.com/dns/api/v1/managedZones/create} - * - * @param {string} localPath The fully qualified path to the zone file. - * @param {ZoneImportCallback} [callback] Callback function. - * @returns {Promise} - * @example - * const {DNS} = require('@google-cloud/dns'); - * const dns = new DNS(); - * const zone = dns.zone('zone-id'); - * - * const zoneFilename = '/Users/dave/zonefile.zone'; - * - * zone.import(zoneFilename, (err, change, apiResponse) => { - * if (!err) { - * // The change was created successfully. - * } - * }); - * - * //- - * // If the callback is omitted, we'll return a Promise. - * //- - * zone.import(zoneFilename).then(data => { - * const change = data[0]; - * const apiResponse = data[1]; - * }); - */ - import(localPath: string, callback: ChangeCallback) { - fs.readFile(localPath, 'utf-8', (err, file) => { +/** + * @typedef {array} ZoneImportResponse + * @property {Change} 0 A {@link Change} object. + * @property {object} 1 The full API response. + */ +/** + * @callback ZoneImportCallback + * @param {?Error} err Request error, if any. + * @param {?Change} change A {@link Change} object. + * @param {object} apiResponse The full API response. + */ +/** + * Copy the records from a zone file into this zone. + * + * @see [ManagedZones: create API Documentation]{@link https://cloud.google.com/dns/api/v1/managedZones/create} + * + * @param {string} localPath The fully qualified path to the zone file. + * @param {ZoneImportCallback} [callback] Callback function. + * @returns {Promise} + * @example + * const {DNS} = require('@google-cloud/dns'); + * const dns = new DNS(); + * const zone = dns.zone('zone-id'); + * + * const zoneFilename = '/Users/dave/zonefile.zone'; + * + * zone.import(zoneFilename, (err, change, apiResponse) => { + * if (!err) { + * // The change was created successfully. + * } + * }); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * zone.import(zoneFilename).then(data => { + * const change = data[0]; + * const apiResponse = data[1]; + * }); + */ +import(localPath: string, callback: CreateChangeCallback) {fs.readFile(localPath, 'utf-8', (err, file) => { if (err) { callback(err); return; @@ -975,8 +1031,7 @@ class Zone extends ServiceObject { }); }); this.addRecords(recordsToCreate, callback); - }); - } + });} /** * A {@link Record} object can be used to construct a record you want to * add to your zone, or to refer to an existing one. @@ -1029,20 +1084,8 @@ class Zone extends ServiceObject { * delete: oldARecord * }, (err, change, apiResponse) => {}); */ - record(type: string, metadata: RecordMetadata) { - return new Record(this, type, metadata); - } - /** - * @typedef {array} ZoneReplaceRecordsResponse - * @property {Change} 0 A {@link Change} object. - * @property {object} 1 The full API response. - */ - /** - * @callback ZoneReplaceRecordsCallback - * @param {?Error} err Request error, if any. - * @param {?Change} change A {@link Change} object. - * @param {object} apiResponse The full API response. - */ + record(type: string, metadata: RecordMetadata) {return new Record(this, type, metadata);} + /** * Provide a record type that should be deleted and replaced with other records. * @@ -1095,20 +1138,28 @@ class Zone extends ServiceObject { * const apiResponse = data[1]; * }); */ - replaceRecords(recordType: string|string[], newRecords: Record|Record[], callback: ChangeCallback) { + replaceRecords(recordType: string|string[], newRecords: Record|Record[]): Promise; + replaceRecords( + recordType: string|string[], newRecords: Record|Record[], + callback: CreateChangeCallback): void; + replaceRecords( + recordType: string|string[], newRecords: Record|Record[], + callback?: CreateChangeCallback): + void|Promise { this.getRecords(recordType, (err, recordsToDelete) => { - if (err) { - callback(err); - return; - } - this.createChange( - { - add: newRecords, - delete: recordsToDelete!, - }, - callback); + if (err) { + callback!(err); + return; + } + this.createChange( + { + add: newRecords, + delete: recordsToDelete!, + }, + callback!); }); } + /** * Delete records from the zone matching an array of types. * @@ -1127,17 +1178,23 @@ class Zone extends ServiceObject { * } * }); */ - deleteRecordsByType_(recordTypes: string[], callback: ChangeCallback) { + deleteRecordsByType_(recordTypes: string[]): + Promise; + deleteRecordsByType_( + recordTypes: string[], callback: ZoneDeleteRecordsCallback): void; + deleteRecordsByType_( + recordTypes: string[], callback?: ZoneDeleteRecordsCallback): + void|Promise { this.getRecords(recordTypes, (err, records) => { - if (err) { - callback(err); - return; - } - if (records!.length === 0) { - callback(null); - return; - } - this.deleteRecords(records!, callback); + if (err) { + callback!(err); + return; + } + if (records!.length === 0) { + callback!(null); + return; + } + this.deleteRecords(records!, callback!); }); } } @@ -1172,58 +1229,58 @@ class Zone extends ServiceObject { */ Zone.prototype.getChangesStream = paginator.streamify('getChanges'); - /** - * Get the list of {module:dns/record} objects for this zone as a readable - * object stream. - * - * @method Zone#getRecordsStream - * @param {GetRecordsRequest} [query] Query object for listing records. - * @returns {ReadableStream} A readable stream that emits {@link Record} - * instances. - * - * @example - * const {DNS} = require('@google-cloud/dns'); - * const dns = new DNS(); - * const zone = dns.zone('zone-id'); - * - * zone.getRecordsStream() - * .on('error', console.error) - * .on('data', record => { - * // record is a Record object. - * }) - * .on('end', () => { - * // All records retrieved. - * }); - * - * //- - * // If you anticipate many results, you can end a stream early to prevent - * // unnecessary processing and API requests. - * //- - * zone.getRecordsStream() - * .on('data', function(change) { - * this.end(); - * }); - */ - Zone.prototype.getRecordsStream = paginator.streamify('getRecords'); +/** + * Get the list of {module:dns/record} objects for this zone as a readable + * object stream. + * + * @method Zone#getRecordsStream + * @param {GetRecordsRequest} [query] Query object for listing records. + * @returns {ReadableStream} A readable stream that emits {@link Record} + * instances. + * + * @example + * const {DNS} = require('@google-cloud/dns'); + * const dns = new DNS(); + * const zone = dns.zone('zone-id'); + * + * zone.getRecordsStream() + * .on('error', console.error) + * .on('data', record => { + * // record is a Record object. + * }) + * .on('end', () => { + * // All records retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * zone.getRecordsStream() + * .on('data', function(change) { + * this.end(); + * }); + */ +Zone.prototype.getRecordsStream = paginator.streamify('getRecords'); - /*! Developer Documentation - * - * These methods can be auto-paginated. - */ - paginator.extend(Zone, ['getChanges', 'getRecords']); +/*! Developer Documentation + * + * These methods can be auto-paginated. + */ +paginator.extend(Zone, ['getChanges', 'getRecords']); - /*! Developer Documentation - * - * All async methods (except for streams) will return a Promise in the event - * that a callback is omitted. - */ - promisifyAll(Zone, { - exclude: ['change', 'record'], - }); +/*! Developer Documentation + * + * All async methods (except for streams) will return a Promise in the event + * that a callback is omitted. + */ +promisifyAll(Zone, { + exclude: ['change', 'record'], +}); - /** - * Reference to the {@link Zone} class. - * @name module:@google-cloud/dns.Zone - * @see Zone - */ - export {Zone}; +/** + * Reference to the {@link Zone} class. + * @name module:@google-cloud/dns.Zone + * @see Zone + */ +export {Zone}; diff --git a/packages/google-cloud-dns/system-test/dns.ts b/packages/google-cloud-dns/system-test/dns.ts index 2802476dd48..2035af87ef0 100644 --- a/packages/google-cloud-dns/system-test/dns.ts +++ b/packages/google-cloud-dns/system-test/dns.ts @@ -24,7 +24,7 @@ import * as fs from 'fs'; const tmp = require('tmp'); import * as uuid from 'uuid'; import {DNS} from '../src'; -import {ChangeCallback} from '../src/change'; +import {CreateChangeCallback} from '../src/change'; import {Record} from '../src'; import {Response} from 'request'; @@ -217,9 +217,9 @@ describe('dns', () => { assert.ifError(err); async.series( [ - next => ZONE.empty(next as ChangeCallback), + next => ZONE.empty(next as CreateChangeCallback), next => ZONE.addRecords( - [records.spf, records.srv], next as ChangeCallback), + [records.spf, records.srv], next as CreateChangeCallback), next => ZONE.export(tmpFilename, next) ], done); @@ -315,8 +315,7 @@ describe('dns', () => { it('should replace records', async () => { const name = 'test-zone-' + uuid.v4().substr(0, 18); // Do this in a new zone so no existing records are affected. - // tslint:disable-next-line:no-any - const [zone] = await (dns as any).createZone(name, {dnsName: DNS_DOMAIN}); + const [zone] = await dns.createZone(name, {dnsName: DNS_DOMAIN}); const [originalRecords] = await zone.getRecords('ns'); const originalData = originalRecords[0].data; const newRecord = zone.record('ns', {