codeceptjs 3.6.10 → 3.7.0-beta.2

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 (105) hide show
  1. package/README.md +81 -110
  2. package/bin/codecept.js +2 -2
  3. package/docs/webapi/clearCookie.mustache +1 -1
  4. package/lib/actor.js +46 -36
  5. package/lib/assert/empty.js +3 -5
  6. package/lib/assert/equal.js +4 -7
  7. package/lib/assert/include.js +4 -6
  8. package/lib/assert/throws.js +2 -4
  9. package/lib/assert/truth.js +2 -2
  10. package/lib/codecept.js +87 -83
  11. package/lib/command/configMigrate.js +2 -4
  12. package/lib/command/definitions.js +5 -25
  13. package/lib/command/generate.js +10 -14
  14. package/lib/command/gherkin/snippets.js +10 -8
  15. package/lib/command/gherkin/steps.js +1 -1
  16. package/lib/command/info.js +1 -3
  17. package/lib/command/init.js +8 -12
  18. package/lib/command/interactive.js +1 -1
  19. package/lib/command/list.js +1 -1
  20. package/lib/command/run-multiple.js +12 -35
  21. package/lib/command/run-workers.js +10 -10
  22. package/lib/command/utils.js +5 -6
  23. package/lib/command/workers/runTests.js +14 -17
  24. package/lib/container.js +327 -237
  25. package/lib/data/context.js +10 -13
  26. package/lib/data/dataScenarioConfig.js +8 -8
  27. package/lib/data/dataTableArgument.js +6 -6
  28. package/lib/data/table.js +5 -11
  29. package/lib/els.js +177 -0
  30. package/lib/event.js +1 -0
  31. package/lib/heal.js +78 -80
  32. package/lib/helper/ApiDataFactory.js +3 -6
  33. package/lib/helper/Appium.js +15 -30
  34. package/lib/helper/FileSystem.js +3 -3
  35. package/lib/helper/GraphQLDataFactory.js +3 -3
  36. package/lib/helper/JSONResponse.js +57 -37
  37. package/lib/helper/Nightmare.js +35 -53
  38. package/lib/helper/Playwright.js +189 -251
  39. package/lib/helper/Protractor.js +54 -77
  40. package/lib/helper/Puppeteer.js +134 -232
  41. package/lib/helper/REST.js +5 -17
  42. package/lib/helper/TestCafe.js +21 -44
  43. package/lib/helper/WebDriver.js +103 -162
  44. package/lib/helper/testcafe/testcafe-utils.js +26 -27
  45. package/lib/listener/artifacts.js +2 -2
  46. package/lib/listener/emptyRun.js +58 -0
  47. package/lib/listener/exit.js +4 -4
  48. package/lib/listener/{retry.js → globalRetry.js} +5 -5
  49. package/lib/listener/{timeout.js → globalTimeout.js} +9 -8
  50. package/lib/listener/helpers.js +15 -15
  51. package/lib/listener/mocha.js +1 -1
  52. package/lib/listener/steps.js +17 -12
  53. package/lib/listener/store.js +12 -0
  54. package/lib/mocha/asyncWrapper.js +204 -0
  55. package/lib/{interfaces → mocha}/bdd.js +3 -3
  56. package/lib/mocha/cli.js +257 -0
  57. package/lib/mocha/factory.js +104 -0
  58. package/lib/{interfaces → mocha}/featureConfig.js +11 -12
  59. package/lib/{interfaces → mocha}/gherkin.js +26 -28
  60. package/lib/mocha/hooks.js +83 -0
  61. package/lib/mocha/index.js +12 -0
  62. package/lib/mocha/inject.js +24 -0
  63. package/lib/{interfaces → mocha}/scenarioConfig.js +10 -6
  64. package/lib/mocha/suite.js +55 -0
  65. package/lib/mocha/test.js +60 -0
  66. package/lib/mocha/types.d.ts +31 -0
  67. package/lib/mocha/ui.js +219 -0
  68. package/lib/output.js +28 -10
  69. package/lib/pause.js +159 -135
  70. package/lib/plugin/autoDelay.js +4 -4
  71. package/lib/plugin/autoLogin.js +6 -7
  72. package/lib/plugin/commentStep.js +1 -1
  73. package/lib/plugin/coverage.js +10 -19
  74. package/lib/plugin/customLocator.js +3 -3
  75. package/lib/plugin/debugErrors.js +2 -2
  76. package/lib/plugin/eachElement.js +1 -1
  77. package/lib/plugin/fakerTransform.js +1 -1
  78. package/lib/plugin/heal.js +6 -9
  79. package/lib/plugin/retryFailedStep.js +4 -4
  80. package/lib/plugin/retryTo.js +2 -2
  81. package/lib/plugin/screenshotOnFail.js +9 -36
  82. package/lib/plugin/selenoid.js +15 -35
  83. package/lib/plugin/stepByStepReport.js +51 -13
  84. package/lib/plugin/stepTimeout.js +4 -11
  85. package/lib/plugin/subtitles.js +4 -4
  86. package/lib/plugin/tryTo.js +1 -1
  87. package/lib/plugin/wdio.js +8 -10
  88. package/lib/recorder.js +142 -121
  89. package/lib/secret.js +1 -1
  90. package/lib/step.js +160 -144
  91. package/lib/store.js +6 -2
  92. package/lib/template/heal.js +2 -11
  93. package/lib/utils.js +224 -216
  94. package/lib/within.js +73 -55
  95. package/lib/workers.js +265 -261
  96. package/package.json +46 -47
  97. package/typings/index.d.ts +172 -184
  98. package/typings/promiseBasedTypes.d.ts +95 -516
  99. package/typings/types.d.ts +169 -587
  100. package/lib/cli.js +0 -256
  101. package/lib/helper/ExpectHelper.js +0 -391
  102. package/lib/helper/SoftExpectHelper.js +0 -381
  103. package/lib/mochaFactory.js +0 -113
  104. package/lib/scenario.js +0 -224
  105. package/lib/ui.js +0 -236
