@wdio/utils 9.0.0-alpha.9 → 9.0.4

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 (43) hide show
  1. package/build/envDetector.d.ts +3 -3
  2. package/build/envDetector.d.ts.map +1 -1
  3. package/build/index.d.ts +2 -2
  4. package/build/index.d.ts.map +1 -1
  5. package/build/index.js +1902 -24
  6. package/build/initializeServices.d.ts +3 -3
  7. package/build/initializeServices.d.ts.map +1 -1
  8. package/build/monad.d.ts.map +1 -1
  9. package/build/node/manager.d.ts +2 -2
  10. package/build/node/manager.d.ts.map +1 -1
  11. package/build/node/startWebDriver.d.ts +2 -3
  12. package/build/node/startWebDriver.d.ts.map +1 -1
  13. package/build/node/utils.d.ts.map +1 -1
  14. package/build/node.js +473 -0
  15. package/build/pIteration.d.ts.map +1 -1
  16. package/build/shim.d.ts.map +1 -1
  17. package/build/startWebDriver.d.ts +2 -3
  18. package/build/startWebDriver.d.ts.map +1 -1
  19. package/build/test-framework/errorHandler.d.ts.map +1 -1
  20. package/build/test-framework/testFnWrapper.d.ts.map +1 -1
  21. package/build/test-framework/testInterfaceWrapper.d.ts.map +1 -1
  22. package/build/utils.d.ts +11 -2
  23. package/build/utils.d.ts.map +1 -1
  24. package/package.json +10 -11
  25. package/build/constants.js +0 -114
  26. package/build/envDetector.js +0 -251
  27. package/build/initializePlugin.js +0 -38
  28. package/build/initializeServices.js +0 -159
  29. package/build/monad.js +0 -196
  30. package/build/node/index.js +0 -3
  31. package/build/node/manager.js +0 -106
  32. package/build/node/startWebDriver.js +0 -140
  33. package/build/node/utils.js +0 -285
  34. package/build/pIteration.js +0 -347
  35. package/build/shim.js +0 -293
  36. package/build/startWebDriver.js +0 -20
  37. package/build/test-framework/errorHandler.js +0 -33
  38. package/build/test-framework/index.js +0 -4
  39. package/build/test-framework/testFnWrapper.js +0 -97
  40. package/build/test-framework/testInterfaceWrapper.js +0 -162
  41. package/build/test-framework/types.js +0 -1
  42. package/build/utils.js +0 -320
  43. /package/{LICENSE-MIT → LICENSE} +0 -0
