-
Notifications
You must be signed in to change notification settings - Fork 115
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement
Set.isSubsetOf()
for Node <22, which defaults to bu…
…iltin implementation whenever possible (#1009)
- Loading branch information
Showing
5 changed files
with
160 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { ReadonlySetLike, isSubsetOf } from "./isSubsetOf"; | ||
|
||
// Tests are adapted from: | ||
// https://github.com/zloirock/core-js/blob/227a758ef96fa585a66cc1e89741e7d0bb696f48/tests/unit-global/es.set.is-subset-of.js | ||
|
||
describe("isSubsetOf", () => { | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
let s1: Set<any>; | ||
let s2: ReadonlySetLike<unknown>; | ||
|
||
it("should implement isSubsetOf correctly", () => { | ||
s1 = new Set([1]); | ||
s2 = new Set([1, 2, 3]); | ||
expect(isSubsetOf(s1, s2)).toBe(true); | ||
|
||
s1 = new Set([1]); | ||
s2 = new Set([2, 3, 4]); | ||
expect(isSubsetOf(s1, s2)).toBe(false); | ||
|
||
s1 = new Set([1, 2, 3]); | ||
s2 = new Set([5, 4, 3, 2, 1]); | ||
expect(isSubsetOf(s1, s2)).toBe(true); | ||
|
||
s1 = new Set([1, 2, 3]); | ||
s2 = new Set([5, 4, 3, 2]); | ||
expect(isSubsetOf(s1, s2)).toBe(false); | ||
|
||
s1 = new Set([1]); | ||
s2 = createSetLike([1, 2, 3]); | ||
expect(isSubsetOf(s1, s2)).toBe(true); | ||
|
||
s1 = new Set([1]); | ||
s2 = createSetLike([2, 3, 4]); | ||
expect(isSubsetOf(s1, s2)).toBe(false); | ||
|
||
s1 = new Set([1, 2, 3]); | ||
s2 = createSetLike([5, 4, 3, 2, 1]); | ||
expect(isSubsetOf(s1, s2)).toBe(true); | ||
|
||
s1 = new Set([1, 2, 3]); | ||
s2 = createSetLike([5, 4, 3, 2]); | ||
expect(isSubsetOf(s1, s2)).toBe(false); | ||
|
||
s1 = new Set([1, 2, 3]); | ||
s2 = new Set([1]); | ||
expect(isSubsetOf(s1, s2)).toBe(false); | ||
|
||
s1 = new Set([1, 2, 3]); | ||
s2 = new Set(); | ||
expect(isSubsetOf(s1, s2)).toBe(false); | ||
|
||
s1 = new Set(); | ||
s2 = new Set([1, 2, 3]); | ||
expect(isSubsetOf(s1, s2)).toBe(true); | ||
}); | ||
}); | ||
|
||
// Helper functions are adapted from: | ||
// https://github.com/zloirock/core-js/blob/227a758ef96fa585a66cc1e89741e7d0bb696f48/tests/helpers/helpers.js | ||
|
||
function createSetLike<T>(elements: T[]): ReadonlySetLike<T> { | ||
return { | ||
size: elements.length, | ||
has(value: T): boolean { | ||
return includes(elements, value); | ||
}, | ||
keys(): Iterator<T> { | ||
return createIterator(elements); | ||
}, | ||
}; | ||
} | ||
|
||
function includes<T>(target: T[], wanted: T) { | ||
return target.some((element) => element === wanted); | ||
} | ||
|
||
function createIterator<T>(elements: T[]): Iterator<T> { | ||
let index = 0; | ||
const iterator = { | ||
called: false, | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
next(): IteratorResult<any> { | ||
iterator.called = true; | ||
return { | ||
value: elements[index++], | ||
done: index > elements.length, | ||
}; | ||
}, | ||
}; | ||
return iterator; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/** Taken from TypeScript collection lib to perfectly match the .isSubsetOf signature */ | ||
export interface ReadonlySetLike<T> { | ||
/** | ||
* Despite its name, returns an iterator of the values in the set-like. | ||
*/ | ||
keys(): Iterator<T>; | ||
/** | ||
* @returns a boolean indicating whether an element with the specified value exists in the set-like or not. | ||
*/ | ||
has(value: T): boolean; | ||
/** | ||
* @returns the number of (unique) elements in the set-like. | ||
*/ | ||
readonly size: number; | ||
} | ||
|
||
/** | ||
* @returns a boolean indicating whether all the elements in Set `one` are also in the `other`. | ||
*/ | ||
export function isSubsetOf<T>( | ||
one: Set<T>, | ||
other: ReadonlySetLike<unknown>, | ||
): boolean { | ||
// If the builtin method exists, just call it | ||
if ("isSubsetOf" in Set.prototype) { | ||
return one.isSubsetOf(other); | ||
} | ||
// If not, provide the implementation | ||
if (one.size > other.size) { | ||
return false; | ||
} | ||
for (const element of one) { | ||
if (!other.has(element)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} |