package/lib/utils.js CHANGED
@@ -1,104 +1,93 @@
1
- const fs = require('fs');
2
- const os = require('os');
3
- const path = require('path');
4
- const getFunctionArguments = require('fn-args');
5
- const deepClone = require('lodash.clonedeep');
6
- const { convertColorToRGBA, isColorProperty } = require('./colorUtils');
1
+ const fs = require('fs')
2
+ const os = require('os')
3
+ const path = require('path')
4
+ const getFunctionArguments = require('fn-args')
5
+ const deepClone = require('lodash.clonedeep')
6
+ const { convertColorToRGBA, isColorProperty } = require('./colorUtils')
7
7
 
8
8
  function deepMerge(target, source) {
9
- const merge = require('lodash.merge');
10
- return merge(target, source);
9
+ const merge = require('lodash.merge')
10
+ return merge(target, source)
11
11
  }
12
12
 
13
- module.exports.genTestId = (test) => {
14
- return require('crypto').createHash('sha256').update(test.fullTitle()).digest('base64')
15
- .slice(0, -2);
16
- };
13
+ module.exports.genTestId = test => {
14
+ return require('crypto').createHash('sha256').update(test.fullTitle()).digest('base64').slice(0, -2)
15
+ }
17
16
 
18
- module.exports.deepMerge = deepMerge;
17
+ module.exports.deepMerge = deepMerge
19
18
 
20
- module.exports.deepClone = deepClone;
19
+ module.exports.deepClone = deepClone
21
20
 
22
21
  module.exports.isGenerator = function (fn) {
23
- return fn.constructor.name === 'GeneratorFunction';
24
- };
22
+ return fn.constructor.name === 'GeneratorFunction'
23
+ }
25
24
 
26
- const isFunction = module.exports.isFunction = function (fn) {
27
- return typeof fn === 'function';
28
- };
25
+ const isFunction = (module.exports.isFunction = function (fn) {
26
+ return typeof fn === 'function'
27
+ })
29
28
 
30
- const isAsyncFunction = module.exports.isAsyncFunction = function (fn) {
31
- if (!fn) return false;
32
- return fn[Symbol.toStringTag] === 'AsyncFunction';
33
- };
29
+ const isAsyncFunction = (module.exports.isAsyncFunction = function (fn) {
30
+ if (!fn) return false
31
+ return fn[Symbol.toStringTag] === 'AsyncFunction'
32
+ })
34
33
 
