express-generator-typescript 2.5.5 → 2.5.7

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.
@@ -13,7 +13,7 @@ const PROJECT_FOLDER_PATH = './project-files';
13
13
  // Project-folder dependencies
14
14
  const DEPENDENCIES = 'express dotenv morgan cookie-parser jet-logger ' +
15
15
  'module-alias express-async-errors helmet jsonfile inserturlparams ' +
16
- 'jet-paths dayjs jet-schema jet-env ',
16
+ 'jet-paths dayjs jet-schema jet-env jet-validators',
17
17
  DEV_DEPENDENCIES = 'ts-node typescript nodemon find jasmine supertest ' +
18
18
  '@types/node @types/express @types/jasmine @types/find @types/morgan ' +
19
19
  '@types/cookie-parser @types/supertest fs-extra tsconfig-paths jiti @swc/core ' +
@@ -4,7 +4,6 @@ import stylisticJs from '@stylistic/eslint-plugin-js';
4
4
  import stylisticTs from '@stylistic/eslint-plugin-ts';
5
5
  import nodePlugin from 'eslint-plugin-n';
6
6
 
7
-
8
7
  export default tseslint.config(
9
8
  eslint.configs.recommended,
10
9
  nodePlugin.configs['flat/recommended-script'],
@@ -18,21 +18,22 @@
18
18
  "dependencies": {
19
19
  "cookie-parser": "^1.4.6",
20
20
  "dayjs": "^1.11.13",
21
- "dotenv": "^16.0.2",
21
+ "dotenv": "^16.4.5",
22
22
  "express": "^4.18.1",
23
23
  "express-async-errors": "^3.1.1",
24
24
  "helmet": "^6.0.0",
25
- "inserturlparams": "^1.0.1",
25
+ "inserturlparams": "^2.0.5",
26
26
  "jet-env": "^1.1.4",
27
- "jet-logger": "^1.3.1",
28
- "jet-paths": "^1.0.5",
27
+ "jet-logger": "^2.0.1",
28
+ "jet-paths": "^1.1.0",
29
29
  "jet-schema": "^1.4.2",
30
+ "jet-validators": "^1.0.6",
30
31
  "jsonfile": "^6.1.0",
31
32
  "module-alias": "^2.2.2",
32
33
  "morgan": "^1.10.0"
33
34
  },
34
35
  "devDependencies": {
35
- "@eslint/js": "^9.11.1",
36
+ "@eslint/js": "^9.16.0",
36
37
  "@stylistic/eslint-plugin-js": "^2.11.0",
37
38
  "@stylistic/eslint-plugin-ts": "^2.8.0",
38
39
  "@swc/core": "^1.9.3",
@@ -48,7 +49,7 @@
48
49
  "@types/node": "^18.7.14",
49
50
  "@types/supertest": "^6.0.2",
50
51
  "eslint": "^9.11.1",
51
- "eslint-plugin-n": "^17.10.3",
52
+ "eslint-plugin-n": "^17.14.0",
52
53
  "find": "^0.3.0",
53
54
  "fs-extra": "^10.1.0",
54
55
  "jasmine": "^4.3.0",
@@ -0,0 +1,18 @@
1
+ import { isValidDate } from 'jet-validators';
2
+ import { traverseObject } from 'jet-validators/utils';
3
+
4
+
5
+ /**
6
+ * Send a date object over an API will convert it to a string, so for jasmine
7
+ * tests to pass we need to convert them back to date objects.
8
+ */
9
+ export function convertValidDates(toConvert: string | string[]) {
10
+ if (!Array.isArray(toConvert)) {
11
+ toConvert = [toConvert];
12
+ }
13
+ return traverseObject((prop, value, parentObj) => {
14
+ if (toConvert.includes(prop) && isValidDate(value)) {
15
+ parentObj[prop] = new Date(value);
16
+ }
17
+ });
18
+ }
@@ -1,22 +1,25 @@
1
1
  import supertest, { Test } from 'supertest';
2
2
  import TestAgent from 'supertest/lib/agent';
3
3
  import insertUrlParams from 'inserturlparams';
4
+ import { safeJsonParse } from 'jet-validators/utils';
5
+ import logger from 'jet-logger';
4
6
 
5
7
  import app from '@src/server';
6
8
 
7
9
  import UserRepo from '@src/repos/UserRepo';
8
10
  import User, { IUser } from '@src/models/User';
9
11
  import { USER_NOT_FOUND_ERR } from '@src/services/UserService';
10
- import { safeJsonParse } from '@src/util/validators';
11
12
 
12
13
  import HttpStatusCodes from '@src/common/HttpStatusCodes';
13
14
  import { IValidationErrFormat, ValidationErr } from '@src/common/route-errors';
14
15
 
15
16
  import Paths from 'spec/support/Paths';
16
- import apiCb from 'spec/support/apiCb';
17
- import { TApiCb } from 'spec/types/misc';
17
+ import { convertValidDates } from 'spec/support';
18
+ import { TApiCb, TRes } from 'spec/types/misc';
18
19
 
19
20
 
21
+ // **** Setup **** //
22
+
20
23
  // Dummy users for GET req
21
24
  const getDummyUsers = () => [
22
25
  User.new({ name: 'Sean Maxwell', email: 'sean.maxwell@gmail.com' }),
@@ -24,8 +27,25 @@ const getDummyUsers = () => [
24
27
  User.new({ name: 'Gordan Freeman', email: 'gordan.freeman@gmail.com' }),
25
28
  ];
26
29
 
30
+ // Convert "created" prop back to Date object
31
+ const createdKeyToDate = convertValidDates('created');
32
+
33
+ // Setup wrap-callback function
34
+ const wrapCb = (cb: TApiCb) => (err: Error, res: TRes) => {
35
+ if (!!err) {
36
+ logger.err(err);
37
+ }
38
+ if (!!res.body.user) {
39
+ createdKeyToDate(res.body.user);
40
+ } else if (!!res.body.users) {
41
+ res.body.users?.map(user => createdKeyToDate(user));
42
+ }
43
+ return cb(res);
44
+ };
45
+
46
+
47
+ // **** Run Tests **** //
27
48
 
28
- // Tests
29
49
  describe('UserRouter', () => {
30
50
 
31
51
  let agent: TestAgent<Test>;
@@ -43,7 +63,7 @@ describe('UserRouter', () => {
43
63
  const api = (cb: TApiCb) =>
44
64
  agent
45
65
  .get(Paths.Users.Get)
46
- .end(apiCb(cb));
66
+ .end(wrapCb(cb));
47
67
 
48
68
  // Success
49
69
  it('should return a JSON object with all the users and a status code ' +
@@ -70,7 +90,7 @@ describe('UserRouter', () => {
70
90
  agent
71
91
  .post(Paths.Users.Add)
72
92
  .send({ user })
73
- .end(apiCb(cb));
93
+ .end(wrapCb(cb));
74
94
 
75
95
  // Test add user success
76
96
  it(`should return a status code of "${HttpStatusCodes.CREATED}" if the ` +
@@ -109,7 +129,7 @@ describe('UserRouter', () => {
109
129
  agent
110
130
  .put(Paths.Users.Update)
111
131
  .send({ user })
112
- .end(apiCb(cb));
132
+ .end(wrapCb(cb));
113
133
 
114
134
  // Success
115
135
  it(`should return a status code of "${HttpStatusCodes.OK}" if the ` +
@@ -154,7 +174,7 @@ describe('UserRouter', () => {
154
174
  const callApi = (id: number, cb: TApiCb) =>
155
175
  agent
156
176
  .delete(insertUrlParams(Paths.Users.Delete, { id }))
157
- .end(apiCb(cb));
177
+ .end(wrapCb(cb));
158
178
 
159
179
  // Success
160
180
  it(`should return a status code of "${HttpStatusCodes.OK}" if the ` +
@@ -1,6 +1,6 @@
1
1
  import jetEnv, { num } from 'jet-env';
2
+ import { isEnumVal } from 'jet-validators';
2
3
 
3
- import { isEnumVal } from '@src/util/validators';
4
4
  import { NodeEnvs } from './constants';
5
5
 
6
6
 
@@ -1,5 +1,7 @@
1
+ import { isString } from 'jet-validators';
2
+
1
3
  import schema from '@src/util/schema';
2
- import { isNum, isStr } from '@src/util/validators';
4
+ import { isRelationalKey } from '@src/util/validators';
3
5
 
4
6
 
5
7
  export interface IUser {
@@ -10,10 +12,10 @@ export interface IUser {
10
12
  }
11
13
 
12
14
  const User = schema<IUser>({
13
- id: isNum,
14
- name: isStr,
15
+ id: isRelationalKey,
16
+ name: isString,
15
17
  created: Date,
16
- email: isStr,
18
+ email: isString,
17
19
  });
18
20
 
19
21
 
@@ -1,7 +1,10 @@
1
+ import { isNumber } from 'jet-validators';
2
+ import { transform } from 'jet-validators/utils';
3
+
1
4
  import HttpStatusCodes from '@src/common/HttpStatusCodes';
2
5
  import UserService from '@src/services/UserService';
3
6
  import User from '@src/models/User';
4
- import { isNum, transform } from '@src/util/validators';
7
+
5
8
 
6
9
  import { parseReq, IReq, IRes } from './common';
7
10
 
@@ -11,7 +14,7 @@ import { parseReq, IReq, IRes } from './common';
11
14
  const Validators = {
12
15
  add: parseReq({ user: User.test }),
13
16
  update: parseReq({ user: User.test }),
14
- delete: parseReq({ id: transform(Number, isNum) }),
17
+ delete: parseReq({ id: transform(Number, isNumber) }),
15
18
  } as const;
16
19
 
17
20
 
@@ -1,14 +1,14 @@
1
1
  import { Response, Request } from 'express';
2
+ import { parseObject, TSchema } from 'jet-validators/utils';
2
3
 
3
- import { parseObj, TSchema } from '@src/util/validators';
4
4
  import { ValidationErr } from '@src/common/route-errors';
5
5
 
6
6
 
7
7
  // **** Types **** //
8
8
 
9
- type TObj = Record<string, unknown>;
10
- export type IReq = Request<TObj, void, TObj, TObj>;
11
- export type IRes = Response<unknown, TObj>;
9
+ type TRecord = Record<string, unknown>;
10
+ export type IReq = Request<TRecord, void, TRecord, TRecord>;
11
+ export type IRes = Response<unknown, TRecord>;
12
12
 
13
13
 
14
14
  // **** Functions **** //
@@ -17,7 +17,7 @@ export type IRes = Response<unknown, TObj>;
17
17
  * Parse a Request object property and throw a Validation error if it fails.
18
18
  */
19
19
  export function parseReq<U extends TSchema>(schema: U) {
20
- return parseObj<U>(schema, _parseReqOnError);
20
+ return parseObject<U>(schema, _parseReqOnError);
21
21
  }
22
22
 
23
23
  /**
@@ -1,11 +1,13 @@
1
1
  import jetSchema from 'jet-schema';
2
- import { isBool, isNum, isStr } from './validators';
2
+ import { isNumber, isString, isBoolean } from 'jet-validators';
3
+ import { isRelationalKey } from './validators';
3
4
 
4
5
 
5
6
  export default jetSchema({
6
7
  globals: [
7
- { vf: isNum, default: 0 },
8
- { vf: isStr, default: '' },
9
- { vf: isBool, default: false },
8
+ { vf: isRelationalKey, default: -1 },
9
+ { vf: isNumber, default: 0 },
10
+ { vf: isString, default: '' },
11
+ { vf: isBoolean, default: false },
10
12
  ],
11
13
  });
@@ -1,326 +1,9 @@
1
- /**
2
- * NOTE: These functions were copied from here:
3
- * https://github.com/seanpmaxwell/ts-validators/blob/master/src/validators.ts
4
- */
5
-
6
- /* eslint-disable max-len */
7
-
8
-
9
- // **** Types **** //
10
-
11
- type TBasicObj = Record<string, unknown>;
12
- type TEnum = Record<string, string | number>;
13
-
14
- // Add modifiers
15
- type AddNull<T, N> = (N extends true ? T | null : T);
16
- type AddNullables<T, O, N> = (O extends true ? AddNull<T, N> | undefined : AddNull<T, N>);
17
- type AddMods<T, O, N, A> = A extends true ? AddNullables<T[], O, N> : AddNullables<T, O, N>;
18
- export type TValidateWithTransform<T> = (arg: unknown, cb?: (arg: T) => void) => arg is T;
19
-
20
-
21
- // **** Functions **** //
22
-
23
- // Nullables
24
- export const isUndef = ((arg: unknown): arg is undefined => arg === undefined);
25
- export const isNull = ((arg: unknown): arg is null => arg === null);
26
-
27
- // Base types
28
- export const isStr = _checkType<string>('string');
29
- export const isNum = _checkType<number>('number');
30
- export const isBool = _checkType<boolean>('boolean');
31
- export const isObj = _checkType<object>('object');
32
-
33
- // Misc
34
- export const parseObj = <U extends TSchema>(arg: U, onError?: TParseOnError<false>) =>
35
- _parseObj<U, false, false, false>(arg, false, false, false, onError);
36
- export const isEnumVal = <T>(arg: T) => _isEnumVal<T, false, false>(arg, false, false);
37
-
38
- // Util
39
- export const transform = _transform;
40
- export const safeJsonParse = _safeJsonParse;
41
-
42
-
43
- // **** Helpers **** //
44
-
45
- /**
46
- * Check if unknown is a valid enum object.
47
- * NOTE: this does not work for mixed enums see: "eslint@typescript-eslint/no-mixed-enums"
48
- */
49
- function _isEnum(arg: unknown): arg is TEnum {
50
- // Check is non-array object
51
- if (!(isObj(arg) && !Array.isArray(arg))) {
52
- return false;
53
- }
54
- // Check if string or number enum
55
- const param = (arg as TBasicObj),
56
- keys = Object.keys(param),
57
- middle = Math.floor(keys.length / 2);
58
- // ** String Enum ** //
59
- if (!isNum(param[keys[middle]])) {
60
- return _checkObjEntries(arg, (key, val) => {
61
- return isStr(key) && isStr(val);
62
- });
63
- }
64
- // ** Number Enum ** //
65
- // Enum key length will always be even
66
- if (keys.length % 2 !== 0) {
67
- return false;
68
- }
69
- // Check key/values
70
- for (let i = 0; i < middle; i++) {
71
- const thisKey = keys[i],
72
- thisVal = param[thisKey],
73
- thatKey = keys[i + middle],
74
- thatVal = param[thatKey];
75
- if (!(thisVal === thatKey && thisKey === String(thatVal))) {
76
- return false;
77
- }
78
- }
79
- // Return
80
- return true;
81
- }
82
-
83
- /**
84
- * Check is value satisfies enum.
85
- */
86
- function _isEnumVal<T,
87
- O extends boolean,
88
- N extends boolean
89
- >(
90
- enumArg: T,
91
- optional: O,
92
- nullable: N,
93
- ): ((arg: unknown) => arg is AddNullables<T[keyof T], O, N>) {
94
- // Check is enum
95
- if (!_isEnum(enumArg)) {
96
- throw Error('Item to check from must be an enum.');
97
- }
98
- // Get keys
99
- let resp = Object.keys(enumArg).reduce((arr: unknown[], key) => {
100
- if (!arr.includes(key)) {
101
- arr.push(enumArg[key]);
102
- }
103
- return arr;
104
- }, []);
105
- // Check if string or number enum
106
- if (isNum(enumArg[resp[0] as string])) {
107
- resp = resp.map(item => enumArg[item as string]);
108
- }
109
- // Return validator function
110
- return (arg: unknown): arg is AddNullables<T[keyof T], O, N> => {
111
- if (isUndef(arg)) {
112
- return !!optional;
113
- }
114
- if (isNull(arg)) {
115
- return !!nullable;
116
- }
117
- return resp.some(val => arg === val);
118
- };
119
- }
120
-
121
- /**
122
- * Do a validator callback function for each object key/value pair.
123
- */
124
- function _checkObjEntries(
125
- val: unknown,
126
- cb: (key: string, val: unknown) => boolean,
127
- ): val is NonNullable<object> {
128
- if (isObj(val)) {
129
- for (const entry of Object.entries(val)) {
130
- if (!cb(entry[0], entry[1])) {
131
- return false;
132
- }
133
- }
134
- }
135
- return true;
136
- }
1
+ import { isNumber } from 'jet-validators';
137
2
 
138
- /**
139
- * Wrapper to check basic type.
140
- */
141
- function _checkType<T>(type: string) {
142
- return (arg: unknown): arg is T => {
143
- return typeof arg === type && (type === 'object' ? (arg !== null) : true);
144
- };
145
- }
146
-
147
- /**
148
- * Transform a value before checking it.
149
- */
150
- function _transform<T>(
151
- transFn: (arg: unknown) => T,
152
- vldt: ((arg: unknown) => arg is T),
153
- ): TValidateWithTransform<T> {
154
- return (arg: unknown, cb?: (arg: T) => void): arg is T => {
155
- if (arg !== undefined) {
156
- arg = transFn(arg);
157
- }
158
- cb?.(arg as T);
159
- return vldt(arg);
160
- };
161
- }
162
-
163
- /**
164
- * Safe JSON parse
165
- */
166
- function _safeJsonParse<T>(arg: unknown): T {
167
- if (isStr(arg)) {
168
- return JSON.parse(arg) as T;
169
- } else {
170
- throw Error('JSON parse argument must be a string');
171
- }
172
- }
173
-
174
-
175
- // **** Parse Object **** //
176
-
177
- export interface TSchema {
178
- [key: string]: TValidateWithTransform<unknown> | TSchema;
179
- }
180
-
181
- type TInferParseRes<U, O, N, A, Schema = TInferParseResHelper<U>> = (
182
- AddMods<Schema, O, N, A>
183
- );
184
-
185
- type TInferParseResHelper<U> = {
186
- [K in keyof U]: (
187
- U[K] extends TValidateWithTransform<infer X>
188
- ? X
189
- : U[K] extends TSchema
190
- ? TInferParseResHelper<U[K]>
191
- : never
192
- );
193
- };
194
-
195
- type TParseOnError<A> = (
196
- A extends true
197
- ? ((property?: string, value?: unknown, index?: number, caughtErr?: unknown) => void)
198
- : ((property?: string, value?: unknown, caughtErr?: unknown) => void)
199
- );
200
-
201
- /**
202
- * validates an object schema, calls an error function is supplied one, returns
203
- * "undefined" if the parse fails, and works recursively too.
204
- */
205
- function _parseObj<
206
- U extends TSchema,
207
- O extends boolean,
208
- N extends boolean,
209
- A extends boolean,
210
- >(
211
- schema: U,
212
- optional: O,
213
- nullable: N,
214
- isArr: A,
215
- onError?: TParseOnError<A>,
216
- ) {
217
- return (arg: unknown) => _parseObjCore(
218
- !!optional,
219
- !!nullable,
220
- !!isArr,
221
- schema,
222
- arg,
223
- onError,
224
- ) as TInferParseRes<U, O, N, A>;
225
- }
226
-
227
- /**
228
- * Validate the schema.
229
- */
230
- function _parseObjCore<A>(
231
- optional: boolean,
232
- nullable: boolean,
233
- isArr: A,
234
- schema: TSchema,
235
- arg: unknown,
236
- onError?: TParseOnError<A>,
237
- ) {
238
- // Check "undefined"
239
- if (arg === undefined) {
240
- if (!optional) {
241
- onError?.('object value was undefined but not optional', arg);
242
- return undefined;
243
- }
244
- }
245
- // Check "null"
246
- if (arg === null) {
247
- if (!nullable) {
248
- onError?.('object value was null but not nullable', arg);
249
- return undefined;
250
- }
251
- return null;
252
- }
253
- // Check "array"
254
- if (isArr) {
255
- if (!Array.isArray(arg)) {
256
- onError?.('object not an array', arg);
257
- return null;
258
- }
259
- // Iterate array
260
- const resp = [];
261
- for (let i = 0; i < arg.length; i++) {
262
- const item: unknown = arg[i];
263
- const parsedItem = _parseObjCoreHelper(schema, item, (prop, val, caughtErr) => {
264
- onError?.(prop, val, i, caughtErr);
265
- });
266
- if (parsedItem === undefined) {
267
- return undefined;
268
- } else {
269
- resp.push(parsedItem);
270
- }
271
- }
272
- return resp;
273
- // Default
274
- } else {
275
- return _parseObjCoreHelper(schema, arg, onError as TParseOnError<false>);
276
- }
277
- }
278
3
 
279
4
  /**
280
- * Iterate an object, apply a validator function to to each property in an
281
- * object using the schema.
5
+ * Database relational key.
282
6
  */
283
- function _parseObjCoreHelper(
284
- schema: TSchema,
285
- arg: unknown,
286
- onError?: TParseOnError<false>,
287
- ): unknown {
288
- if (!isObj(arg)) {
289
- return;
290
- }
291
- const retVal = (arg as TBasicObj);
292
- for (const key in schema) {
293
- const schemaProp = schema[key],
294
- val = retVal[key];
295
- // Nested object
296
- if (typeof schemaProp === 'object') {
297
- const childVal = _parseObjCoreHelper(schemaProp, val, onError);
298
- if (childVal === undefined) {
299
- return undefined;
300
- }
301
- // Run validator
302
- } else if (typeof schemaProp === 'function') {
303
- try {
304
- if (!schemaProp(val, (tval: unknown) => {
305
- retVal[key] = tval;
306
- })) {
307
- return onError?.(key, val);
308
- }
309
- } catch (err) {
310
- if (err instanceof Error) {
311
- return onError?.(key, val, err.message);
312
- } else {
313
- return onError?.(key, val, err);
314
- }
315
- }
316
- }
317
- }
318
- // Purse keys not in schema
319
- for (const key in retVal) {
320
- if (!(key in schema)) {
321
- Reflect.deleteProperty(arg, key);
322
- }
323
- }
324
- // Return
325
- return retVal;
7
+ export function isRelationalKey(arg: unknown): arg is number {
8
+ return isNumber(arg) && arg >= -1;
326
9
  }
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2020",
4
- "module": "commonjs",
4
+ "module": "NodeNext",
5
5
  "lib": [
6
6
  "ES2020"
7
- ],
7
+ ],
8
8
  "strict": true,
9
- "moduleResolution": "node",
10
9
  "baseUrl": "./",
11
10
  "esModuleInterop": true,
12
11
  "skipLibCheck": true,
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2020",
4
- "module": "commonjs",
4
+ "module": "NodeNext",
5
5
  "lib": [
6
6
  "ES2020"
7
- ],
7
+ ],
8
8
  "strict": true,
9
- "moduleResolution": "node",
10
9
  "baseUrl": "./",
11
10
  "outDir": "temp",
12
11
  "esModuleInterop": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-generator-typescript",
3
- "version": "2.5.5",
3
+ "version": "2.5.7",
4
4
  "description": "Generate new Express applications similar to express-generate which but sets it up to use TypeScript instead",
5
5
  "scripts": {
6
6
  "express-generator-typescript": "node bin/cli.js",
@@ -1,18 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const path_1 = __importDefault(require("path"));
7
- const dotenv_1 = __importDefault(require("dotenv"));
8
- const module_alias_1 = __importDefault(require("module-alias"));
9
- const NODE_ENV = (process.env.NODE_ENV ?? 'development');
10
- const result2 = dotenv_1.default.config({
11
- path: path_1.default.join(__dirname, `./config/.env.${NODE_ENV}`),
12
- });
13
- if (result2.error) {
14
- throw result2.error;
15
- }
16
- if (__filename.endsWith('js')) {
17
- module_alias_1.default.addAlias('@src', __dirname + '/dist');
18
- }
@@ -1,88 +0,0 @@
1
- import { CallbackHandler } from 'supertest';
2
- import dayjs, { Dayjs } from 'dayjs';
3
- import logger from 'jet-logger';
4
-
5
- import { TApiCb, TRes } from 'spec/types/misc';
6
-
7
-
8
- /**
9
- * API callback function.
10
- */
11
- function apiCb(
12
- cb: TApiCb,
13
- dateParam = 'created',
14
- printErr?: boolean,
15
- ): CallbackHandler {
16
- return (err: Error, res: TRes) => {
17
- if (printErr) {
18
- logger.err(err);
19
- }
20
- _strToDate(res.body, dateParam);
21
- return cb(res);
22
- };
23
- }
24
-
25
- /**
26
- * When date objects get sent through supertest they are converted to
27
- * iso-strings. This will cause "toEqual()"" tests to fail, so we need to
28
- * convert them back to Date objects.
29
- */
30
- function _strToDate(
31
- param: unknown,
32
- prop: string,
33
- ): void {
34
- return _iterate(param, prop);
35
- }
36
-
37
- /**
38
- * Interate object recursively and convert string-dates to "Date" objects.
39
- */
40
- function _iterate(param: unknown, prop: string): void {
41
- if (!param || typeof param !== 'object') {
42
- return;
43
- }
44
- const paramF = param as Record<string, unknown>;
45
- // For Arrays
46
- if (Array.isArray(paramF)) {
47
- for (const item of paramF) {
48
- _iterate(item, prop);
49
- }
50
- return;
51
- }
52
- // Check valid string or Date object. If undefined just skip
53
- const val = paramF[prop];
54
- if (val !== undefined && !_isValidDate(val)) {
55
- throw new Error('Property must be a valid date-string or Date() object');
56
- }
57
- // Convert and iterate
58
- if (typeof val !== 'undefined') {
59
- paramF[prop] = new Date(val as string | Date);
60
- }
61
- for (const key in paramF) {
62
- const oval = paramF[key];
63
- if (typeof oval === 'object' && key !== prop) {
64
- _iterate(oval, prop);
65
- }
66
- }
67
- }
68
-
69
- /**
70
- * Is date a valid date.
71
- */
72
- function _isValidDate(date: unknown): boolean {
73
- if (
74
- typeof date === 'string' ||
75
- (date instanceof Date) ||
76
- (date instanceof Dayjs) ||
77
- typeof date === 'number'
78
- ) {
79
- return dayjs(date).isValid();
80
- } else {
81
- return false;
82
- }
83
- }
84
-
85
-
86
- // **** Export default **** //
87
-
88
- export default apiCb;