Skip to content

Commit 31a15a1

Browse files
authored
feat: add generator detection functions to utils (#2923)
Functions like this are used in several places in the stack so move them to the utils package for reuse. Incorporates changes from #2918
1 parent 827a38a commit 31a15a1

File tree

7 files changed

+138
-0
lines changed

7 files changed

+138
-0
lines changed

packages/utils/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@
8484
"types": "./dist/src/ip-port-to-multiaddr.d.ts",
8585
"import": "./dist/src/ip-port-to-multiaddr.js"
8686
},
87+
"./is-async-generator": {
88+
"types": "./dist/src/is-async-generator.d.ts",
89+
"import": "./dist/src/is-async-generator.js"
90+
},
91+
"./is-generator": {
92+
"types": "./dist/src/is-generator.d.ts",
93+
"import": "./dist/src/is-generator.js"
94+
},
8795
"./is-promise": {
8896
"types": "./dist/src/is-promise.d.ts",
8997
"import": "./dist/src/is-promise.js"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export function isAsyncGenerator (obj: unknown): obj is AsyncGenerator {
2+
if (obj == null) return false
3+
const asyncIterator = (obj as { [Symbol.asyncIterator]?: unknown })?.[
4+
Symbol.asyncIterator
5+
]
6+
if (typeof asyncIterator !== 'function') return false
7+
8+
const instance = obj as { next?: unknown }
9+
return typeof instance.next === 'function'
10+
}

packages/utils/src/is-generator.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function isGenerator (obj: unknown): obj is Generator {
2+
if (obj == null) return false
3+
const iterator = (obj as { [Symbol.iterator]?: unknown })?.[Symbol.iterator]
4+
if (typeof iterator !== 'function') return false
5+
6+
const instance = obj as { next?: unknown }
7+
return typeof instance.next === 'function'
8+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { expect } from 'aegir/chai'
2+
import { isAsyncGenerator } from '../src/is-async-generator.js'
3+
4+
describe('is-async-generator', () => {
5+
it('should return true if the value is an async generator', () => {
6+
async function * asyncGen (): AsyncGenerator<number> {
7+
yield 1
8+
}
9+
const asyncGenerator = asyncGen()
10+
expect(isAsyncGenerator(asyncGenerator)).to.be.true()
11+
12+
const asyncGenObj = (async function * () {
13+
yield 1
14+
})()
15+
expect(isAsyncGenerator(asyncGenObj)).to.be.true()
16+
})
17+
18+
it('should return false if the value is not an async generator', () => {
19+
expect(isAsyncGenerator(1)).to.be.false()
20+
expect(isAsyncGenerator('string')).to.be.false()
21+
expect(isAsyncGenerator({})).to.be.false()
22+
expect(isAsyncGenerator([])).to.be.false()
23+
expect(isAsyncGenerator(null)).to.be.false()
24+
expect(isAsyncGenerator(undefined)).to.be.false()
25+
expect(isAsyncGenerator(() => {})).to.be.false()
26+
expect(isAsyncGenerator(async () => {})).to.be.false()
27+
expect(
28+
isAsyncGenerator(function * () {
29+
yield 1
30+
})
31+
).to.be.false()
32+
expect(
33+
isAsyncGenerator(async function * () {
34+
yield 1
35+
})
36+
).to.be.false() // async generator function, not generator
37+
expect(isAsyncGenerator(Promise.resolve())).to.be.false()
38+
expect(isAsyncGenerator({ next: async () => {} })).to.be.false()
39+
expect(isAsyncGenerator({ [Symbol.asyncIterator]: () => {} })).to.be.false()
40+
})
41+
})
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { expect } from 'aegir/chai'
2+
import { isGenerator } from '../src/is-generator.js'
3+
4+
describe('is-generator', () => {
5+
it('should return true if the value is a generator', () => {
6+
function * gen (): Generator<number> {
7+
yield 1
8+
}
9+
const generator = gen()
10+
expect(isGenerator(generator)).to.be.true()
11+
12+
const genObj = (function * () {
13+
yield 1
14+
})()
15+
expect(isGenerator(genObj)).to.be.true()
16+
})
17+
18+
it('should return false if the value is not a generator', () => {
19+
expect(isGenerator(1)).to.be.false()
20+
expect(isGenerator('string')).to.be.false()
21+
expect(isGenerator({})).to.be.false()
22+
expect(isGenerator([])).to.be.false()
23+
expect(isGenerator(null)).to.be.false()
24+
expect(isGenerator(undefined)).to.be.false()
25+
expect(isGenerator(() => {})).to.be.false()
26+
expect(isGenerator(async () => {})).to.be.false()
27+
expect(
28+
isGenerator(function * () {
29+
yield 1
30+
})
31+
).to.be.false() // generator function, not generator
32+
expect(
33+
isGenerator(async function * () {
34+
yield 1
35+
})
36+
).to.be.false()
37+
expect(isGenerator(Promise.resolve())).to.be.false()
38+
expect(isGenerator({ next: () => {} })).to.be.false()
39+
expect(isGenerator({ [Symbol.iterator]: () => {} })).to.be.false()
40+
})
41+
})

packages/utils/test/is-promise.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,32 @@ describe('is-promise', () => {
3131
it('should not detect partial promise', () => {
3232
expect(isPromise({ then: true })).to.be.false()
3333
})
34+
35+
it('should return true if the value is a promise', () => {
36+
expect(isPromise(Promise.resolve())).to.be.true()
37+
expect(isPromise(new Promise(() => {}))).to.be.true()
38+
expect(isPromise(Promise.reject(new Error('test')))).to.be.true()
39+
})
40+
41+
it('should return false if the value is not a promise', () => {
42+
expect(isPromise(1)).to.be.false()
43+
expect(isPromise('string')).to.be.false()
44+
expect(isPromise({})).to.be.false()
45+
expect(isPromise([])).to.be.false()
46+
expect(isPromise(null)).to.be.false()
47+
expect(isPromise(undefined)).to.be.false()
48+
expect(isPromise(() => {})).to.be.false()
49+
expect(isPromise(async () => {})).to.be.false()
50+
expect(
51+
isPromise(function * () {
52+
yield 1
53+
})
54+
).to.be.false()
55+
expect(
56+
isPromise(async function * () {
57+
yield 1
58+
})
59+
).to.be.false()
60+
expect(isPromise({ then: 1 })).to.be.false()
61+
})
3462
})

packages/utils/typedoc.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"./src/filters/index.ts",
1212
"./src/global-unicast-ip.ts",
1313
"./src/ip-port-to-multiaddr.ts",
14+
"./src/is-async-generator.ts",
15+
"./src/is-generator.ts",
1416
"./src/is-promise.ts",
1517
"./src/link-local-ip.ts",
1618
"./src/moving-average.ts",

0 commit comments

Comments
 (0)