35
34
  module.exports.fileExists = function (filePath) {
36
- return fs.existsSync(filePath);
37
- };
35
+ return fs.existsSync(filePath)
36
+ }
38
37
 
39
38
  module.exports.isFile = function (filePath) {
40
- let filestat;
39
+ let filestat
41
40
  try {
42
- filestat = fs.statSync(filePath);
41
+ filestat = fs.statSync(filePath)
43
42
  } catch (err) {
44
- if (err.code === 'ENOENT') return false;
43
+ if (err.code === 'ENOENT') return false
45
44
  }
46
- if (!filestat) return false;
47
- return filestat.isFile();
48
- };
45
+ if (!filestat) return false
46
+ return filestat.isFile()
47
+ }
49
48
 
50
49
  module.exports.getParamNames = function (fn) {
51
- if (fn.isSinonProxy) return [];
52
- return getFunctionArguments(fn);
53
- };
50
+ if (fn.isSinonProxy) return []
51
+ return getFunctionArguments(fn)
52
+ }
54
53
 
55
54
  module.exports.installedLocally = function () {
56
- return path.resolve(`${__dirname}/../`).indexOf(process.cwd()) === 0;
57
- };
55
+ return path.resolve(`${__dirname}/../`).indexOf(process.cwd()) === 0
56
+ }
58
57
 
59
58
  module.exports.methodsOfObject = function (obj, className) {
60
- const methods = [];
61
-
62
- const standard = [
63
- 'constructor',
64
- 'toString',
65
- 'toLocaleString',
66
- 'valueOf',
67
- 'hasOwnProperty',
68
- 'bind',
69
- 'apply',
70
- 'call',
71
- 'isPrototypeOf',
72
- 'propertyIsEnumerable',
73
- ];
59
+ const methods = []
60
+
61
+ const standard = ['constructor', 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'bind', 'apply', 'call', 'isPrototypeOf', 'propertyIsEnumerable']
74
62
 
75
63
  function pushToMethods(prop) {
76
64
  try {
77
- if (!isFunction(obj[prop]) && !isAsyncFunction(obj[prop])) return;
78
- } catch (err) { // can't access property
79
- return;
65
+ if (!isFunction(obj[prop]) && !isAsyncFunction(obj[prop])) return
66
+ } catch (err) {
67
+ // can't access property
68
+ return
80
69
  }
81
- if (standard.indexOf(prop) >= 0) return;
82
- if (prop.indexOf('_') === 0) return;
83
- methods.push(prop);
70
+ if (standard.indexOf(prop) >= 0) return
71
+ if (prop.indexOf('_') === 0) return
72
+ methods.push(prop)
84
73
  }
85
74
 
86
75
  while (obj.constructor.name !== className) {
87
- Object.getOwnPropertyNames(obj).forEach(pushToMethods);
88
- obj = Object.getPrototypeOf(obj);
76
+ Object.getOwnPropertyNames(obj).forEach(pushToMethods)
77
+ obj = Object.getPrototypeOf(obj)
89
78
 
90
- if (!obj || !obj.constructor) break;
79
+ if (!obj || !obj.constructor) break
91
80
  }
92
- return methods;
93
- };
81
+ return methods
82
+ }
94
83
 
95
84
  module.exports.template = function (template, data) {
96
85
  return template.replace(/{{([^{}]*)}}/g, (a, b) => {
97
- const r = data[b];
98
- if (r === undefined) return '';
99
- return r.toString();
100
- });
101
- };
86
+ const r = data[b]
87
+ if (r === undefined) return ''
88
+ return r.toString()
89
+ })
90
+ }
102
91
 
103
92
  /**
104
93
  * Make first char uppercase.
@@ -106,8 +95,8 @@ module.exports.template = function (template, data) {
106
95
  * @returns {string}
107
96
  */
108
97
  module.exports.ucfirst = function (str) {
109
- return str.charAt(0).toUpperCase() + str.substr(1);
110
- };
98
+ return str.charAt(0).toUpperCase() + str.substr(1)
99
+ }
111
100
 
112
101
  /**
113
102
  * Make first char lowercase.
@@ -115,25 +104,25 @@ module.exports.ucfirst = function (str) {
115
104
  * @returns {string}
116
105
  */
117
106
  module.exports.lcfirst = function (str) {
118
- return str.charAt(0).toLowerCase() + str.substr(1);
119
- };
107
+ return str.charAt(0).toLowerCase() + str.substr(1)
108
+ }
120
109
 
