diff --git a/lib/auth/base-dse-authenticator.ts b/lib/auth/base-dse-authenticator.ts index 62760442..07678b26 100644 --- a/lib/auth/base-dse-authenticator.ts +++ b/lib/auth/base-dse-authenticator.ts @@ -15,64 +15,62 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const util = require('util'); -const { Authenticator } = require('./provider'); + +import { Authenticator } from './provider'; const dseAuthenticatorName = 'com.datastax.bdp.cassandra.auth.DseAuthenticator'; /** * Base class for Authenticator implementations that want to make use of * the authentication scheme negotiation in the DseAuthenticator - * @param {String} authenticatorName - * @extends Authenticator - * @constructor - * @ignore */ -function BaseDseAuthenticator(authenticatorName) { - this.authenticatorName = authenticatorName; -} +class BaseDseAuthenticator extends Authenticator { + authenticatorName: string; -util.inherits(BaseDseAuthenticator, Authenticator); + constructor(authenticatorName: string) { + super(); + this.authenticatorName = authenticatorName; + } -/** - * Return a Buffer containing the required SASL mechanism. - * @abstract - * @returns {Buffer} - */ -BaseDseAuthenticator.prototype.getMechanism = function () { - throw new Error('Not implemented'); -}; + /** + * Return a Buffer containing the required SASL mechanism. + * @abstract + * @returns {Buffer} + */ + getMechanism(): Buffer { + throw new Error('Not implemented'); + } -/** - * Return a byte array containing the expected successful server challenge. - * @abstract - * @returns {Buffer} - */ -BaseDseAuthenticator.prototype.getInitialServerChallenge = function () { - throw new Error('Not implemented'); -}; + /** + * Return a byte array containing the expected successful server challenge. + * @abstract + * @returns {Buffer} + */ + getInitialServerChallenge(): Buffer { + throw new Error('Not implemented'); + } -/** - * @param {Function} callback - * @override - */ -BaseDseAuthenticator.prototype.initialResponse = function (callback) { - if (!this._isDseAuthenticator()) { - //fallback - return this.evaluateChallenge(this.getInitialServerChallenge(), callback); + /** + * @param {Function} callback + * @override + */ + initialResponse(callback: Function) { + if (!this._isDseAuthenticator()) { + // fallback + return this.evaluateChallenge(this.getInitialServerChallenge(), callback); + } + // send the mechanism as a first auth message + callback(null, this.getMechanism()); } - //send the mechanism as a first auth message - callback(null, this.getMechanism()); -}; -/** - * Determines if the name of the authenticator matches DSE 5+ - * @protected - * @ignore - */ -BaseDseAuthenticator.prototype._isDseAuthenticator = function () { - return this.authenticatorName === dseAuthenticatorName; -}; + /** + * Determines if the name of the authenticator matches DSE 5+ + * @protected + * @ignore @internal + */ + protected _isDseAuthenticator(): boolean { + return this.authenticatorName === dseAuthenticatorName; + } +} -module.exports = BaseDseAuthenticator; \ No newline at end of file +export default BaseDseAuthenticator; \ No newline at end of file diff --git a/lib/auth/dse-gssapi-auth-provider.ts b/lib/auth/dse-gssapi-auth-provider.ts index e56657b7..b5479e2b 100644 --- a/lib/auth/dse-gssapi-auth-provider.ts +++ b/lib/auth/dse-gssapi-auth-provider.ts @@ -15,135 +15,151 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const util = require('util'); -const { AuthProvider } = require('./provider'); -const BaseDseAuthenticator = require('./base-dse-authenticator'); -const GssapiClient = require('./gssapi-client'); -const dns = require('dns'); -const utils = require('../utils'); + +import dns from "dns"; +import utils from "../utils"; +import BaseDseAuthenticator from './base-dse-authenticator'; +import GssapiClient from './gssapi-client'; +import { Authenticator, AuthProvider } from "./provider"; const mechanism = utils.allocBufferFromString('GSSAPI'); const initialServerChallenge = 'GSSAPI-START'; const emptyBuffer = utils.allocBuffer(0); /** - * Creates a new instance of DseGssapiAuthProvider. * @classdesc * AuthProvider that provides GSSAPI authenticator instances for clients to connect * to DSE clusters secured with the DseAuthenticator. - * @param {Object} [gssOptions] GSSAPI authenticator options - * @param {String} [gssOptions.authorizationId] The optional authorization ID. Providing an authorization ID allows the - * currently authenticated user to act as a different user (a.k.a. proxy authentication). - * @param {String} [gssOptions.service] The service to use. Defaults to 'dse'. - * @param {Function} [gssOptions.hostNameResolver] A method to be used to resolve the name of the Cassandra node based - * on the IP Address. Defaults to [lookupServiceResolver]{@link module:auth~DseGssapiAuthProvider.lookupServiceResolver} - * which resolves the FQDN of the provided IP to generate principals in the format of - * dse/example.com@MYREALM.COM. - * Alternatively, you can use [reverseDnsResolver]{@link module:auth~DseGssapiAuthProvider.reverseDnsResolver} to do a - * reverse DNS lookup or [useIpResolver]{@link module:auth~DseGssapiAuthProvider.useIpResolver} to simply use the IP - * address provided. - * @param {String} [gssOptions.user] DEPRECATED, it will be removed in future versions. For proxy authentication, use - * authorizationId instead. * @example * const client = new cassandra.Client({ * contactPoints: ['h1', 'h2'], * authProvider: new cassandra.auth.DseGssapiAuthProvider() * }); * @alias module:auth~DseGssapiAuthProvider - * @constructor */ -function DseGssapiAuthProvider(gssOptions) { - //load the kerberos at construction time - try { - // eslint-disable-next-line - this._kerberos = require('kerberos'); - } - catch (err) { - if (err.code === 'MODULE_NOT_FOUND') { - const newErr = new Error('You must install module "kerberos" to use GSSAPI auth provider: ' + - 'https://www.npmjs.com/package/kerberos'); - newErr.code = err.code; - throw newErr; +class DseGssapiAuthProvider extends AuthProvider { + private _kerberos: any; + private authorizationId: string; + private service: string; + private hostNameResolver: Function; + + /** + * Creates a new instance of DseGssapiAuthProvider. + * @classdesc + * AuthProvider that provides GSSAPI authenticator instances for clients to connect + * to DSE clusters secured with the DseAuthenticator. + * @param {Object} [gssOptions] GSSAPI authenticator options + * @param {String} [gssOptions.authorizationId] The optional authorization ID. Providing an authorization ID allows the + * currently authenticated user to act as a different user (a.k.a. proxy authentication). + * @param {String} [gssOptions.service] The service to use. Defaults to 'dse'. + * @param {Function} [gssOptions.hostNameResolver] A method to be used to resolve the name of the Cassandra node based + * on the IP Address. Defaults to [lookupServiceResolver]{@link module:auth~DseGssapiAuthProvider.lookupServiceResolver} + * which resolves the FQDN of the provided IP to generate principals in the format of + * dse/example.com@MYREALM.COM. + * Alternatively, you can use [reverseDnsResolver]{@link module:auth~DseGssapiAuthProvider.reverseDnsResolver} to do a + * reverse DNS lookup or [useIpResolver]{@link module:auth~DseGssapiAuthProvider.useIpResolver} to simply use the IP + * address provided. + * @param {String} [gssOptions.user] DEPRECATED, it will be removed in future versions. For proxy authentication, use + * authorizationId instead. + * @example + * const client = new cassandra.Client({ + * contactPoints: ['h1', 'h2'], + * authProvider: new cassandra.auth.DseGssapiAuthProvider() + * }); + * @alias module:auth~DseGssapiAuthProvider + * @constructor + */ + constructor(gssOptions: { authorizationId?: string; service?: string; hostNameResolver?: Function; user?: string; }) { + super(); + // Load the kerberos at construction time + try { + // eslint-disable-next-line + this._kerberos = require('kerberos'); + } catch (err) { + if (err.code === 'MODULE_NOT_FOUND') { + const newErr = new Error('You must install module "kerberos" to use GSSAPI auth provider: ' + + 'https://www.npmjs.com/package/kerberos'); + newErr["code"] = err.code; + throw newErr; + } + throw err; } - throw err; + gssOptions = gssOptions || utils.emptyObject; + this.authorizationId = gssOptions.authorizationId || gssOptions.user; + this.service = gssOptions.service; + this.hostNameResolver = gssOptions.hostNameResolver || DseGssapiAuthProvider.lookupServiceResolver; } - gssOptions = gssOptions || utils.emptyObject; - this.authorizationId = gssOptions.authorizationId || gssOptions.user; - this.service = gssOptions.service; - this.hostNameResolver = gssOptions.hostNameResolver || DseGssapiAuthProvider.lookupServiceResolver; -} - -util.inherits(DseGssapiAuthProvider, AuthProvider); -/** - * Returns an Authenticator instance to be used by the driver when connecting to a host. - * @param {String} endpoint The IP address and port number in the format ip:port. - * @param {String} name Authenticator name. - * @override - * @returns {Authenticator} - */ -DseGssapiAuthProvider.prototype.newAuthenticator = function (endpoint, name) { - let address = endpoint; - if (endpoint.indexOf(':') > 0) { - address = endpoint.split(':')[0]; + /** + * Returns an Authenticator instance to be used by the driver when connecting to a host. + * @param {String} endpoint The IP address and port number in the format ip:port. + * @param {String} name Authenticator name. + * @override + * @returns {Authenticator} + */ + newAuthenticator(endpoint: string, name: string): Authenticator { + let address = endpoint; + if (endpoint.indexOf(':') > 0) { + address = endpoint.split(':')[0]; + } + return new GssapiAuthenticator( + this._kerberos, address, name, this.authorizationId, this.service, this.hostNameResolver); } - return new GssapiAuthenticator( - this._kerberos, address, name, this.authorizationId, this.service, this.hostNameResolver); -}; -/** - * Performs a lookupService query that resolves an IPv4 or IPv6 address to a hostname. This ultimately makes a - * getnameinfo() system call which depends on the OS to do hostname resolution. - *

- * Note: Depends on dns.lookupService which was added in 0.12. For older versions falls back on - * [reverseDnsResolver]{@link module:auth~DseGssapiAuthProvider.reverseDnsResolver}. - * - * @param {String} ip IP address to resolve. - * @param {Function} callback The callback function with err and hostname arguments. - */ -DseGssapiAuthProvider.lookupServiceResolver = function (ip, callback) { - if (!dns.lookupService) { - return DseGssapiAuthProvider.reverseDnsResolver(ip, callback); - } - dns.lookupService(ip, 0, function (err, hostname) { - if (err) { - return callback(err); - } - if (!hostname) { - //fallback to ip - return callback(null, ip); + /** + * Performs a lookupService query that resolves an IPv4 or IPv6 address to a hostname. This ultimately makes a + * getnameinfo() system call which depends on the OS to do hostname resolution. + *

+ * Note: Depends on dns.lookupService which was added in 0.12. For older versions falls back on + * [reverseDnsResolver]{@link module:auth~DseGssapiAuthProvider.reverseDnsResolver}. + * + * @param {String} ip IP address to resolve. + * @param {Function} callback The callback function with err and hostname arguments. + */ + private static lookupServiceResolver(ip: string, callback: Function) { + if (!dns.lookupService) { + return DseGssapiAuthProvider.reverseDnsResolver(ip, callback); } - callback(null, hostname); - }); -}; + dns.lookupService(ip, 0, function (err, hostname) { + if (err) { + return callback(err); + } + if (!hostname) { + // Fallback to ip + return callback(null, ip); + } + callback(null, hostname); + }); + } -/** - * Performs a reverse DNS query that resolves an IPv4 or IPv6 address to a hostname. - * @param {String} ip IP address to resolve. - * @param {Function} callback The callback function with err and hostname arguments. - */ -DseGssapiAuthProvider.reverseDnsResolver = function (ip, callback) { - dns.reverse(ip, function (err, names) { - if (err) { - return callback(err); - } - if (!names || !names.length) { - //fallback to ip - return callback(null, ip); - } - callback(null, names[0]); - }); -}; + //TODO: reverseDnsResolver and useIpResolver are in JSDoc but we didn't expose them in .d.ts. Should we? + /** + * Performs a reverse DNS query that resolves an IPv4 or IPv6 address to a hostname. + * @param {String} ip IP address to resolve. + * @param {Function} callback The callback function with err and hostname arguments. + */ + static reverseDnsResolver(ip: string, callback: Function) { + dns.reverse(ip, function (err, names) { + if (err) { + return callback(err); + } + if (!names || !names.length) { + // Fallback to ip + return callback(null, ip); + } + callback(null, names[0]); + }); + } -/** - * Effectively a no op operation, returns the IP address provided. - * @param {String} ip IP address to use. - * @param {Function} callback The callback function with err and hostname arguments. - */ -DseGssapiAuthProvider.useIpResolver = function (ip, callback) { - callback(null, ip); -}; + /** + * Effectively a no op operation, returns the IP address provided. + * @param {String} ip IP address to use. + * @param {Function} callback The callback function with err and hostname arguments. + */ + static useIpResolver(ip: string, callback: Function) { + callback(null, ip); + } +} /** * @param {Object} kerberosModule @@ -153,81 +169,95 @@ DseGssapiAuthProvider.useIpResolver = function (ip, callback) { * @param {String} service * @param {Function} hostNameResolver * @extends Authenticator - * @private + * @private @internal */ -function GssapiAuthenticator(kerberosModule, address, authenticatorName, authorizationId, service, hostNameResolver) { - BaseDseAuthenticator.call(this, authenticatorName); - this.authorizationId = authorizationId; - this.address = address; - this.client = GssapiClient.createNew(kerberosModule, authorizationId, service); - this.hostNameResolver = hostNameResolver; -} - -//noinspection JSCheckFunctionSignatures -util.inherits(GssapiAuthenticator, BaseDseAuthenticator); +class GssapiAuthenticator extends BaseDseAuthenticator { + authorizationId: any; + address: any; + client: GssapiClient; + hostNameResolver: any; -GssapiAuthenticator.prototype.getMechanism = function () { - return mechanism; -}; + /** + * @param {Object} kerberosModule + * @param {String} address Host address. + * @param {String} authenticatorName + * @param {String} authorizationId + * @param {String} service + * @param {Function} hostNameResolver + * @extends Authenticator + * @private + */ + constructor(kerberosModule: object, address: string, authenticatorName: string, authorizationId: string, service: string, hostNameResolver: Function) { + super(authenticatorName); + this.authorizationId = authorizationId; + this.address = address; + this.client = GssapiClient.createNew(kerberosModule, authorizationId, service); + this.hostNameResolver = hostNameResolver; + } -GssapiAuthenticator.prototype.getInitialServerChallenge = function () { - return utils.allocBufferFromString(initialServerChallenge); -}; + getMechanism() { + return mechanism; + } -//noinspection JSUnusedGlobalSymbols -/** - * Obtain an initial response token for initializing the SASL handshake. - * @param {Function} callback - */ -GssapiAuthenticator.prototype.initialResponse = function (callback) { - const self = this; - //initialize the GSS client - let host = this.address; - utils.series([ - function getHostName(next) { - self.hostNameResolver(self.address, function (err, name) { - if (!err && name) { - host = name; - } - next(); - }); - }, - function initClient(next) { - self.client.init(host, function (err) { - if (err) { - return next(err); - } - if (!self._isDseAuthenticator()) { - //fallback - return self.evaluateChallenge(self.getInitialServerChallenge(), next); - } - //send the mechanism as a first auth message - next(null, self.getMechanism()); - }); - } - ], callback); -}; + getInitialServerChallenge() { + return utils.allocBufferFromString(initialServerChallenge); + } -/** - * Evaluates a challenge received from the Server. Generally, this method should callback with - * no error and no additional params when authentication is complete from the client perspective. - * @param {Buffer} challenge - * @param {Function} callback - * @override - */ -GssapiAuthenticator.prototype.evaluateChallenge = function (challenge, callback) { - if (!challenge || challenge.toString() === initialServerChallenge) { - challenge = emptyBuffer; + //noinspection JSUnusedGlobalSymbols + /** + * Obtain an initial response token for initializing the SASL handshake. + * @param {Function} callback + */ + initialResponse(callback: Function) { + const self = this; + // Initialize the GSS client + let host = this.address; + utils.series([ + function getHostName(next) { + self.hostNameResolver(self.address, function (err, name) { + if (!err && name) { + host = name; + } + next(); + }); + }, + function initClient(next) { + self.client.init(host, function (err) { + if (err) { + return next(err); + } + if (!self._isDseAuthenticator()) { + // Fallback + return self.evaluateChallenge(self.getInitialServerChallenge(), next); + } + // Send the mechanism as a first auth message + next(null, self.getMechanism()); + }); + } + ], callback); } - this.client.evaluateChallenge(challenge, callback); -}; -/** - * @override - */ -GssapiAuthenticator.prototype.onAuthenticationSuccess = function (token) { - this.client.shutdown(function noop() { }); -}; + /** + * Evaluates a challenge received from the Server. Generally, this method should callback with + * no error and no additional params when authentication is complete from the client perspective. + * @param {Buffer} challenge + * @param {Function} callback + * @override + */ + evaluateChallenge(challenge: Buffer, callback: Function) { + if (!challenge || challenge.toString() === initialServerChallenge) { + challenge = emptyBuffer; + } + this.client.evaluateChallenge(challenge, callback); + } + /** + * @override + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + onAuthenticationSuccess(token?: Buffer) { + this.client.shutdown(function noop() { }); + } +} -module.exports = DseGssapiAuthProvider; \ No newline at end of file +export default DseGssapiAuthProvider; \ No newline at end of file diff --git a/lib/auth/dse-plain-text-auth-provider.ts b/lib/auth/dse-plain-text-auth-provider.ts index e476b260..dca75e32 100644 --- a/lib/auth/dse-plain-text-auth-provider.ts +++ b/lib/auth/dse-plain-text-auth-provider.ts @@ -15,25 +15,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const util = require('util'); -const { AuthProvider } = require('./provider'); -const BaseDseAuthenticator = require('./base-dse-authenticator'); -const utils = require('../utils'); + +import utils from "../utils"; +import BaseDseAuthenticator from './base-dse-authenticator'; +import { Authenticator, AuthProvider } from './provider'; const mechanism = utils.allocBufferFromString('PLAIN'); const separatorBuffer = utils.allocBufferFromArray([0]); const initialServerChallenge = 'PLAIN-START'; /** - * Creates a new instance of DsePlainTextAuthProvider. * @classdesc * AuthProvider that provides plain text authenticator instances for clients to connect * to DSE clusters secured with the DseAuthenticator. - * @param {String} username The username; cannot be null. - * @param {String} password The password; cannot be null. - * @param {String} [authorizationId] The optional authorization ID. Providing an authorization ID allows the currently - * authenticated user to act as a different user (a.k.a. proxy authentication). * @extends AuthProvider * @alias module:auth~DsePlainTextAuthProvider * @example @@ -41,72 +35,100 @@ const initialServerChallenge = 'PLAIN-START'; * contactPoints: ['h1', 'h2'], * authProvider: new cassandra.auth.DsePlainTextAuthProvider('user', 'p@ssword1'); * }); - * @constructor */ -function DsePlainTextAuthProvider(username, password, authorizationId) { - if (typeof username !== 'string' || typeof password !== 'string') { - // Validate for null and undefined - throw new TypeError('Username and password must be a string'); +class DsePlainTextAuthProvider extends AuthProvider { + private username: string; + private password: string; + private authorizationId: string; + /** + * Creates a new instance of DsePlainTextAuthProvider. + * @classdesc + * AuthProvider that provides plain text authenticator instances for clients to connect + * to DSE clusters secured with the DseAuthenticator. + * @param {String} username The username; cannot be null. + * @param {String} password The password; cannot be null. + * @param {String} [authorizationId] The optional authorization ID. Providing an authorization ID allows the currently + * authenticated user to act as a different user (a.k.a. proxy authentication). + * @extends AuthProvider + * @alias module:auth~DsePlainTextAuthProvider + * @example + * const client = new cassandra.Client({ + * contactPoints: ['h1', 'h2'], + * authProvider: new cassandra.auth.DsePlainTextAuthProvider('user', 'p@ssword1'); + * }); + * @constructor + */ + constructor(username: string, password: string, authorizationId?: string) { + super(); + if (typeof username !== 'string' || typeof password !== 'string') { + // Validate for null and undefined + throw new TypeError('Username and password must be a string'); + } + this.username = username; + this.password = password; + this.authorizationId = authorizationId; } - this.username = username; - this.password = password; - this.authorizationId = authorizationId; -} - -util.inherits(DsePlainTextAuthProvider, AuthProvider); -/** - * Returns an Authenticator instance to be used by the driver when connecting to a host. - * @param {String} endpoint The IP address and port number in the format ip:port. - * @param {String} name Authenticator name. - * @override - * @returns {Authenticator} - */ -DsePlainTextAuthProvider.prototype.newAuthenticator = function (endpoint, name) { - return new PlainTextAuthenticator(name, this.username, this.password, this.authorizationId); -}; + /** + * Returns an Authenticator instance to be used by the driver when connecting to a host. + * @param {String} endpoint The IP address and port number in the format ip:port. + * @param {String} name Authenticator name. + * @override + * @returns {Authenticator} + */ + newAuthenticator(endpoint: string, name: string): Authenticator { + return new PlainTextAuthenticator(name, this.username, this.password, this.authorizationId); + } +} /** - * @param {String} authenticatorName - * @param {String} authenticatorId - * @param {String} password - * @param {String} authorizationId * @extends BaseDseAuthenticator - * @constructor - * @private + * @private @internal */ -function PlainTextAuthenticator(authenticatorName, authenticatorId, password, authorizationId) { - BaseDseAuthenticator.call(this, authenticatorName); - this.authenticatorId = utils.allocBufferFromString(authenticatorId); - this.password = utils.allocBufferFromString(password); - this.authorizationId = utils.allocBufferFromString(authorizationId || ''); -} +class PlainTextAuthenticator extends BaseDseAuthenticator { + authenticatorId: Buffer; + password: Buffer; + authorizationId: Buffer; -util.inherits(PlainTextAuthenticator, BaseDseAuthenticator); + /** + * @param {String} authenticatorName + * @param {String} authenticatorId + * @param {String} password + * @param {String} authorizationId + * @constructor + * @private + */ + constructor(authenticatorName: string, authenticatorId: string, password: string, authorizationId: string) { + super(authenticatorName); + this.authenticatorId = utils.allocBufferFromString(authenticatorId); + this.password = utils.allocBufferFromString(password); + this.authorizationId = utils.allocBufferFromString(authorizationId || ''); + } -/** @override */ -PlainTextAuthenticator.prototype.getMechanism = function () { - return mechanism; -}; + /** @override */ + getMechanism() { + return mechanism; + } -/** @override */ -PlainTextAuthenticator.prototype.getInitialServerChallenge = function () { - return utils.allocBufferFromString(initialServerChallenge); -}; + /** @override */ + getInitialServerChallenge() { + return utils.allocBufferFromString(initialServerChallenge); + } -/** @override */ -PlainTextAuthenticator.prototype.evaluateChallenge = function (challenge, callback) { - if (!challenge || challenge.toString() !== initialServerChallenge) { - return callback(new Error('Incorrect SASL challenge from server')); + /** @override */ + evaluateChallenge(challenge, callback) { + if (!challenge || challenge.toString() !== initialServerChallenge) { + return callback(new Error('Incorrect SASL challenge from server')); + } + // The SASL plain text format is authorizationId 0 username 0 password + callback(null, Buffer.concat([ + this.authorizationId, + separatorBuffer, + this.authenticatorId, + separatorBuffer, + this.password + ])); } - // The SASL plain text format is authorizationId 0 username 0 password - callback(null, Buffer.concat([ - this.authorizationId, - separatorBuffer, - this.authenticatorId, - separatorBuffer, - this.password - ])); -}; +} -module.exports = DsePlainTextAuthProvider; \ No newline at end of file +export default DsePlainTextAuthProvider; \ No newline at end of file diff --git a/lib/auth/gssapi-client.ts b/lib/auth/gssapi-client.ts index 6a89ab87..8d685737 100644 --- a/lib/auth/gssapi-client.ts +++ b/lib/auth/gssapi-client.ts @@ -15,22 +15,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import util from "util"; +import utils from "../utils"; -'use strict'; -const util = require('util'); -const utils = require('../utils'); /** * GSSAPI Client interface. * @ignore + * @internal */ class GssapiClient { + authorizationId: string; + service: string; /** * @param {String} [authorizationId] * @param {String} [service] */ - constructor(authorizationId, service) { + constructor(authorizationId: string, service: string) { this.authorizationId = authorizationId; this.service = service !== undefined ? service : 'dse'; } @@ -40,7 +43,7 @@ class GssapiClient { * @param {String} host Host name or ip * @param {Function} callback */ - init(host, callback) { + init(host: string, callback: Function) { throw new Error('Not implemented'); } @@ -49,7 +52,7 @@ class GssapiClient { * @param {Function} callback * @abstract */ - evaluateChallenge(challenge, callback) { + evaluateChallenge(challenge: Buffer, callback: Function) { throw new Error('Not implemented'); } @@ -57,7 +60,7 @@ class GssapiClient { * @abstract * @param {Function} [callback] */ - shutdown(callback) { + shutdown(callback: Function) { throw new Error('Not implemented'); } @@ -68,16 +71,20 @@ class GssapiClient { * @param {String} [service] The service to use. (defaults to 'dse') * @returns GssapiClient */ - static createNew(kerberosModule, authorizationId, service) { + static createNew(kerberosModule: object, authorizationId?: string, service?: string) { return new StandardGssClient(kerberosModule, authorizationId, service); } } /** * GSSAPI Client implementation using kerberos module. - * @ignore + * @ignore @internal */ class StandardGssClient extends GssapiClient { + kerberos: any; + transitionIndex: number; + host: any; + kerberosClient: any; constructor(kerberosModule, authorizationId, service) { if (typeof kerberosModule.initializeClient !== 'function') { throw new Error('The driver expects version 1.x of the kerberos library'); @@ -154,4 +161,4 @@ class StandardGssClient extends GssapiClient { } } -module.exports = GssapiClient; \ No newline at end of file +export default GssapiClient; \ No newline at end of file diff --git a/lib/auth/index.d.ts b/lib/auth/index.d.ts deleted file mode 100644 index 2d2a4bed..00000000 --- a/lib/auth/index.d.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export namespace auth { - interface Authenticator { - initialResponse(callback: Function): void; - - evaluateChallenge(challenge: Buffer, callback: Function): void; - - onAuthenticationSuccess(token?: Buffer): void; - } - - interface AuthProvider { - newAuthenticator(endpoint: string, name: string): Authenticator; - } - - class PlainTextAuthProvider implements AuthProvider { - constructor(username: string, password: string); - - newAuthenticator(endpoint: string, name: string): Authenticator; - } - - class DsePlainTextAuthProvider implements AuthProvider { - constructor(username: string, password: string, authorizationId?: string); - - newAuthenticator(endpoint: string, name: string): Authenticator; - } - - class DseGssapiAuthProvider implements AuthProvider { - constructor(gssOptions?: { authorizationId?: string, service?: string, hostNameResolver?: Function }); - - newAuthenticator(endpoint: string, name: string): Authenticator; - } -} \ No newline at end of file diff --git a/lib/auth/index.ts b/lib/auth/index.ts index a0d6c6ce..1a868603 100644 --- a/lib/auth/index.ts +++ b/lib/auth/index.ts @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; + /** * DSE Authentication module. @@ -25,17 +25,28 @@ * @module auth */ -const { Authenticator, AuthProvider } = require('./provider'); -const { PlainTextAuthProvider } = require('./plain-text-auth-provider'); -const DseGssapiAuthProvider = require('./dse-gssapi-auth-provider'); -const DsePlainTextAuthProvider = require('./dse-plain-text-auth-provider'); -const NoAuthProvider = require('./no-auth-provider'); +import DseGssapiAuthProvider from './dse-gssapi-auth-provider'; +import DsePlainTextAuthProvider from './dse-plain-text-auth-provider'; +import NoAuthProvider from './no-auth-provider'; +import { PlainTextAuthProvider } from './plain-text-auth-provider'; +import { Authenticator, AuthProvider } from './provider'; -module.exports = { +export { Authenticator, AuthProvider, DseGssapiAuthProvider, DsePlainTextAuthProvider, + /** @internal */ NoAuthProvider, PlainTextAuthProvider }; + +export default { + Authenticator, + AuthProvider, + DseGssapiAuthProvider, + DsePlainTextAuthProvider, + /** @internal */ + NoAuthProvider, + PlainTextAuthProvider +}; \ No newline at end of file diff --git a/lib/auth/no-auth-provider.ts b/lib/auth/no-auth-provider.ts index 75b0b45a..d2d25cb7 100644 --- a/lib/auth/no-auth-provider.ts +++ b/lib/auth/no-auth-provider.ts @@ -16,17 +16,16 @@ * limitations under the License. */ -'use strict'; -const { AuthProvider, Authenticator } = require('./provider'); -const { PlainTextAuthenticator } = require('./plain-text-auth-provider'); -const errors = require('../errors'); +import errors from "../errors"; +import { PlainTextAuthenticator } from './plain-text-auth-provider'; +import { Authenticator, AuthProvider } from './provider'; const dseAuthenticator = 'com.datastax.bdp.cassandra.auth.DseAuthenticator'; /** * Internal authentication provider that is used when no provider has been set by the user. - * @ignore + * @ignore @internal */ class NoAuthProvider extends AuthProvider { newAuthenticator(endpoint, name) { @@ -42,9 +41,10 @@ class NoAuthProvider extends AuthProvider { /** * An authenticator throws an error when authentication flow is started. - * @ignore + * @ignore @internal */ class NoAuthAuthenticator extends Authenticator { + endpoint: any; constructor(endpoint) { super(); this.endpoint = endpoint; @@ -62,6 +62,7 @@ class NoAuthAuthenticator extends Authenticator { * In this situation, the client is allowed to connect without authentication, but DSE * would still send an AUTHENTICATE response. This Authenticator handles this situation * by sending back a dummy credential. + * @internal */ class TransitionalModePlainTextAuthenticator extends PlainTextAuthenticator { constructor() { @@ -69,4 +70,4 @@ class TransitionalModePlainTextAuthenticator extends PlainTextAuthenticator { } } -module.exports = NoAuthProvider; +export default NoAuthProvider; diff --git a/lib/auth/plain-text-auth-provider.ts b/lib/auth/plain-text-auth-provider.ts index bae8aaaa..67546e0b 100644 --- a/lib/auth/plain-text-auth-provider.ts +++ b/lib/auth/plain-text-auth-provider.ts @@ -15,15 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const util = require('util'); -const provider = require('./provider'); -const utils = require('../utils'); -const AuthProvider = provider.AuthProvider; -const Authenticator = provider.Authenticator; +import utils from "../utils"; +import { Authenticator, AuthProvider } from './provider'; + /** - * Creates a new instance of the Authenticator provider * @classdesc Provides plain text [Authenticator]{@link module:auth~Authenticator} instances to be used when * connecting to a host. * @extends module:auth~AuthProvider @@ -31,53 +27,70 @@ const Authenticator = provider.Authenticator; * var authProvider = new cassandra.auth.PlainTextAuthProvider('my_user', 'p@ssword1!'); * //Set the auth provider in the clientOptions when creating the Client instance * const client = new Client({ contactPoints: contactPoints, authProvider: authProvider }); - * @param {String} username User name in plain text - * @param {String} password Password in plain text * @alias module:auth~PlainTextAuthProvider - * @constructor */ -function PlainTextAuthProvider(username, password) { - this.username = username; - this.password = password; -} +class PlainTextAuthProvider extends AuthProvider { + private username: string; + private password: string; -util.inherits(PlainTextAuthProvider, AuthProvider); + /** + * Creates a new instance of the Authenticator provider + * @classdesc Provides plain text [Authenticator]{@link module:auth~Authenticator} instances to be used when + * connecting to a host. + * @example + * var authProvider = new cassandra.auth.PlainTextAuthProvider('my_user', 'p@ssword1!'); + * //Set the auth provider in the clientOptions when creating the Client instance + * const client = new Client({ contactPoints: contactPoints, authProvider: authProvider }); + * @param {String} username User name in plain text + * @param {String} password Password in plain text + * @alias module:auth~PlainTextAuthProvider + * @constructor + */ + constructor(username: string, password: string) { + super(); + this.username = username; + this.password = password; + } -/** - * Returns a new [Authenticator]{@link module:auth~Authenticator} instance to be used for plain text authentication. - * @override - * @returns {Authenticator} - */ -PlainTextAuthProvider.prototype.newAuthenticator = function () { - return new PlainTextAuthenticator(this.username, this.password); -}; + /** + * Returns a new [Authenticator]{@link module:auth~Authenticator} instance to be used for plain text authentication. + * @override + * @returns {Authenticator} + */ + newAuthenticator(): Authenticator { + return new PlainTextAuthenticator(this.username, this.password); + } +} /** - * @ignore + * @ignore @internal */ -function PlainTextAuthenticator(username, password) { - this.username = username; - this.password = password; -} - -util.inherits(PlainTextAuthenticator, Authenticator); +class PlainTextAuthenticator extends Authenticator { + username: any; + password: any; + constructor(username, password) { + super(); + this.username = username; + this.password = password; + } -PlainTextAuthenticator.prototype.initialResponse = function (callback) { - const initialToken = Buffer.concat([ - utils.allocBufferFromArray([0]), - utils.allocBufferFromString(this.username, 'utf8'), - utils.allocBufferFromArray([0]), - utils.allocBufferFromString(this.password, 'utf8') - ]); - callback(null, initialToken); -}; + initialResponse(callback) { + const initialToken = Buffer.concat([ + utils.allocBufferFromArray([0]), + utils.allocBufferFromString(this.username, 'utf8'), + utils.allocBufferFromArray([0]), + utils.allocBufferFromString(this.password, 'utf8') + ]); + callback(null, initialToken); + } -PlainTextAuthenticator.prototype.evaluateChallenge = function (challenge, callback) { - //noop - callback(); -}; + evaluateChallenge(challenge, callback) { + // noop + callback(); + } +} -module.exports = { +export { PlainTextAuthenticator, - PlainTextAuthProvider, + PlainTextAuthProvider }; diff --git a/lib/auth/provider.ts b/lib/auth/provider.ts index 036dbb4c..82aae557 100644 --- a/lib/auth/provider.ts +++ b/lib/auth/provider.ts @@ -15,67 +15,63 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; +/* eslint-disable @typescript-eslint/no-unused-vars */ + /** - * @classdesc Provides [Authenticator]{@link module:auth~Authenticator} instances to be used when connecting to a host. - * @constructor + * Provides [Authenticator]{@link module:auth~Authenticator} instances to be used when connecting to a host. * @abstract * @alias module:auth~AuthProvider */ -function AuthProvider() { - +class AuthProvider { + /** + * Returns an [Authenticator]{@link module:auth~Authenticator} instance to be used when connecting to a host. + * @param {String} endpoint The ip address and port number in the format ip:port + * @param {String} name Authenticator name + * @abstract + * @returns {Authenticator} + */ + newAuthenticator(endpoint: string, name: string): Authenticator { + throw new Error('This is an abstract class, you must implement newAuthenticator method or ' + + 'use another auth provider that inherits from this class'); + } } /** - * Returns an [Authenticator]{@link module:auth~Authenticator} instance to be used when connecting to a host. - * @param {String} endpoint The ip address and port number in the format ip:port - * @param {String} name Authenticator name - * @abstract - * @returns {Authenticator} - */ -AuthProvider.prototype.newAuthenticator = function (endpoint, name) { - throw new Error('This is an abstract class, you must implement newAuthenticator method or ' + - 'use another auth provider that inherits from this class'); -}; - -/** - * @class - * @classdesc Handles SASL authentication with Cassandra servers. + * Handles SASL authentication with Cassandra servers. * Each time a new connection is created and the server requires authentication, * a new instance of this class will be created by the corresponding. - * @constructor * @alias module:auth~Authenticator */ -function Authenticator() { - -} - -/** - * Obtain an initial response token for initializing the SASL handshake. - * @param {Function} callback - */ -Authenticator.prototype.initialResponse = function (callback) { - callback(new Error('Not implemented')); -}; +class Authenticator { + /** + * Obtain an initial response token for initializing the SASL handshake. + * @param {Function} callback + */ + initialResponse(callback: Function) { + callback(new Error('Not implemented')); + } -/** - * Evaluates a challenge received from the Server. Generally, this method should callback with - * no error and no additional params when authentication is complete from the client perspective. - * @param {Buffer} challenge - * @param {Function} callback - */ -Authenticator.prototype.evaluateChallenge = function (challenge, callback) { - callback(new Error('Not implemented')); -}; + /** + * Evaluates a challenge received from the Server. Generally, this method should callback with + * no error and no additional params when authentication is complete from the client perspective. + * @param {Buffer} challenge + * @param {Function} callback + */ + evaluateChallenge(challenge: Buffer, callback: Function) { + callback(new Error('Not implemented')); + } -/** - * Called when authentication is successful with the last information - * optionally sent by the server. - * @param {Buffer} [token] - */ -Authenticator.prototype.onAuthenticationSuccess = function (token) { + /** + * Called when authentication is successful with the last information + * optionally sent by the server. + * @param {Buffer} [token] + */ + onAuthenticationSuccess(token?: Buffer) { + // No-op + } +} +export { + Authenticator, + AuthProvider }; - -exports.AuthProvider = AuthProvider; -exports.Authenticator = Authenticator; \ No newline at end of file diff --git a/lib/geometry/geometry.ts b/lib/geometry/geometry.ts index 0189f7c8..9c2614fe 100644 --- a/lib/geometry/geometry.ts +++ b/lib/geometry/geometry.ts @@ -15,121 +15,123 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; const endianness = { '0': 'BE', '1': 'LE' }; -function Geometry() { +class Geometry { + static types = { + Point2D: 1, + LineString: 2, + Polygon: 3 + } as const; -} - -Geometry.types = { - Point2D: 1, - LineString: 2, - Polygon: 3 -}; - -/** - * @protected - * @param {Number} code - * @returns {String} - * @ignore - */ -Geometry.getEndianness = function (code) { - const value = endianness[code.toString()]; - if (typeof value === 'undefined') { - throw new TypeError('Invalid endianness with code ' + code); + /** + * @protected + * @param {Number} code + * @returns {String} + * @ignore @internal + */ + static getEndianness(code: number): string { + const value = endianness[code.toString()]; + if (typeof value === 'undefined') { + throw new TypeError('Invalid endianness with code ' + code); + } + return value; } - return value; -}; -/** - * Reads an int32 from binary representation based on endianness. - * @protected - * @param {Buffer} buffer - * @param {String} endianness - * @param {Number} offset - * @returns Number - * @ignore - */ -Geometry.readInt32 = function (buffer, endianness, offset) { - if (endianness === 'BE') { - return buffer.readInt32BE(offset, true); + /** + * Reads an int32 from binary representation based on endianness. + * @protected + * @param {Buffer} buffer + * @param {String} endianness + * @param {Number} offset + * @returns Number + * @ignore @internal + */ + static readInt32(buffer: Buffer, endianness: string, offset: number): number { + if (endianness === 'BE') { + // Old Node.js versions, e.g. v8, has buf.readInt32BE(offset[, noAssert]) + // Newer versions do not have the noAssert parameter anymore + return buffer.readInt32BE(offset); + } + return buffer.readInt32LE(offset); } - return buffer.readInt32LE(offset, true); -}; -/** - * Reads an 64-bit double from binary representation based on endianness. - * @protected - * @param {Buffer} buffer - * @param {String} endianness - * @param {Number} offset - * @returns Number - * @ignore - */ -Geometry.readDouble = function (buffer, endianness, offset) { - if (endianness === 'BE') { - return buffer.readDoubleBE(offset, true); + /** + * Reads a 64-bit double from binary representation based on endianness. + * @protected + * @param {Buffer} buffer + * @param {String} endianness + * @param {Number} offset + * @returns Number + * @ignore @internal + */ + static readDouble(buffer: Buffer, endianness: string, offset: number): number { + if (endianness === 'BE') { + return buffer.readDoubleBE(offset); + } + return buffer.readDoubleLE(offset); } - return buffer.readDoubleLE(offset, true); -}; -/** - * Writes an 32-bit integer to binary representation based on OS endianness. - * @protected - * @param {Number} val - * @param {Buffer} buffer - * @param {Number} offset - * @ignore - */ -Geometry.prototype.writeInt32 = function (val, buffer, offset) { - if (this.useBESerialization()) { - return buffer.writeInt32BE(val, offset, true); + /** + * Writes a 32-bit integer to binary representation based on OS endianness. + * @protected + * @param {Number} val + * @param {Buffer} buffer + * @param {Number} offset + * @ignore @internal + */ + writeInt32(val: number, buffer: Buffer, offset: number): void { + if (this.useBESerialization()) { + buffer.writeInt32BE(val, offset); + } else { + buffer.writeInt32LE(val, offset); + } } - return buffer.writeInt32LE(val, offset, true); -}; -/** - * Writes an 64-bit double to binary representation based on OS endianness. - * @protected - * @param {Number} val - * @param {Buffer} buffer - * @param {Number} offset - * @ignore - */ -Geometry.prototype.writeDouble = function (val, buffer, offset) { - if (this.useBESerialization()) { - return buffer.writeDoubleBE(val, offset, true); + /** + * Writes a 64-bit double to binary representation based on OS endianness. + * @protected + * @param {Number} val + * @param {Buffer} buffer + * @param {Number} offset + * @ignore @internal + */ + writeDouble(val: number, buffer: Buffer, offset: number): void { + if (this.useBESerialization()) { + buffer.writeDoubleBE(val, offset); + } else { + buffer.writeDoubleLE(val, offset); + } } - return buffer.writeDoubleLE(val, offset, true); -}; -/** - * Writes an 8-bit int that represents the OS endianness. - * @protected - * @param {Buffer} buffer - * @param {Number} offset - * @ignore - */ -Geometry.prototype.writeEndianness = function (buffer, offset) { - if (this.useBESerialization()) { - return buffer.writeInt8(0, offset, true); + /** + * Writes an 8-bit int that represents the OS endianness. + * @protected + * @param {Buffer} buffer + * @param {Number} offset + * @ignore @internal + */ + writeEndianness(buffer: Buffer, offset: number): void { + if (this.useBESerialization()) { + buffer.writeInt8(0, offset); + } else { + buffer.writeInt8(1, offset); + } } - return buffer.writeInt8(1, offset, true); -}; -/** - * Returns true if the serialization must be done in big-endian format. - * Designed to allow injection of OS endianness. - * @abstract - * @ignore - */ -Geometry.prototype.useBESerialization = function () { - throw new Error('Not Implemented'); -}; + /** + * Returns true if the serialization must be done in big-endian format. + * Designed to allow injection of OS endianness. + * @abstract + * @ignore @internal + */ + useBESerialization(): boolean { + throw new Error('Not Implemented'); + } +} -module.exports = Geometry; \ No newline at end of file +export default Geometry; \ No newline at end of file diff --git a/lib/geometry/index.d.ts b/lib/geometry/index.d.ts deleted file mode 100644 index 9484817c..00000000 --- a/lib/geometry/index.d.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export namespace geometry { - class LineString { - constructor(...args: Point[]); - - static fromBuffer(buffer: Buffer): LineString; - - static fromString(textValue: string): LineString; - - equals(other: LineString): boolean; - - toBuffer(): Buffer; - - toJSON(): string; - - toString(): string; - - } - - class Point { - constructor(x: number, y: number); - - static fromBuffer(buffer: Buffer): Point; - - static fromString(textValue: string): Point; - - equals(other: Point): boolean; - - toBuffer(): Buffer; - - toJSON(): string; - - toString(): string; - - } - - class Polygon { - constructor(...args: Point[]); - - static fromBuffer(buffer: Buffer): Polygon; - - static fromString(textValue: string): Polygon; - - equals(other: Polygon): boolean; - - toBuffer(): Buffer; - - toJSON(): string; - - toString(): string; - } -} \ No newline at end of file diff --git a/lib/geometry/index.ts b/lib/geometry/index.ts index f530268b..a4e39875 100644 --- a/lib/geometry/index.ts +++ b/lib/geometry/index.ts @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; + /** * Geometry module. @@ -26,7 +26,18 @@ * @module geometry */ -exports.Geometry = require('./geometry'); -exports.LineString = require('./line-string'); -exports.Point = require('./point'); -exports.Polygon = require('./polygon'); \ No newline at end of file +import Geometry from './geometry'; +import LineString from './line-string'; +import Point from './point'; +import Polygon from './polygon'; + +export default { + Point, + LineString, + Polygon, + Geometry +}; + +export { + Geometry, LineString, Point, Polygon +}; diff --git a/lib/geometry/line-string.ts b/lib/geometry/line-string.ts index 1cec008c..f805c058 100644 --- a/lib/geometry/line-string.ts +++ b/lib/geometry/line-string.ts @@ -15,185 +15,191 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const util = require('util'); -const utils = require('../utils'); -const Geometry = require('./geometry'); -const Point = require('./point'); +import util from "util"; +import utils from "../utils"; +import Geometry from "./geometry"; +import Point from "./point"; /** - * Creates a new {@link LineString} instance. * @classdesc * A LineString is a one-dimensional object representing a sequence of points and the line segments connecting them. - * @param {...Point}[point] A sequence of [Point]{@link module:geometry~Point} items as arguments. * @example * new LineString(new Point(10.99, 20.02), new Point(14, 26), new Point(34, 1.2)); - * @constructor * @alias module:geometry~LineString * @extends {Geometry} */ -function LineString(point) { - let points = Array.prototype.slice.call(arguments); - if (points.length === 1 && Array.isArray(points) && Array.isArray(points[0])) { - //The first argument is an array of the points - points = points[0]; - } - if (points.length === 1) { - throw new TypeError('LineString can be either empty or contain 2 or more points'); - } +class LineString extends Geometry { + /** @internal */ + points: ReadonlyArray; + /** - * Returns a frozen Array of points that represent the line. - * @type {Array.} + * Creates a new {@link LineString} instance. + * @param {...Point} points A sequence of {@link Point} items as arguments. */ - this.points = Object.freeze(points); -} - -//noinspection JSCheckFunctionSignatures -util.inherits(LineString, Geometry); - -/** - * Creates a {@link LineString} instance from - * a Well-known Text (WKT) - * representation of a line. - * @param {Buffer} buffer - * @returns {LineString} - */ -LineString.fromBuffer = function (buffer) { - if (!buffer || buffer.length < 9) { - throw new TypeError('A linestring buffer should contain at least 9 bytes'); - } - const endianness = Geometry.getEndianness(buffer.readInt8(0, true)); - let offset = 1; - if (Geometry.readInt32(buffer, endianness, offset) !== Geometry.types.LineString) { - throw new TypeError('Binary representation was not a LineString'); - } - offset += 4; - const length = Geometry.readInt32(buffer, endianness, offset); - offset += 4; - if (buffer.length !== offset + length * 16) { - throw new TypeError(util.format('Length of the buffer does not match %d !== %d', buffer.length, offset + length * 8)); - } - const points = new Array(length); - for (let i = 0; i < length; i++) { - points[i] = new Point( - Geometry.readDouble(buffer, endianness, offset), - Geometry.readDouble(buffer, endianness, offset + 8)); - offset += 16; - } - //noinspection JSCheckFunctionSignatures - return new LineString(points); -}; - -/** - * Creates a {@link LineString} instance from - * a Well-known Text (WKT) - * representation of a line. - * @param {String} textValue - * @returns {LineString} - */ -LineString.fromString = function (textValue) { - const wktRegex = /^LINESTRING ?\(([-0-9. ,]+)\)+$/g; - const matches = wktRegex.exec(textValue); - if (!matches || matches.length !== 2) { - throw new TypeError('Invalid WKT: ' + textValue); + constructor(...points: Point[] | Point[][]) { + super(); + if (points.length === 1 && Array.isArray(points) && Array.isArray(points[0])) { + //The first argument is an array of the points + points = points[0]; + } + if (points.length === 1) { + throw new TypeError('LineString can be either empty or contain 2 or more points'); + } + /** + * Returns a frozen Array of points that represent the line. + * @type {Array.} + */ + this.points = Object.freeze(points as Point[]); } - const points = LineString.parseSegments(matches[1]); - return new LineString(points); -}; -/** - * Internal method that parses a series of WKT points. - * @param {String} textValue - * @returns {Array} - * @internal - * @ignore - */ -LineString.parseSegments = function (textValue) { - const points = []; - const pointParts = textValue.split(','); - for (let i = 0; i < pointParts.length; i++) { - const p = pointParts[i].trim(); - if (p.length === 0) { - throw new TypeError('Invalid WKT segment: ' + textValue); + /** + * Creates a {@link LineString} instance from + * a Well-known Text (WKT) + * representation of a line. + * @param {Buffer} buffer + * @returns {LineString} + */ + static fromBuffer(buffer: Buffer): LineString { + if (!buffer || buffer.length < 9) { + throw new TypeError('A linestring buffer should contain at least 9 bytes'); } - const xyText = p.split(' ').filter(function (element) { - return (element.trim().length > 0); - }); - if (xyText.length !== 2) { - throw new TypeError('Invalid WKT segment: ' + textValue); + const endianness = Geometry.getEndianness(buffer.readInt8(0)); + let offset = 1; + if (Geometry.readInt32(buffer, endianness, offset) !== Geometry.types.LineString) { + throw new TypeError('Binary representation was not a LineString'); + } + offset += 4; + const length = Geometry.readInt32(buffer, endianness, offset); + offset += 4; + if (buffer.length !== offset + length * 16) { + throw new TypeError(util.format('Length of the buffer does not match %d !== %d', buffer.length, offset + length * 8)); + } + const points = new Array(length); + for (let i = 0; i < length; i++) { + points[i] = new Point( + Geometry.readDouble(buffer, endianness, offset), + Geometry.readDouble(buffer, endianness, offset + 8)); + offset += 16; } - points.push(new Point(parseFloat(xyText[0]), parseFloat(xyText[1]))); + //noinspection JSCheckFunctionSignatures + return new LineString(points); } - return points; -}; -/** - * Returns a Well-known Binary (WKB) - * representation of this instance. - * @returns {Buffer} - */ -LineString.prototype.toBuffer = function () { - const buffer = utils.allocBufferUnsafe(9 + this.points.length * 16); - this.writeEndianness(buffer, 0); - let offset = 1; - this.writeInt32(Geometry.types.LineString, buffer, offset); - offset += 4; - this.writeInt32(this.points.length, buffer, offset); - offset += 4; - this.points.forEach(function (p) { - this.writeDouble(p.x, buffer, offset); - this.writeDouble(p.y, buffer, offset + 8); - offset += 16; - }, this); - return buffer; -}; + /** + * Creates a {@link LineString} instance from + * a Well-known Text (WKT) + * representation of a line. + * @param {String} textValue + * @returns {LineString} + */ + static fromString(textValue: string): LineString { + const wktRegex = /^LINESTRING ?\(([-0-9. ,]+)\)+$/g; + const matches = wktRegex.exec(textValue); + if (!matches || matches.length !== 2) { + throw new TypeError("Invalid WKT: " + textValue); + } + const points = LineString.parseSegments(matches[1]); + return new LineString(points); + } -/** - * Returns true if the values of the linestrings are the same, otherwise it returns false. - * @param {LineString} other - * @returns {Boolean} - */ -LineString.prototype.equals = function (other) { - if (!(other instanceof LineString)) { - return false; + /** + * Internal method that parses a series of WKT points. + * @param {String} textValue + * @returns {Array} + * @internal + * @ignore + */ + static parseSegments(textValue: string): Point[] { + const points: Point[] = []; + const pointParts = textValue.split(","); + for (const part of pointParts) { + const p = part.trim(); + if (p.length === 0) { + throw new TypeError("Invalid WKT segment: " + textValue); + } + const xyText = p.split(" ").filter((element) => element.trim().length > 0); + if (xyText.length !== 2) { + throw new TypeError("Invalid WKT segment: " + textValue); + } + points.push(new Point(parseFloat(xyText[0]), parseFloat(xyText[1]))); + } + return points; } - if (this.points.length !== other.points.length) { - return false; + + /** + * Returns a Well-known Binary (WKB) + * representation of this instance. + * @returns {Buffer} + */ + toBuffer(): Buffer { + const buffer = utils.allocBufferUnsafe(9 + this.points.length * 16); + this.writeEndianness(buffer, 0); + let offset = 1; + this.writeInt32(Geometry.types.LineString, buffer, offset); + offset += 4; + this.writeInt32(this.points.length, buffer, offset); + offset += 4; + this.points.forEach((p) => { + this.writeDouble(p.x, buffer, offset); + this.writeDouble(p.y, buffer, offset + 8); + offset += 16; + }); + return buffer; } - for (let i = 0; i < this.points.length; i++) { - if (!this.points[i].equals(other.points[i])) { + + /** + * Returns true if the values of the linestrings are the same, otherwise it returns false. + * @param {LineString} other + * @returns {Boolean} + */ + equals(other: LineString): boolean { + if (!(other instanceof LineString)) { + return false; + } + if (this.points.length !== other.points.length) { return false; } + for (let i = 0; i < this.points.length; i++) { + if (!this.points[i].equals(other.points[i])) { + return false; + } + } + return true; } - return true; -}; -/** - * Returns Well-known text (WKT) representation of the geometry object. - * @returns {String} - */ -LineString.prototype.toString = function () { - if (this.points.length === 0) { - return 'LINESTRING EMPTY'; + /** + * Returns Well-known Text (WKT) representation of the geometry object. + * @returns {String} + */ + toString(): string { + if (this.points.length === 0) { + return 'LINESTRING EMPTY'; + } + return 'LINESTRING (' + + this.points.map(function (p) { + return p.x + ' ' + p.y; + }).join(', ') + + ')'; } - return 'LINESTRING (' - + this.points.map(function (p) { - return p.x + ' ' + p.y; - }).join(', ') - + ')'; -}; -LineString.prototype.useBESerialization = function () { - return false; -}; + /** + * Returns false to indicate little-endian serialization. + * @internal + * @returns {Boolean} + */ + useBESerialization(): boolean { + return false; + } -/** - * Returns a JSON representation of this geo-spatial type. - */ -LineString.prototype.toJSON = function () { - return { type: 'LineString', coordinates: this.points.map(function (p) { - return [p.x, p.y]; - })}; -}; + //TODO: it was exposed as toJSON(): string; But it clearly returns an object + /** + * Returns a JSON representation of this geo-spatial type. + */ + toJSON(): object { + return { type: 'LineString', coordinates: this.points.map(function (p) { + return [p.x, p.y]; + })}; + } +} -module.exports = LineString; \ No newline at end of file +export default LineString; \ No newline at end of file diff --git a/lib/geometry/point.ts b/lib/geometry/point.ts index 3b53e9b3..1ab76c1d 100644 --- a/lib/geometry/point.ts +++ b/lib/geometry/point.ts @@ -15,122 +15,130 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const util = require('util'); -const utils = require('../utils'); -const Geometry = require('./geometry'); +import util from "util"; +import utils from "../utils"; +import Geometry from "./geometry"; /** - * Creates a new {@link Point} instance. * @classdesc * A Point is a zero-dimensional object that represents a specific (X,Y) * location in a two-dimensional XY-Plane. In case of Geographic Coordinate * Systems, the X coordinate is the longitude and the Y is the latitude. - * @param {Number} x The X coordinate. - * @param {Number} y The Y coordinate. * @extends {Geometry} * @alias module:geometry~Point - * @constructor */ -function Point(x, y) { - if (typeof x !== 'number' || typeof y !== 'number') { - throw new TypeError('X and Y must be numbers'); - } - if (isNaN(x) || isNaN(y)) { - throw new TypeError('X and Y must be numbers'); - } +class Point extends Geometry { + /** @internal */ + x: number; + /** @internal */ + y: number; + /** - * Returns the X coordinate of this 2D point. - * @type {Number} + * Creates a new {@link Point} instance. + * @param {Number} x The X coordinate. + * @param {Number} y The Y coordinate. */ - this.x = x; + constructor(x: number, y: number) { + super(); + if (typeof x !== 'number' || typeof y !== 'number') { + throw new TypeError('X and Y must be numbers'); + } + if (isNaN(x) || isNaN(y)) { + throw new TypeError('X and Y must be numbers'); + } + /** + * Returns the X coordinate of this 2D point. + * @type {Number} + */ + this.x = x; + /** + * Returns the Y coordinate of this 2D point. + * @type {Number} + */ + this.y = y; + } + /** - * Returns the Y coordinate of this 2D point. - * @type {Number} + * Creates a {@link Point} instance from + * a Well-known Text (WKT) + * representation of a 2D point. + * @param {Buffer} buffer + * @returns {Point} */ - this.y = y; -} - -//noinspection JSCheckFunctionSignatures -util.inherits(Point, Geometry); + static fromBuffer(buffer: Buffer): Point { + if (!buffer || buffer.length !== 21) { + throw new TypeError('2D Point buffer should contain 21 bytes'); + } + const endianness = Geometry.getEndianness(buffer.readInt8(0)); + if (Geometry.readInt32(buffer, endianness, 1) !== Geometry.types.Point2D) { + throw new TypeError('Binary representation was not a point'); + } + return new Point(Geometry.readDouble(buffer, endianness, 5), Geometry.readDouble(buffer, endianness, 13)); + } -/** - * Creates a {@link Point} instance from - * a Well-known Text (WKT) - * representation of a 2D point. - * @param {Buffer} buffer - * @returns {Point} - */ -Point.fromBuffer = function (buffer) { - if (!buffer || buffer.length !== 21) { - throw new TypeError('2D Point buffer should contain 21 bytes'); + /** + * Creates a {@link Point} instance from + * a Well-known Text (WKT) + * representation of a 2D point. + * @param {String} textValue + * @returns {Point} + */ + static fromString(textValue: string): Point { + const wktRegex = /^POINT\s?\(([-0-9.]+) ([-0-9.]+)\)$/g; + const matches = wktRegex.exec(textValue); + if (!matches || matches.length !== 3) { + throw new TypeError("2D Point WKT should contain 2 coordinates"); + } + return new Point(parseFloat(matches[1]), parseFloat(matches[2])); } - const endianness = Geometry.getEndianness(buffer.readInt8(0, true)); - if (Geometry.readInt32(buffer, endianness, 1) !== Geometry.types.Point2D) { - throw new TypeError('Binary representation was not a point'); + + /** + * Returns a Well-known Binary (WKB) + * representation of this instance. + * @returns {Buffer} + */ + toBuffer(): Buffer { + const buffer = utils.allocBufferUnsafe(21); + this.writeEndianness(buffer, 0); + this.writeInt32(Geometry.types.Point2D, buffer, 1); + this.writeDouble(this.x, buffer, 5); + this.writeDouble(this.y, buffer, 13); + return buffer; } - return new Point(Geometry.readDouble(buffer, endianness, 5), Geometry.readDouble(buffer, endianness, 13)); -}; -/** - * Creates a {@link Point} instance from - * a Well-known Text (WKT) - * representation of a 2D point. - * @param {String} textValue - * @returns {Point} - */ -Point.fromString = function (textValue) { - const wktRegex = /^POINT\s?\(([-0-9.]+) ([-0-9.]+)\)$/g; - const matches = wktRegex.exec(textValue); - if (!matches || matches.length !== 3) { - throw new TypeError('2D Point WTK should contain 2 coordinates'); + /** + * Returns true if the values of the point are the same, otherwise it returns false. + * @param {Point} other + * @returns {Boolean} + */ + equals(other: Point): boolean { + if (!(other instanceof Point)) { + return false; + } + return this.x === other.x && this.y === other.y; } - return new Point(parseFloat(matches[1]), parseFloat(matches[2])); -}; -/** - * Returns a Well-known Binary (WKB) - * representation of this instance. - * @returns {Buffer} - */ -Point.prototype.toBuffer = function () { - const buffer = utils.allocBufferUnsafe(21); - this.writeEndianness(buffer, 0); - this.writeInt32(Geometry.types.Point2D, buffer, 1); - this.writeDouble(this.x, buffer, 5); - this.writeDouble(this.y, buffer, 13); - return buffer; -}; + /** + * Returns Well-known Text (WKT) representation of the geometry object. + * @returns {String} + */ + toString(): string { + return util.format("POINT (%d %d)", this.x, this.y); + } -/** - * Returns true if the values of the point are the same, otherwise it returns false. - * @param {Point} other - * @returns {Boolean} - */ -Point.prototype.equals = function (other) { - if (!(other instanceof Point)) { + /** @internal */ + useBESerialization(): boolean { return false; } - return (this.x === other.x && this.y === other.y); -}; - -/** - * Returns Well-known text (WKT) representation of the geometry object. - * @returns {String} - */ -Point.prototype.toString = function () { - return util.format('POINT (%d %d)', this.x, this.y); -}; - -Point.prototype.useBESerialization = function () { - return false; -}; -/** - * Returns a JSON representation of this geo-spatial type. - */ -Point.prototype.toJSON = function () { - return { type: 'Point', coordinates: [ this.x, this.y ]}; -}; + //TODO: exposed as toJSON(): string;, but clearly returning object + /** + * Returns a JSON representation of this geo-spatial type. + * @returns {Object} + */ + toJSON(): object { + return { type: "Point", coordinates: [this.x, this.y] }; + } +} -module.exports = Point; \ No newline at end of file +export default Point; \ No newline at end of file diff --git a/lib/geometry/polygon.ts b/lib/geometry/polygon.ts index aa4eff41..dba693c3 100644 --- a/lib/geometry/polygon.ts +++ b/lib/geometry/polygon.ts @@ -15,20 +15,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -'use strict'; -const util = require('util'); -const utils = require('../utils'); -const Geometry = require('./geometry'); -const Point = require('./point'); -const LineString = require('./line-string'); + +import utils from "../utils"; +import Geometry from "./geometry"; +import LineString from "./line-string"; +import Point from "./point"; /** - * Creates a new {@link Polygon} instance. * @classdesc * Represents is a plane geometry figure that is bounded by a finite chain of straight line segments closing in a loop * to form a closed chain or circuit. - * @param {...Array.}[ringPoints] A sequence of Array of [Point]{@link module:geometry~Point} items as arguments - * representing the rings of the polygon. * @example * new Polygon([ new Point(30, 10), new Point(40, 40), new Point(10, 20), new Point(30, 10) ]); * @example @@ -38,204 +34,199 @@ const LineString = require('./line-string'); * [ new Point(25, 20), new Point(30, 30), new Point(20, 20), new Point(25, 20) ] * ); * @alias module:geometry~Polygon - * @constructor */ -function Polygon(ringPoints) { - const rings = Array.prototype.slice.call(arguments); +class Polygon extends Geometry { + /** @internal */ + rings: ReadonlyArray>; + + //TODO: exposed as constructor(...args: Point[]); but clearly constructor(...args: Point[][]) /** - * Returns a frozen Array of array of points that represent the different rings in the polygon. - * @type {Array} + * Creates a new {@link Polygon} instance. + * @param {...Array.}[ringPoints] A sequence of Array of [Point]{@link module:geometry~Point} items as arguments + * representing the rings of the polygon. + * @example + * new Polygon([ new Point(30, 10), new Point(40, 40), new Point(10, 20), new Point(30, 10) ]); + * @example + * //polygon with a hole + * new Polygon( + * [ new Point(30, 10), new Point(40, 40), new Point(10, 20), new Point(30, 10) ], + * [ new Point(25, 20), new Point(30, 30), new Point(20, 20), new Point(25, 20) ] + * ); + * @constructor */ - this.rings = Object.freeze(rings); -} - -//noinspection JSCheckFunctionSignatures -util.inherits(Polygon, Geometry); - -/** - * Creates a {@link Polygon} instance from - * a Well-known Text (WKT) - * representation of a polygon. - * @param {Buffer} buffer - * @returns {Polygon} - */ -Polygon.fromBuffer = function (buffer) { - if (!buffer || buffer.length < 9) { - throw new TypeError('A Polygon buffer should contain at least 9 bytes'); + constructor(...ringPoints: Point[][]) { + super(); + this.rings = Object.freeze(ringPoints); } - const endianness = Geometry.getEndianness(buffer.readInt8(0, true)); - let offset = 1; - if (Geometry.readInt32(buffer, endianness, offset) !== Geometry.types.Polygon) { - throw new TypeError('Binary representation was not a Polygon'); - } - offset += 4; - const ringsLength = Geometry.readInt32(buffer, endianness, offset); - offset += 4; - const ringsArray = new Array(ringsLength); - for (let ringIndex = 0; ringIndex < ringsLength; ringIndex++) { - const pointsLength = Geometry.readInt32(buffer, endianness, offset); - offset += 4; - if (buffer.length < offset + pointsLength * 16) { - throw new TypeError(util.format('Length of the buffer does not match')); + + /** + * Creates a {@link Polygon} instance from + * a Well-known Text (WKT) + * representation of a polygon. + * @param {Buffer} buffer + * @returns {Polygon} + */ + static fromBuffer(buffer: Buffer): Polygon { + if (!buffer || buffer.length < 9) { + throw new TypeError("A Polygon buffer should contain at least 9 bytes"); } - const ring = new Array(pointsLength); - for (let i = 0; i < pointsLength; i++) { - ring[i] = new Point( - Geometry.readDouble(buffer, endianness, offset), - Geometry.readDouble(buffer, endianness, offset + 8)); - offset += 16; + const endianness = Geometry.getEndianness(buffer.readInt8(0)); + let offset = 1; + if (Geometry.readInt32(buffer, endianness, offset) !== Geometry.types.Polygon) { + throw new TypeError("Binary representation was not a Polygon"); } - ringsArray[ringIndex] = ring; - } - //Invoke the constructor with each ring as a parameter - //ringsArray.unshift(null); - //return new (Function.prototype.bind.apply(Polygon, ringsArray)); - return construct(ringsArray); -}; - -/** - * Creates a {@link Polygon} instance from - * a Well-known Text (WKT) - * representation of a shape. - * @param {String} textValue - * @returns {Polygon} - */ -Polygon.fromString = function (textValue) { - const wktRegex = /^POLYGON ?\((\(.*\))\)$/g; - const matches = wktRegex.exec(textValue); - function validateWkt(condition) { - if (condition) { - throw new TypeError('Invalid WKT: ' + textValue); + offset += 4; + const ringsLength = Geometry.readInt32(buffer, endianness, offset); + offset += 4; + const ringsArray : Point[][]= new Array(ringsLength); + for (let ringIndex = 0; ringIndex < ringsLength; ringIndex++) { + const pointsLength = Geometry.readInt32(buffer, endianness, offset); + offset += 4; + if (buffer.length < offset + pointsLength * 16) { + throw new TypeError("Length of the buffer does not match"); + } + const ring = new Array(pointsLength); + for (let i = 0; i < pointsLength; i++) { + ring[i] = new Point( + Geometry.readDouble(buffer, endianness, offset), + Geometry.readDouble(buffer, endianness, offset + 8) + ); + offset += 16; + } + ringsArray[ringIndex] = ring; } + return new Polygon(...ringsArray); } - validateWkt(!matches || matches.length !== 2); - const ringsText = matches[1]; - const ringsArray = []; - let ringStart = null; - for (let i = 0; i < ringsText.length; i++) { - const c = ringsText[i]; - if (c === '(') { - validateWkt(ringStart !== null); - ringStart = i+1; - continue; + /** + * Creates a {@link Polygon} instance from a Well-known Text (WKT) representation. + * @param {String} textValue + * @returns {Polygon} + */ + static fromString(textValue: string): Polygon { + const wktRegex = /^POLYGON ?\((\(.*\))\)$/g; + const matches = wktRegex.exec(textValue); + function validateWkt(condition) { + if (condition) { + throw new TypeError('Invalid WKT: ' + textValue); + } } - if (c === ')') { - validateWkt(ringStart === null); - ringsArray.push(ringsText.substring(ringStart, i)); - ringStart = null; - continue; + validateWkt(!matches || matches.length !== 2); + + const ringsText = matches[1]; + const ringsArray : string[] = []; + let ringStart = null; + for (let i = 0; i < ringsText.length; i++) { + const c = ringsText[i]; + if (c === '(') { + validateWkt(ringStart !== null); + ringStart = i+1; + continue; + } + if (c === ')') { + validateWkt(ringStart === null); + ringsArray.push(ringsText.substring(ringStart, i)); + ringStart = null; + continue; + } + validateWkt(ringStart === null && c !== ' ' && c !== ','); } - validateWkt(ringStart === null && c !== ' ' && c !== ','); + return new Polygon(...ringsArray.map(LineString.parseSegments)); } - return construct(ringsArray.map(LineString.parseSegments)); -}; -/** - * Creates a new instance of Polygon with each array item as a parameter - * @private - * @param {Array>} argsArray - * @returns {Polygon} - */ -function construct(argsArray) { - function F() { - return Polygon.apply(this, argsArray); - } - F.prototype = Polygon.prototype; - return new F(); -} - -/** - * Returns a Well-known Binary (WKB) - * representation of this instance. - * @returns {Buffer} - */ -Polygon.prototype.toBuffer = function () { - let totalRingsLength = 0; - this.rings.forEach(function (ring) { - totalRingsLength += 4 + ring.length * 16; - }, this); - const buffer = utils.allocBufferUnsafe(9 + totalRingsLength); - this.writeEndianness(buffer, 0); - let offset = 1; - this.writeInt32(Geometry.types.Polygon, buffer, offset); - offset += 4; - this.writeInt32(this.rings.length, buffer, offset); - offset += 4; - this.rings.forEach(function (ring) { - this.writeInt32(ring.length, buffer, offset); + /** + * Returns a Well-known Binary (WKB) + * representation of this instance. + * @returns {Buffer} + */ + toBuffer(): Buffer { + let totalRingsLength = 0; + this.rings.forEach((ring) => { + totalRingsLength += 4 + ring.length * 16; + }); + const buffer = utils.allocBufferUnsafe(9 + totalRingsLength); + this.writeEndianness(buffer, 0); + let offset = 1; + this.writeInt32(Geometry.types.Polygon, buffer, offset); offset += 4; - ring.forEach(function (p) { - this.writeDouble(p.x, buffer, offset); - this.writeDouble(p.y, buffer, offset + 8); - offset += 16; - }, this); - }, this); - return buffer; -}; - -/** - * Returns true if the values of the polygons are the same, otherwise it returns false. - * @param {Polygon} other - * @returns {Boolean} - */ -Polygon.prototype.equals = function (other) { - if (!(other instanceof Polygon)) { - return false; - } - if (this.rings.length !== other.rings.length) { - return false; + this.writeInt32(this.rings.length, buffer, offset); + offset += 4; + this.rings.forEach((ring) => { + this.writeInt32(ring.length, buffer, offset); + offset += 4; + ring.forEach((p) => { + this.writeDouble(p.x, buffer, offset); + this.writeDouble(p.y, buffer, offset + 8); + offset += 16; + }); + }); + return buffer; } - for (let i = 0; i < this.rings.length; i++) { - const r1 = this.rings[i]; - const r2 = other.rings[i]; - if (r1.length !== r2.length) { + + /** + * Returns true if the values of the polygons are the same, otherwise it returns false. + * @param {Polygon} other + * @returns {Boolean} + */ + equals(other: Polygon): boolean { + if (!(other instanceof Polygon)) { return false; } - for (let j = 0; j < r1.length; j++) { - if (!r1[i].equals(r2[i])) { + if (this.rings.length !== other.rings.length) { + return false; + } + for (let i = 0; i < this.rings.length; i++) { + const r1 = this.rings[i]; + const r2 = other.rings[i]; + if (r1.length !== r2.length) { return false; } + for (let j = 0; j < r1.length; j++) { + if (!r1[j].equals(r2[j])) { + return false; + } + } } + return true; } - return true; -}; - -Polygon.prototype.useBESerialization = function () { - return false; -}; -/** - * Returns Well-known text (WKT) representation of the geometry object. - * @returns {String} - */ -Polygon.prototype.toString = function () { - if (this.rings.length === 0) { - return 'POLYGON EMPTY'; + /** @internal */ + useBESerialization(): boolean { + return false; } - let ringStrings = ''; - this.rings.forEach(function (r, i) { - if (i > 0) { - ringStrings += ', '; - } - ringStrings += '(' + - r.map(function (p) { - return p.x + ' ' + p.y; - }).join(', ') - + ')'; - }); - return 'POLYGON (' + ringStrings + ')'; -}; -/** - * Returns a JSON representation of this geo-spatial type. - */ -Polygon.prototype.toJSON = function () { - return { type: 'Polygon', coordinates: this.rings.map(function (r) { - return r.map(function (p) { - return [ p.x, p.y ]; + /** + * Returns Well-known Text (WKT) representation of the geometry object. + * @returns {String} + */ + toString(): string { + if (this.rings.length === 0) { + return 'POLYGON EMPTY'; + } + let ringStrings = ''; + this.rings.forEach(function (r, i) { + if (i > 0) { + ringStrings += ', '; + } + ringStrings += '(' + + r.map(function (p) { + return p.x + ' ' + p.y; + }).join(', ') + + ')'; }); - })}; -}; + return 'POLYGON (' + ringStrings + ')'; + } + + /** + * Returns a JSON representation of this geo-spatial type. + */ + toJSON(): object { + return { type: 'Polygon', coordinates: this.rings.map(function (r) { + return r.map(function (p) { + return [ p.x, p.y ]; + }); + })}; + } +} -module.exports = Polygon; \ No newline at end of file +export default Polygon; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index b80ad4e9..ec13528b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,7 @@ "resolveJsonModule": true, "moduleResolution": "nodenext", "checkJs": true, + "types": ["node"], }, "include": [ "lib/**/*.ts",