Skip to content

Commit ed8a171

Browse files
authored
Refactor Iterator.prototype.flatMap goody to use Iterator.from (#483)
Closes #429.
1 parent d9e82dc commit ed8a171

File tree

4 files changed

+72
-34
lines changed

4 files changed

+72
-34
lines changed

workspaces/adventure-pack/goodies/typescript/Iterator.prototype.flatMap/index.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import "../Iterator.from/index.ts";
12
import "../Iterator.prototype.toIterable/index.ts";
23
import { iteratorPrototype } from "../Iterator.prototype/index.ts";
34

@@ -19,13 +20,7 @@ iteratorPrototype.flatMap ??= function* <TIn, TOut>(
1920
): Generator<TOut, void, undefined> {
2021
let index = 0;
2122
for (const element of this.toIterable()) {
22-
const res = callbackFn(element, index);
23-
if (!(Symbol.iterator in res || typeof res.next === "function")) {
24-
throw new TypeError("Callback must return an iterable or iterator");
25-
}
26-
yield* Symbol.iterator in res
27-
? (res as Iterable<TOut>)
28-
: (res as Iterator<TOut>).toIterable();
23+
yield* Iterator.from(callbackFn(element, index)).toIterable();
2924
++index;
3025
}
3126
};

workspaces/adventure-pack/src/app/__tests__/__snapshots__/equip-test.ts.snap

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,14 +1571,34 @@ iteratorPrototype.toIterable = function () {
15711571
return this;
15721572
};
15731573

1574+
globalThis.Iterator ??= {};
1575+
globalThis.Iterator.from ??= function (object) {
1576+
const toIterable = iteratorPrototype.toIterable;
1577+
1578+
const iteratorFactory = object[Symbol.iterator];
1579+
if (typeof iteratorFactory === "function") {
1580+
return toIterable.call(iteratorFactory.call(object));
1581+
}
1582+
1583+
if (Object.prototype.isPrototypeOf.call(iteratorPrototype, object)) {
1584+
return toIterable.call(object);
1585+
}
1586+
1587+
if (typeof object.next === "function") {
1588+
return (function* () {
1589+
yield* toIterable.call(object);
1590+
})();
1591+
}
1592+
1593+
throw new TypeError(
1594+
"Object is not an iterator, iterable, or an object with a next method",
1595+
);
1596+
};
1597+
15741598
iteratorPrototype.flatMap ??= function* (callbackFn) {
15751599
let index = 0;
15761600
for (const element of this.toIterable()) {
1577-
const res = callbackFn(element, index);
1578-
if (!(Symbol.iterator in res || typeof res.next === "function")) {
1579-
throw new TypeError("Callback must return an iterable or iterator");
1580-
}
1581-
yield* Symbol.iterator in res ? res : res.toIterable();
1601+
yield* Iterator.from(callbackFn(element, index)).toIterable();
15821602
++index;
15831603
}
15841604
};
@@ -3719,6 +3739,14 @@ declare global {
37193739

37203740
toIterable(this: Iterator<T>): IterableIterator<T>;
37213741
}
3742+
3743+
interface IteratorConstructor {
3744+
from<T>(
3745+
object: Iterator<T> | Iterable<T> | { next(): IteratorResult<T> },
3746+
): IterableIterator<T>;
3747+
}
3748+
3749+
const Iterator: IteratorConstructor;
37223750
}
37233751