121
110
  module.exports.chunkArray = function (arr, chunk) {
122
- let i;
123
- let j;
124
- const tmp = [];
111
+ let i
112
+ let j
113
+ const tmp = []
125
114
  for (i = 0, j = arr.length; i < j; i += chunk) {
126
- tmp.push(arr.slice(i, i + chunk));
115
+ tmp.push(arr.slice(i, i + chunk))
127
116
  }
128
- return tmp;
129
- };
117
+ return tmp
118
+ }
130
119
 
131
120
  module.exports.clearString = function (str) {
132
- if (!str) return '';
121
+ if (!str) return ''
133
122
  /* Replace forbidden symbols in string
134
123
  */
135
124
  if (str.endsWith('.')) {
136
- str = str.slice(0, -1);
125
+ str = str.slice(0, -1)
137
126
  }
138
127
  return str
139
128
  .replace(/ /g, '_')
@@ -146,26 +135,29 @@ module.exports.clearString = function (str) {
146
135
  .replace(/\|/g, '_')
147
136
  .replace(/\?/g, '.')
148
137
  .replace(/\*/g, '^')
149
- .replace(/'/g, '');
150
- };
138
+ .replace(/'/g, '')
139
+ }
151
140
 
152
141
  module.exports.decodeUrl = function (url) {
153
142
  /* Replace forbidden symbols in string
154
143
  */
155
- return decodeURIComponent(decodeURIComponent(decodeURIComponent(url)));
156
- };
144
+ return decodeURIComponent(decodeURIComponent(decodeURIComponent(url)))
145
+ }
157
146
 
158
147
  module.exports.xpathLocator = {
159
148
  /**
160
149
  * @param {string} string
161
150
  * @returns {string}
162
151
  */
163
- literal: (string) => {
152
+ literal: string => {
164
153
  if (string.indexOf("'") > -1) {
165
- string = string.split("'", -1).map(substr => `'${substr}'`).join(',"\'",');
166
- return `concat(${string})`;
154
+ string = string
155
+ .split("'", -1)
156
+ .map(substr => `'${substr}'`)
157
+ .join(',"\'",')
158
+ return `concat(${string})`
167
159
  }
168
- return `'${string}'`;
160
+ return `'${string}'`
169
161
  },
170
162
 
171
163
  /**
@@ -174,55 +166,53 @@ module.exports.xpathLocator = {
174
166
  * @returns {string}
175
167
  */
176
168
  combine: locators => locators.join(' | '),
177
- };
169
+ }
178
170
 
179
171
  module.exports.test = {
180
-
181
172
  grepLines(array, startString, endString) {
182
- let startIndex = 0;
183
- let endIndex;
173
+ let startIndex = 0
174
+ let endIndex
184
175
  array.every((elem, index) => {
185
176
  if (elem === startString) {
186
- startIndex = index;
187
- return true;
177
+ startIndex = index
178
+ return true
188
179
  }
189
180
  if (elem === endString) {
190
- endIndex = index;
191
- return false;
181
+ endIndex = index
182
+ return false
192
183
  }
193
- return true;
194
- });
195
- return array.slice(startIndex + 1, endIndex);
184
+ return true
185
+ })
186
+ return array.slice(startIndex + 1, endIndex)
196
187
  },
197
188
 
198
189
  submittedData(dataFile) {
199
190
  return function (key) {
200
191
  if (!fs.existsSync(dataFile)) {
201
- const waitTill = new Date(new Date().getTime() + 1 * 1000); // wait for one sec for file to be created
202
- while (waitTill > new Date()) {} // eslint-disable-line no-empty
192
+ const waitTill = new Date(new Date().getTime() + 1 * 1000) // wait for one sec for file to be created
193
+ while (waitTill > new Date()) {}
203
194
  }
204
195
  if (!fs.existsSync(dataFile)) {
205
- throw new Error('Data file was not created in time');
196
+ throw new Error('Data file was not created in time')
206
197
  }
207
- const data = JSON.parse(fs.readFileSync(dataFile, 'utf8'));
198
+ const data = JSON.parse(fs.readFileSync(dataFile, 'utf8'))
208
199
  if (key) {
209
- return data.form[key];
200
+ return data.form[key]
210
201
  }
211
- return data;
212
- };
202
+ return data
203
+ }
213
204
  },
