@appium/support 7.1.0 → 7.2.0

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.
Files changed (78) hide show
  1. package/build/lib/console.d.ts +2 -2
  2. package/build/lib/console.d.ts.map +1 -1
  3. package/build/lib/console.js +4 -5
  4. package/build/lib/console.js.map +1 -1
  5. package/build/lib/doctor.d.ts +6 -6
  6. package/build/lib/doctor.d.ts.map +1 -1
  7. package/build/lib/doctor.js +7 -7
  8. package/build/lib/doctor.js.map +1 -1
  9. package/build/lib/env.d.ts +12 -5
  10. package/build/lib/env.d.ts.map +1 -1
  11. package/build/lib/env.js +5 -5
  12. package/build/lib/env.js.map +1 -1
  13. package/build/lib/fs.d.ts.map +1 -1
  14. package/build/lib/fs.js +11 -14
  15. package/build/lib/fs.js.map +1 -1
  16. package/build/lib/image-util.d.ts.map +1 -1
  17. package/build/lib/image-util.js +1 -1
  18. package/build/lib/image-util.js.map +1 -1
  19. package/build/lib/index.d.ts +1 -1
  20. package/build/lib/index.d.ts.map +1 -1
  21. package/build/lib/logging.d.ts.map +1 -1
  22. package/build/lib/logging.js +5 -8
  23. package/build/lib/logging.js.map +1 -1
  24. package/build/lib/mjpeg.d.ts.map +1 -1
  25. package/build/lib/mjpeg.js +7 -7
  26. package/build/lib/mjpeg.js.map +1 -1
  27. package/build/lib/net.d.ts.map +1 -1
  28. package/build/lib/net.js +21 -14
  29. package/build/lib/net.js.map +1 -1
  30. package/build/lib/node.d.ts.map +1 -1
  31. package/build/lib/node.js +7 -8
  32. package/build/lib/node.js.map +1 -1
  33. package/build/lib/npm.d.ts.map +1 -1
  34. package/build/lib/npm.js +3 -3
  35. package/build/lib/npm.js.map +1 -1
  36. package/build/lib/plist.js +11 -11
  37. package/build/lib/plist.js.map +1 -1
  38. package/build/lib/process.d.ts.map +1 -1
  39. package/build/lib/process.js +2 -2
  40. package/build/lib/process.js.map +1 -1
  41. package/build/lib/system.d.ts.map +1 -1
  42. package/build/lib/system.js +2 -3
  43. package/build/lib/system.js.map +1 -1
  44. package/build/lib/tempdir.d.ts +3 -2
  45. package/build/lib/tempdir.d.ts.map +1 -1
  46. package/build/lib/tempdir.js +2 -2
  47. package/build/lib/tempdir.js.map +1 -1
  48. package/build/lib/timing.d.ts.map +1 -1
  49. package/build/lib/timing.js +3 -7
  50. package/build/lib/timing.js.map +1 -1
  51. package/build/lib/util.d.ts +103 -24
  52. package/build/lib/util.d.ts.map +1 -1
  53. package/build/lib/util.js +158 -22
  54. package/build/lib/util.js.map +1 -1
  55. package/build/lib/zip.d.ts +42 -42
  56. package/build/lib/zip.d.ts.map +1 -1
  57. package/build/lib/zip.js +142 -142
  58. package/build/lib/zip.js.map +1 -1
  59. package/lib/console.ts +8 -9
  60. package/lib/doctor.ts +6 -6
  61. package/lib/env.ts +5 -5
  62. package/lib/fs.ts +14 -14
  63. package/lib/image-util.ts +2 -1
  64. package/lib/index.ts +7 -1
  65. package/lib/logging.ts +5 -5
  66. package/lib/mjpeg.ts +9 -7
  67. package/lib/net.ts +25 -19
  68. package/lib/node.ts +7 -8
  69. package/lib/npm.ts +5 -3
  70. package/lib/plist.ts +11 -11
  71. package/lib/process.ts +8 -2
  72. package/lib/system.ts +2 -3
  73. package/lib/tempdir.ts +2 -2
  74. package/lib/timing.ts +3 -5
  75. package/lib/util.ts +197 -44
  76. package/lib/zip.ts +223 -221
  77. package/package.json +11 -12
  78. package/tsconfig.json +1 -0
package/lib/mjpeg.ts CHANGED
@@ -1,4 +1,3 @@
1
- import _ from 'lodash';
2
1
  import log from './logger';
