style: apply stricter ts lint rules

This commit is contained in:
Michel Jonathan Schmitz
2019-06-19 16:13:50 +02:00
parent 38f5445634
commit 45755000f3
15 changed files with 145 additions and 104 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 StApps
* Copyright (C) 2018, 2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -46,9 +46,9 @@ export class Bulk<T extends SCThings> {
* @see Client.bulk
*/
constructor(
private type: SCThingType,
private client: Client,
private bulkResponse: SCBulkResponse,
private readonly type: SCThingType,
private readonly client: Client,
private readonly bulkResponse: SCBulkResponse,
) {
// noop
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 StApps
* Copyright (C) 2018, 2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -19,38 +19,43 @@ import {join} from 'path';
import {URL} from 'url';
import {copy} from './copy';
import {indexSamples} from './e2e';
import {HttpClient} from './httpClient';
import {HttpClient} from './http-client';
const logger = new Logger();
const pkgJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json')).toString());
const pkgJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'))
.toString());
const client = new HttpClient();
let actionDone = false;
process.on('unhandledRejection', (error) => {
logger.error('unhandledRejection', error);
process.on('unhandledRejection', async (error) => {
await Logger.error('unhandledRejection', error);
});
commander
.command('e2e <to>')
.description('Run in end to end test mode. Indexing all test files from @openstapp/core to the backend')
.option('-s --samples [path]', 'Path to @openstapp/core test files', './node_modules/@openstapps/core/test/resources')
.action((to, e2eCommand) => {
.action(async (to, e2eCommand) => {
let toURL = '';
// validate url
try {
to = (new URL(to)).toString();
toURL = (new URL(to)).toString();
} catch (err) {
logger.error('expected parameter "to" to be valid url', err);
await Logger.error('expected parameter "to" to be valid url', err);
e2eCommand.outputHelp();
process.exit(-1);
}
actionDone = true;
indexSamples(client, {to: to, samples: e2eCommand.samples}).then(() => {
logger.ok('Done');
});
indexSamples(client, {to: toURL, samples: e2eCommand.samples})
.then(() => {
Logger.ok('Done');
})
.catch(async (reason) => {
await Logger.error(reason);
});
});
commander
@@ -65,48 +70,52 @@ commander
// TODO: remove
.option('-a, --appVersion <version>', 'The App version to use [unset by default]')
.allowUnknownOption(false)
.action((type, from, to, batchSize, copyCommand) => {
.action(async (type, from, to, batchSize, copyCommand) => {
// validate type
if (typeof type !== 'string') {
logger.error('expected parameter "type" to be of type: string');
await Logger.error('expected parameter "type" to be of type: string');
copyCommand.outputHelp();
process.exit(-1);
}
let fromURL = '';
let toURL = '';
// validate urls
try {
from = (new URL(from)).toString();
to = (new URL(to)).toString();
fromURL = (new URL(from)).toString();
toURL = (new URL(to)).toString();
} catch (err) {
logger.error('expected parameters "from" and "to" to be valid urls', err);
await Logger.error('expected parameters "from" and "to" to be valid urls', err);
copyCommand.outputHelp();
process.exit(-1);
}
// validate batchSize
if (isNaN(parseInt(batchSize, 10))) {
logger.error('expected parameter "batchSize" to be of type: number');
await Logger.error('expected parameter "batchSize" to be of type: number');
copyCommand.outputHelp();
process.exit(-1);
}
actionDone = true;
logger.info('Copying ' + type + ' objects from ' + from + ' to ' + to);
Logger.info(`Copying ${type} objects from ${fromURL} to ${toURL}`);
copy(client, {
batchSize: parseInt(batchSize, 10),
from: from,
from: fromURL,
source: copyCommand.bulkSource,
to: to,
to: toURL,
type: type,
version: copyCommand.appVersion,
}).then(() => {
logger.ok('Done');
}, (err) => {
throw err;
});
})
.then(() => {
Logger.ok('Done');
}, (err) => {
throw err;
});
});
commander

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 StApps
* Copyright (C) 2018, 2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -14,6 +14,7 @@
*/
import {
SCAbstractRoute,
SCErrorResponse,
SCFeedbackRequest,
SCFeedbackResponse,
SCFeedbackRoute,
@@ -32,7 +33,7 @@ import {
SCThings,
} from '@openstapps/core';
import {ApiError, CoreVersionIncompatibleError, OutOfRangeError} from './errors';
import {HttpClientHeaders, HttpClientInterface} from './httpClientInterface';
import {HttpClientHeaders, HttpClientInterface} from './http-client-interface';
/**
* StApps-API client
@@ -115,7 +116,7 @@ export class Client {
* @param feedback Feedback to send
*/
async feedback(feedback: SCFeedbackRequest): Promise<SCFeedbackResponse> {
return await this.invokeRoute<SCFeedbackResponse>(this.feedbackRoute, undefined, feedback);
return this.invokeRoute<SCFeedbackResponse>(this.feedbackRoute, undefined, feedback);
}
/**
@@ -167,7 +168,7 @@ export class Client {
* @param body Body for the request
*/
async invokeRoute<T>(route: SCAbstractRoute,
parameters?: { [k: string]: string },
parameters?: { [k: string]: string; },
body?: SCRequests): Promise<T> {
// make the request
const response = await this.httpClient.request({
@@ -182,7 +183,7 @@ export class Client {
return response.body as T;
}
throw new ApiError(response.body);
throw new ApiError(response.body as SCErrorResponse);
}
/**
@@ -197,21 +198,24 @@ export class Client {
let preFlightNecessary = false;
// gather search requests where size is not set
Object.keys(multiSearchRequest).forEach((key) => {
const searchRequest = multiSearchRequest[key];
Object.keys(multiSearchRequest)
.forEach((key) => {
const searchRequest = multiSearchRequest[key];
if (typeof searchRequest.size === 'undefined') {
preFlightRequest[key] = {
...searchRequest,
};
preFlightRequest[key].size = 0;
preFlightNecessary = true;
}
});
if (typeof searchRequest.size === 'undefined') {
preFlightRequest[key] = {
...searchRequest,
};
preFlightRequest[key].size = 0;
preFlightNecessary = true;
}
});
let returnMultiSearchRequest = multiSearchRequest;
if (preFlightNecessary) {
// copy multi search request
multiSearchRequest = {
returnMultiSearchRequest = {
...multiSearchRequest,
};
@@ -223,13 +227,14 @@ export class Client {
);
// set size for multi search requests that were in pre flight request
Object.keys(preFlightRequest).forEach((key) => {
multiSearchRequest[key].size = preFlightResponse[key].pagination.total;
});
Object.keys(preFlightRequest)
.forEach((key) => {
returnMultiSearchRequest[key].size = preFlightResponse[key].pagination.total;
});
}
// actually invoke the route
return await this.invokeRoute<SCMultiSearchResponse>(this.multiSearchRoute, undefined, multiSearchRequest);
return this.invokeRoute<SCMultiSearchResponse>(this.multiSearchRoute, undefined, returnMultiSearchRequest);
}
/**
@@ -251,7 +256,7 @@ export class Client {
size = preFlightResponse.pagination.total;
}
return await this.invokeRoute<SCSearchResponse>(this.searchRoute, undefined, {
return this.invokeRoute<SCSearchResponse>(this.searchRoute, undefined, {
...searchRequest,
size,
});
@@ -264,8 +269,10 @@ export class Client {
* @param searchResponse Search response for supplied search request
*/
async searchNext(searchRequest: SCSearchRequest, searchResponse: SCSearchResponse): Promise<{
/* tslint:disable:completed-docs */
searchRequest: SCSearchRequest;
searchResponse: SCSearchResponse;
/* tslint:enable:completed-docs */
}> {
const nextSearchRequest = Client.nextWindow(searchRequest, searchResponse);

View File

@@ -30,19 +30,32 @@ import {Bulk} from './bulk';
import {Client} from './client';
import {EmptyBulkError, NamespaceNotDefinedError} from './errors';
/* tslint:disable:no-var-requires */
const V5_VERSION = 0x50;
/* tslint:disable:no-var-requires */
/**
* The package @types/uuid unfortunately doesn't expose the browser versions of the hashing functions.
* That's why we need to use a little trickery to get to it.
*/
const v35 = require('uuid/lib/v35');
const sha1Browser = require('uuid/lib/sha1-browser');
const v5 = v35('v5', 0x50, sha1Browser);
const v5 = v35('v5', V5_VERSION, sha1Browser);
/* tslint:enable */
/* tslint:enable:no-var-requires */
/**
* StApps-API client
*/
export class ConnectorClient extends Client {
/**
* The default timeout for the bulk to expire
*/
static readonly BULK_TIMEOUT = 3600;
/**
* The limit of how many items should be indexed concurrently
*/
static readonly ITEM_CONCURRENT_LIMIT = 5;
/**
* Instance of multi search request route
*/
@@ -78,10 +91,12 @@ export class ConnectorClient extends Client {
* @param thing Thing to remove references from
*/
static removeReferences<THING extends SCThings>(thing: THING): SCAssociatedThingWithoutReferences<THING> {
/* tslint:disable:no-any */
const thingWithoutReferences: any = {
...{},
...thing,
};
/* tslint:enable:no-any */
// iterate over all properties
for (const key in thingWithoutReferences) {
@@ -151,13 +166,18 @@ export class ConnectorClient extends Client {
* @param timeout Timeout in seconds when the bulk should expire
*/
async bulk<T extends SCThings>(type: SCThingType, source: string, timeout?: number): Promise<Bulk<T>> {
let bulkTimeout: number;
// set default value for timeout to one hour
if (typeof timeout !== 'number') {
timeout = 3600;
bulkTimeout = ConnectorClient.BULK_TIMEOUT;
} else {
bulkTimeout = timeout;
}
const bulkData = await this.invokeRoute<SCBulkResponse>(this.bulkRoute, undefined, {
expiration: moment().add(timeout, 'seconds').format(),
expiration: moment()
.add(bulkTimeout, 'seconds')
.format(),
source: source,
type: type,
});
@@ -182,16 +202,19 @@ export class ConnectorClient extends Client {
throw new EmptyBulkError();
}
let thingSource: string;
// set default source if none is given
if (typeof source === 'undefined') {
source = 'stapps-api';
thingSource = 'stapps-api';
} else {
thingSource = source;
}
// request a new bulk
const bulk = await this.bulk(things[0].type, source, timeout);
const bulk = await this.bulk(things[0].type, thingSource, timeout);
// add items to the bulk - 5 concurrently
await asyncPool(5, things, (thing) => bulk.add(thing));
await asyncPool(ConnectorClient.ITEM_CONCURRENT_LIMIT, things, (thing) => bulk.add(thing));
// close bulk
await bulk.done();

View File

@@ -16,9 +16,9 @@ import {asyncPool} from '@krlwlfrt/async-pool';
import {SCSearchRequest, SCThingType} from '@openstapps/core';
import {Bar} from 'cli-progress';
import {Client} from './client';
import {ConnectorClient} from './connectorClient';
import {ConnectorClient} from './connector-client';
import {OutOfRangeError} from './errors';
import {HttpClientInterface} from './httpClientInterface';
import {HttpClientInterface} from './http-client-interface';
/**
* Options to set up copying data from one backend to another
@@ -93,7 +93,7 @@ export async function copy(client: HttpClientInterface, options: CopyOptions): P
try {
({searchRequest, searchResponse} = await apiIn.searchNext(searchRequest, searchResponse));
await asyncPool(5, searchResponse.data, (item) => {
await asyncPool(ConnectorClient.ITEM_CONCURRENT_LIMIT, searchResponse.data, async (item) => {
progressBar.increment(1);
return bulk.add(item);

View File

@@ -17,8 +17,8 @@ import {SCThings, SCThingType} from '@openstapps/core';
import {readdir, readFile} from 'fs';
import {join} from 'path';
import {promisify} from 'util';
import {ConnectorClient} from './connectorClient';
import {HttpClientInterface} from './httpClientInterface';
import {ConnectorClient} from './connector-client';
import {HttpClientInterface} from './http-client-interface';
/**
* Options to set up indexing core test files to backend
@@ -100,5 +100,6 @@ export async function getItemsFromSamples<T extends SCThings>(samplesDirectory:
} catch (error) {
return error;
}
return things;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 StApps
* Copyright (C) 2018, 2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -39,12 +39,12 @@ export class ApiError extends Error {
// add additional data
if (typeof this.data.additionalData !== 'undefined') {
str += '\n\n' + JSON.stringify(this.data.additionalData);
str += `\n\n${JSON.stringify(this.data.additionalData)}`;
}
// add "remote" stack trace
if (typeof this.data.stack !== 'undefined') {
str += '\n\n' + this.data.stack;
str += `\n\n${this.data.stack}`;
}
return str;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 StApps
* Copyright (C) 2018, 2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -32,7 +32,9 @@ export interface HttpClientInterface {
* A map of headers
*/
export interface HttpClientHeaders {
/* tslint:disable:no-any */
[key: string]: any;
/* tslint:enable:no-any */
}
/**
@@ -72,6 +74,9 @@ export interface HttpClientRequest {
* A HTTP client response
*/
export interface HttpClientResponse<T extends SCResponses> {
/**
* Body of the response
*/
body: T | SCErrorResponse;
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 StApps
* Copyright (C) 2018, 2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -18,6 +18,9 @@ import * as request from 'request';
* Request options that requires a url
*/
export interface RequestOptions extends request.CoreOptions {
/**
* Target URL of the request
*/
url: URL;
}
@@ -25,6 +28,9 @@ export interface RequestOptions extends request.CoreOptions {
* Response with generic for the type of body that is returned from the request
*/
export interface Response<TYPE_OF_BODY> extends request.Response {
/**
* Typed body of the response
*/
body: TYPE_OF_BODY;
}
@@ -36,7 +42,8 @@ export class HttpClient {
* Make a request
* @param requestConfig Configuration of the request
*/
request<TYPE_OF_BODY>(
// tslint:disable-next-line:prefer-function-over-method
async request<TYPE_OF_BODY>(
requestConfig: RequestOptions,
): Promise<Response<TYPE_OF_BODY>> {
const params: request.CoreOptions = {

View File

@@ -22,7 +22,7 @@ import * as moment from 'moment';
import {Bulk} from '../src/bulk';
import {Client} from '../src/client';
import {BulkWithMultipleTypesError} from '../src/errors';
import {HttpClient} from '../src/httpClient';
import {HttpClient} from '../src/http-client';
chai.should();
chai.use(chaiSpies);
@@ -89,7 +89,7 @@ export class BulkSpec {
audiences: [
'students',
],
message: 'Lorem ipsum.',
messageBody: 'Lorem ipsum.',
name: 'foobar',
origin: {
indexed: moment().format(),

View File

@@ -34,8 +34,8 @@ import * as chaiSpies from 'chai-spies';
import {suite, test} from 'mocha-typescript';
import {Client} from '../src/client';
import {ApiError, OutOfRangeError} from '../src/errors';
import {HttpClient} from '../src/httpClient';
import {HttpClientResponse} from '../src/httpClientInterface';
import {HttpClient} from '../src/http-client';
import {HttpClientResponse} from '../src/http-client-interface';
chai.should();
chai.use(chaiSpies);
@@ -133,7 +133,7 @@ export class ClientSpec {
audiences: [
'employees',
],
message: 'Lorem ipsum.',
messageBody: 'Lorem ipsum.',
metaData: {
debug: true,
platform: 'android',
@@ -168,7 +168,7 @@ export class ClientSpec {
audiences: [
'employees',
],
message: 'Lorem ipsum.',
messageBody: 'Lorem ipsum.',
name: 'foo',
origin: {
indexed: 'foo',
@@ -254,7 +254,7 @@ export class ClientSpec {
audiences: [
'employees',
],
message: 'Lorem ipsum.',
messageBody: 'Lorem ipsum.',
name: 'foo',
origin: {
indexed: 'foo',

View File

@@ -22,11 +22,11 @@ import {
SCBulkResponse,
SCBulkRoute,
SCMessage,
SCThing,
SCThingOriginType,
SCThingType,
SCThingUpdateResponse,
SCThingUpdateRoute,
SCThingWithoutReferences,
} from '@openstapps/core';
import * as chai from 'chai';
import {expect} from 'chai';
@@ -38,10 +38,10 @@ import * as moment from 'moment';
import {join, resolve} from 'path';
import * as traverse from 'traverse';
import {promisify} from 'util';
import {ConnectorClient} from '../src/connectorClient';
import {ConnectorClient} from '../src/connector-client';
import {EmptyBulkError, NamespaceNotDefinedError} from '../src/errors';
import {HttpClient} from '../src/httpClient';
import {HttpClientRequest, HttpClientResponse} from '../src/httpClientInterface';
import {HttpClient} from '../src/http-client';
import {HttpClientRequest, HttpClientResponse} from '../src/http-client-interface';
chai.should();
chai.use(chaiSpies);
@@ -64,7 +64,7 @@ const httpClient = new HttpClient();
*
* @param thing Thing to check
*/
function doesContainThings<T extends SCThing>(thing: T): boolean {
function doesContainThings<T extends SCThingWithoutReferences>(thing: T): boolean {
/* tslint:disable-next-line:only-arrow-functions */
return traverse(thing).reduce(function(sum, item) {
if (this.isRoot) {
@@ -154,7 +154,7 @@ export class ConnectorClientSpec {
audiences: [
'employees',
],
message: 'Lorem ipsum.',
messageBody: 'Lorem ipsum.',
name: 'foo',
origin: {
indexed: 'foo',
@@ -168,7 +168,7 @@ export class ConnectorClientSpec {
audiences: [
'employees',
],
message: 'Lorem ipsum.',
messageBody: 'Lorem ipsum.',
name: 'foo',
origin: {
indexed: 'foo',
@@ -241,7 +241,7 @@ export class ConnectorClientSpec {
audiences: [
'employees',
],
message: 'Lorem ipsum.',
messageBody: 'Lorem ipsum.',
name: 'foo',
origin: {
indexed: 'foo',
@@ -255,7 +255,7 @@ export class ConnectorClientSpec {
audiences: [
'employees',
],
message: 'Lorem ipsum.',
messageBody: 'Lorem ipsum.',
name: 'foo',
origin: {
indexed: 'foo',
@@ -367,7 +367,7 @@ export class ConnectorClientSpec {
audiences: [
'employees',
],
message: 'Lorem ipsum.',
messageBody: 'Lorem ipsum.',
name: 'foo',
origin: {
indexed: 'foo',

View File

@@ -31,7 +31,7 @@ import {suite, test} from 'mocha-typescript';
import * as moment from 'moment';
import {copy} from '../src/copy';
import {ApiError} from '../src/errors';
import {HttpClient, RequestOptions, Response} from '../src/httpClient';
import {HttpClient, RequestOptions, Response} from '../src/http-client';
import {RecursivePartial} from './client.spec';
chai.should();

View File

@@ -24,13 +24,14 @@ import {
import * as chai from 'chai';
import * as chaiAsPromised from 'chai-as-promised';
import * as chaiSpies from 'chai-spies';
import {existsSync, mkdirSync} from 'fs';
import {existsSync, mkdirSync, rmdirSync, unlinkSync} from 'fs';
import {suite, test} from 'mocha-typescript';
import {join} from 'path';
import {getItemsFromSamples, indexSamples} from '../src/e2e';
import {ApiError} from '../src/errors';
import {HttpClient, RequestOptions, Response} from '../src/httpClient';
import {HttpClient, RequestOptions, Response} from '../src/http-client';
import {RecursivePartial} from './client.spec';
import {createFileSync} from 'fs-extra';
chai.should();
chai.use(chaiSpies);

View File

@@ -12,25 +12,13 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import * as chai from 'chai';
import {expect} from 'chai';
import * as chaiAsPromised from 'chai-as-promised';
import * as chaiSpies from 'chai-spies';
import {suite, test} from 'mocha-typescript';
import * as nock from 'nock';
import {HttpClient} from '../src/httpClient';
chai.should();
chai.use(chaiSpies);
chai.use(chaiAsPromised);
const sandbox = chai.spy.sandbox();
import {HttpClient} from '../src/http-client';
@suite()
export class ConnectorClientSpec {
async after() {
sandbox.restore();
}
export class HttpClientSpec {
@test
async construct() {