214
-
215
- };
205
+ }
216
206
 
217
207
  function toCamelCase(name) {
218
208
  if (typeof name !== 'string') {
219
- return name;
209
+ return name
220
210
  }
221
211
  return name.replace(/-(\w)/gi, (_word, letter) => {
222
- return letter.toUpperCase();
223
- });
212
+ return letter.toUpperCase()
213
+ })
224
214
  }
225
- module.exports.toCamelCase = toCamelCase;
215
+ module.exports.toCamelCase = toCamelCase
226
216
 
227
217
  function convertFontWeightToNumber(name) {
228
218
  const fontWeightPatterns = [
@@ -235,106 +225,110 @@ function convertFontWeightToNumber(name) {
235
225
  { num: 700, pattern: /^Bold$/i },
236
226
  { num: 800, pattern: /^(Extra|Ultra)-?bold$/i },
237
227
  { num: 900, pattern: /^(Black|Heavy)$/i },
238
- ];
228
+ ]
239
229
 
240
230
  if (/^[1-9]00$/.test(name)) {
241
- return Number(name);
231
+ return Number(name)
242
232
  }
243
233
 
244
- const matches = fontWeightPatterns.filter(fontWeight => fontWeight.pattern.test(name));
234
+ const matches = fontWeightPatterns.filter(fontWeight => fontWeight.pattern.test(name))
245
235
 
246
236
  if (matches.length) {
247
- return String(matches[0].num);
237
+ return String(matches[0].num)
248
238
  }
249
- return name;
239
+ return name
250
240
  }
251
241
 
252
242
  function isFontWeightProperty(prop) {
253
- return prop === 'fontWeight';
243
+ return prop === 'fontWeight'
254
244
  }
255
245
 
256
246
  module.exports.convertCssPropertiesToCamelCase = function (props) {
257
- const output = {};
258
- Object.keys(props).forEach((key) => {
259
- const keyCamel = toCamelCase(key);
247
+ const output = {}
248
+ Object.keys(props).forEach(key => {
249
+ const keyCamel = toCamelCase(key)
260
250
 
261
251
  if (isFontWeightProperty(keyCamel)) {
262
- output[keyCamel] = convertFontWeightToNumber(props[key]);
252
+ output[keyCamel] = convertFontWeightToNumber(props[key])
263
253
  } else if (isColorProperty(keyCamel)) {
264
- output[keyCamel] = convertColorToRGBA(props[key]);
254
+ output[keyCamel] = convertColorToRGBA(props[key])
265
255
  } else {
266
- output[keyCamel] = props[key];
256
+ output[keyCamel] = props[key]
267
257
  }
268
- });
269
- return output;
270
- };
258
+ })
259
+ return output
260
+ }
271
261
 
272
262
  module.exports.deleteDir = function (dir_path) {
273
263
  if (fs.existsSync(dir_path)) {
274
264
  fs.readdirSync(dir_path).forEach(function (entry) {
275
- const entry_path = path.join(dir_path, entry);
265
+ const entry_path = path.join(dir_path, entry)
276
266
  if (fs.lstatSync(entry_path).isDirectory()) {
277
- this.deleteDir(entry_path);
267
+ this.deleteDir(entry_path)
278
268
  } else {
279
- fs.unlinkSync(entry_path);
269
+ fs.unlinkSync(entry_path)
280
270
  }
281
- });
282
- fs.rmdirSync(dir_path);
271
+ })
272
+ fs.rmdirSync(dir_path)
283
273
  }
284
- };
274
+ }
285
275
 
286
276
  /**
287
277
  * Returns absolute filename to save screenshot.
288
278
  * @param fileName {string} - filename.
289
279
  */