3
2
  import B from 'bluebird';
4
3
  import {requireSharp} from './image-util';
@@ -18,10 +17,11 @@ async function initMJpegConsumer(): Promise<MJpegConsumerConstructor> {
18
17
  if (!MJpegConsumer) {
19
18
  try {
20
19
  MJpegConsumer = (await requirePackage('mjpeg-consumer')) as MJpegConsumerConstructor;
21
- } catch {
20
+ } catch (e) {
22
21
  throw new Error(
23
22
  'mjpeg-consumer module is required to use MJPEG-over-HTTP features. ' +
24
- 'Please install it first (npm i -g mjpeg-consumer) and restart Appium.'
23
+ 'Please install it first (npm i -g mjpeg-consumer) and restart Appium.',
24
+ {cause: e}
25
25
  );
26
26
  }
27
27
  }
@@ -29,6 +29,7 @@ async function initMJpegConsumer(): Promise<MJpegConsumerConstructor> {
29
29
  }
30
30
 
31
31
  const MJPEG_SERVER_TIMEOUT_MS = 10000;
32
+ const noop = () => {};
32
33
 
33
34
  /** Class which stores the last bit of data streamed into it */
34
35
  export class MJpegStream extends Writable {
@@ -50,7 +51,7 @@ export class MJpegStream extends Writable {
50
51
  */
51
52
  constructor(
52
53
  mJpegUrl: string,
53
- errorHandler: (err: Error) => void = _.noop,
54
+ errorHandler: (err: Error) => void = noop,
54
55
  options: WritableOptions = {}
55
56
  ) {
56
57
  super(options);
@@ -61,7 +62,7 @@ export class MJpegStream extends Writable {
61
62
 
62
63
  get lastChunkBase64(): string | null {
63
64
  const lastChunk = this.lastChunk;
64
- if (lastChunk && !_.isEmpty(lastChunk) && _.isBuffer(lastChunk)) {
65
+ if (lastChunk && lastChunk.length > 0 && Buffer.isBuffer(lastChunk)) {
65
66
  return lastChunk.toString('base64');
66
67
  }
67
68
  return null;
@@ -69,7 +70,7 @@ export class MJpegStream extends Writable {
69
70
 
70
71
  async lastChunkPNG(): Promise<Buffer | null> {
71
72
  const chunk = this.lastChunk;
72
- if (!chunk || _.isEmpty(chunk) || !_.isBuffer(chunk)) {
73
+ if (!chunk || chunk.length === 0 || !Buffer.isBuffer(chunk)) {
73
74
  return null;
74
75
  }
75
76
  try {
@@ -118,7 +119,8 @@ export class MJpegStream extends Writable {
118
119
  message = String(e);
119
120
  }
120
121
  throw new Error(
121
- `Cannot connect to the MJPEG stream at ${url}. Original error: ${message}`
122
+ `Cannot connect to the MJPEG stream at ${url}. Original error: ${message}`,
123
+ {cause: e}
122
124
  );
123
125
  }
124
126
 
package/lib/net.ts CHANGED
@@ -1,6 +1,5 @@
1
- import _ from 'lodash';
2
1
  import {fs} from './fs';
3
- import {toReadableSizeString} from './util';
2
+ import {isPlainObject, toReadableSizeString} from './util';
4
3
  import log from './logger';
5
4
  import Ftp from 'jsftp';
6
5
  import {Timer} from './timing';
@@ -63,6 +62,8 @@ export interface FtpUploadOptions extends NetOptions {}
63
62
  /** @deprecated Use {@linkcode FtpUploadOptions} instead. */
64
63
  export type NotHttpUploadOptions = FtpUploadOptions;
65
64
 
65
+ type AuthLike = AuthCredentials | AxiosBasicCredentials;
66
+
66
67
  /**
67
68
  * Uploads the given file to a remote location. HTTP(S) and FTP protocols are supported.
68
69
  */
@@ -85,7 +86,7 @@ export async function uploadFile(
85
86
  if (isHttpUploadOptions(uploadOptions, url)) {
86
87
  if (!uploadOptions.fileFieldName) {
87
88
  uploadOptions.headers = {
88
- ...(_.isPlainObject(uploadOptions.headers) ? uploadOptions.headers : {}),
89
+ ...(isPlainObject(uploadOptions.headers) ? uploadOptions.headers : {}),
89
90
  'Content-Length': size,
90
91
  };
91
92
  }
@@ -107,6 +108,8 @@ export async function uploadFile(
107
108
  }
108
109
  }
109
110
 
111
+ // #region Private helpers
112
+
110
113
  /**
111
114
  * Downloads the given file via HTTP(S).
112
115
  *
@@ -128,7 +131,7 @@ export async function downloadFile(
128
131
  if (axiosAuth) {
129
132
  requestOpts.auth = axiosAuth;
130
133
  }
131
- if (_.isPlainObject(headers)) {
134
+ if (isPlainObject(headers)) {
132
135
  requestOpts.headers = headers as RawAxiosRequestConfig['headers'];
133
136
  }
134
137
 
@@ -150,7 +153,7 @@ export async function downloadFile(
150
153
  });
151
154
  } catch (err) {
152
155
  const message = err instanceof Error ? err.message : String(err);
153
- throw new Error(`Cannot download the file from ${remoteUrl}: ${message}`);
156
+ throw new Error(`Cannot download the file from ${remoteUrl}: ${message}`, {cause: err});
154
157
  }
155
158
 
156
159
  const {size} = await fs.stat(dstPath);
@@ -174,18 +177,17 @@ export async function downloadFile(
174
177
  }
175
178
  }
176
179
 
177
- // #region Private helpers
178
-
179
- type AuthLike = AuthCredentials | AxiosBasicCredentials;
180
-
181
180
  function toAxiosAuth(auth: AuthLike | undefined): AxiosBasicCredentials | null {
182
- if (!auth || !_.isPlainObject(auth)) {
181
+ if (!auth || !isPlainObject(auth)) {
183
182
  return null;
184
183
  }
185
184
 
186
185
  const username = 'username' in auth ? auth.username : auth.user;
187
186
  const password = 'password' in auth ? auth.password : auth.pass;
188
- return username && password ? {username, password} : null;
187
+ if (typeof username !== 'string' || typeof password !== 'string' || !username || !password) {
188
+ return null;
189
+ }
190
+ return {username, password};
189
191
  }
190
192
 
191
193
  async function uploadFileToHttp(
@@ -218,13 +220,13 @@ async function uploadFileToHttp(
218
220
  const form = new FormData();
219
221
  if (formFields) {
220
222
  let pairs: [string, unknown][] = [];
221
- if (_.isArray(formFields)) {
223
+ if (Array.isArray(formFields)) {
222
224
  pairs = formFields as [string, unknown][];
223
- } else if (_.isPlainObject(formFields)) {
224
- pairs = _.toPairs(formFields);
225
+ } else if (isPlainObject(formFields)) {
226
+ pairs = Object.entries(formFields);
225
227
  }
226
228
  for (const [key, value] of pairs) {
227
- if (_.toLower(key) !== _.toLower(fileFieldName)) {
229
+ if (key.toLowerCase() !== fileFieldName?.toLowerCase()) {
228
230
  form.append(key, value as string | Buffer);
229
231
  }
230
232
  }
@@ -232,19 +234,23 @@ async function uploadFileToHttp(
232
234
  // AWS S3 POST upload requires this to be the last field; do not move before formFields.
233
235
  form.append(fileFieldName, localFileStream);
234
236
  requestOpts.headers = {
235
- ...(_.isPlainObject(headers) ? headers : {}),
237
+ ...(isPlainObject(headers) ? headers : {}),
236
238
  ...form.getHeaders(),
237
239
  };
238
240
  requestOpts.data = form;
239
241
  } else {
240
- if (_.isPlainObject(headers)) {
242
+ if (isPlainObject(headers)) {
241
243
  requestOpts.headers = headers;
242
244
  }
243
245
  requestOpts.data = localFileStream;
244
246
  }
245
247
  log.debug(
246
248
  `Performing ${method} to ${href} with options (excluding data): ` +
247
- JSON.stringify(_.omit(requestOpts, ['data']))
249
+ JSON.stringify((() => {
250
+ const requestOptsWithoutData = {...requestOpts} as Record<string, unknown>;
251
+ delete requestOptsWithoutData.data;
252
+ return requestOptsWithoutData;
253
+ })())
248
254
  );
249
255
 
250
256
  const {status, statusText} = await axios(requestOpts);
@@ -261,7 +267,7 @@ async function uploadFileToFtp(
261
267
 
262
268
  const ftpOpts: {host: string; port: number; user?: string; pass?: string} = {
263
269
  host: hostname ?? '',
264
- port: port !== undefined && port !== '' ? _.parseInt(port, 10) : 21,
270
+ port: port !== undefined && port !== '' ? Number.parseInt(port, 10) : 21,
265
271
  };
266
272
  if (auth?.user && auth?.pass) {
267
273
  ftpOpts.user = auth.user;
package/lib/node.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import {isWindows} from './system';
2
2
  import log from './logger';
3
- import _ from 'lodash';
4
3
  import {exec} from 'teen_process';
5
4
  import path from 'node:path';
6
5
  import _fs from 'node:fs';
@@ -156,7 +155,7 @@ async function linkGlobalPackage(packageName: string): Promise<void> {
156
155
  if (e.stderr) {
157
156
  log.debug(e.stderr);
158
157
  }
159
- throw new Error(msg);
158
+ throw new Error(msg, {cause: err});
160
159
  }
161
160
  }
162
161
 
@@ -165,14 +164,14 @@ function extractAllProperties(obj: object): (string | symbol)[] {
165
164
  for (const prop in obj) {
166
165
  stringProperties.push(prop);
167
166
  }
168
- if (_.isFunction(Object.getOwnPropertySymbols)) {
167
+ if (typeof Object.getOwnPropertySymbols === 'function') {
169
168
  stringProperties.push(...Object.getOwnPropertySymbols(obj));
170
169
  }
171
170
  return stringProperties;
172
171
  }
173
172
 
174
173
  function _getSizeOfObject(seen: WeakSet<object>, object: object): number {
175
- if (_.isNil(object)) {
174
+ if (object == null) {
176
175
  return 0;
177
176
  }
178
177
 
@@ -181,7 +180,7 @@ function _getSizeOfObject(seen: WeakSet<object>, object: object): number {
181
180
  const calc = getCalculator(seen);
182
181
  for (const key of properties) {
183
182
  const val = (object as Record<string | symbol, unknown>)[key];
184
- if (typeof val === 'object' && !_.isNil(val)) {
183
+ if (typeof val === 'object' && val != null) {
185
184
  if (seen.has(val as object)) {
186
185
  continue;
187
186
  }
@@ -203,7 +202,7 @@ function _getSizeOfObject(seen: WeakSet<object>, object: object): number {
203
202
 
204
203
  function getCalculator(seen: WeakSet<object>): SizeCalculator {
205
204
  return function calculator(obj: unknown): number {
206
- if (_.isBuffer(obj)) {
205
+ if (Buffer.isBuffer(obj)) {
207
206
  return (obj as Buffer).length;
208
207
  }
209
208
 
@@ -215,11 +214,11 @@ function getCalculator(seen: WeakSet<object>): SizeCalculator {
215
214
  case 'number':
216
215
  return ECMA_SIZES.NUMBER;
217
216
  case 'symbol':
218
- return _.isFunction(Symbol.keyFor) && Symbol.keyFor(obj)
217
+ return typeof Symbol.keyFor === 'function' && Symbol.keyFor(obj)
219
218
  ? (Symbol.keyFor(obj) as string).length * ECMA_SIZES.STRING
220
219
  : (obj.toString().length - 8) * ECMA_SIZES.STRING;
221
220
  case 'object':
222
- return _.isArray(obj)
221
+ return Array.isArray(obj)
223
222
  ? obj.map(getCalculator(seen)).reduce((acc, curr) => acc + curr, 0)
224
223
  : _getSizeOfObject(seen, obj as object);
225
224
  default:
package/lib/npm.ts CHANGED
@@ -104,7 +104,8 @@ export class NPM {
104
104
  } catch (e) {
105
105
  const {stdout = '', stderr = '', code = null} = e as ExecError;
106
106
  throw new Error(
107
- `npm command '${argsCopy.join(' ')}' failed with code ${code}.\n\nSTDOUT:\n${stdout.trim()}\n\nSTDERR:\n${stderr.trim()}`
107
+ `npm command '${argsCopy.join(' ')}' failed with code ${code}.\n\nSTDOUT:\n${stdout.trim()}\n\nSTDERR:\n${stderr.trim()}`,
108
+ {cause: e}
108
109
  );
109
110
  }
110
111
  return ret;
@@ -245,11 +246,12 @@ export class NPM {
245
246
  const pkgJson = await fs.readFile(pkgJsonPath, 'utf8');
246
247
  const pkg = JSON.parse(pkgJson) as PackageJson;
247
248
  return {installPath: path.dirname(pkgJsonPath), pkg};
248
- } catch {
249
+ } catch (e) {
249
250
  throw new Error(
250
251
  'The package was not downloaded correctly; its package.json ' +
251
252
  'did not exist or was unreadable. We looked for it at ' +
252
- pkgJsonPath
253
+ pkgJsonPath,
254
+ {cause: e}
253
255
  );
254
256
  }
255
257
  }
package/lib/plist.ts CHANGED
@@ -1,9 +1,9 @@
1
- import xmlplist from 'plist';
1
+ import {build as plistBuild, parse as plistParse} from 'plist';
2
2
  import bplistCreate from 'bplist-creator';
3
3
  import {parseFile, parseBuffer} from 'bplist-parser';
4
4
  import {fs} from './fs';
5
5
  import log from './logger';
6
- import _ from 'lodash';
6
+ import {truncateString} from './util';
7
7
 
8
8
  const BPLIST_IDENTIFIER = {
9
9
  BUFFER: Buffer.from('bplist00'),
@@ -37,7 +37,7 @@ export async function parsePlistFile(
37
37
  return {};
38
38
  }
39
39
 
40
- let obj: object = {};
40
+ let obj: object;
41
41
  let type = 'binary';
42
42
  try {
43
43
  const parsed = await parseFile(plist);
@@ -85,8 +85,8 @@ export async function updatePlistFile(
85
85
  } catch (err) {
86
86
  throw log.errorWithException(`Could not update plist: ${(err as Error).message}`);
87
87
  }
88
- _.extend(obj, updatedFields);
89
- const newPlist = binary ? bplistCreate(obj) : xmlplist.build(obj);
88
+ Object.assign(obj as Record<string, unknown>, updatedFields);
89
+ const newPlist = binary ? bplistCreate(obj) : plistBuild(obj);
90
90
  try {
91
91
  await fs.writeFile(plist, newPlist);
92
92
  } catch (err) {
@@ -128,7 +128,7 @@ export function createPlist(object: object, binary = false): Buffer | string {
128
128
  if (binary) {
129
129
  return createBinaryPlist(object);
130
130
  }
131
- return xmlplist.build(object);
131
+ return plistBuild(object);
132
132
  }
133
133
 
134
134
  /**
@@ -141,7 +141,7 @@ export function createPlist(object: object, binary = false): Buffer | string {
141
141
  export function parsePlist(data: string | Buffer): object {
142
142
  const textPlist = getXmlPlist(data);
143
143
  if (textPlist) {
144
- return xmlplist.parse(textPlist);
144
+ return plistParse(textPlist);
145
145
  }
146
146
 
147
147
  const binaryPlist = getBinaryPlist(data);
@@ -150,17 +150,17 @@ export function parsePlist(data: string | Buffer): object {
150
150
  }
151
151
 
152
152
  throw new Error(
153
- `Unknown type of plist, data: ${_.truncate(data.toString(), {length: 200})}`
153
+ `Unknown type of plist, data: ${truncateString(data.toString(), {length: 200})}`
154
154
  );
155
155
  }
156
156
 
157
157
  async function parseXmlPlistFile(plistFilename: string): Promise<object> {
158
158
  const xmlContent = await fs.readFile(plistFilename, 'utf8');
159
- return xmlplist.parse(xmlContent);
159
+ return plistParse(xmlContent);
160
160
  }
161
161
 
162
162
  function getXmlPlist(data: string | Buffer): string | null {
163
- if (_.isString(data) && data.startsWith(PLIST_IDENTIFIER.TEXT)) {
163
+ if (typeof data === 'string' && data.startsWith(PLIST_IDENTIFIER.TEXT)) {
164
164
  return data;
165
165
  }
166
166
  if (
@@ -173,7 +173,7 @@ function getXmlPlist(data: string | Buffer): string | null {
173
173
  }
174
174
 
175
175
  function getBinaryPlist(data: string | Buffer): Buffer | null {
176
- if (_.isString(data) && data.startsWith(BPLIST_IDENTIFIER.TEXT)) {
176
+ if (typeof data === 'string' && data.startsWith(BPLIST_IDENTIFIER.TEXT)) {
177
177
  return Buffer.from(data);
178
178
  }
179
179
 
package/lib/process.ts CHANGED
@@ -28,7 +28,10 @@ export async function getProcessIds(appName: string): Promise<number[]> {
28
28
  } catch (err) {
29
29
  const code = (err as ExecError).code;
30
30
  if (code !== 1) {
31
- throw new Error(`Error getting process ids for app '${appName}': ${(err as Error).message}`);
31
+ throw new Error(
32
+ `Error getting process ids for app '${appName}': ${(err as Error).message}`,
33
+ {cause: err}
34
+ );
32
35
  }
33
36
  pids = [];
34
37
  }
@@ -56,7 +59,10 @@ export async function killProcess(appName: string, force = false): Promise<void>
56
59
  } catch (err) {
57
60
  const code = (err as ExecError).code;
58
61
  if (code !== 1) {
59
- throw new Error(`Error killing app '${appName}' with pkill: ${(err as Error).message}`);
62
+ throw new Error(
63
+ `Error killing app '${appName}' with pkill: ${(err as Error).message}`,
64
+ {cause: err}
65
+ );
60
66
  }
61
67
  }
62
68
  }
package/lib/system.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import {exec} from 'teen_process';
2
- import _ from 'lodash';
3
2
  import os from 'node:os';
4
3
 
5
4
  const VERSION_PATTERN = /^(\d+\.\d+)/m;
@@ -29,7 +28,7 @@ export function isLinux(): boolean {
29
28
  * Whether the current Windows process is 64-bit (or WOW64).
30
29
  */
31
30
  export function isOSWin64(): boolean {
32
- return process.arch === 'x64' || _.has(process.env, 'PROCESSOR_ARCHITEW6432');
31
+ return process.arch === 'x64' || Object.hasOwn(process.env, 'PROCESSOR_ARCHITEW6432');
33
32
  }
34
33
 
35
34
  /**
@@ -43,7 +42,7 @@ export async function macOsxVersion(): Promise<string> {
43
42
  try {
44
43
  stdout = (await exec('sw_vers', ['-productVersion'])).stdout.trim();
45
44
  } catch (err) {
46
- throw new Error(`Could not detect Mac OS X Version: ${err}`);
45
+ throw new Error(`Could not detect Mac OS X Version: ${err}`, {cause: err});
47
46
  }
48
47
 
49
48
  const versionMatch = VERSION_PATTERN.exec(stdout);
package/lib/tempdir.ts CHANGED
@@ -2,9 +2,9 @@
2
2
  import {fs} from './fs';
3
3
  import os from 'node:os';
4
4
  import nodePath from 'node:path';
5
- import _ from 'lodash';
6
5
  import {constants} from 'node:fs';
7
6
  import log from './logger';
7
+ import {memoize} from './util';
8
8
 
9
9
  const RDWR_EXCL = constants.O_CREAT | constants.O_TRUNC | constants.O_RDWR | constants.O_EXCL;
10
10
 
@@ -61,7 +61,7 @@ export const openDir = tempDir;
61
61
  *
62
62
  * @returns The same temp directory path on every call.
63
63
  */
64
- export const staticDir = _.memoize(async function staticDir (): Promise<string> {
64
+ export const staticDir = memoize(async function staticDir (): Promise<string> {
65
65
  return tempDir();
66
66
  });
67
67
 
package/lib/timing.ts CHANGED
@@ -1,5 +1,3 @@
1
- import _ from 'lodash';
2
-
3
1
  const NS_PER_S = 1e9;
4
2
  const NS_PER_MS = 1e6;
5
3
 
@@ -65,7 +63,7 @@ export class Timer {
65
63
  * @return {Timer} The current instance, for chaining
66
64
  */
67
65
  start(): this {
68
- if (!_.isNull(this._startTime)) {
66
+ if (this._startTime !== null) {
69
67
  throw new Error('Timer has already been started.');
70
68
  }
71
69
  this._startTime = process.hrtime.bigint();
@@ -78,12 +76,12 @@ export class Timer {
78
76
  * @return {Duration} the duration
79
77
  */
80
78
  getDuration(): Duration {
81
- if (_.isNull(this._startTime)) {
79
+ if (this._startTime === null) {
82
80
  throw new Error('Unable to get duration. Timer was not started');
83
81
  }
84
82
 
85
83
  let nanoDuration: number;
86
- if (_.isArray(this._startTime)) {
84
+ if (Array.isArray(this._startTime)) {
87
85
  // startTime was created using process.hrtime()
88
86
  const [seconds, nanos] = process.hrtime(this._startTime as [number, number]);
89
87
  nanoDuration = seconds * NS_PER_S + nanos;