37243752
Function.returnThis = function <T>(this: T): T {
@@ -3737,19 +3765,42 @@ iteratorPrototype.toIterable = function <T>(
37373765
return this as unknown as IterableIterator<T>;
37383766
};
37393767

3768+
(globalThis as Record<string, unknown>).Iterator ??= {};
3769+
((globalThis as Record<string, unknown>).Iterator as { from: unknown }).from ??=
3770+
function <T>(
3771+
object: Iterator<T> | Iterable<T> | { next(): IteratorResult<T> },
3772+
): IterableIterator<T> {
3773+
const toIterable = iteratorPrototype.toIterable as (
3774+
this: Iterator<T>,
3775+
) => IterableIterator<T>;
3776+
3777+
const iteratorFactory = (object as Iterable<T>)[Symbol.iterator];
3778+
if (typeof iteratorFactory === "function") {
3779+
return toIterable.call(iteratorFactory.call(object));
3780+
}
3781+
3782+
if (Object.prototype.isPrototypeOf.call(iteratorPrototype, object)) {
3783+
return toIterable.call(object as Iterator<T>);
3784+
}
3785+
3786+
if (typeof (object as Record<string, unknown>).next === "function") {
3787+
return (function* () {
3788+
yield* toIterable.call(object as Iterator<T>);
3789+
})();
3790+
}
3791+
3792+
throw new TypeError(
3793+
"Object is not an iterator, iterable, or an object with a next method",
3794+
);
3795+
};
3796+
37403797
iteratorPrototype.flatMap ??= function* <TIn, TOut>(
37413798
this: Iterator<TIn>,
37423799
callbackFn: (element: TIn, index: number) => Iterator<TOut> | Iterable<TOut>,
37433800
): Generator<TOut, void, undefined> {
37443801
let index = 0;
37453802
for (const element of this.toIterable()) {
3746-
const res = callbackFn(element, index);
3747-
if (!(Symbol.iterator in res || typeof res.next === "function")) {
3748-
throw new TypeError("Callback must return an iterable or iterator");
3749-
}
3750-
yield* Symbol.iterator in res
3751-
? (res as Iterable<TOut>)
3752-
: (res as Iterator<TOut>).toIterable();
3803+
yield* Iterator.from(callbackFn(element, index)).toIterable();
37533804
++index;
37543805
}
37553806
};

workspaces/adventure-pack/src/app/__tests__/__snapshots__/render-test.ts.snap

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -904,17 +904,14 @@ iteratorPrototype.find ??= function (callbackFn) {
904904
`;
905905
906906
exports[`App can render goody: JavaScript Iterator.prototype.flatMap 1`] = `
907-
"import "Iterator.prototype";
907+
"import "Iterator.from";
908+
import "Iterator.prototype";
908909
import "Iterator.prototype.toIterable";
909910
910911
iteratorPrototype.flatMap ??= function* (callbackFn) {
911912
let index = 0;
912913
for (const element of this.toIterable()) {
913-
const res = callbackFn(element, index);
914-
if (!(Symbol.iterator in res || typeof res.next === "function")) {
915-
throw new TypeError("Callback must return an iterable or iterator");
916-
}
917-
yield* Symbol.iterator in res ? res : res.toIterable();
914+
yield* Iterator.from(callbackFn(element, index)).toIterable();
918915
++index;
919916
}
920917
};"
@@ -2171,7 +2168,8 @@ iteratorPrototype.find ??= function <T>(
21712168
`;
21722169
21732170
exports[`App can render goody: TypeScript Iterator.prototype.flatMap 1`] = `
2174-
"import "Iterator.prototype";
2171+
"import "Iterator.from";
2172+
import "Iterator.prototype";
21752173
import "Iterator.prototype.toIterable";
21762174
21772175
declare global {
@@ -2192,13 +2190,7 @@ iteratorPrototype.flatMap ??= function* <TIn, TOut>(
21922190
): Generator<TOut, void, undefined> {
21932191
let index = 0;
21942192
for (const element of this.toIterable()) {
2195-
const res = callbackFn(element, index);
2196-
if (!(Symbol.iterator in res || typeof res.next === "function")) {
2197-
throw new TypeError("Callback must return an iterable or iterator");
2198-
}
2199-
yield* Symbol.iterator in res
2200-
? (res as Iterable<TOut>)
2201-
: (res as Iterator<TOut>).toIterable();
2193+
yield* Iterator.from(callbackFn(element, index)).toIterable();
22022194
++index;
22032195
}
22042196
};"

workspaces/leetcode-api/src/api/question-list/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const questionZodType = z
2121
titleSlug: slugZodType,
2222
})
2323
.transform(({ challengeQuestionsV2, ...rest }) => ({
24-
chalengeQuestionDates: challengeQuestionsV2,
24+
challengeQuestionDates: challengeQuestionsV2,
2525
...rest,
2626
}));
2727

0 commit comments

Comments
 (0)