290
280
  module.exports.screenshotOutputFolder = function (fileName) {
291
- const fileSep = path.sep;
281
+ const fileSep = path.sep
292
282
 
293
283
  if (!fileName.includes(fileSep) || fileName.includes('record_')) {
294
- return path.resolve(global.output_dir, fileName);
284
+ return path.resolve(global.output_dir, fileName)
295
285
  }
296
- return path.resolve(global.codecept_dir, fileName);
297
- };
286
+ return path.resolve(global.codecept_dir, fileName)
287
+ }
288
+
289
+ module.exports.relativeDir = function (fileName) {
290
+ return fileName.replace(global.codecept_dir, '').replace(/^\//, '')
291
+ }
298
292
 
299
293
  module.exports.beautify = function (code) {
300
- const format = require('js-beautify').js;
301
- return format(code, { indent_size: 2, space_in_empty_paren: true });
302
- };
294
+ const format = require('js-beautify').js
295
+ return format(code, { indent_size: 2, space_in_empty_paren: true })
296
+ }
303
297
 
304
298
  function shouldAppendBaseUrl(url) {
305
- return !/^\w+\:\/\//.test(url);
299
+ return !/^\w+\:\/\//.test(url)
306
300
  }
307
301
 
308
302
  function trimUrl(url) {
309
- const firstChar = url.substr(1);
303
+ const firstChar = url.substr(1)
310
304
  if (firstChar === '/') {
311
- url = url.slice(1);
305
+ url = url.slice(1)
312
306
  }
313
- return url;
307
+ return url
314
308
  }
315
309
 
316
310
  function joinUrl(baseUrl, url) {
317
- return shouldAppendBaseUrl(url) ? `${baseUrl}/${trimUrl(url)}` : url;
311
+ return shouldAppendBaseUrl(url) ? `${baseUrl}/${trimUrl(url)}` : url
318
312
  }
319
313
 
320
314
  module.exports.appendBaseUrl = function (baseUrl = '', oneOrMoreUrls) {
321
315
  if (typeof baseUrl !== 'string') {
322
- throw new Error(`Invalid value for baseUrl: ${baseUrl}`);
316
+ throw new Error(`Invalid value for baseUrl: ${baseUrl}`)
323
317
  }
324
318
  if (!(typeof oneOrMoreUrls === 'string' || Array.isArray(oneOrMoreUrls))) {
325
- throw new Error(`Expected type of Urls is 'string' or 'array', Found '${typeof oneOrMoreUrls}'.`);
319
+ throw new Error(`Expected type of Urls is 'string' or 'array', Found '${typeof oneOrMoreUrls}'.`)
326
320
  }
327
321
  // Remove '/' if it's at the end of baseUrl
328
- const lastChar = baseUrl.substr(-1);
322
+ const lastChar = baseUrl.substr(-1)
329
323
  if (lastChar === '/') {
330
- baseUrl = baseUrl.slice(0, -1);
324
+ baseUrl = baseUrl.slice(0, -1)
331
325
  }
332
326
 
333
327
  if (!Array.isArray(oneOrMoreUrls)) {
334
- return joinUrl(baseUrl, oneOrMoreUrls);
328
+ return joinUrl(baseUrl, oneOrMoreUrls)
335
329
  }
336
- return oneOrMoreUrls.map(url => joinUrl(baseUrl, url));
337
- };
330
+ return oneOrMoreUrls.map(url => joinUrl(baseUrl, url))
331
+ }
338
332
 
339
333
  /**
340
334
  * Recursively search key in object and replace it's value.
@@ -344,56 +338,53 @@ module.exports.appendBaseUrl = function (baseUrl = '', oneOrMoreUrls) {
344
338
  * @param {*} value value to set for key
345
339
  */
346
340
  module.exports.replaceValueDeep = function replaceValueDeep(obj, key, value) {
347
- if (!obj) return;
341
+ if (!obj) return
348
342
 
349
343
  if (obj instanceof Array) {
350
344
  for (const i in obj) {
351
- replaceValueDeep(obj[i], key, value);
345
+ replaceValueDeep(obj[i], key, value)
352
346
  }
353
347
  }
354
348
 
355
349
  if (Object.prototype.hasOwnProperty.call(obj, key)) {
356
- obj[key] = value;
350
+ obj[key] = value
357
351
  }
358
352
 
359
353
  if (typeof obj === 'object' && obj !== null) {
360
- const children = Object.values(obj);
354
+ const children = Object.values(obj)
361
355
  for (const child of children) {
362
- replaceValueDeep(child, key, value);
356
+ replaceValueDeep(child, key, value)
363
357
  }
364
358
  }
365
- return obj;
366
- };
359
+ return obj
360
+ }
367
361
 
