Skip to content

Commit 2707e3e

Browse files
authored
Merge pull request #19 from jsr-core/add-repeat
feat(repeat): add `repeat` module
2 parents 1ecde88 + fe2b91f commit 2707e3e

File tree

14 files changed

+315
-0
lines changed

14 files changed

+315
-0
lines changed

README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,48 @@ const joined = await pipe(
10731073
console.log(joined); // 12345
10741074
```
10751075

1076+
### repeat
1077+
1078+
Returns an finite iterable that repeats through the given iterable.
1079+
1080+
```ts
1081+
import { repeat } from "@core/iterutil/repeat";
1082+
1083+
const iter = repeat([1, 2, 3], 2);
1084+
console.log(Array.from(iter)); // [1, 2, 3, 1, 2, 3]
1085+
```
1086+
1087+
```ts
1088+
import { repeat } from "@core/iterutil/async/repeat";
1089+
1090+
const iter = repeat([1, 2, 3], 2);
1091+
console.log(await Array.fromAsync(iter)); // [1, 2, 3, 1, 2, 3]
1092+
```
1093+
1094+
Use `pipe` and `pipe/async` modules for [@core/pipe] package like.
1095+
1096+
```ts
1097+
import { pipe } from "@core/pipe";
1098+
import { repeat } from "@core/iterutil/pipe/repeat";
1099+
1100+
const iter = pipe(
1101+
[1, 2, 3],
1102+
repeat(2),
1103+
);
1104+
console.log(Array.from(iter)); // [1, 2, 3, 1, 2, 3]
1105+
```
1106+
1107+
```ts
1108+
import { pipe } from "@core/pipe";
1109+
import { repeat } from "@core/iterutil/pipe/async/repeat";
1110+
1111+
const iter = pipe(
1112+
[1, 2, 3],
1113+
repeat(2),
1114+
);
1115+
console.log(await Array.fromAsync(iter)); // [1, 2, 3, 1, 2, 3]
1116+
```
1117+
10761118
### some
10771119

10781120
Returns true if at least one element in the iterable satisfies the provided

async/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export * from "./nth.ts";
2020
export * from "./pairwise.ts";
2121
export * from "./partition.ts";
2222
export * from "./reduce.ts";
23+
export * from "./repeat.ts";
2324
export * from "./some.ts";
2425
export * from "./take.ts";
2526
export * from "./take_while.ts";

async/repeat.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Returns an infinite iterable that repeats through the given iterable.
3+
*
4+
* Use {@linkcode https://jsr.io/@core/iterutil/doc/async/cycle/~/cycle cycle} to cycle the iterable
5+
* Use {@linkcode https://jsr.io/@core/iterutil/doc/repeat/~/repeat repeat} to repeat the iterable synchronously.
6+
*
7+
* @param iterable The iterable to repeat.
8+
* @returns The repeatd iterable.
9+
*
10+
* @example
11+
* ```ts
12+
* import { repeat } from "@core/iterutil/async/repeat";
13+
*
14+
* const iter = repeat([1, 2, 3], 2);
15+
* console.log(await Array.fromAsync(iter)); // [1, 2, 3, 1, 2, 3]
16+
* ```
17+
*/
18+
export function repeat<T>(
19+
iterable: Iterable<T> | AsyncIterable<T>,
20+
n: number,
21+
): AsyncIterable<T> {
22+
if (n < 0 || !Number.isSafeInteger(n)) {
23+
throw new RangeError(
24+
`n must be 0 or positive safe integer, but got ${n}.`,
25+
);
26+
}
27+
if (n === 0) {
28+
return async function* () {}();
29+
}
30+
return async function* () {
31+
const array = await Array.fromAsync(iterable);
32+
if (array.length === 0) {
33+
return;
34+
}
35+
for (let i = 0; i < n; i++) {
36+
yield* array;
37+
}
38+
}();
39+
}

async/repeat_test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { assertEquals, assertThrows } from "@std/assert";
2+
import { assertType, type IsExact } from "@std/testing/types";
3+
import { toAsyncIterable } from "./to_async_iterable.ts";
4+
import { repeat } from "./repeat.ts";
5+
6+
Deno.test("repeat", async (t) => {
7+
await t.step("with async iterable", async (t) => {
8+
await t.step("with non empty iterable", async () => {
9+
const result = repeat(toAsyncIterable([0, 1, 2]), 2);
10+
const expected = [0, 1, 2, 0, 1, 2];
11+
assertEquals(await Array.fromAsync(result), expected);
12+
assertType<IsExact<typeof result, AsyncIterable<number>>>(true);
13+
});
14+
15+
await t.step("with single value iterable", async () => {
16+
const result = repeat(toAsyncIterable([0]), 2);
17+
const expected = [0, 0];
18+
assertEquals(await Array.fromAsync(result), expected);
19+
assertType<IsExact<typeof result, AsyncIterable<number>>>(true);
20+
});
21+
22+
await t.step("with empty iterable", async () => {
23+
const result = repeat(toAsyncIterable([] as number[]), 2);
24+
const expected: number[] = [];
25+
assertEquals(await Array.fromAsync(result), expected);
26+
assertType<IsExact<typeof result, AsyncIterable<number>>>(true);
27+
});
28+
});
29+
30+
await t.step("with iterable", async (t) => {
31+
await t.step("with non empty iterable", async () => {
32+
const result = repeat([0, 1, 2], 2);
33+
const expected = [0, 1, 2, 0, 1, 2];
34+
assertEquals(await Array.fromAsync(result), expected);
35+
assertType<IsExact<typeof result, AsyncIterable<number>>>(true);
36+
});
37+
38+
await t.step("with single value iterable", async () => {
39+
const result = repeat([0], 2);
40+
const expected = [0, 0];
41+
assertEquals(await Array.fromAsync(result), expected);
42+
assertType<IsExact<typeof result, AsyncIterable<number>>>(true);
43+
});
44+
45+
await t.step("with empty iterable", async () => {
46+
const result = repeat([] as number[], 2);
47+
const expected: number[] = [];
48+
assertEquals(await Array.fromAsync(result), expected);
49+
assertType<IsExact<typeof result, AsyncIterable<number>>>(true);
50+
});
51+
});
52+
53+
await t.step("with n=0", async () => {
54+
const result = repeat([0, 1, 2], 0);
55+
const expected: number[] = [];
56+
assertEquals(await Array.fromAsync(result), expected);
57+
assertType<IsExact<typeof result, AsyncIterable<number>>>(true);
58+
});
59+
60+
await t.step("throws RangeError", async (t) => {
61+
await t.step("if the limit is not 0 nor positive safe integer", () => {
62+
assertThrows(() => repeat([], NaN), RangeError);
63+
assertThrows(() => repeat([], Infinity), RangeError);
64+
assertThrows(() => repeat([], -Infinity), RangeError);
65+
assertThrows(() => repeat([], -1), RangeError);
66+
assertThrows(() => repeat([], 1.1), RangeError);
67+
});
68+
});
69+
});

deno.jsonc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"./async/pairwise": "./async/pairwise.ts",
2727
"./async/partition": "./async/partition.ts",
2828
"./async/reduce": "./async/reduce.ts",
29+
"./async/repeat": "./async/repeat.ts",
2930
"./async/some": "./async/some.ts",
3031
"./async/take": "./async/take.ts",
3132
"./async/take-while": "./async/take_while.ts",
@@ -77,6 +78,7 @@
7778
"./pipe/async/pairwise": "./pipe/async/pairwise.ts",
7879
"./pipe/async/partition": "./pipe/async/partition.ts",
7980
"./pipe/async/reduce": "./pipe/async/reduce.ts",
81+
"./pipe/async/repeat": "./pipe/async/repeat.ts",
8082
"./pipe/async/some": "./pipe/async/some.ts",
8183
"./pipe/async/take": "./pipe/async/take.ts",
8284
"./pipe/async/take-while": "./pipe/async/take_while.ts",
@@ -103,13 +105,15 @@
103105
"./pipe/pairwise": "./pipe/pairwise.ts",
104106
"./pipe/partition": "./pipe/partition.ts",
105107
"./pipe/reduce": "./pipe/reduce.ts",
108+
"./pipe/repeat": "./pipe/repeat.ts",
106109
"./pipe/some": "./pipe/some.ts",
107110
"./pipe/take": "./pipe/take.ts",
108111
"./pipe/take-while": "./pipe/take_while.ts",
109112
"./pipe/uniq": "./pipe/uniq.ts",
110113
"./pipe/zip": "./pipe/zip.ts",
111114
"./range": "./range.ts",
112115
"./reduce": "./reduce.ts",
116+
"./repeat": "./repeat.ts",
113117
"./some": "./some.ts",
114118
"./take": "./take.ts",
115119
"./take-while": "./take_while.ts",
@@ -156,6 +160,7 @@
156160
"@core/iterutil/async/pairwise": "./async/pairwise.ts",
157161
"@core/iterutil/async/partition": "./async/partition.ts",
158162
"@core/iterutil/async/reduce": "./async/reduce.ts",
163+
"@core/iterutil/async/repeat": "./async/repeat.ts",
159164
"@core/iterutil/async/some": "./async/some.ts",
160165
"@core/iterutil/async/take": "./async/take.ts",
161166
"@core/iterutil/async/take-while": "./async/take_while.ts",
@@ -209,6 +214,7 @@
209214
"@core/iterutil/pipe/async/pairwise": "./pipe/async/pairwise.ts",
210215
"@core/iterutil/pipe/async/partition": "./pipe/async/partition.ts",
211216
"@core/iterutil/pipe/async/reduce": "./pipe/async/reduce.ts",
217+
"@core/iterutil/pipe/async/repeat": "./pipe/async/repeat.ts",
212218
"@core/iterutil/pipe/async/some": "./pipe/async/some.ts",
213219
"@core/iterutil/pipe/async/take": "./pipe/async/take.ts",
214220
"@core/iterutil/pipe/async/take-while": "./pipe/async/take_while.ts",
@@ -237,13 +243,15 @@
237243
"@core/iterutil/pipe/pairwise": "./pipe/pairwise.ts",
238244
"@core/iterutil/pipe/partition": "./pipe/partition.ts",
239245
"@core/iterutil/pipe/reduce": "./pipe/reduce.ts",
246+
"@core/iterutil/pipe/repeat": "./pipe/repeat.ts",
240247
"@core/iterutil/pipe/some": "./pipe/some.ts",
241248
"@core/iterutil/pipe/take": "./pipe/take.ts",
242249
"@core/iterutil/pipe/take-while": "./pipe/take_while.ts",
243250
"@core/iterutil/pipe/uniq": "./pipe/uniq.ts",
244251
"@core/iterutil/pipe/zip": "./pipe/zip.ts",
245252
"@core/iterutil/range": "./range.ts",
246253
"@core/iterutil/reduce": "./reduce.ts",
254+
"@core/iterutil/repeat": "./repeat.ts",
247255
"@core/iterutil/some": "./some.ts",
248256
"@core/iterutil/take": "./take.ts",
249257
"@core/iterutil/take-while": "./take_while.ts",

mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export * from "./pairwise.ts";
2222
export * from "./partition.ts";
2323
export * from "./range.ts";
2424
export * from "./reduce.ts";
25+
export * from "./repeat.ts";
2526
export * from "./some.ts";
2627
export * from "./take.ts";
2728
export * from "./take_while.ts";

pipe/async/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export * from "./nth.ts";
1919
export * from "./pairwise.ts";
2020
export * from "./partition.ts";
2121
export * from "./reduce.ts";
22+
export * from "./repeat.ts";
2223
export * from "./some.ts";
2324
export * from "./take.ts";
2425
export * from "./take_while.ts";

pipe/async/repeat.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { repeat as base } from "@core/iterutil/async/repeat";
2+
3+
/**
4+
* An operator to return a function that repeats the elements of an iterable.
5+
*
6+
* See {@linkcode https://jsr.io/@core/iterutil/doc/async/repeat/~/repeat repeat} for native repeat.
7+
*
8+
* @example
9+
* ```ts
10+
* import { pipe } from "@core/pipe";
11+
* import { repeat } from "@core/iterutil/pipe/async/repeat";
12+
*
13+
* const iter = pipe(
14+
* [1, 2, 3],
15+
* repeat(2),
16+
* );
17+
* console.log(await Array.fromAsync(iter)); // [1, 2, 3, 1, 2, 3]
18+
* ```
19+
*/
20+
export function repeat<T>(
21+
n: number,
22+
): (iterable: Iterable<T> | AsyncIterable<T>) => AsyncIterable<T> {
23+
return (iterable: Iterable<T> | AsyncIterable<T>) => base(iterable, n);
24+
}

pipe/async/repeat_test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { assertEquals } from "@std/assert";
2+
import { assertType, type IsExact } from "@std/testing/types";
3+
import { pipe } from "@core/pipe";
4+
import { repeat } from "./repeat.ts";
5+
6+
Deno.test("repeat", async (t) => {
7+
await t.step("usage", async () => {
8+
const result = pipe([0, 1, 2], repeat(2));
9+
const expected = [0, 1, 2, 0, 1, 2];
10+
assertEquals(await Array.fromAsync(result), expected);
11+
assertType<IsExact<typeof result, AsyncIterable<number>>>(true);
12+
});
13+
});

pipe/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export * from "./nth.ts";
1919
export * from "./pairwise.ts";
2020
export * from "./partition.ts";
2121
export * from "./reduce.ts";
22+
export * from "./repeat.ts";
2223
export * from "./some.ts";
2324
export * from "./take.ts";
2425
export * from "./take_while.ts";

0 commit comments

Comments
 (0)