@appium/support 2.55.4 → 2.56.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 (54) hide show
  1. package/build/lib/env.js +102 -0
  2. package/build/lib/fs.js +74 -56
  3. package/build/lib/image-util.js +2 -4
  4. package/build/lib/index.js +18 -6
  5. package/build/lib/log-internal.js +2 -4
  6. package/build/lib/logger.js +2 -4
  7. package/build/lib/logging.js +2 -4
  8. package/build/lib/mjpeg.js +2 -4
  9. package/build/lib/mkdirp.js +7 -11
  10. package/build/lib/net.js +2 -4
  11. package/build/lib/node.js +99 -2
  12. package/build/lib/npm.js +240 -0
  13. package/build/lib/plist.js +2 -4
  14. package/build/lib/process.js +2 -4
  15. package/build/lib/system.js +2 -4
  16. package/build/lib/tempdir.js +2 -4
  17. package/build/lib/timing.js +2 -4
  18. package/build/lib/util.js +6 -8
  19. package/build/lib/zip.js +4 -8
  20. package/lib/env.js +162 -0
  21. package/lib/fs.js +193 -69
  22. package/lib/index.js +8 -2
  23. package/lib/log-internal.js +2 -2
  24. package/lib/logging.js +1 -1
  25. package/lib/mkdirp.js +3 -6
  26. package/lib/net.js +4 -4
  27. package/lib/node.js +104 -1
  28. package/lib/npm.js +335 -0
  29. package/lib/tempdir.js +6 -6
  30. package/lib/util.js +28 -24
  31. package/lib/zip.js +7 -8
  32. package/package.json +20 -10
  33. package/build/test/assets/sample_binary.plist +0 -0
  34. package/build/test/assets/sample_text.plist +0 -28
  35. package/build/test/fs-specs.js +0 -264
  36. package/build/test/helpers.js +0 -35
  37. package/build/test/image-util-e2e-specs.js +0 -78
  38. package/build/test/index-specs.js +0 -49
  39. package/build/test/log-internals-specs.js +0 -97
  40. package/build/test/logger/helpers.js +0 -71
  41. package/build/test/logger/logger-force-specs.js +0 -41
  42. package/build/test/logger/logger-normal-specs.js +0 -113
  43. package/build/test/logger/logger-test-specs.js +0 -40
  44. package/build/test/mjpeg-e2e-specs.js +0 -96
  45. package/build/test/net-e2e-specs.js +0 -32
  46. package/build/test/node-e2e-specs.js +0 -22
  47. package/build/test/plist-specs.js +0 -54
  48. package/build/test/process-specs.js +0 -104
  49. package/build/test/system-specs.js +0 -136
  50. package/build/test/tempdir-specs.js +0 -86
  51. package/build/test/timing-specs.js +0 -125
  52. package/build/test/util-e2e-specs.js +0 -136
  53. package/build/test/util-specs.js +0 -537
  54. package/build/test/zip-e2e-specs.js +0 -233
package/lib/fs.js CHANGED
@@ -1,76 +1,162 @@
1
- // jshint ignore: start
2
- import _ from 'lodash';
3
- import path from 'path';
4
- import _fs from 'fs';
5
- import rimraf from 'rimraf';
6
- import ncp from 'ncp';
1
+ // @ts-check
2
+
7
3
  import B from 'bluebird';
8
- import mv from 'mv';
9
- import which from 'which';
10
- import glob from 'glob';
11
4
  import crypto from 'crypto';
5
+ import { close, constants, createReadStream, createWriteStream, promises as fsPromises, read, write, open } from 'fs';
6
+ import glob from 'glob';
12
7
  import klaw from 'klaw';
8
+ import _ from 'lodash';
9
+ import mv from 'mv';
10
+ import ncp from 'ncp';
11
+ import path from 'path';
12
+ import pkgDir from 'pkg-dir';
13
+ import readPkg from 'read-pkg';
14
+ import rimraf from 'rimraf';
13
15
  import sanitize from 'sanitize-filename';
14
- import findRoot from 'find-root';
15
- import { pluralize } from './util';
16
+ import which from 'which';
16
17
  import log from './logger';
17
18
  import Timer from './timing';
19
+ import { pluralize } from './util';
18
20
 
