Skip to content

Commit

Permalink
Fix Flow issues with Symbol.asyncIterator
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanGoncharov committed May 3, 2021
1 parent b9fd53b commit f9c83c0
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 26 deletions.
4 changes: 2 additions & 2 deletions flow-typed/core.js
Expand Up @@ -260,7 +260,7 @@ declare opaque type $SymbolToStringTag: symbol;
declare opaque type $SymbolUnscopables: symbol;

declare class Symbol {
static asyncIterator: string; // graphql-js HACK
static asyncIterator: '@@asyncIterator'; // graphql-js HACK

/**
* Returns a new unique Symbol value.
Expand All @@ -287,7 +287,7 @@ declare class Symbol {
* by Array.prototype.concat.
*/
static isConcatSpreadable: $SymboIsConcatSpreadable;
static iterator: string; // polyfill '@@iterator'
static iterator: '@@iterator';
/**
* Returns a key from the global symbol registry matching the given Symbol if found.
* Otherwise, returns a undefined.
Expand Down
6 changes: 3 additions & 3 deletions src/subscription/__tests__/mapAsyncIterator-test.js
Expand Up @@ -25,7 +25,7 @@ describe('mapAsyncIterator', () => {
it('maps over async iterable', async () => {
const items = [1, 2, 3];

const iterable: $FlowFixMe = {
const iterable = {
[Symbol.asyncIterator]() {
return this;
},
Expand Down Expand Up @@ -122,7 +122,7 @@ describe('mapAsyncIterator', () => {
it('allows returning early from mapped async iterable', async () => {
const items = [1, 2, 3];

const iterable: any = {
const iterable = {
[Symbol.asyncIterator]() {
return this;
},
Expand Down Expand Up @@ -185,7 +185,7 @@ describe('mapAsyncIterator', () => {
it('allows throwing errors through async iterable', async () => {
const items = [1, 2, 3];

const iterable: any = {
const iterable = {
[Symbol.asyncIterator]() {
return this;
},
Expand Down
2 changes: 1 addition & 1 deletion src/subscription/__tests__/simplePubSub-test.js
Expand Up @@ -6,7 +6,7 @@ import { SimplePubSub } from './simplePubSub';
describe('SimplePubSub', () => {
it('subscribe async-iterator mock', async () => {
const pubsub = new SimplePubSub();
const iterator = pubsub.getSubscriber();
const iterator = pubsub.getSubscriber((x) => x);

// Queue up publishes
expect(pubsub.emit('Apple')).to.equal(true);
Expand Down
14 changes: 6 additions & 8 deletions src/subscription/__tests__/simplePubSub.js
Expand Up @@ -16,8 +16,8 @@ export class SimplePubSub<T> {
return this._subscribers.size > 0;
}

getSubscriber<R>(transform?: (T) => R): AsyncGenerator<R, void, void> {
const pullQueue = [];
getSubscriber<R>(transform: (T) => R): AsyncGenerator<R, void, void> {
const pullQueue: Array<(result: IteratorResult<R, void>) => void> = [];
const pushQueue = [];
let listening = true;
this._subscribers.add(pushValue);
Expand All @@ -32,9 +32,7 @@ export class SimplePubSub<T> {
pushQueue.length = 0;
};

/* TODO: Flow doesn't support symbols as keys:
https://github.com/facebook/flow/issues/3258 */
return ({
return {
next() {
if (!listening) {
return Promise.resolve({ value: undefined, done: true });
Expand All @@ -45,7 +43,7 @@ export class SimplePubSub<T> {
}
return new Promise((resolve) => pullQueue.push(resolve));
},
return() {
return(): Promise<IteratorResult<R, void>> {
emptyQueue();
return Promise.resolve({ value: undefined, done: true });
},
Expand All @@ -56,10 +54,10 @@ export class SimplePubSub<T> {
[Symbol.asyncIterator]() {
return this;
},
}: any);
};

function pushValue(event: T): void {
const value = transform != null ? transform(event) : event;
const value: R = transform(event);
if (pullQueue.length > 0) {
pullQueue.shift()({ value, done: false });
} else {
Expand Down
9 changes: 5 additions & 4 deletions src/subscription/__tests__/subscribe-test.js
Expand Up @@ -187,7 +187,7 @@ describe('Subscription Initialization Phase', () => {
fields: {
importantEmail: {
type: GraphQLString,
subscribe: () => pubsub.getSubscriber(),
subscribe: () => pubsub.getSubscriber((x) => x),
},
},
}),
Expand Down Expand Up @@ -219,7 +219,7 @@ describe('Subscription Initialization Phase', () => {
type: GraphQLString,
subscribe: async () => {
await resolveOnNextTick();
return pubsub.getSubscriber();
return pubsub.getSubscriber((x) => x);
},
},
},
Expand Down Expand Up @@ -253,15 +253,16 @@ describe('Subscription Initialization Phase', () => {
type: EmailEventType,
subscribe() {
didResolveImportantEmail = true;
return new SimplePubSub().getSubscriber();
// istanbul ignore next (FIXME)
return new SimplePubSub().getSubscriber((x) => x);
},
},
nonImportantEmail: {
type: EmailEventType,
// istanbul ignore next (Shouldn't be called)
subscribe() {
didResolveNonImportantEmail = true;
return new SimplePubSub().getSubscriber();
return new SimplePubSub().getSubscriber((x) => x);
},
},
},
Expand Down
13 changes: 5 additions & 8 deletions src/subscription/mapAsyncIterator.js
Expand Up @@ -8,9 +8,8 @@ export function mapAsyncIterator<T, U>(
iterable: AsyncIterable<T> | AsyncGenerator<T, void, void>,
callback: (T) => PromiseOrValue<U>,
): AsyncGenerator<U, void, void> {
// $FlowFixMe[prop-missing]
const iteratorMethod = iterable[Symbol.asyncIterator];
const iterator: any = iteratorMethod.call(iterable);
// $FlowIssue[incompatible-use]
const iterator = iterable[Symbol.asyncIterator]();

async function abruptClose(error: mixed) {
if (typeof iterator.return === 'function') {
Expand All @@ -37,13 +36,11 @@ export function mapAsyncIterator<T, U>(
}
}

/* TODO: Flow doesn't support symbols as keys:
https://github.com/facebook/flow/issues/3258 */
return ({
return {
next(): Promise<IteratorResult<U, void>> {
return mapResult(iterator.next());
},
return() {
return(): Promise<IteratorResult<U, void>> {
return typeof iterator.return === 'function'
? mapResult(iterator.return())
: Promise.resolve({ value: undefined, done: true });
Expand All @@ -57,5 +54,5 @@ export function mapAsyncIterator<T, U>(
[Symbol.asyncIterator]() {
return this;
},
}: $FlowFixMe);
};
}

0 comments on commit f9c83c0

Please sign in to comment.