@@ -1,285 +0,0 @@
1
- import os from 'node:os';
2
- import fs from 'node:fs';
3
- import fsp from 'node:fs/promises';
4
- import path from 'node:path';
5
- import cp from 'node:child_process';
6
- import decamelize from 'decamelize';
7
- import logger from '@wdio/logger';
8
- import { install, canDownload, resolveBuildId, detectBrowserPlatform, Browser, ChromeReleaseChannel, computeExecutablePath } from '@puppeteer/browsers';
9
- import { download as downloadGeckodriver } from 'geckodriver';
10
- import { download as downloadEdgedriver } from 'edgedriver';
11
- import { locateChrome, locateFirefox, locateApp } from 'locate-app';
12
- const log = logger('webdriver');
13
- const EXCLUDED_PARAMS = ['version', 'help'];
14
- /**
15
- * Helper utility to check file access
16
- * @param {string} file file to check access for
17
- * @return true if file can be accessed
18
- */
19
- export const canAccess = (file) => {
20
- if (!file) {
21
- return false;
22
- }
23
- try {
24
- fs.accessSync(file);
25
- return true;
26
- }
27
- catch (err) {
28
- return false;
29
- }
30
- };
31
- export function parseParams(params) {
32
- return Object.entries(params)
33
- .filter(([key,]) => !EXCLUDED_PARAMS.includes(key))
34
- .map(([key, val]) => {
35
- if (typeof val === 'boolean' && !val) {
36
- return '';
37
- }
38
- const vals = Array.isArray(val) ? val : [val];
39
- return vals.map((v) => `--${decamelize(key, { separator: '-' })}${typeof v === 'boolean' ? '' : `=${v}`}`);
40
- })
41
- .flat()
42
- .filter(Boolean);
43
- }
44
- export function getBuildIdByChromePath(chromePath) {
45
- if (!chromePath) {
46
- return;
47
- }
48
- if (os.platform() === 'win32') {
49
- const versionPath = path.dirname(chromePath);
50
- const contents = fs.readdirSync(versionPath);
51
- const versions = contents.filter(a => /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/g.test(a));
52
- // returning oldest in case there is an updated version and chrome still hasn't relaunched
53
- const oldest = versions.sort((a, b) => a > b ? -1 : 1)[0];
54
- return oldest;
55
- }
56
- const versionString = cp.execSync(`"${chromePath}" --version --no-sandbox`).toString();
57
- const versionSanitized = versionString.trim().split(' ').find((s) => s.split('.').length === 4);
58
- if (!versionSanitized) {
59
- throw new Error(`Couldn't find valid Chrome version from "${versionString}", please raise an issue in the WebdriverIO project (https://github.com/webdriverio/webdriverio/issues/new/choose)`);
60
- }
61
- return versionSanitized;
62
- }
63
- export async function getBuildIdByFirefoxPath(firefoxPath) {
64
- if (!firefoxPath) {
65
- return;
66
- }
67
- if (os.platform() === 'win32') {
68
- const appPath = path.dirname(firefoxPath);
69
- const contents = (await fsp.readFile(path.join(appPath, 'application.ini'))).toString('utf-8');
70
- return contents
71
- .split('\n')
72
- .filter((line) => line.startsWith('Version='))
73
- .map((line) => line.replace('Version=', '').replace(/\r/, ''))
74
- .pop();
75
- }
76
- const versionString = cp.execSync(`"${firefoxPath}" --version`).toString();
77
- return versionString.trim().split(' ').pop()?.trim();
78
- }
79
- let lastTimeCalled = Date.now();
80
- export const downloadProgressCallback = (artifact, downloadedBytes, totalBytes) => {
81
- if (Date.now() - lastTimeCalled < 1000) {
82
- return;
83
- }
84
- const percentage = ((downloadedBytes / totalBytes) * 100).toFixed(2);
85
- log.progress(`Downloading ${artifact} ${percentage}%`);
86
- lastTimeCalled = Date.now();
87
- };
88
- /**
89
- * Installs a package using the provided installation options and clears the progress log afterward.
90
- *
91
- * @description
92
- * When installing a package, progress updates are logged using `log.progress`.
93
- * To ensure the formatting of subsequent logs is not disrupted, it's essential to clear the progress log after the installation is complete.
94
- * This method combines the installation step and the clearing of the progress log.
95
- *
96
- * @see {@link https://github.com/webdriverio/webdriverio/blob/main/packages/wdio-logger/README.md#custom-log-levels} for more information.
97
- *
98
- * @param {InstallOptions & { unpack?: true | undefined }} args - An object containing installation options and an optional `unpack` flag.
99
- * @returns {Promise<void>} A Promise that resolves once the package is installed and clear the progress log.
100
- */
101
- const _install = async (args, retry = false) => {
102
- await install(args).catch((err) => {
103
- const error = `Failed downloading ${args.browser} v${args.buildId}: ${err.message}, retrying ...`;
104
- if (retry) {
105
- throw new Error(error);
106
- }
107
- log.error(error);
108
- return _install(args, true);
109
- });
110
- log.progress('');
111
- };
112
- function locateChromeSafely() {
113
- return locateChrome().catch(() => undefined);
114
- }
115
- export async function setupPuppeteerBrowser(cacheDir, caps) {
116
- caps.browserName = caps.browserName?.toLowerCase();
117
- const browserName = caps.browserName === Browser.FIREFOX
118
- ? Browser.FIREFOX
119
- : caps.browserName === Browser.CHROMIUM
120
- ? Browser.CHROMIUM
121
- : Browser.CHROME;
122
- const exist = await fsp.access(cacheDir).then(() => true, () => false);
123
- const isChromeOrChromium = browserName === Browser.CHROME || caps.browserName === Browser.CHROMIUM;
124
- if (!exist) {
125
- await fsp.mkdir(cacheDir, { recursive: true });
126
- }
127
- /**
128
- * in case we run Chromium tests we have to switch back to browserName: 'chrome'
129
- * as 'chromium' is not recognised as a valid browser name by Chromedriver
130
- */
131
- if (browserName === Browser.CHROMIUM) {
132
- caps.browserName = Browser.CHROME;
133
- }
134
- /**
135
- * don't set up Chrome/Firefox if a binary was defined in caps
136
- */
137
- const browserOptions = (isChromeOrChromium
138
- ? caps['goog:chromeOptions']
139
- : caps['moz:firefoxOptions']) || {};
140
- if (typeof browserOptions.binary === 'string') {
141
- return {
142
- executablePath: browserOptions.binary,
143
- browserVersion: (caps.browserVersion ||
144
- (isChromeOrChromium
145
- ? getBuildIdByChromePath(browserOptions.binary)
146
- : await getBuildIdByFirefoxPath(browserOptions.binary)))
147
- };
148
- }
149
- const platform = detectBrowserPlatform();
150
- if (!platform) {
151
- throw new Error('The current platform is not supported.');
152
- }
153
- if (!caps.browserVersion) {
154
- const executablePath = browserName === Browser.CHROME
155
- ? await locateChromeSafely()
156
- : browserName === Browser.CHROMIUM
157
- ? await locateApp({
158
- appName: Browser.CHROMIUM,
159
- macOsName: Browser.CHROMIUM,
160
- linuxWhich: 'chromium-browser'
161
- }).catch(() => undefined)
162
- : await locateFirefox().catch(() => undefined);
163
- const tag = isChromeOrChromium
164
- ? getBuildIdByChromePath(executablePath)
165
- : await getBuildIdByFirefoxPath(executablePath);
166
- /**
167
- * verify that we have a valid Chrome/Firefox browser installed
168
- */
169
- if (tag) {
170
- return {
171
- executablePath,
172
- browserVersion: await resolveBuildId(browserName, platform, tag)
173
- };
174
- }
175
- }
176
- /**
177
- * otherwise download provided Chrome/Firefox browser version or "stable"
178
- */
179
- const tag = browserName === Browser.CHROME
180
- ? caps.browserVersion || ChromeReleaseChannel.STABLE
181
- : caps.browserVersion || 'latest';
182
- const buildId = await resolveBuildId(browserName, platform, tag);
183
- const installOptions = {
184
- unpack: true,
185
- cacheDir,
186
- platform,
187
- buildId,
188
- browser: browserName,
189
- downloadProgressCallback: (downloadedBytes, totalBytes) => downloadProgressCallback(`${browserName} (${buildId})`, downloadedBytes, totalBytes)
190
- };
191
- const isCombinationAvailable = await canDownload(installOptions);
192
- if (!isCombinationAvailable) {
193
- throw new Error(`Couldn't find a matching ${browserName} browser for tag "${buildId}" on platform "${platform}"`);
194
- }
195
- log.info(`Setting up ${browserName} v${buildId}`);
196
- await _install(installOptions);
197
- const executablePath = computeExecutablePath(installOptions);
198
- /**
199
- * for Chromium browser `resolveBuildId` returns with a useless build id
200
- * which will not find a Chromedriver, therefor we need to resolve the
201
- * id using Chrome as browser name
202
- */
203
- let browserVersion = buildId;
204
- if (browserName === Browser.CHROMIUM) {
205
- browserVersion = await resolveBuildId(Browser.CHROME, platform, tag);
206
- }
207
- return { executablePath, browserVersion };
208
- }
209
- export function getDriverOptions(caps) {
210
- return (caps['wdio:chromedriverOptions'] ||
211
- caps['wdio:geckodriverOptions'] ||
212
- caps['wdio:edgedriverOptions'] ||
213
- // Safaridriver does not have any options as it already
214
- // is installed on macOS
215
- {});
216
- }
217
- export function getCacheDir(options, caps) {
218
- const driverOptions = getDriverOptions(caps);
219
- return driverOptions.cacheDir || options.cacheDir || os.tmpdir();
220
- }
221
- export function getMajorVersionFromString(fullVersion) {
222
- let prefix;
223
- if (fullVersion) {
224
- prefix = fullVersion.match(/^[+-]?([0-9]+)/);
225
- }
226
- return prefix && prefix.length > 0 ? prefix[0] : '';
227
- }
228
- export async function setupChromedriver(cacheDir, driverVersion) {
229
- const platform = detectBrowserPlatform();
230
- if (!platform) {
231
- throw new Error('The current platform is not supported.');
232
- }
233
- const version = driverVersion || getBuildIdByChromePath(await locateChromeSafely()) || ChromeReleaseChannel.STABLE;
234
- const buildId = await resolveBuildId(Browser.CHROMEDRIVER, platform, version);
235
- let executablePath = computeExecutablePath({
236
- browser: Browser.CHROMEDRIVER,
237
- buildId,
238
- platform,
239
- cacheDir
240
- });
241
- const hasChromedriverInstalled = await fsp.access(executablePath).then(() => true, () => false);
242
- if (!hasChromedriverInstalled) {
243
- log.info(`Downloading Chromedriver v${buildId}`);
244
- const chromedriverInstallOpts = {
245
- cacheDir,
246
- buildId,
247
- platform,
248
- browser: Browser.CHROMEDRIVER,
249
- unpack: true,
250
- downloadProgressCallback: (downloadedBytes, totalBytes) => downloadProgressCallback('Chromedriver', downloadedBytes, totalBytes)
251
- };
252
- let knownBuild = buildId;
253
- if (await canDownload(chromedriverInstallOpts)) {
254
- await _install({ ...chromedriverInstallOpts, buildId });
255
- log.info(`Download of Chromedriver v${buildId} was successful`);
256
- }
257
- else {
258
- log.warn(`Chromedriver v${buildId} don't exist, trying to find known good version...`);
259
- knownBuild = await resolveBuildId(Browser.CHROMEDRIVER, platform, getMajorVersionFromString(version));
260
- if (knownBuild) {
261
- await _install({ ...chromedriverInstallOpts, buildId: knownBuild });
262
- log.info(`Download of Chromedriver v${knownBuild} was successful`);
263
- }
264
- else {
265
- throw new Error(`Couldn't download any known good version from Chromedriver major v${getMajorVersionFromString(version)}, requested full version - v${version}`);
266
- }
267
- }
268
- executablePath = computeExecutablePath({
269
- browser: Browser.CHROMEDRIVER,
270
- buildId: knownBuild,
271
- platform,
272
- cacheDir
273
- });
274
- }
275
- else {
276
- log.info(`Using Chromedriver v${buildId} from cache directory ${cacheDir}`);
277
- }
278
- return { executablePath };
279
- }
280
- export function setupGeckodriver(cacheDir, driverVersion) {
281
- return downloadGeckodriver(driverVersion, cacheDir);
282
- }
283
- export function setupEdgedriver(cacheDir, driverVersion) {
284
- return downloadEdgedriver(driverVersion, cacheDir);
285
- }
@@ -1,347 +0,0 @@
1
- /**
2
- * Implements ES5 [`Array#forEach()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) method.<br><br>
3
- * Executes the provided callback once for each element.<br>
4
- * Callbacks are run concurrently,
5
- * and are only invoked for properties of the array that have been initialized (including those initialized with *undefined*), for unassigned ones `callback` is not run.<br>
6
- * @param {Array} array - Array to iterate over.
7
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
8
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
9
- * @return {Promise} - Returns a Promise with undefined value.
10
- */
11
- export const forEach = async (array, callback, thisArg) => {
12
- const promiseArray = [];
13
- for (let i = 0; i < array.length; i++) {
14
- if (i in array) {
15
- const p = Promise.resolve(array[i]).then((currentValue) => {
16
- return callback.call(thisArg || this, currentValue, i, array);
17
- });
18
- promiseArray.push(p);
19
- }
20
- }
21
- await Promise.all(promiseArray);
22
- };
23
- /**
24
- * Same functionality as [`forEach()`](global.html#forEach), but runs only one callback at a time.
25
- * @param {Array} array - Array to iterate over.
26
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
27
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
28
- * @return {Promise} - Returns a Promise with undefined value.
29
- */
30
- export const forEachSeries = async (array, callback, thisArg) => {
31
- for (let i = 0; i < array.length; i++) {
32
- if (i in array) {
33
- await callback.call(thisArg || this, await array[i], i, array);
34
- }
35
- }
36
- };
37
- /**
38
- * Implements ES5 [`Array#map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) method.<br><br>
39
- * Creates a new array with the results of calling the provided callback once for each element.<br>
40
- * Callbacks are run concurrently,
41
- * and are only invoked for properties of the array that have been initialized (including those initialized with *undefined*), for unassigned ones`callback` is not run.<br>
42
- * Resultant *Array* is always the same *length* as the original one.
43
- * @param {Array} array - Array to iterate over.
44
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
45
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
46
- * @return {Promise} - Returns a Promise with the resultant *Array* as value.
47
- */
48
- export const map = async (array, callback, thisArg) => {
49
- const promiseArray = [];
50
- for (let i = 0; i < array.length; i++) {
51
- if (i in array) {
52
- promiseArray[i] = Promise.resolve(array[i]).then((currentValue) => {
53
- return callback.call(thisArg || this, currentValue, i, array);
54
- });
55
- }
56
- }
57
- return Promise.all(promiseArray);
58
- };
59
- /**
60
- * Same functionality as [`map()`](global.html#map), but runs only one callback at a time.
61
- * @param {Array} array - Array to iterate over.
62
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
63
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
64
- * @return {Promise} - Returns a Promise with the resultant *Array* as value.
65
- */
66
- export const mapSeries = async (array, callback, thisArg) => {
67
- const result = [];
68
- for (let i = 0; i < array.length; i++) {
69
- if (i in array) {
70
- result[i] = await callback.call(thisArg || this, await array[i], i, array);
71
- }
72
- }
73
- return result;
74
- };
75
- /**
76
- * Implements ES5 [`Array#find()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) method.<br><br>
77
- * Returns the value of the element that satisfies the provided `callback`. The value returned is the one found first.<br>
78
- * Callbacks are run concurrently, meaning that all the callbacks are going to run even if the returned value is found in one of the first elements of `array`,
79
- * depending on the async calls you are going to use, consider using instead [`findSeries()`](global.html#findSeries).<br>
80
- * @param {Array} array - Array to iterate over.
81
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
82
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
83
- * @return {Promise} - Returns a Promise with the element that passed the test as value, otherwise *undefined*.
84
- */
85
- export const find = (array, callback, thisArg) => {
86
- return new Promise((resolve, reject) => {
87
- if (array.length === 0) {
88
- return resolve(undefined);
89
- }
90
- let counter = 1;
91
- for (let i = 0; i < array.length; i++) {
92
- const check = (found) => {
93
- if (found) {
94
- resolve(array[i]);
95
- }
96
- else if (counter === array.length) {
97
- resolve(undefined);
98
- }
99
- counter++;
100
- };
101
- Promise.resolve(array[i])
102
- .then((elem) => callback.call(thisArg || this, elem, i, array))
103
- .then(check)
104
- .catch(reject);
105
- }
106
- });
107
- };
108
- /**
109
- * Same functionality as [`find()`](global.html#find), but runs only one callback at a time.
110
- * @param {Array} array - Array to iterate over.
111
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
112
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
113
- * @return {Promise} - Returns a Promise with the element that passed the test as value, otherwise *undefined*.
114
- */
115
- export const findSeries = async (array, callback, thisArg) => {
116
- for (let i = 0; i < array.length; i++) {
117
- if (await callback.call(thisArg || this, await array[i], i, array)) {
118
- return array[i];
119
- }
120
- }
121
- };
122
- /**
123
- * Implements ES5 [`Array#findIndex()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) method.<br><br>
124
- * Returns the index of the element that satisfies the provided `callback`. The index returned is the one found first.<br>
125
- * Callbacks are run concurrently, meaning that all the callbacks are going to run even if the returned index is found in one of the first elements of `array`,
126
- * depending on the async calls you are going to use, consider using instead [`findSeries()`](global.html#findSeries).<br>
127
- * @param {Array} array - Array to iterate over.
128
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
129
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
130
- * @return {Promise} - Returns a Promise with the index that passed the test as value, otherwise *-1*.
131
- */
132
- export const findIndex = (array, callback, thisArg) => {
133
- return new Promise((resolve, reject) => {
134
- if (array.length === 0) {
135
- return resolve(-1);
136
- }
137
- let counter = 1;
138
- for (let i = 0; i < array.length; i++) {
139
- const check = (found) => {
140
- if (found) {
141
- resolve(i);
142
- }
143
- else if (counter === array.length) {
144
- resolve(-1);
145
- }
146
- counter++;
147
- };
148
- Promise.resolve(array[i])
149
- .then((elem) => callback.call(thisArg || this, elem, i, array))
150
- .then(check)
151
- .catch(reject);
152
- }
153
- });
154
- };
155
- /**
156
- * Same functionality as [`findIndex()`](global.html#findIndex), but runs only one callback at a time.
157
- * @param {Array} array - Array to iterate over.
158
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
159
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
160
- * @return {Promise} - Returns a Promise with the index that passed the test, otherwise *-1*.
161
- */
162
- export const findIndexSeries = async (array, callback, thisArg) => {
163
- for (let i = 0; i < array.length; i++) {
164
- if (await callback.call(thisArg || this, await array[i], i, array)) {
165
- return i;
166
- }
167
- }
168
- };
169
- /**
170
- * Implements ES5 [`Array#some()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) method.<br><br>
171
- * Test if some element in `array` passes the test implemented in `callback`.<br>
172
- * Callbacks are run concurrently, meaning that all the callbacks are going to run even if some of the first elements pass the test,
173
- * depending on the async calls you are going to use, consider using instead [`someSeries()`](global.html#someSeries).<br>
174
- * @param {Array} array - Array to iterate over.
175
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
176
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
177
- * @return {Promise} - Returns a Promise with *true* as value if some element passed the test, otherwise *false*.
178
- */
179
- export const some = (array, callback, thisArg) => {
180
- return new Promise((resolve, reject) => {
181
- if (array.length === 0) {
182
- return resolve(false);
183
- }
184
- let counter = 1;
185
- for (let i = 0; i < array.length; i++) {
186
- if (!(i in array)) {
187
- counter++;
188
- continue;
189
- }
190
- const check = (found) => {
191
- if (found) {
192
- resolve(true);
193
- }
194
- else if (counter === array.length) {
195
- resolve(false);
196
- }
197
- counter++;
198
- };
199
- Promise.resolve(array[i])
200
- .then((elem) => callback.call(thisArg || this, elem, i, array))
201
- .then(check)
202
- .catch(reject);
203
- }
204
- });
205
- };
206
- /**
207
- * Same functionality as [`some()`](global.html#some), but runs only one callback at a time.
208
- * @param {Array} array - Array to iterate over.
209
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
210
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
211
- * @return {Promise} - Returns a Promise with *true* as value if some element passed the test, otherwise *false*.
212
- */
213
- export const someSeries = async (array, callback, thisArg) => {
214
- for (let i = 0; i < array.length; i++) {
215
- if (i in array && await callback.call(thisArg || this, await array[i], i, array)) {
216
- return true;
217
- }
218
- }
219
- return false;
220
- };
221
- /**
222
- * Implements ES5 [`Array#every()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) method.<br><br>
223
- * Test if all elements in `array` pass the test implemented in `callback`.<br>
224
- * Callbacks are run concurrently, meaning that all the callbacks are going to run even if any of the first elements do not pass the test,
225
- * depending on the async calls you are going to use, consider using instead [`everySeries()`](global.html#everySeries).<br>
226
- * @param {Array} array - Array to iterate over.
227
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
228
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
229
- * @return {Promise} - Returns a Promise with *true* as value if all elements passed the test, otherwise *false*.
230
- */
231
- export const every = (array, callback, thisArg) => {
232
- return new Promise((resolve, reject) => {
233
- if (array.length === 0) {
234
- return resolve(true);
235
- }
236
- let counter = 1;
237
- for (let i = 0; i < array.length; i++) {
238
- if (!(i in array)) {
239
- counter++;
240
- continue;
241
- }
242
- const check = (found) => {
243
- if (!found) {
244
- resolve(false);
245
- }
246
- else if (counter === array.length) {
247
- resolve(true);
248
- }
249
- counter++;
250
- };
251
- Promise.resolve(array[i])
252
- .then((elem) => callback.call(thisArg || this, elem, i, array))
253
- .then(check)
254
- .catch(reject);
255
- }
256
- });
257
- };
258
- /**
259
- * Same functionality as [`every()`](global.html#every), but runs only one callback at a time.<br><br>
260
- * @param {Array} array - Array to iterate over.
261
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
262
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
263
- * @return {Promise} - Returns a Promise with *true* as value if all elements passed the test, otherwise *false*.
264
- */
265
- export const everySeries = async (array, callback, thisArg) => {
266
- for (let i = 0; i < array.length; i++) {
267
- if (i in array && !await callback.call(thisArg || this, await array[i], i, array)) {
268
- return false;
269
- }
270
- }
271
- return true;
272
- };
273
- /**
274
- * Implements ES5 [`Array#filter()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) method.<br><br>
275
- * Creates a new array with the elements that passed the test implemented in `callback`.<br>
276
- * Callbacks are run concurrently.<br>
277
- * @param {Array} array - Array to iterate over.
278
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
279
- * @param {Object} [thisArg] - Value to use as *this* when executing the `callback`.
280
- * @return {Promise} - Returns a Promise with the resultant filtered *Array* as value.
281
- */
282
- export const filter = (array, callback, thisArg) => {
283
- /* two loops are necessary in order to do the filtering concurrently
284
- * while keeping the order of the elements
285
- * (if you find a better way to do it please send a PR!)
286
- */
287
- return new Promise((resolve, reject) => {
288
- const promiseArray = [];
289
- for (let i = 0; i < array.length; i++) {
290
- if (i in array) {
291
- promiseArray[i] = Promise.resolve(array[i]).then((currentValue) => {
292
- return callback.call(thisArg || this, currentValue, i, array);
293
- }).catch(reject);
294
- }
295
- }
296
- return Promise.all(promiseArray.map(async (p, i) => {
297
- if (await p) {
298
- return await array[i];
299
- }
300
- return undefined;
301
- })).then((result) => result.filter((val) => typeof val !== 'undefined')).then(resolve, reject);
302
- });
303
- };
304
- /**
305
- * Same functionality as [`filter()`](global.html#filter), but runs only one callback at a time.
306
- * @param {Array} array - Array to iterate over.
307
- * @param {Function} callback - Function to apply each item in `array`. Accepts three arguments: `currentValue`, `index` and `array`.
308
- * @return {Promise} - Returns a Promise with the resultant filtered *Array* as value.
309
- */
310
- export const filterSeries = async (array, callback, thisArg) => {
311
- const result = [];
312
- for (let i = 0; i < array.length; i++) {
313
- if (i in array && await callback.call(thisArg || this, await array[i], i, array)) {
314
- result.push(await array[i]);
315
- }
316
- }
317
- return result;
318
- };
319
- /**
320
- * Implements ES5 [`Array#reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) method.<br><br>
321
- * Applies a `callback` against an accumulator and each element in `array`.
322
- * @param {Array} array - Array to iterate over.
323
- * @param {Function} callback - Function to apply each item in `array`. Accepts four arguments: `accumulator`, `currentValue`, `currentIndex` and `array`.
324
- * @param {Object} [initialValue] - Used as first argument to the first call of `callback`.
325
- * @return {Promise} - Returns a Promise with the resultant value from the reduction.
326
- */
327
- export const reduce = async (array, callback, initialValue) => {
328
- if (array.length === 0 && initialValue === undefined) {
329
- throw TypeError('Reduce of empty array with no initial value');
330
- }
331
- let i;
332
- let previousValue;
333
- if (initialValue !== undefined) {
334
- previousValue = initialValue;
335
- i = 0;
336
- }
337
- else {
338
- previousValue = array[0];
339
- i = 1;
340
- }
341
- for (i; i < array.length; i++) {
342
- if (i in array) {
343
- previousValue = await callback(await previousValue, await array[i], i, array);
344
- }
345
- }
346
- return previousValue;
347
- };