368
362
  module.exports.ansiRegExp = function ({ onlyFirst = false } = {}) {
369
- const pattern = [
370
- '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
371
- '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))',
372
- ].join('|');
363
+ const pattern = ['[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'].join('|')
373
364
 
374
- return new RegExp(pattern, onlyFirst ? undefined : 'g');
375
- };
365
+ return new RegExp(pattern, onlyFirst ? undefined : 'g')
366
+ }
376
367
 
377
368
  module.exports.tryOrDefault = function (fn, defaultValue) {
378
369
  try {
379
- return fn();
370
+ return fn()
380
371
  } catch (_) {
381
- return defaultValue;
372
+ return defaultValue
382
373
  }
383
- };
374
+ }
384
375
 
385
376
  function normalizeKeyReplacer(match, prefix, key, suffix, offset, string) {
386
377
  if (typeof key !== 'string') {
387
- return string;
378
+ return string
388
379
  }
389
- const normalizedKey = key.charAt(0).toUpperCase() + key.substr(1).toLowerCase();
390
- let position = '';
380
+ const normalizedKey = key.charAt(0).toUpperCase() + key.substr(1).toLowerCase()
381
+ let position = ''
391
382
  if (typeof prefix === 'string') {
392
- position = prefix;
383
+ position = prefix
393
384
  } else if (typeof suffix === 'string') {
394
- position = suffix;
385
+ position = suffix
395
386
  }
396
- return normalizedKey + position.charAt(0).toUpperCase() + position.substr(1).toLowerCase();
387
+ return normalizedKey + position.charAt(0).toUpperCase() + position.substr(1).toLowerCase()
397
388
  }
398
389
 
399
390
  /**
@@ -403,76 +394,93 @@ function normalizeKeyReplacer(match, prefix, key, suffix, offset, string) {
403
394
  */
404
395
  module.exports.getNormalizedKeyAttributeValue = function (key) {
405
396
  // Use operation modifier key based on operating system
406
- key = key.replace(/(Ctrl|Control|Cmd|Command)[ _]?Or[ _]?(Ctrl|Control|Cmd|Command)/i, os.platform() === 'darwin' ? 'Meta' : 'Control');
397
+ key = key.replace(/(Ctrl|Control|Cmd|Command)[ _]?Or[ _]?(Ctrl|Control|Cmd|Command)/i, os.platform() === 'darwin' ? 'Meta' : 'Control')
407
398
  // Selection of keys (https://www.w3.org/TR/uievents-key/#named-key-attribute-values)
408
399
  // which can be written in various ways and should be normalized.
409
400
  // For example 'LEFT ALT', 'ALT_Left', 'alt left' or 'LeftAlt' will be normalized as 'AltLeft'.
410
- key = key.replace(/^\s*(?:(Down|Left|Right|Up)[ _]?)?(Arrow|Alt|Ctrl|Control|Cmd|Command|Meta|Option|OS|Page|Shift|Super)(?:[ _]?(Down|Left|Right|Up|Gr(?:aph)?))?\s*$/i, normalizeKeyReplacer);
401
+ key = key.replace(/^\s*(?:(Down|Left|Right|Up)[ _]?)?(Arrow|Alt|Ctrl|Control|Cmd|Command|Meta|Option|OS|Page|Shift|Super)(?:[ _]?(Down|Left|Right|Up|Gr(?:aph)?))?\s*$/i, normalizeKeyReplacer)
411
402
  // Map alias to corresponding key value
412
- key = key.replace(/^(Add|Divide|Decimal|Multiply|Subtract)$/, 'Numpad$1');
413
- key = key.replace(/^AltGr$/, 'AltGraph');
414
- key = key.replace(/^(Cmd|Command|Os|Super)/, 'Meta');
415
- key = key.replace('Ctrl', 'Control');
416
- key = key.replace('Option', 'Alt');
417
- key = key.replace(/^(NumpadComma|Separator)$/, 'Comma');
418
- return key;
419
- };
420
-
421
- const modifierKeys = [
422
- 'Alt', 'AltGraph', 'AltLeft', 'AltRight',
423
- 'Control', 'ControlLeft', 'ControlRight',
424
- 'Meta', 'MetaLeft', 'MetaRight',
425
- 'Shift', 'ShiftLeft', 'ShiftRight',
426
- ];
427
-
428
- module.exports.modifierKeys = modifierKeys;
403
+ key = key.replace(/^(Add|Divide|Decimal|Multiply|Subtract)$/, 'Numpad$1')
404
+ key = key.replace(/^AltGr$/, 'AltGraph')
405
+ key = key.replace(/^(Cmd|Command|Os|Super)/, 'Meta')
406
+ key = key.replace('Ctrl', 'Control')
407
+ key = key.replace('Option', 'Alt')
408
+ key = key.replace(/^(NumpadComma|Separator)$/, 'Comma')
409
+ return key
410
+ }
411
+
412
+ const modifierKeys = ['Alt', 'AltGraph', 'AltLeft', 'AltRight', 'Control', 'ControlLeft', 'ControlRight', 'Meta', 'MetaLeft', 'MetaRight', 'Shift', 'ShiftLeft', 'ShiftRight']
413
+
414
+ module.exports.modifierKeys = modifierKeys
429
415
  module.exports.isModifierKey = function (key) {
430
- return modifierKeys.includes(key);
431
- };
416
+ return modifierKeys.includes(key)
417
+ }
432
418
 
