@ava/cooperate
Version:
Plugin to enable cooperation between AVA test files
313 lines • 12.6 kB
JavaScript
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _Lock_context, _ManagedSemaphore_context, _UnmanagedSemaphore_context;
import { registerSharedWorker } from 'ava/plugin';
import never from 'never';
const protocol = registerSharedWorker({
filename: new URL('worker.js', import.meta.url),
supportedProtocols: ['ava-4'],
});
export class Lock {
constructor(context, id) {
Object.defineProperty(this, "id", {
enumerable: true,
configurable: true,
writable: true,
value: id
});
_Lock_context.set(this, void 0);
__classPrivateFieldSet(this, _Lock_context, context, "f");
}
async acquire() {
// Allow acquire() to be called before the shared worker is availabe.
await protocol.available;
const message = protocol.publish({
type: 10 /* LOCK */,
contextId: __classPrivateFieldGet(this, _Lock_context, "f").id,
lockId: this.id,
wait: true,
});
for await (const reply of message.replies()) {
if (reply.data.type === 11 /* LOCK_ACQUIRED */) {
return () => {
reply.reply({ type: 13 /* LOCK_RELEASE */ });
};
}
}
// The above loop will never actually break if the lock is not acquired.
return never();
}
async acquireNow() {
// Publish immediately, which will fail if the protocol is not available.
// "Now" should not mean "wait until we're ready."
const message = protocol.publish({
type: 10 /* LOCK */,
contextId: __classPrivateFieldGet(this, _Lock_context, "f").id,
lockId: this.id,
wait: false,
});
for await (const reply of message.replies()) {
if (reply.data.type === 11 /* LOCK_ACQUIRED */) {
return () => {
reply.reply({ type: 13 /* LOCK_RELEASE */ });
};
}
if (reply.data.type === 12 /* LOCK_FAILED */) {
throw new LockAcquisitionError(this.id);
}
}
// The above loop will never actually break if the lock is not acquired.
return never();
}
}
_Lock_context = new WeakMap();
export class LockAcquisitionError extends Error {
constructor(lockId) {
super('Could not immediately acquire the lock');
Object.defineProperty(this, "lockId", {
enumerable: true,
configurable: true,
writable: true,
value: lockId
});
}
get name() {
return 'LockAcquisitionError';
}
}
export class ManagedSemaphore {
constructor(context, id, initialValue) {
Object.defineProperty(this, "id", {
enumerable: true,
configurable: true,
writable: true,
value: id
});
Object.defineProperty(this, "initialValue", {
enumerable: true,
configurable: true,
writable: true,
value: initialValue
});
_ManagedSemaphore_context.set(this, void 0);
if (initialValue < 0 || !Number.isSafeInteger(initialValue)) {
throw new RangeError('initialValue must be a non-negative safe integer');
}
__classPrivateFieldSet(this, _ManagedSemaphore_context, context, "f");
}
async acquire(amount = 1) {
if (amount < 0 || !Number.isSafeInteger(amount)) {
throw new RangeError('amount must be a non-negative safe integer');
}
// Allow acquire() to be called before the shared worker is availabe.
await protocol.available;
const reply = await downSemaphore(this, __classPrivateFieldGet(this, _ManagedSemaphore_context, "f").id, amount, true);
return (release = amount) => {
if (release < 0 || !Number.isSafeInteger(release) || release > amount) {
throw new RangeError('Amount to release must be a non-negative safe integer and <= remaining amount');
}
amount -= release;
reply.reply({
type: 33 /* SEMAPHORE_RELEASE */,
amount: release,
});
};
}
async acquireNow(amount = 1) {
if (amount < 0 || !Number.isSafeInteger(amount)) {
throw new RangeError('amount must be a non-negative safe integer');
}
// Down immediately, which will fail if the protocol is not available.
// "Now" should not mean "wait until we're ready."
const reply = await downSemaphore(this, __classPrivateFieldGet(this, _ManagedSemaphore_context, "f").id, amount, false);
return (release = amount) => {
if (release < 0 || release > amount) {
throw new RangeError('Amount to release must be >= 0 and <= remaining amount');
}
amount -= release;
reply.reply({
type: 33 /* SEMAPHORE_RELEASE */,
amount: release,
});
};
}
}
_ManagedSemaphore_context = new WeakMap();
export class UnmanagedSemaphore {
constructor(context, id, initialValue) {
Object.defineProperty(this, "id", {
enumerable: true,
configurable: true,
writable: true,
value: id
});
Object.defineProperty(this, "initialValue", {
enumerable: true,
configurable: true,
writable: true,
value: initialValue
});
_UnmanagedSemaphore_context.set(this, void 0);
if (initialValue < 0 || !Number.isSafeInteger(initialValue)) {
throw new RangeError('initialValue must be a non-negative safe integer');
}
__classPrivateFieldSet(this, _UnmanagedSemaphore_context, context, "f");
}
async down(amount = 1) {
if (amount < 0 || !Number.isSafeInteger(amount)) {
throw new RangeError('amount must be a non-negative safe integer');
}
// Allow down() to be called before the shared worker is availabe.
await protocol.available;
await downSemaphore(this, __classPrivateFieldGet(this, _UnmanagedSemaphore_context, "f").id, amount, true);
}
async downNow(amount = 1) {
if (amount < 0 || !Number.isSafeInteger(amount)) {
throw new RangeError('amount must be a non-negative safe integer');
}
// Down immediately, which will fail if the protocol is not available.
// "Now" should not mean "wait until we're ready."
await downSemaphore(this, __classPrivateFieldGet(this, _UnmanagedSemaphore_context, "f").id, amount, false);
}
async up(amount = 1) {
if (amount < 0 || !Number.isSafeInteger(amount)) {
throw new RangeError('amount must be a non-negative safe integer');
}
// Allow up() to be called before the shared worker is availabe.
await protocol.available;
const { id, initialValue } = this;
const message = protocol.publish({
type: 35 /* SEMAPHORE_UP */,
contextId: __classPrivateFieldGet(this, _UnmanagedSemaphore_context, "f").id,
semaphore: { managed: false, id, initialValue },
amount,
});
for await (const reply of message.replies()) {
if (reply.data.type === 34 /* SEMAPHORE_SUCCEEDED */) {
return;
}
if (reply.data.type === 30 /* SEMAPHORE_CREATION_FAILED */) {
throw new SemaphoreCreationError(this, reply.data);
}
}
// The above loop will never actually break if the resources are not acquired.
return never();
}
}
_UnmanagedSemaphore_context = new WeakMap();
async function downSemaphore(semaphore, contextId, amount, wait) {
const { id, initialValue } = semaphore;
const message = protocol.publish({
type: 31 /* SEMAPHORE_DOWN */,
contextId,
semaphore: { managed: semaphore instanceof ManagedSemaphore, id, initialValue },
amount,
wait,
});
for await (const reply of message.replies()) {
if (reply.data.type === 34 /* SEMAPHORE_SUCCEEDED */) {
return reply;
}
if (reply.data.type === 32 /* SEMAPHORE_FAILED */) {
throw new SemaphoreDownError(id, amount);
}
if (reply.data.type === 30 /* SEMAPHORE_CREATION_FAILED */) {
throw new SemaphoreCreationError(semaphore, reply.data);
}
}
// The above loop will never actually break if the resources are not acquired.
return never();
}
export class SemaphoreDownError extends Error {
constructor(semaphoreId, amount) {
super(`Could not immediately decrement with ${amount}`);
Object.defineProperty(this, "semaphoreId", {
enumerable: true,
configurable: true,
writable: true,
value: semaphoreId
});
Object.defineProperty(this, "amount", {
enumerable: true,
configurable: true,
writable: true,
value: amount
});
}
get name() {
return 'SemaphoreDownError';
}
}
const creationMessage = (semaphore, { initialValue, managed }) => {
const initialValueSuffix = `initial value ${semaphore.initialValue} (got ${initialValue})`;
if (semaphore instanceof ManagedSemaphore) {
if (managed) {
return `Failed to create semaphore: expected ${initialValueSuffix}`;
}
return `Failed to create semaphore: expected unmanaged and ${initialValueSuffix}`;
}
if (managed) {
return `Failed to create unmanaged semaphore: expected managed and ${initialValueSuffix}`;
}
return `Failed to create unmanaged semaphore: expected ${initialValueSuffix}`;
};
export class SemaphoreCreationError extends Error {
constructor(semaphore, reason) {
super(creationMessage(semaphore, reason));
Object.defineProperty(this, "semaphoreId", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.semaphoreId = semaphore.id;
}
get name() {
return 'SemaphoreCreationError';
}
}
export class SharedContext {
constructor(id) {
Object.defineProperty(this, "id", {
enumerable: true,
configurable: true,
writable: true,
value: id
});
}
createLock(id) {
return new Lock(this, id);
}
createSemaphore(id, initialValue) {
return new ManagedSemaphore(this, id, initialValue);
}
createUnmanagedSemaphore(id, initialValue) {
return new UnmanagedSemaphore(this, id, initialValue);
}
async reserve(...values) {
// Allow reserve() to be called before the shared worker is availabe.
await protocol.available;
const message = protocol.publish({
type: 20 /* RESERVE */,
contextId: this.id,
values,
});
for await (const { data } of message.replies()) {
if (data.type === 21 /* RESERVED_INDEXES */) {
return data.indexes.map(index => { var _a; return (_a = values[index]) !== null && _a !== void 0 ? _a : never(); });
}
}
// The above loop will never actually break if the lock is not acquired.
return never();
}
}
//# sourceMappingURL=index.js.map