@loadmill/universal 0.3.46 → 0.3.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loadmill/universal",
3
- "version": "0.3.46",
3
+ "version": "0.3.47",
4
4
  "description": "Loadmill universal utilities",
5
5
  "main": "dist/",
6
6
  "types": "dist/index.d.ts",
@@ -1,59 +0,0 @@
1
- import reverse from 'lodash/reverse';
2
- import uniqBy from 'lodash/uniqBy';
3
-
4
- export function deleteOne(arr: any[], index: number) {
5
- if (index > -1) {
6
- arr.splice(index, 1);
7
- }
8
- }
9
-
10
- export function swap(arr: any[], oldIndex: number, newIndex: number) {
11
- if (newIndex < oldIndex) {
12
- arr.splice(newIndex, 0, arr[oldIndex]);
13
- arr.splice(oldIndex + 1, 1);
14
- } else {
15
- arr.splice(newIndex + 1, 0, arr[oldIndex]);
16
- arr.splice(oldIndex, 1);
17
- }
18
- }
19
-
20
- export const isNonEmptyArray = <T>(arr: T[] | T | undefined): arr is NonEmptyArray<T> =>
21
- Array.isArray(arr) && arr.length > 0;
22
-
23
- export type NonEmptyArray<T> = [T, ...T[]];
24
-
25
- export const filterFalsyElements = (arr: any[] = []): any[] =>
26
- arr.filter((p) => !!p);
27
-
28
- export const filterFalsyElementsByProp = (arr: object[], prop: string): any[] =>
29
- arr.filter((p) => !!p[prop]);
30
-
31
- export const arrayify = (something: any) => Array.isArray(something) ? something : [something];
32
-
33
- export function uniqByKeepLast(arr: any[], cmp) {
34
- return reverse(uniqBy(reverse(arr), cmp));
35
- }
36
-
37
- /**
38
- * Returns the closest element to target in arr
39
- * ex.
40
- * arr = ['2', '8', '16', '32', '64', '128'], target = '60', toNumber = (x) => Number(x)
41
- * will return '64'
42
- * @param {*} arr array of numberifyable elemets
43
- * @param {*} target numberifyable argument
44
- * @param {*} toNumber a predicate function that converts each n in arr to a number
45
- * If not provided, will use JavaScript's Number constructor
46
- * @returns undefined if arr is not an array, or is an empty array, or target . Otherwise, returns the closest element to target in arr.
47
- */
48
- export const getClosestNumberifyableElement = (arr: any[], target: any, toNumber: (n: any) => number = Number) => {
49
- if (!Array.isArray(arr) || arr.length === 0 || !target) {
50
- return;
51
- }
52
- return arr.reduce(
53
- (prev, curr) =>
54
- Math.abs(toNumber(curr) - toNumber(target)) <
55
- Math.abs(toNumber(prev) - toNumber(target)) ?
56
- curr :
57
- prev
58
- );
59
- };
package/src/countries.ts DELETED
@@ -1,44 +0,0 @@
1
- import { getCode, getName, getData } from 'country-list';
2
-
3
- const uglyToPretty = {
4
- 'Russian Federation': 'Russia',
5
- 'Syrian Arab Republic': 'Syria',
6
- 'Moldova, Republic of': 'Moldova',
7
- 'Palestine, State of': 'Palestine',
8
- 'Iran, Islamic Republic of': 'Iran',
9
- 'Korea, Republic of': 'South Korea',
10
- 'Taiwan, Province of China': 'Taiwan',
11
- 'Tanzania, United Republic of': 'Tanzania',
12
- 'Bolivia, Plurinational State of': 'Bolivia',
13
- 'Bonaire, Sint Eustatius and Saba': 'Bonaire',
14
- 'Virgin Islands, U.S.': 'U.S. Virgin Islands',
15
- 'Micronesia, Federated States of': 'Micronesia',
16
- 'Venezuela, Bolivarian Republic of': 'Venezuela',
17
- 'Virgin Islands, British': 'British Virgin Islands',
18
- 'Saint Helena, Ascension and Tristan da Cunha': 'Saint Helena',
19
- 'South Georgia and the South Sandwich Islands': 'South Georgia',
20
- 'Congo, the Democratic Republic of the': 'Congo (Democratic Republic)',
21
- };
22
-
23
- const prettyToUgly = {};
24
-
25
- Object.keys(uglyToPretty).forEach((key) => {
26
- prettyToUgly[uglyToPretty[key]] = key;
27
- });
28
-
29
- export const prettyCountryNames = getData().map(
30
- ({ name }) => uglyToPretty[name] || name
31
- );
32
-
33
- export function getCode(country) {
34
- return getCode(prettyToUgly[country] || country);
35
- }
36
-
37
- export function getCountry(countryCode: string) {
38
- const name = getName(countryCode);
39
- return uglyToPretty[name] || name;
40
- }
41
-
42
- export function isCode(countryCode: string) {
43
- return getName(countryCode) != null;
44
- }
package/src/cron-utils.ts DELETED
@@ -1,53 +0,0 @@
1
- import cronstrue from 'cronstrue';
2
- import parser from 'cron-parser';
3
-
4
- const isProduction = process.env.NODE_ENV === 'production';
5
- const TZ = isProduction ? { utc: true } : {};
6
-
7
- // For "0 23 ? * MON-FRI" returns "At 11:00 PM, Monday through Friday"
8
- export const getRecurrence = (cron) => {
9
- try {
10
- return cronstrue.toString(cron);
11
- } catch (error) {
12
- return '';
13
- }
14
- };
15
-
16
- export const parseCron = (cron) => parser.parseExpression(cron, TZ) as any;
17
-
18
-
19
- export const getCronLabel = cronStr => {
20
- let label = Object.keys(VALID_EXPRESSIONS).find(key => VALID_EXPRESSIONS[key] == cronStr);
21
-
22
- if (!label) {
23
- label = cronStr.match(/0 ([0-9]|1[0-9]|2[0-3]) \* \* [0-6]/) ? 'Once a Week' : '';
24
- }
25
- return label;
26
- };
27
-
28
- export const isAllowedExpression = cronStr => {
29
- return !!getCronLabel(cronStr);
30
- };
31
-
32
- export const VALID_EXPRESSIONS = {
33
- 'No scheduling': 'No scheduling',
34
- 'Every 10 minutes': '*/10 * * * *',
35
- 'Every 1 Hour': '0 */1 * * *',
36
- 'Every night': '0 2 * * *',
37
- 'Once a Week': '0 1 * * 1'
38
- };
39
-
40
- export const VALID_DAYS = {
41
- 'Sunday': 0,
42
- 'Monday': 1,
43
- 'Tuesday': 2,
44
- 'Wednsday': 3,
45
- 'Thursday': 4,
46
- 'Friday': 5,
47
- 'Saturday': 6
48
- };
49
-
50
- export const VALID_HOURS = [
51
- '00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00', '07:00', '08:00', '09:00', '10:00', '11:00',
52
- '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00'
53
- ];
package/src/enum-utils.ts DELETED
@@ -1,26 +0,0 @@
1
- /**
2
- * Works only for enums without string initializers.
3
- */
4
- export function names(anEnum) {
5
- return Object.keys(anEnum).filter((key) => typeof anEnum[key] === 'number');
6
- }
7
-
8
- /**
9
- * Works only for enums without string initializers.
10
- */
11
- export function values(anEnum) {
12
- return names(anEnum).map((name) => anEnum[name]);
13
- }
14
-
15
- /**
16
- * Works only for enums WITH string initializers.
17
- */
18
- export function stringValues(anEnum) {
19
- const res: string[] = [];
20
- for (const key in anEnum) {
21
- if (key) {
22
- res.push(anEnum[key]);
23
- }
24
- }
25
- return res;
26
- }
package/src/env-utils.ts DELETED
@@ -1,3 +0,0 @@
1
- export function isBrowser() {
2
- return typeof location === 'object';
3
- }
@@ -1,19 +0,0 @@
1
- import PresentableError from './presentable-error';
2
-
3
- /**
4
- * Represents an exception caused by a client error.
5
- * The specified message will be delivered to the client in the response body with
6
- * the given code as the status code.
7
- *
8
- */
9
- export default class ClientError extends PresentableError {
10
- constructor(
11
- public readonly code: number,
12
- prettyMessage: string,
13
- public readonly payload?: any
14
- ) {
15
- super(prettyMessage);
16
- // Workaround suggested in: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
17
- Object.setPrototypeOf(this, ClientError.prototype);
18
- }
19
- }
@@ -1,118 +0,0 @@
1
- import ClientError from './client-error';
2
- import { FieldErrors } from './field-errors';
3
-
4
- export function NullTokenClientError() {
5
- return new ClientError(400, 'null token');
6
- }
7
-
8
- export function BadFormClientError(
9
- fieldErrors: FieldErrors = {},
10
- code = 400,
11
- message = 'Bad Form submission failed'
12
- ) {
13
- return new ClientError(code, message, { fieldErrors });
14
- }
15
-
16
- export function ConfValidationClientError(err: {
17
- message: string;
18
- validation: any;
19
- }) {
20
- return new ClientError(400, err.message, { validation: err.validation });
21
- }
22
-
23
- export function IntegrationValidationClientError(message: string) {
24
- return new ClientError(400, message);
25
- }
26
-
27
- export function InvalidFormatClientError(badValue: string, type?: string) {
28
- return new ClientError(
29
- 400,
30
- `Invalid ${type ? type + ' ' : ''}format: '${badValue}'`
31
- );
32
- }
33
-
34
- export function InvalidRequestClientError(prettyMessage: string, payload?) {
35
- return new ClientError(400, prettyMessage, payload);
36
- }
37
-
38
- export function EntityAlreadyExistsError(prettyMessage: string, payload?) {
39
- return new ClientError(422, prettyMessage, payload);
40
- }
41
-
42
- export function MalformedHeaderClientError(headerName: string, value?: string) {
43
- return new ClientError(
44
- 400,
45
- `Malformed header: "${headerName}${value && `: ${value}`}"`
46
- );
47
- }
48
-
49
- export function UnauthorizedClientError(prettyMessage: string) {
50
- return new ClientError(401, prettyMessage);
51
- }
52
-
53
- export function CardClientError(message) {
54
- return new ClientError(402, message);
55
- }
56
-
57
- export function InsufficientCreditClientError(message) {
58
- return ForbiddenClientError(message);
59
- }
60
-
61
- export function NonDraftUpdateClientError(id: string) {
62
- return ForbiddenClientError(
63
- `Launched load test with id [${id}] cannot be edited any more.`
64
- );
65
- }
66
-
67
- export function ForbiddenClientError(message = 'You do not have permission for this operation', payload?) {
68
- return new ClientError(403, 'Not Allowed - ' + message, payload);
69
- }
70
-
71
- export function DeprecationClientError(message) {
72
- return new ClientError(403, 'Deprecation error - ' + message);
73
- }
74
-
75
- export function EmailTakenClientError() {
76
- return BadFormClientError({ email: 'This email is already taken' }, 403);
77
- }
78
-
79
- export function NonBetaEmailClientError() {
80
- return BadFormClientError(
81
- {
82
- email:
83
- 'This email is not on the beta users list. Please contact admin@loadmill.com.',
84
- },
85
- 403
86
- );
87
- }
88
-
89
- //todo: should be BadFormError:
90
- export function UnknownEmailClientError() {
91
- return new ClientError(404, 'Unknown email', {
92
- email: 'No account found for that email',
93
- });
94
- }
95
-
96
- export function EntityNotFoundClientError(name: string, id: string) {
97
- return new ClientError(404, `${name} with id [${id}] not found.`);
98
- }
99
-
100
- export function LoadTestNotFoundClientError(id: string) {
101
- return EntityNotFoundClientError('Load test', id);
102
- }
103
-
104
- export function LoadTestDraftNotFoundClientError(id: string) {
105
- return EntityNotFoundClientError('Load test draft', id);
106
- }
107
-
108
- export function LoadTestScheduledDraftNotFoundClientError(id: string) {
109
- return EntityNotFoundClientError('Scheduled load test draft', id);
110
- }
111
-
112
- export function TestSuiteScheduledNotFoundClientError(id: string) {
113
- return EntityNotFoundClientError('Scheduled test suite', id);
114
- }
115
-
116
- export function ArgumentNotFoundClientError(type: string, name: string) {
117
- return new ClientError(404, `${type} - '${name}' not found.`);
118
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * A mapping from form field names to their respective errors (if any).
3
- */
4
- export type FieldErrors = {
5
- [name: string]: string;
6
- };
@@ -1,27 +0,0 @@
1
- import PresentableError from './presentable-error';
2
- import ClientError from './client-error';
3
- import { FieldErrors } from './field-errors';
4
- import * as errors from './client-errors';
5
- import {
6
- superagentCorsError,
7
- corsErrorStatusPrefix,
8
- corsPreFlightErrorStatusPrefix,
9
- unknownStatusCorsError,
10
- isKnownStatusCorsError,
11
- isCorsError
12
- } from './known-errors';
13
- import JSONSchemaAssertionError from './json-schema-error';
14
-
15
- export {
16
- PresentableError,
17
- ClientError,
18
- errors,
19
- FieldErrors,
20
- superagentCorsError,
21
- corsErrorStatusPrefix,
22
- corsPreFlightErrorStatusPrefix,
23
- unknownStatusCorsError,
24
- isKnownStatusCorsError,
25
- isCorsError,
26
- JSONSchemaAssertionError
27
- };
@@ -1,10 +0,0 @@
1
- import PresentableError from './presentable-error';
2
-
3
- export default class JSONSchemaAssertionError extends PresentableError {
4
- constructor(public readonly prettyMessage) {
5
- super(prettyMessage);
6
-
7
- // Workaround suggested in: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
8
- Object.setPrototypeOf(this, JSONSchemaAssertionError.prototype);
9
- }
10
- }
@@ -1,21 +0,0 @@
1
- export const superagentCorsError =
2
- 'Request has been terminated\nPossible causes: ' +
3
- 'the network is offline, Origin is not allowed by Access-Control-Allow-Origin, ' +
4
- 'the page is being unloaded, etc.',
5
- corsErrorStatusPrefix =
6
- 'Missing Access-Control response headers - HTTP status ',
7
- corsPreFlightErrorStatusPrefix =
8
- 'Failed pre-flight (OPTIONS request) - HTTP status ',
9
- unknownStatusCorsError =
10
- 'Failed pre-flight or missing Access-Control response headers - HTTP status unknown';
11
-
12
- export function isKnownStatusCorsError(message: string) {
13
- return (
14
- message.startsWith(corsErrorStatusPrefix) ||
15
- message.startsWith(corsPreFlightErrorStatusPrefix)
16
- );
17
- }
18
-
19
- export function isCorsError(message: string) {
20
- return isKnownStatusCorsError(message) || message === unknownStatusCorsError;
21
- }
@@ -1,8 +0,0 @@
1
- export default class PresentableError extends Error {
2
- constructor(public readonly prettyMessage) {
3
- super(prettyMessage);
4
-
5
- // Workaround suggested in: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
6
- Object.setPrototypeOf(this, PresentableError.prototype);
7
- }
8
- }
package/src/log/cli.ts DELETED
@@ -1,63 +0,0 @@
1
- import chalk from 'chalk';
2
-
3
- const getPrefix = (color: string, level: string) => {
4
- return chalk[color](`[${new Date().toISOString()}] [${level.toUpperCase()}]`);
5
- };
6
-
7
- const filterStd = (std) => {
8
- const oldWrite = std._write;
9
-
10
- std._write = (chunk, encoding, done) => {
11
- if (chunk && chunk.includes('DeprecationWarning')) {
12
- done();
13
- } else {
14
- oldWrite.apply(std, [chunk, encoding, done]);
15
- }
16
- };
17
- };
18
-
19
- filterStd(process.stdout);
20
- filterStd(process.stderr);
21
-
22
- /* eslint no-console: 0 */
23
- class CliLogger {
24
- _level;
25
-
26
- trace(): void {}
27
- debug(): void {}
28
- info(): void {}
29
- warn(): void {}
30
- fatal(): void {}
31
-
32
- error(text, ...args: any[]): void {
33
- let err;
34
-
35
- args.forEach(arg => {
36
- if (arg instanceof Error) {
37
- err = arg;
38
- } else if (arg && typeof arg === 'object') {
39
- Object.keys(arg).forEach(key => {
40
- if (arg[key] instanceof Error) {
41
- err = arg;
42
- }
43
- });
44
- }
45
- });
46
-
47
- console.error(getPrefix('redBright', 'error'), text, ...(err ? ['\n', err.stack] : []));
48
- }
49
-
50
- cli(text: string) {
51
- console.log(getPrefix('green', 'info'), text);
52
- }
53
-
54
- set level(level: string) {
55
- this._level = level;
56
- }
57
-
58
- get level() {
59
- return this._level;
60
- }
61
- }
62
-
63
- export default new CliLogger();
package/src/log/client.ts DELETED
@@ -1,56 +0,0 @@
1
- /* eslint no-console: 0 */
2
- import dayjs from 'dayjs';
3
-
4
- export enum Levels {
5
- TRACE,
6
- DEBUG,
7
- INFO,
8
- WARN,
9
- ERROR,
10
- FATAL,
11
- }
12
-
13
- export class SimpleLogger {
14
- _level: number;
15
-
16
- trace = (...args) => this.log(Levels.TRACE, ...args);
17
-
18
- debug = (...args) => this.log(Levels.DEBUG, ...args);
19
-
20
- info = (...args) => this.log(Levels.INFO, ...args);
21
-
22
- warn = (...args) => this.log(Levels.WARN, ...args);
23
-
24
- error = (...args) => this.log(Levels.ERROR, ...args);
25
-
26
- fatal = (...args) => this.log(Levels.FATAL, ...args);
27
-
28
- cli = () => {};
29
-
30
- log = (level: Levels, ...args) => {
31
- if (level >= this._level) {
32
- const time = dayjs().format('HH:mm:ss.SSS');
33
-
34
- const out =
35
- level < Levels.WARN
36
- ? console['log']
37
- : level === Levels.WARN
38
- ? console['warn']
39
- : console['error'];
40
-
41
- out(`[${time}]`, `[${Levels[level]}] -`, ...args);
42
- }
43
- };
44
-
45
- set level(level: string | Levels) {
46
- if (typeof level === 'string') {
47
- level = Levels[level.toUpperCase()] as number;
48
- }
49
-
50
- this._level = level;
51
- }
52
-
53
- get level() {
54
- return this._level;
55
- }
56
- }
package/src/log/index.ts DELETED
@@ -1,24 +0,0 @@
1
- export declare interface Logger {
2
- level: any;
3
- cli(...args: any[]): void;
4
- trace(...args: any[]): void;
5
- debug(...args: any[]): void;
6
- info(...args: any[]): void;
7
- warn(...args: any[]): void;
8
- error(...args: any[]): void;
9
- fatal(...args: any[]): void;
10
- }
11
-
12
- let log: Logger;
13
-
14
- if (process.env.APP_ENV === 'browser') {
15
- const { SimpleLogger } = require('./client');
16
-
17
- log = new SimpleLogger();
18
- } else if (process.env.APP_ENV === 'cli') {
19
- log = require('./cli').default;
20
- } else {
21
- log = require('./server').default;
22
- }
23
-
24
- export default log;
package/src/log/server.ts DELETED
@@ -1,120 +0,0 @@
1
- import 'source-map-support/register';
2
- import log4js from 'log4js';
3
- import stackTrace from 'stack-trace';
4
- import CircularJSON from 'circular-json';
5
- import { wrapCallSite } from 'source-map-support';
6
- import { myId } from '../my-id';
7
-
8
- const isDev = process.env.NODE_ENV !== 'production';
9
- const level = process.env.LOG_LEVEL || 'info';
10
- const LOG_NEW_LINES = process.env.LOG_NEW_LINES ? process.env.LOG_NEW_LINES === 'true' : isDev;
11
-
12
- log4js.configure({
13
- disableClustering: true,
14
-
15
- appenders: {
16
- out: {
17
- type: 'console',
18
- },
19
- },
20
-
21
- categories: {
22
- default: {
23
- level,
24
- appenders: ['out'],
25
- },
26
-
27
- [myId]: {
28
- level,
29
- appenders: ['out'],
30
- },
31
- },
32
- });
33
-
34
- const log = log4js.getLogger(myId);
35
- log.level = level;
36
-
37
- const loggingMethods = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
38
-
39
- // Adds logging-source information (for ALL loggers!) if and only if logging
40
- // will actually take place, i.e. if the current log level permits:
41
- loggingMethods.forEach((method) => {
42
- const original = log.constructor.prototype[method];
43
-
44
- log.constructor.prototype[method] = function methodRef(this: any) {
45
- // eslint-disable-next-line
46
- let newArguments: any = arguments;
47
-
48
- try {
49
- if (
50
- (log4js.levels as any)
51
- .getLevel(method)
52
- .isGreaterThanOrEqualTo(this.level)
53
- ) {
54
- // logging WILL take place:
55
- const trace = stackTrace.get(methodRef);
56
-
57
- const { file, line, funcName } = extractSourceInfo(trace[0]);
58
-
59
- // See https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments
60
- newArguments = new Array(arguments.length);
61
- for (let i = 0; i < newArguments.length; ++i) {
62
- // eslint-disable-next-line
63
- newArguments[i] = processArgument(arguments[i]);
64
- }
65
-
66
- newArguments.push(`[${file}:${line}#${funcName}]`);
67
- }
68
- } catch (e) {
69
- // like nothing ever happened...
70
- // eslint-disable-next-line
71
- return original.apply(this, arguments);
72
- }
73
-
74
- return original.apply(this, newArguments);
75
- };
76
- });
77
-
78
- function extractSourceInfo(originalFrame) {
79
- // This line uses the source maps:
80
- const frame = wrapCallSite(originalFrame);
81
-
82
- const originalFile = frame.getFileName();
83
-
84
- // remove leading "../"s:
85
- const srcIndex = originalFile.indexOf('src');
86
- const file = srcIndex >= 0 ? originalFile.slice(srcIndex) : originalFile;
87
-
88
- const line = frame.getLineNumber();
89
- const funcName =
90
- frame.getMethodName() || frame.getFunctionName() || '<anonymous>';
91
-
92
- return {
93
- file,
94
- line,
95
- funcName,
96
- };
97
- }
98
-
99
- function processArgument(argument: any) {
100
- const isError = argument instanceof Error;
101
-
102
- if (typeof argument !== 'string' && !isError) {
103
- argument = stringify(argument);
104
- }
105
-
106
- return isError || !argument || LOG_NEW_LINES
107
- ? argument
108
- : argument.replace(/(?:\r\n|\r|\n)/g, '^');
109
- }
110
-
111
- function stringify(argument: any) {
112
- return LOG_NEW_LINES
113
- ? CircularJSON.stringify(argument, null, 4)
114
- : CircularJSON.stringify(argument);
115
- }
116
-
117
- // @ts-ignore
118
- log.cli = (...args) => log.info(...args);
119
-
120
- export default log;