433
419
  module.exports.requireWithFallback = function (...packages) {
434
420
  const exists = function (pkg) {
435
421
  try {
436
- require.resolve(pkg);
422
+ require.resolve(pkg)
437
423
  } catch (e) {
438
- return false;
424
+ return false
439
425
  }
440
426
 
441
- return true;
442
- };
427
+ return true
428
+ }
443
429
 
444
430
  for (const pkg of packages) {
445
431
  if (exists(pkg)) {
446
- return require(pkg);
432
+ return require(pkg)
447
433
  }
448
434
  }
449
435
 
450
- throw new Error(`Cannot find modules ${packages.join(',')}`);
451
- };
436
+ throw new Error(`Cannot find modules ${packages.join(',')}`)
437
+ }
452
438
 
453
439
  module.exports.isNotSet = function (obj) {
454
- if (obj === null) return true;
455
- if (obj === undefined) return true;
456
- return false;
457
- };
440
+ if (obj === null) return true
441
+ if (obj === undefined) return true
442
+ return false
443
+ }
458
444
 
459
- module.exports.emptyFolder = async (directoryPath) => {
460
- require('child_process').execSync(`rm -rf ${directoryPath}/*`);
461
- };
445
+ module.exports.emptyFolder = async directoryPath => {
446
+ require('child_process').execSync(`rm -rf ${directoryPath}/*`)
447
+ }
462
448
 
463
- module.exports.printObjectProperties = (obj) => {
449
+ module.exports.printObjectProperties = obj => {
464
450
  if (typeof obj !== 'object' || obj === null) {
465
- return obj;
451
+ return obj
466
452
  }
467
453
 
468
- let result = '';
454
+ let result = ''
469
455
  for (const [key, value] of Object.entries(obj)) {
470
- result += `${key}: "${value}"; `;
456
+ result += `${key}: "${value}"; `
471
457
  }
472
458
 
473
- return `{${result}}`;
474
- };
459
+ return `{${result}}`
460
+ }
461
+
462
+ module.exports.normalizeSpacesInString = string => {
463
+ return string.replace(/\s+/g, ' ')
464
+ }
475
465
 
476
- module.exports.normalizeSpacesInString = (string) => {
477
- return string.replace(/\s+/g, ' ');
478
- };
466
+ module.exports.humanizeFunction = function (fn) {
467
+ const fnStr = fn.toString().trim()
468
+ // Remove arrow function syntax, async, and parentheses
469
+ let simplified = fnStr
470
+ .replace(/^async\s*/, '')
471
+ .replace(/^\([^)]*\)\s*=>/, '')
472
+ .replace(/^function\s*\([^)]*\)/, '')
473
+ // Remove curly braces and any whitespace around them
474
+ .replace(/{\s*(.*)\s*}/, '$1')
475
+ // Remove return statement
476
+ .replace(/return\s+/, '')
477
+ // Remove trailing semicolon
478
+ .replace(/;$/, '')
479
+ .trim()
480
+
481
+ if (simplified.length > 100) {
482
+ simplified = simplified.slice(0, 97) + '...'
483
+ }
484
+
485
+ return simplified
486
+ }