@percy/core 1.7.0 → 1.8.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.
package/dist/percy.js CHANGED
@@ -5,7 +5,7 @@ import Queue from './queue.js';
5
5
  import Browser from './browser.js';
6
6
  import { createPercyServer, createStaticServer } from './api.js';
7
7
  import { gatherSnapshots, validateSnapshotOptions, discoverSnapshotResources } from './snapshot.js';
8
- import { generatePromise } from './utils.js'; // A Percy instance will create a new build when started, handle snapshot
8
+ import { generatePromise, yieldAll } from './utils.js'; // A Percy instance will create a new build when started, handle snapshot
9
9
  // creation, asset discovery, and resource uploads, and will finalize the build
10
10
  // when stopped. Snapshots are processed concurrently and the build is not
11
11
  // finalized until all snapshots have been handled.
@@ -371,7 +371,7 @@ export class Percy {
371
371
  } else if ((_this$build3 = this.build) !== null && _this$build3 !== void 0 && _this$build3.error) {
372
372
  throw new Error(this.build.error);
373
373
  } else if (Array.isArray(options)) {
374
- return Promise.all(options.map(o => this.snapshot(o)));
374
+ return yieldAll(options.map(o => this.yield.snapshot(o)));
375
375
  }
376
376
 
377
377
  if (typeof options === 'string') {
@@ -398,13 +398,11 @@ export class Percy {
398
398
  } // gather snapshots from options
399
399
 
400
400
 
401
- let snapshots = yield gatherSnapshots(this, options);
401
+ let snapshots = yield* gatherSnapshots(this, options);
402
402
 
403
403
  try {
404
- // yield each task individually to allow canceling
405
- let tasks = snapshots.map(s => this._takeSnapshot(s));
406
-
407
- for (let task of tasks) yield task;
404
+ // use a try-catch to cancel snapshots that haven't started when the error occurred
405
+ yield* yieldAll(snapshots.map(s => this._takeSnapshot(s)));
408
406
  } catch (error) {
409
407
  // cancel queued snapshots that may not have started
410
408
  snapshots.map(s => this._cancelSnapshot(s));
package/dist/snapshot.js CHANGED
@@ -2,7 +2,7 @@ import logger from '@percy/logger';
2
2
  import PercyConfig from '@percy/config';
3
3
  import micromatch from 'micromatch';
4
4
  import { configSchema } from './config.js';
5
- import { request, hostnameMatches, createRootResource, createPercyCSSResource, createLogResource } from './utils.js'; // Throw a better error message for missing or invalid urls
5
+ import { request, hostnameMatches, createRootResource, createPercyCSSResource, createLogResource, yieldTo } from './utils.js'; // Throw a better error message for missing or invalid urls
6
6
 
7
7
  export function validURL(url, base) {
8
8
  if (!url) {
@@ -92,21 +92,20 @@ export function mapSnapshotOptions(percy, snapshots, config) {
92
92
  }, []);
93
93
  } // Returns an array of derived snapshot options
94
94
 
95
- export async function gatherSnapshots(percy, options) {
95
+ export async function* gatherSnapshots(percy, options) {
96
96
  let {
97
97
  baseUrl,
98
98
  snapshots
99
99
  } = options;
100
100
  if ('url' in options) snapshots = [options];
101
- if ('sitemap' in options) snapshots = await getSitemapSnapshots(options); // validate evaluated snapshots
101
+ if ('sitemap' in options) snapshots = yield getSitemapSnapshots(options); // validate evaluated snapshots
102
102
 
103
103
  if (typeof snapshots === 'function') {
104
- ({
105
- snapshots
106
- } = validateSnapshotOptions({
104
+ snapshots = yield* yieldTo(snapshots(baseUrl));
105
+ snapshots = validateSnapshotOptions({
107
106
  baseUrl,
108
- snapshots: await snapshots(baseUrl)
109
- }));
107
+ snapshots
108
+ }).snapshots;
110
109
  } // map snapshots with snapshot options
111
110
 
112
111
 
package/dist/utils.js CHANGED
@@ -46,23 +46,25 @@ export function createPercyCSSResource(url, css) {
46
46
 
47
47
  export function createLogResource(logs) {
48
48
  return createResource(`/percy.${Date.now()}.log`, JSON.stringify(logs), 'text/plain');
49
+ } // Returns true or false if the provided object is a generator or not
50
+
51
+ export function isGenerator(subject) {
52
+ return typeof (subject === null || subject === void 0 ? void 0 : subject.next) === 'function' && (typeof subject[Symbol.iterator] === 'function' || typeof subject[Symbol.asyncIterator] === 'function');
49
53
  } // Iterates over the provided generator and resolves to the final value when done. With an
50
54
  // AbortSignal, the generator will throw with the abort reason when aborted. Also accepts an
51
55
  // optional node-style callback, called before the returned promise resolves.
52
56
 
53
57
  export async function generatePromise(gen, signal, cb) {
54
58
  try {
55
- var _gen;
56
-
57
59
  if (typeof signal === 'function') [cb, signal] = [signal];
58
60
  if (typeof gen === 'function') gen = await gen();
59
61
  let {
60
62
  done,
61
63
  value
62
- } = typeof ((_gen = gen) === null || _gen === void 0 ? void 0 : _gen.next) === 'function' && (typeof gen[Symbol.iterator] === 'function' || typeof gen[Symbol.asyncIterator] === 'function') ? await gen.next() : {
64
+ } = !isGenerator(gen) ? {
63
65
  done: true,
64
66
  value: await gen
65
- };
67
+ } : await gen.next();
66
68
 
67
69
  while (!done) {
68
70
  var _signal;
@@ -103,6 +105,37 @@ export class AbortError extends Error {
103
105
  });
104
106
  }
105
107
 
108
+ } // An async generator that yields after every event loop until the promise settles
109
+
110
+ export async function* yieldTo(subject) {
111
+ // yield to any provided generator or return non-promise values
112
+ if (isGenerator(subject)) return yield* subject;
113
+ if (typeof (subject === null || subject === void 0 ? void 0 : subject.then) !== 'function') return subject; // update local variables with the provided promise
114
+
115
+ let result,
116
+ error,
117
+ pending = !!subject.then(r => result = r, e => error = e).finally(() => pending = false);
118
+ /* eslint-disable-next-line no-unmodified-loop-condition */
119
+
120
+ while (pending) yield new Promise(r => setImmediate(r));
121
+
122
+ if (error) throw error;
123
+ return result;
124
+ } // An async generator that runs provided generators concurrently
125
+
126
+ export async function* yieldAll(all) {
127
+ let res = new Array(all.length).fill();
128
+ all = all.map(yieldTo);
129
+
130
+ while (true) {
131
+ res = await Promise.all(all.map((g, i) => {
132
+ var _res$i, _res$i2;
133
+
134
+ return (_res$i = res[i]) !== null && _res$i !== void 0 && _res$i.done ? res[i] : g.next((_res$i2 = res[i]) === null || _res$i2 === void 0 ? void 0 : _res$i2.value);
135
+ }));
136
+ let vals = res.map(r => r === null || r === void 0 ? void 0 : r.value);
137
+ if (res.some(r => !(r !== null && r !== void 0 && r.done))) yield vals;else return vals;
138
+ }
106
139
  } // An async generator that infinitely yields to the predicate function until a truthy value is
107
140
  // returned. When a timeout is provided, an error will be thrown during the next iteration after the
108
141
  // timeout has been exceeded. If an idle option is provided, the predicate will be yielded to a
@@ -207,7 +240,7 @@ export function serializeFunction(fn) {
207
240
  } // wrap the function body with percy helpers
208
241
 
209
242
 
210
- fnbody = 'function withPercyHelpers() {\n' + ['const { config, snapshot } = window.__PERCY__ ?? {};', `return (${fnbody})({`, ' config, snapshot, generatePromise, yieldFor,', ' waitFor, waitForTimeout, waitForSelector, waitForXPath,', ' scrollToBottom', '}, ...arguments);', `${generatePromise}`, `${yieldFor}`, `${waitFor}`, `${waitForTimeout}`, `${waitForSelector}`, `${waitForXPath}`, `${scrollToBottom}`].join('\n') + '\n}';
243
+ fnbody = 'function withPercyHelpers() {\n' + ['const { config, snapshot } = window.__PERCY__ ?? {};', `return (${fnbody})({`, ' config, snapshot, generatePromise, yieldFor,', ' waitFor, waitForTimeout, waitForSelector, waitForXPath,', ' scrollToBottom', '}, ...arguments);', `${isGenerator}`, `${generatePromise}`, `${yieldFor}`, `${waitFor}`, `${waitForTimeout}`, `${waitForSelector}`, `${waitForXPath}`, `${scrollToBottom}`].join('\n') + '\n}';
211
244
  /* istanbul ignore else: ironic. */
212
245
 
213
246
  if (fnbody.includes('cov_')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percy/core",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -39,10 +39,10 @@
39
39
  "test:types": "tsd"
40
40
  },
41
41
  "dependencies": {
42
- "@percy/client": "1.7.0",
43
- "@percy/config": "1.7.0",
44
- "@percy/dom": "1.7.0",
45
- "@percy/logger": "1.7.0",
42
+ "@percy/client": "1.8.0",
43
+ "@percy/config": "1.8.0",
44
+ "@percy/dom": "1.8.0",
45
+ "@percy/logger": "1.8.0",
46
46
  "content-disposition": "^0.5.4",
47
47
  "cross-spawn": "^7.0.3",
48
48
  "extract-zip": "^2.0.1",
@@ -53,5 +53,5 @@
53
53
  "rimraf": "^3.0.2",
54
54
  "ws": "^8.0.0"
55
55
  },
56
- "gitHead": "f1418fb1effdaad2d32c65d1a358282ab1f9ec32"
56
+ "gitHead": "596808e5775a87514d3c7ffc8ac593cdc9289ad7"
57
57
  }