Skip to content

Commit 947ca28

Browse files
Use correct terminology around iterators and iterable (#3041)
1 parent a75e95b commit 947ca28

File tree

11 files changed

+116
-113
lines changed

11 files changed

+116
-113
lines changed

src/execution/execute.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { isObjectLike } from '../jsutils/isObjectLike';
1010
import { promiseReduce } from '../jsutils/promiseReduce';
1111
import { promiseForObject } from '../jsutils/promiseForObject';
1212
import { addPath, pathToArray } from '../jsutils/Path';
13-
import { isIteratableObject } from '../jsutils/isIteratableObject';
13+
import { isIterableObject } from '../jsutils/isIterableObject';
1414

1515
import type { GraphQLFormattedError } from '../error/formatError';
1616
import { GraphQLError } from '../error/GraphQLError';
@@ -822,7 +822,7 @@ function completeListValue(
822822
path: Path,
823823
result: mixed,
824824
): PromiseOrValue<$ReadOnlyArray<mixed>> {
825-
if (!isIteratableObject(result)) {
825+
if (!isIterableObject(result)) {
826826
throw new GraphQLError(
827827
`Expected Iterable, but did not find one for field "${info.parentType.name}.${info.fieldName}".`,
828828
);

src/jsutils/__tests__/isAsyncIterable-test.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { isAsyncIterable } from '../isAsyncIterable';
66

77
describe('isAsyncIterable', () => {
88
it('should return `true` for AsyncIterable', () => {
9-
const asyncIteratable = { [Symbol.asyncIterator]: identityFunc };
10-
expect(isAsyncIterable(asyncIteratable)).to.equal(true);
9+
const asyncIterable = { [Symbol.asyncIterator]: identityFunc };
10+
expect(isAsyncIterable(asyncIterable)).to.equal(true);
1111

1212
// istanbul ignore next (Never called and use just as a placeholder)
1313
async function* asyncGeneratorFunc() {
@@ -16,7 +16,7 @@ describe('isAsyncIterable', () => {
1616

1717
expect(isAsyncIterable(asyncGeneratorFunc())).to.equal(true);
1818

19-
// But async generator function itself is not iteratable
19+
// But async generator function itself is not iterable
2020
expect(isAsyncIterable(asyncGeneratorFunc)).to.equal(false);
2121
});
2222

@@ -34,18 +34,21 @@ describe('isAsyncIterable', () => {
3434
expect(isAsyncIterable({})).to.equal(false);
3535
expect(isAsyncIterable({ iterable: true })).to.equal(false);
3636

37-
const iterator = { [Symbol.iterator]: identityFunc };
38-
expect(isAsyncIterable(iterator)).to.equal(false);
37+
const asyncIteratorWithoutSymbol = { next: identityFunc };
38+
expect(isAsyncIterable(asyncIteratorWithoutSymbol)).to.equal(false);
39+
40+
const nonAsyncIterable = { [Symbol.iterator]: identityFunc };
41+
expect(isAsyncIterable(nonAsyncIterable)).to.equal(false);
3942

4043
// istanbul ignore next (Never called and use just as a placeholder)
4144
function* generatorFunc() {
4245
/* do nothing */
4346
}
4447
expect(isAsyncIterable(generatorFunc())).to.equal(false);
4548

46-
const invalidAsyncIteratable = {
49+
const invalidAsyncIterable = {
4750
[Symbol.asyncIterator]: { next: identityFunc },
4851
};
49-
expect(isAsyncIterable(invalidAsyncIteratable)).to.equal(false);
52+
expect(isAsyncIterable(invalidAsyncIterable)).to.equal(false);
5053
});
5154
});
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { expect } from 'chai';
2+
import { describe, it } from 'mocha';
3+
4+
import { identityFunc } from '../identityFunc';
5+
import { isIterableObject } from '../isIterableObject';
6+
7+
describe('isIterableObject', () => {
8+
it('should return `true` for collections', () => {
9+
expect(isIterableObject([])).to.equal(true);
10+
expect(isIterableObject(new Int8Array(1))).to.equal(true);
11+
12+
// eslint-disable-next-line no-new-wrappers
13+
expect(isIterableObject(new String('ABC'))).to.equal(true);
14+
15+
function getArguments() {
16+
return arguments;
17+
}
18+
expect(isIterableObject(getArguments())).to.equal(true);
19+
20+
const iterable = { [Symbol.iterator]: identityFunc };
21+
expect(isIterableObject(iterable)).to.equal(true);
22+
23+
// istanbul ignore next (Never called and use just as a placeholder)
24+
function* generatorFunc() {
25+
/* do nothing */
26+
}
27+
expect(isIterableObject(generatorFunc())).to.equal(true);
28+
29+
// But generator function itself is not iterable
30+
expect(isIterableObject(generatorFunc)).to.equal(false);
31+
});
32+
33+
it('should return `false` for non-collections', () => {
34+
expect(isIterableObject(null)).to.equal(false);
35+
expect(isIterableObject(undefined)).to.equal(false);
36+
37+
expect(isIterableObject('ABC')).to.equal(false);
38+
expect(isIterableObject('0')).to.equal(false);
39+
expect(isIterableObject('')).to.equal(false);
40+
41+
expect(isIterableObject(1)).to.equal(false);
42+
expect(isIterableObject(0)).to.equal(false);
43+
expect(isIterableObject(NaN)).to.equal(false);
44+
// eslint-disable-next-line no-new-wrappers
45+
expect(isIterableObject(new Number(123))).to.equal(false);
46+
47+
expect(isIterableObject(true)).to.equal(false);
48+
expect(isIterableObject(false)).to.equal(false);
49+
// eslint-disable-next-line no-new-wrappers
50+
expect(isIterableObject(new Boolean(true))).to.equal(false);
51+
52+
expect(isIterableObject({})).to.equal(false);
53+
expect(isIterableObject({ iterable: true })).to.equal(false);
54+
55+
const iteratorWithoutSymbol = { next: identityFunc };
56+
expect(isIterableObject(iteratorWithoutSymbol)).to.equal(false);
57+
58+
const invalidIterable = {
59+
[Symbol.iterator]: { next: identityFunc },
60+
};
61+
expect(isIterableObject(invalidIterable)).to.equal(false);
62+
63+
const arrayLike = {};
64+
arrayLike[0] = 'Alpha';
65+
arrayLike[1] = 'Bravo';
66+
arrayLike[2] = 'Charlie';
67+
arrayLike.length = 3;
68+
69+
expect(isIterableObject(arrayLike)).to.equal(false);
70+
});
71+
});

src/jsutils/__tests__/isIteratableObject-test.js

Lines changed: 0 additions & 71 deletions
This file was deleted.

src/jsutils/isAsyncIterable.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* Returns true if the provided object implements the AsyncIterator protocol via
3-
* either implementing a `Symbol.asyncIterator` or `"@@asyncIterator"` method.
3+
* implementing a `Symbol.asyncIterator` method.
44
*/
55
export function isAsyncIterable(
66
maybeAsyncIterable: unknown,

src/jsutils/isAsyncIterable.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* Returns true if the provided object implements the AsyncIterator protocol via
3-
* either implementing a `Symbol.asyncIterator` or `"@@asyncIterator"` method.
3+
* implementing a `Symbol.asyncIterator` method.
44
*/
55
declare function isAsyncIterable(
66
value: mixed,

src/jsutils/isIteratableObject.d.ts renamed to src/jsutils/isIterableObject.d.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
*
99
* @example
1010
*
11-
* isIteratableObject([ 1, 2, 3 ]) // true
12-
* isIteratableObject(new Map()) // true
13-
* isIteratableObject('ABC') // false
14-
* isIteratableObject({ key: 'value' }) // false
15-
* isIteratableObject({ length: 1, 0: 'Alpha' }) // false
11+
* isIterableObject([ 1, 2, 3 ]) // true
12+
* isIterableObject(new Map()) // true
13+
* isIterableObject('ABC') // false
14+
* isIterableObject({ key: 'value' }) // false
15+
* isIterableObject({ length: 1, 0: 'Alpha' }) // false
1616
*/
17-
export function isIteratableObject(
18-
maybeIteratable: unknown,
19-
): maybeIteratable is Iterable<unknown>;
17+
export function isIterableObject(
18+
maybeIterable: unknown,
19+
): maybeIterable is Iterable<unknown>;

src/jsutils/isIteratableObject.js renamed to src/jsutils/isIterableObject.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,21 @@
88
*
99
* @example
1010
*
11-
* isIteratableObject([ 1, 2, 3 ]) // true
12-
* isIteratableObject(new Map()) // true
13-
* isIteratableObject('ABC') // false
14-
* isIteratableObject({ key: 'value' }) // false
15-
* isIteratableObject({ length: 1, 0: 'Alpha' }) // false
11+
* isIterableObject([ 1, 2, 3 ]) // true
12+
* isIterableObject(new Map()) // true
13+
* isIterableObject('ABC') // false
14+
* isIterableObject({ key: 'value' }) // false
15+
* isIterableObject({ length: 1, 0: 'Alpha' }) // false
1616
*/
17-
declare function isIteratableObject(
17+
declare function isIterableObject(
1818
value: mixed,
1919
// $FlowFixMe[invalid-in-rhs]
2020
): boolean %checks(value instanceof Iterable);
2121

2222
// eslint-disable-next-line no-redeclare
23-
export function isIteratableObject(maybeIteratable: mixed): boolean {
23+
export function isIterableObject(maybeIterable: mixed): boolean {
2424
return (
25-
typeof maybeIteratable === 'object' &&
26-
typeof maybeIteratable?.[Symbol.iterator] === 'function'
25+
typeof maybeIterable === 'object' &&
26+
typeof maybeIterable?.[Symbol.iterator] === 'function'
2727
);
2828
}

src/subscription/__tests__/mapAsyncIterator-test.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ describe('mapAsyncIterator', () => {
2222
});
2323
});
2424

25-
it('maps over async iterator', async () => {
25+
it('maps over async iterable', async () => {
2626
const items = [1, 2, 3];
2727

28-
const iterator: $FlowFixMe = {
28+
const iterable: $FlowFixMe = {
2929
[Symbol.asyncIterator]() {
3030
return this;
3131
},
@@ -39,7 +39,7 @@ describe('mapAsyncIterator', () => {
3939
},
4040
};
4141

42-
const doubles = mapAsyncIterator(iterator, (x) => x + x);
42+
const doubles = mapAsyncIterator(iterable, (x) => x + x);
4343

4444
expect(await doubles.next()).to.deep.equal({ value: 2, done: false });
4545
expect(await doubles.next()).to.deep.equal({ value: 4, done: false });
@@ -119,10 +119,10 @@ describe('mapAsyncIterator', () => {
119119
});
120120
});
121121

122-
it('allows returning early from mapped async iterator', async () => {
122+
it('allows returning early from mapped async iterable', async () => {
123123
const items = [1, 2, 3];
124124

125-
const iterator: any = {
125+
const iterable: any = {
126126
[Symbol.asyncIterator]() {
127127
return this;
128128
},
@@ -134,7 +134,7 @@ describe('mapAsyncIterator', () => {
134134
},
135135
};
136136

137-
const doubles = mapAsyncIterator(iterator, (x) => x + x);
137+
const doubles = mapAsyncIterator(iterable, (x) => x + x);
138138

139139
expect(await doubles.next()).to.deep.equal({ value: 2, done: false });
140140
expect(await doubles.next()).to.deep.equal({ value: 4, done: false });
@@ -182,10 +182,10 @@ describe('mapAsyncIterator', () => {
182182
});
183183
});
184184

185-
it('allows throwing errors through async iterators', async () => {
185+
it('allows throwing errors through async iterable', async () => {
186186
const items = [1, 2, 3];
187187

188-
const iterator: any = {
188+
const iterable: any = {
189189
[Symbol.asyncIterator]() {
190190
return this;
191191
},
@@ -197,7 +197,7 @@ describe('mapAsyncIterator', () => {
197197
},
198198
};
199199

200-
const doubles = mapAsyncIterator(iterator, (x) => x + x);
200+
const doubles = mapAsyncIterator(iterable, (x) => x + x);
201201

202202
expect(await doubles.next()).to.deep.equal({ value: 2, done: false });
203203
expect(await doubles.next()).to.deep.equal({ value: 4, done: false });

src/utilities/astFromValue.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { inspect } from '../jsutils/inspect';
22
import { invariant } from '../jsutils/invariant';
33
import { isObjectLike } from '../jsutils/isObjectLike';
4-
import { isIteratableObject } from '../jsutils/isIteratableObject';
4+
import { isIterableObject } from '../jsutils/isIterableObject';
55

66
import type { ValueNode } from '../language/ast';
77
import { Kind } from '../language/kinds';
@@ -60,10 +60,10 @@ export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode {
6060
// the value is not an array, convert the value using the list's item type.
6161
if (isListType(type)) {
6262
const itemType = type.ofType;
63-
if (isIteratableObject(value)) {
63+
if (isIterableObject(value)) {
6464
const valuesNodes = [];
6565
// Since we transpile for-of in loose mode it doesn't support iterators
66-
// and it's required to first convert iteratable into array
66+
// and it's required to first convert iterable into array
6767
for (const item of Array.from(value)) {
6868
const itemNode = astFromValue(item, itemType);
6969
if (itemNode != null) {

src/utilities/coerceInputValue.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { isObjectLike } from '../jsutils/isObjectLike';
66
import { suggestionList } from '../jsutils/suggestionList';
77
import { printPathArray } from '../jsutils/printPathArray';
88
import { addPath, pathToArray } from '../jsutils/Path';
9-
import { isIteratableObject } from '../jsutils/isIteratableObject';
9+
import { isIterableObject } from '../jsutils/isIterableObject';
1010

1111
import { GraphQLError } from '../error/GraphQLError';
1212

@@ -75,7 +75,7 @@ function coerceInputValueImpl(
7575

7676
if (isListType(type)) {
7777
const itemType = type.ofType;
78-
if (isIteratableObject(inputValue)) {
78+
if (isIterableObject(inputValue)) {
7979
return Array.from(inputValue, (itemValue, index) => {
8080
const itemPath = addPath(path, index, undefined);
8181
return coerceInputValueImpl(itemValue, itemType, onError, itemPath);

0 commit comments

Comments
 (0)