19
- const mkdirAsync = B.promisify(_fs.mkdir);
20
- const ncpAsync = B.promisify(ncp);
21
- const findRootCached = _.memoize(findRoot);
21
+ const ncpAsync = /** @type {(source: string, dest: string, opts: ncp.Options|undefined) => B<void>} */(B.promisify(ncp));
22
+ const findRootCached = _.memoize(pkgDir.sync);
22
23
 
23
24
  const fs = {
25
+ /**
26
+ * Resolves `true` if `path` is _readable_, which differs from Node.js' default behavior of "can we see it?"
27
+ * @param {import('fs').PathLike} path
28
+ * @returns {Promise<boolean>}
29
+ */
24
30
  async hasAccess (path) {
25
31
  try {
26
- await this.access(path, _fs.R_OK);
32
+ await fsPromises.access(path, constants.R_OK);
27
33
  } catch (err) {
28
34
  return false;
29
35
  }
30
36
  return true;
31
37
  },
32
- exists (path) { return this.hasAccess(path); },
33
- rimraf: B.promisify(rimraf),
34
- rimrafSync: rimraf.sync.bind(rimraf),
35
- async mkdir (...args) {
38
+
39
+ /**
40
+ * Alias for {@linkcode fs.hasAccess}
41
+ * @param {import('fs').PathLike} path
42
+ */
43
+ async exists (path) {
44
+ return await fs.hasAccess(path);
45
+ },
46
+
47
+ /**
48
+ * Remove a directory and all its contents, recursively
49
+ * @todo Replace with `rm()` from `fs.promises` when Node.js v12 support is dropped.
50
+ */
51
+ rimraf: /** @type {(dirpath: string, opts?: rimraf.Options) => Promise<void>} */(B.promisify(rimraf)),
52
+
53
+ /**
54
+ * Alias of {@linkcode rimraf.sync}
55
+ * @todo Replace with `rmSync()` from `fs` when Node.js v12 support is dropped.
56
+ */
57
+ rimrafSync: rimraf.sync,
58
+
59
+ /**
60
+ * Like Node.js' `fsPromises.mkdir()`, but will _not_ reject if the directory already exists.
61
+ *
62
+ * @param {string|Buffer|URL} filepath
63
+ * @param {import('fs').MakeDirectoryOptions} [opts]
64
+ * @returns {Promise<string|undefined>}
65
+ * @see https://nodejs.org/api/fs.html#fspromisesmkdirpath-options
66
+ */
67
+ async mkdir (filepath, opts = {}) {
36
68
  try {
37
- return await mkdirAsync(...args);
69
+ return await fsPromises.mkdir(filepath, opts);
38
70
  } catch (err) {
39
- if (err && err.code !== 'EEXIST') {
71
+ if (err?.code !== 'EEXIST') {
40
72
  throw err;
41
73
  }
42
74
  }
43
75
  },
44
- async copyFile (source, destination, ...otherArgs) {
45
- if (!await this.hasAccess(source)) {
76
+ /**
77
+ * Copies files _and entire directories_
78
+ * @param {string} source - Source to copy
79
+ * @param {string} destination - Destination to copy to
80
+ * @param {ncp.Options} [opts] - Additional arguments to pass to `ncp`
81
+ * @see https://npm.im/ncp
82
+ * @returns {Promise<void>}
83
+ */
84
+ async copyFile (source, destination, opts = {}) {
85
+ if (!await fs.hasAccess(source)) {
46
86
  throw new Error(`The file at '${source}' does not exist or is not accessible`);
47
87
  }
48
- return await ncpAsync(source, destination, ...otherArgs);
88
+ return await ncpAsync(source, destination, opts);
49
89
  },
90
+
91
+ /**
92
+ * Create an MD5 hash of a file.
93
+ * @param {import('fs').PathLike} filePath
94
+ * @returns {Promise<string>}
95
+ */
50
96
  async md5 (filePath) {
51
- return await this.hash(filePath, 'md5');
97
+ return await fs.hash(filePath, 'md5');
52
98
  },
53
- mv: B.promisify(mv),
54
- which: B.promisify(which),
55
- glob: B.promisify(glob),
99
+
100
+ /**
101
+ * Move a file
102
+ */
103
+ mv: /** @type {(from: string, to: string, opts?: mv.Options) => B<void>} */(B.promisify(mv)),
104
+
105
+ /**
106
+ * Find path to an executable in system `PATH`
107
+ * @see https://github.com/npm/node-which
108
+ */
109
+ which,
110
+
111
+ /**
112
+ * Given a glob pattern, resolve with list of files matching that pattern
113
+ * @see https://github.com/isaacs/node-glob
114
+ */
115
+ glob: /** @type {(pattern: string, opts?: glob.IOptions) => B<string[]>} */(B.promisify(glob)),
116
+
117
+ /**
118
+ * Sanitize a filename
119
+ * @see https://github.com/parshap/node-sanitize-filename
120
+ */
56
121
  sanitizeName: sanitize,
122
+
123
+ /**
124
+ * Create a hex digest of some file at `filePath`
125
+ * @param {import('fs').PathLike} filePath
126
+ * @param {string} [algorithm]
127
+ * @returns {Promise<string>}
128
+ */
57
129
  async hash (filePath, algorithm = 'sha1') {
58
130
  return await new B((resolve, reject) => {
59
131
  const fileHash = crypto.createHash(algorithm);
60
- const readStream = _fs.createReadStream(filePath);
132
+ const readStream = createReadStream(filePath);
61
133
  readStream.on('error', (e) => reject(
62
134
  new Error(`Cannot calculate ${algorithm} hash for '${filePath}'. Original error: ${e.message}`)));
63
135
  readStream.on('data', (chunk) => fileHash.update(chunk));
64
136
  readStream.on('end', () => resolve(fileHash.digest('hex')));
65
137
  });
66
138
  },
67
- /** The callback function which will be called during the directory walking
68
- * @name WalkDirCallback
69
- * @function
70
- * @param {string} itemPath The path of the file or folder
71
- * @param {boolean} isDirectory Shows if it is a directory or a file
72
- * @return {boolean} return true if you want to stop walking
73
- */
139
+
140
+ /**
141
+ * Returns an `Walker` instance, which is a readable stream (and thusly an async iterator).
142
+ *
143
+ * @param {string} dir - Dir to start walking at
144
+ * @param {import('klaw').Options} [opts]
145
+ * @returns {import('klaw').Walker}
146
+ * @see https://www.npmjs.com/package/klaw
147
+ */
148
+ walk (dir, opts) {
149
+ return klaw(dir, opts);
150
+ },
151
+
152
+ /**
153
+ * Recursively create a directory.
154
+ * @param {import('fs').PathLike} dir
155
+ * @returns {Promise<string|undefined>}
156
+ */
157
+ async mkdirp (dir) {
158
+ return await fs.mkdir(dir, {recursive: true});
159
+ },
74
160
 
75
161
  /**
76
162
  * Walks a directory given according to the parameters given. The callback will be invoked with a path joined with the dir parameter
@@ -78,7 +164,7 @@ const fs = {
78
164
  * @param {boolean} recursive Set it to true if you want to continue walking sub directories
79
165
  * @param {WalkDirCallback} callback The callback to be called when a new path is found
80
166
  * @throws {Error} If the `dir` parameter contains a path to an invalid folder
81
- * @return {?string} returns the found path or null if the item was not found
167
+ * @returns {Promise<string?>} returns the found path or null if the item was not found
82
168
  */
83
169
  async walkDir (dir, recursive, callback) { //eslint-disable-line promise/prefer-await-to-callbacks
84
170
  let isValidRoot = false;
@@ -131,7 +217,9 @@ const fs = {
131
217
  })
132
218
  .on('end', function () {
133
219
  lastFileProcessed
134
- .then(resolve)
220
+ .then((file) => {
221
+ resolve(/** @type {string|undefined} */(file) ?? null);
222
+ })
135
223
  .catch(function (err) {
136
224
  log.warn(`Unexpected error: ${err.message}`);
137
225
  reject(err);
@@ -149,14 +237,14 @@ const fs = {
149
237
  /**
150
238
  * Reads the closest `package.json` file from absolute path `dir`.
151
239
  * @param {string} dir - Directory to search from
152
- * @throws {TypeError} If `dir` is not a nonempty string or relative path
240
+ * @param {import('read-pkg').Options} [opts] - Additional options for `read-pkg`
153
241
  * @throws {Error} If there were problems finding or reading a `package.json` file
154
242
  * @returns {object} A parsed `package.json`
155
243
  */
156
- readPackageJsonFrom (dir) {
157
- const root = fs.findRoot(dir);
244
+ readPackageJsonFrom (dir, opts = {}) {
245
+ const cwd = fs.findRoot(dir);
158
246
  try {
159
- return JSON.parse(_fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
247
+ return readPkg.sync({...opts, cwd});
160
248
  } catch (err) {
161
249
  err.message = `Failed to read a \`package.json\` from dir \`${dir}\`:\n\n${err.message}`;
162
250
  throw err;
@@ -178,34 +266,70 @@ const fs = {
178
266
  throw new Error(`\`findRoot()\` could not find \`package.json\` from ${dir}`);
179
267
  }
180
268
  return result;
181
- }
182
- };
269
+ },
270
+
271
+ // add the supported `fs` functions
272
+ access: fsPromises.access,
273
+ appendFile: fsPromises.appendFile,
274
+ chmod: fsPromises.chmod,
275
+ close: B.promisify(close),
276
+ constants,
277
+ createWriteStream,
278
+ createReadStream,
279
+ lstat: fsPromises.lstat,
280
+ /**
281
+ * Warning: this is a promisified {@linkcode open fs.open}.
282
+ * It resolves w/a file descriptor instead of a {@linkcode fsPromises.FileHandle FileHandle} object, as {@linkcode fsPromises.open} does. Use {@linkcode fs.openFile} if you want a `FileHandle`.
283
+ */
284
+ open: B.promisify(open),
285
+ openFile: fsPromises.open,
286
+ readdir: fsPromises.readdir,
287
+ read: B.promisify(read),
288
+ readFile: fsPromises.readFile,
289
+ readlink: fsPromises.readlink,
290
+ realpath: fsPromises.realpath,
291
+ rename: fsPromises.rename,
292
+ stat: fsPromises.stat,
293
+ symlink: fsPromises.symlink,
294
+ unlink: fsPromises.unlink,
295
+ write: B.promisify(write),
296
+ writeFile: fsPromises.writeFile,
297
+
298
+ // deprecated props
299
+
300
+ /**
301
+ * Use `constants.F_OK` instead.
302
+ * @deprecated
303
+ */
304
+ F_OK: constants.F_OK,
305
+
306
+ /**
307
+ * Use `constants.R_OK` instead.
308
+ * @deprecated
309
+ */
310
+ R_OK: constants.R_OK,
311
+
312
+ /**
313
+ * Use `constants.W_OK` instead.
314
+ * @deprecated
315
+ */
316
+ W_OK: constants.W_OK,
183
317
 
184
- // add the supported `fs` functions
185
- const simples = [
186
- 'open', 'close', 'access', 'readFile', 'writeFile', 'write', 'read',
187
- 'readlink', 'chmod', 'unlink', 'readdir', 'stat', 'rename', 'lstat',
188
- 'appendFile', 'realpath', 'symlink',
189
- ];
190
- for (const s of simples) {
191
- fs[s] = B.promisify(_fs[s]);
192
- }
193
-
194
- const syncFunctions = [
195
- 'createReadStream',
196
- 'createWriteStream',
197
- ];
198
- for (const s of syncFunctions) {
199
- fs[s] = _fs[s];
200
- }
201
-
202
- // add the constants from `fs`
203
- const constants = [
204
- 'F_OK', 'R_OK', 'W_OK', 'X_OK', 'constants',
205
- ];
206
- for (const c of constants) {
207
- fs[c] = _fs[c];
208
- }
318
+ /**
319
+ * Use `constants.X_OK` instead.
320
+ * @deprecated
321
+ */
322
+ X_OK: constants.X_OK
323
+ };
209
324
 
210
325
  export { fs };
211
326
  export default fs;
327
+
328
+ /**
329
+ * The callback function which will be called during the directory walking
330
+ * @callback WalkDirCallback
331
+ * @param {string} itemPath The path of the file or folder
332
+ * @param {boolean} isDirectory Shows if it is a directory or a file
333
+ * @return {boolean} return true if you want to stop walking
334
+ */
335
+
package/lib/index.js CHANGED
@@ -12,17 +12,23 @@ import * as imageUtil from './image-util';
12
12
  import * as mjpeg from './mjpeg';
13
13
  import * as node from './node';
14
14
  import * as timing from './timing';
15
+ import * as env from './env';
15
16
 
17
+ export { npm } from './npm';
16
18
 
17
19
  const { fs } = fsIndex;
18
20
  const { cancellableDelay } = util;
21
+ /**
22
+ * Alias for `fs.mkdir(dir, {recursive: true}`). Use `fs.mkdirp` instead.
23
+ * @deprecated
24
+ */
19
25
  const { mkdirp } = mkdirpIndex;
20
26
 
21
27
  export {
22
28
  tempDir, system, util, fs, cancellableDelay, plist, mkdirp, logger, process,
23
- zip, imageUtil, net, mjpeg, node, timing,
29
+ zip, imageUtil, net, mjpeg, node, timing, env
24
30
  };
25
31
  export default {
26
32
  tempDir, system, util, fs, cancellableDelay, plist, mkdirp, logger, process,
27
- zip, imageUtil, net, mjpeg, node, timing,
33
+ zip, imageUtil, net, mjpeg, node, timing, env
28
34
  };
@@ -4,7 +4,7 @@ import _ from 'lodash';
4
4
  const DEFAULT_REPLACER = '**SECURE**';
5
5
 
6
6
  /**
7
- * @typedef {Object} SecureValuePreprocessingRule
7
+ * @typedef SecureValuePreprocessingRule
8
8
  * @property {RegExp} pattern The parsed pattern which is going to be used for replacement
9
9
  * @property {string} replacer [DEFAULT_SECURE_REPLACER] The replacer value to use. By default
10
10
  * equals to `DEFAULT_SECURE_REPLACER`
@@ -24,7 +24,7 @@ class SecureValuesPreprocessor {
24
24
  }
25
25
 
26
26
  /**
27
- * @typedef {Object} Rule
27
+ * @typedef Rule
28
28
  * @property {string} pattern A valid RegExp pattern to be replaced
29
29
  * @property {string} text A text match to replace. Either this property or the
30
30
  * above one must be provided. `pattern` has priority over `text` if both are provided.
package/lib/logging.js CHANGED
@@ -104,7 +104,7 @@ function getLogger (prefix = null) {
104
104
  }
105
105
 
106
106
  /**
107
- * @typedef {Object} LoadResult
107
+ * @typedef LoadResult
108
108
  * @property {List<string>} issues The list of rule parsing issues (one item per rule).
109
109
  * Rules with issues are skipped. An empty list is returned if no parsing issues exist.
110
110
  * @property {List<SecureValuePreprocessingRule>} rules The list of successfully loaded
package/lib/mkdirp.js CHANGED
@@ -1,9 +1,6 @@
1
- import mkdirp from 'mkdirp';
2
-
1
+ import { fs } from './fs';
3
2
  /**
4
- * TODO: once we drop support for Node 10, this should be removed in favor
5
- * of fs.mkdir(dir, {recursive: true});
3
+ * @deprecated Use `fs.mkdirp` instead.
6
4
  */
7
-
8
-
5
+ const { mkdirp } = fs;
9
6
  export { mkdirp };
package/lib/net.js CHANGED
@@ -111,20 +111,20 @@ async function uploadFileToFtp (localFileStream, parsedUri, uploadOptions = {})
111
111
  }
112
112
 
113
113
  /**
114
- * @typedef {Object} AuthCredentials
114
+ * @typedef AuthCredentials
115
115
  * @property {string} user - Non-empty user name
116
116
  * @property {string} pass - Non-empty password
117
117
  */
118
118
 
119
119
  /**
120
- * @typedef {Object} FtpUploadOptions
120
+ * @typedef FtpUploadOptions
121
121
  * @property {boolean} isMetered [true] - Whether to log the actual upload performance
122
122
  * (e.g. timings and speed)
123
123
  * @property {AuthCredentials} auth
124
124
  */
125
125
 
126
126
  /**
127
- * @typedef {Object} HttpUploadOptions
127
+ * @typedef HttpUploadOptions
128
128
  * @property {boolean} isMetered [true] - Whether to log the actual upload performance
129
129
  * (e.g. timings and speed)
130
130
  * @property {string} method [POST] - The HTTP method used for file upload
@@ -183,7 +183,7 @@ async function uploadFile (localPath, remoteUri, uploadOptions = {}) {
183
183
  }
184
184
 
185
185
  /**
186
- * @typedef {Object} DownloadOptions
186
+ * @typedef DownloadOptions
187
187
  * @property {boolean} isMetered [true] - Whether to log the actual download performance
188
188
  * (e.g. timings and speed)
189
189
  * @property {AuthCredentials} auth
package/lib/node.js CHANGED
@@ -1,7 +1,15 @@
1
1
  import { isWindows } from './system';
2
2
  import log from './logger';
3
+ import _ from 'lodash';
3
4
  import { exec } from 'teen_process';
4
5
  import path from 'path';
6
+ import { v4 as uuidV4 } from 'uuid';
7
+
8
+ const ECMA_SIZES = Object.freeze({
9
+ STRING: 2,
10
+ BOOLEAN: 4,
11
+ NUMBER: 8,
12
+ });
5
13
 
6
14
  /**
7
15
  * Internal utility to link global package to local context
@@ -63,4 +71,99 @@ async function requirePackage (packageName) {
63
71
  }
64
72
  }
65
73
 
66
- export { requirePackage };
74
+ function extractAllProperties (obj) {
75
+ const stringProperties = [];
76
+ for (const prop in obj) {
77
+ stringProperties.push(prop);
78
+ }
79
+ if (_.isFunction(Object.getOwnPropertySymbols)) {
80
+ stringProperties.push(...(Object.getOwnPropertySymbols(obj)));
81
+ }
82
+ return stringProperties;
83
+ }
84
+
85
+ function _getSizeOfObject (seen, object) {
86
+ if (_.isNil(object)) {
87
+ return 0;
88
+ }
89
+
90
+ let bytes = 0;
91
+ const properties = extractAllProperties(object);
92
+ for (const key of properties) {
93
+ // Do not recalculate circular references
94
+ if (typeof object[key] === 'object' && !_.isNil(object[key])) {
95
+ if (seen.has(object[key])) {
96
+ continue;
97
+ }
98
+ seen.add(object[key]);
99
+ }
100
+
101
+ bytes += getCalculator(seen)(key);
102
+ try {
103
+ bytes += getCalculator(seen)(object[key]);
104
+ } catch (ex) {
105
+ if (ex instanceof RangeError) {
106
+ // circular reference detected, final result might be incorrect
107
+ // let's be nice and not throw an exception
108
+ bytes = 0;
109
+ }
110
+ }
111
+ }
112
+
113
+ return bytes;
114
+ }
115
+
116
+ function getCalculator (seen) {
117
+ return function calculator (obj) {
118
+ if (_.isBuffer(obj)) {
119
+ return obj.length;
120
+ }
121
+
122
+ switch (typeof (obj)) {
123
+ case 'string':
124
+ return obj.length * ECMA_SIZES.STRING;
125
+ case 'boolean':
126
+ return ECMA_SIZES.BOOLEAN;
127
+ case 'number':
128
+ return ECMA_SIZES.NUMBER;
129
+ case 'symbol':
130
+ return _.isFunction(Symbol.keyFor) && Symbol.keyFor(obj)
131
+ ? Symbol.keyFor(obj).length * ECMA_SIZES.STRING
132
+ : (obj.toString().length - 8) * ECMA_SIZES.STRING;
133
+ case 'object':
134
+ return _.isArray(obj)
135
+ ? obj.map(getCalculator(seen)).reduce((acc, curr) => acc + curr, 0)
136
+ : _getSizeOfObject(seen, obj);
137
+ default:
138
+ return 0;
139
+ }
140
+ };
141
+ }
142
+
143
+ /**
144
+ * Calculate the in-depth size in memory of the provided object.
145
+ * The original implementation is borrowed from https://github.com/miktam/sizeof.
146
+ *
147
+ * @param {*} obj An object whose size should be calculated
148
+ * @returns {number} Object size in bytes.
149
+ */
150
+ function getObjectSize (obj) {
151
+ return getCalculator(new WeakSet())(obj);
152
+ }
153
+
154
+ const OBJECTS_MAPPING = new WeakMap();
155
+
156
+ /**
157
+ * Calculates a unique object identifier
158
+ *
159
+ * @param {object} object Any valid ECMA object
160
+ * @returns {string} A uuidV4 string that uniquely identifies given object
161
+ */
162
+ function getObjectId (object) {
163
+ if (!OBJECTS_MAPPING.has(object)) {
164
+ OBJECTS_MAPPING.set(object, uuidV4());
165
+ }
166
+ return OBJECTS_MAPPING.get(object);
167
+ }
168
+
169
+ export { requirePackage, getObjectSize, getObjectId };