complete-common 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +7 -0
- package/dist/index.cjs +535 -0
- package/dist/index.d.cts +705 -0
- package/dist/index.d.mts +705 -0
- package/dist/index.d.ts +705 -0
- package/dist/index.mjs +463 -0
- package/package.json +36 -0
- package/src/constants.ts +3 -0
- package/src/functions/array.ts +209 -0
- package/src/functions/enums.ts +105 -0
- package/src/functions/map.ts +90 -0
- package/src/functions/math.ts +9 -0
- package/src/functions/object.ts +27 -0
- package/src/functions/random.ts +43 -0
- package/src/functions/set.ts +131 -0
- package/src/functions/sort.ts +18 -0
- package/src/functions/string.test.ts +42 -0
- package/src/functions/string.ts +304 -0
- package/src/functions/tuple.ts +31 -0
- package/src/functions/types.ts +15 -0
- package/src/functions/utils.test.ts +910 -0
- package/src/functions/utils.ts +238 -0
- package/src/index.ts +27 -0
- package/src/types/AddSubtract.ts +19 -0
- package/src/types/CompositionTypeSatisfiesEnum.ts +67 -0
- package/src/types/ERange.ts +15 -0
- package/src/types/IRange.ts +16 -0
- package/src/types/Immutable.ts +28 -0
- package/src/types/NaturalNumbersLessThan.ts +12 -0
- package/src/types/NaturalNumbersLessThanOrEqualTo.ts +14 -0
- package/src/types/ObjectValues.ts +1 -0
- package/src/types/ReadonlyMap.ts +12 -0
- package/src/types/ReadonlyRecord.ts +3 -0
- package/src/types/ReadonlySet.ts +9 -0
- package/src/types/Tuple.ts +14 -0
- package/src/types/WidenLiteral.ts +11 -0
- package/src/types/Writeable.ts +6 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
type TranspiledEnum = Record<string, string | number>;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Helper function to get the entries of an enum.
|
|
5
|
+
*
|
|
6
|
+
* (By default, TypeScript will put the keys inside of the values of a number-based enum, so those
|
|
7
|
+
* have to be filtered out.)
|
|
8
|
+
*
|
|
9
|
+
* This function will work properly for both number and string enums.
|
|
10
|
+
*/
|
|
11
|
+
export function getEnumEntries<T extends TranspiledEnum>(
|
|
12
|
+
transpiledEnum: T,
|
|
13
|
+
): ReadonlyArray<[key: string, value: T[keyof T]]> {
|
|
14
|
+
const entries = Object.entries(transpiledEnum);
|
|
15
|
+
const numberEntries = entries.filter(
|
|
16
|
+
([_key, value]) => typeof value === "number",
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
// If there are no number values, then this must be a string enum, and no filtration is required.
|
|
20
|
+
const entriesToReturn = numberEntries.length > 0 ? numberEntries : entries;
|
|
21
|
+
return entriesToReturn as never;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Helper function to get the keys of an enum.
|
|
26
|
+
*
|
|
27
|
+
* (By default, TypeScript will put the keys inside of the values of a number-based enum, so those
|
|
28
|
+
* have to be filtered out.)
|
|
29
|
+
*
|
|
30
|
+
* This function will work properly for both number and string enums.
|
|
31
|
+
*/
|
|
32
|
+
export function getEnumKeys(transpiledEnum: TranspiledEnum): readonly string[] {
|
|
33
|
+
const enumEntries = getEnumEntries(transpiledEnum);
|
|
34
|
+
return enumEntries.map(([key, _value]) => key);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Helper function to get the only the values of an enum.
|
|
39
|
+
*
|
|
40
|
+
* (By default, TypeScript will put the keys inside of the values of a number-based enum, so those
|
|
41
|
+
* have to be filtered out.)
|
|
42
|
+
*
|
|
43
|
+
* This function will work properly for both number and string enums.
|
|
44
|
+
*/
|
|
45
|
+
export function getEnumValues<T extends TranspiledEnum>(
|
|
46
|
+
transpiledEnum: T,
|
|
47
|
+
): ReadonlyArray<T[keyof T]> {
|
|
48
|
+
const enumEntries = getEnumEntries(transpiledEnum);
|
|
49
|
+
return enumEntries.map(([_key, value]) => value);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Helper function to validate that an interface contains all of the keys of an enum. You must
|
|
54
|
+
* specify both generic parameters in order for this to work properly (i.e. the interface and then
|
|
55
|
+
* the enum).
|
|
56
|
+
*
|
|
57
|
+
* For example:
|
|
58
|
+
*
|
|
59
|
+
* ```ts
|
|
60
|
+
* enum MyEnum {
|
|
61
|
+
* Value1,
|
|
62
|
+
* Value2,
|
|
63
|
+
* Value3,
|
|
64
|
+
* }
|
|
65
|
+
*
|
|
66
|
+
* interface MyEnumToType {
|
|
67
|
+
* [MyEnum.Value1]: boolean;
|
|
68
|
+
* [MyEnum.Value2]: number;
|
|
69
|
+
* [MyEnum.Value3]: string;
|
|
70
|
+
* }
|
|
71
|
+
*
|
|
72
|
+
* interfaceSatisfiesEnum<MyEnumToType, MyEnum>();
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* This function is only meant to be used with interfaces (i.e. types that will not exist at
|
|
76
|
+
* run-time). If you are generating an object that will contain all of the keys of an enum, use the
|
|
77
|
+
* `satisfies` operator with the `Record` type instead.
|
|
78
|
+
*/
|
|
79
|
+
export function interfaceSatisfiesEnum<
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-unnecessary-type-parameters
|
|
81
|
+
T extends Record<Enum, unknown>,
|
|
82
|
+
Enum extends string | number,
|
|
83
|
+
>(): void {} // eslint-disable-line @typescript-eslint/no-empty-function
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Helper function to validate that a particular value exists inside of an enum.
|
|
87
|
+
*
|
|
88
|
+
* @param value The value to check.
|
|
89
|
+
* @param transpiledEnum The enum to check against.
|
|
90
|
+
* @param set Optional. A set that contains all of the values of an enum. If provided, this function
|
|
91
|
+
* will check for existence using the set (instead of the enum itself). Using a set
|
|
92
|
+
* should be more performant for enums with around 52 or more elements.
|
|
93
|
+
*/
|
|
94
|
+
export function isEnumValue<T extends TranspiledEnum>(
|
|
95
|
+
value: number | string,
|
|
96
|
+
transpiledEnum: T,
|
|
97
|
+
set?: ReadonlySet<string | number>,
|
|
98
|
+
): value is T[keyof T] {
|
|
99
|
+
if (set !== undefined) {
|
|
100
|
+
return set.has(value);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const enumValues = getEnumValues(transpiledEnum);
|
|
104
|
+
return enumValues.includes(value as T[keyof T]);
|
|
105
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to get the values in a `Map` that match an arbitrary condition. Similar to the
|
|
3
|
+
* `Array.map` method, but works for maps.
|
|
4
|
+
*
|
|
5
|
+
* This is efficient such that it avoids converting the map values into an array.
|
|
6
|
+
*
|
|
7
|
+
* If you want to perform a filter and a map at the same time on an array, use the `filterMap`
|
|
8
|
+
* helper function instead.
|
|
9
|
+
*/
|
|
10
|
+
// eslint-disable-next-line complete/no-mutable-return
|
|
11
|
+
export function mapFilter<K, V>(
|
|
12
|
+
map: ReadonlyMap<K, V>,
|
|
13
|
+
predicate: (value: V) => boolean,
|
|
14
|
+
): V[] {
|
|
15
|
+
const array: V[] = [];
|
|
16
|
+
|
|
17
|
+
for (const value of map.values()) {
|
|
18
|
+
const match = predicate(value);
|
|
19
|
+
if (match) {
|
|
20
|
+
array.push(value);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return array;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Helper function to find a value in a `Map`. Similar to the `Array.find` method, but works for
|
|
29
|
+
* maps.
|
|
30
|
+
*
|
|
31
|
+
* This is efficient such that it avoids converting the map values into an array.
|
|
32
|
+
*/
|
|
33
|
+
export function mapFind<K, V>(
|
|
34
|
+
map: ReadonlyMap<K, V>,
|
|
35
|
+
predicate: (value: V) => boolean,
|
|
36
|
+
): V | undefined {
|
|
37
|
+
for (const value of map.values()) {
|
|
38
|
+
const match = predicate(value);
|
|
39
|
+
if (match) {
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Helper function to convert an object to a map.
|
|
49
|
+
*
|
|
50
|
+
* This is useful when you need to construct a type safe object with the `satisfies` operator, but
|
|
51
|
+
* then later on you need to query it in a way where you expect the return value to be T or
|
|
52
|
+
* undefined. In this situation, by converting the object to a map, you can avoid unsafe type
|
|
53
|
+
* assertions.
|
|
54
|
+
*
|
|
55
|
+
* Note that the map values will be inserted in a random order, due to how `pairs` works under the
|
|
56
|
+
* hood.
|
|
57
|
+
*
|
|
58
|
+
* Also see the `objectToReadonlyMap` function.
|
|
59
|
+
*/
|
|
60
|
+
// eslint-disable-next-line complete/no-mutable-return
|
|
61
|
+
export function objectToMap<K extends string | number | symbol, V>(
|
|
62
|
+
object: Record<K, V>,
|
|
63
|
+
): Map<K, V> {
|
|
64
|
+
const map = new Map<K, V>();
|
|
65
|
+
|
|
66
|
+
for (const [key, value] of Object.entries(object)) {
|
|
67
|
+
map.set(key as K, value as V);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return map;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Helper function to convert an object to a read-only map.
|
|
75
|
+
*
|
|
76
|
+
* This is useful when you need to construct a type safe object with the `satisfies` operator, but
|
|
77
|
+
* then later on you need to query it in a way where you expect the return value to be T or
|
|
78
|
+
* undefined. In this situation, by converting the object to a map, you can avoid unsafe type
|
|
79
|
+
* assertions.
|
|
80
|
+
*
|
|
81
|
+
* Note that the map values will be inserted in a random order, due to how `pairs` works under the
|
|
82
|
+
* hood.
|
|
83
|
+
*
|
|
84
|
+
* Also see the `objectToMap` function.
|
|
85
|
+
*/
|
|
86
|
+
export function objectToReadonlyMap<K extends string | number | symbol, V>(
|
|
87
|
+
object: Record<K, V>,
|
|
88
|
+
): ReadonlyMap<K, V> {
|
|
89
|
+
return objectToMap(object);
|
|
90
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to normalize a number, ensuring that it is within a certain range.
|
|
3
|
+
*
|
|
4
|
+
* - If `num` is less than `min`, then it will be clamped to `min`.
|
|
5
|
+
* - If `num` is greater than `max`, then it will be clamped to `max`.
|
|
6
|
+
*/
|
|
7
|
+
export function clamp(num: number, min: number, max: number): number {
|
|
8
|
+
return Math.max(min, Math.min(num, max));
|
|
9
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to get the values in an object that match an arbitrary condition. Similar to the
|
|
3
|
+
* `Array.map` method, but works for objects.
|
|
4
|
+
*
|
|
5
|
+
* This is efficient such that it avoids converting the object values into an array.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ReadonlyRecord } from "../types/ReadonlyRecord.js";
|
|
9
|
+
|
|
10
|
+
// eslint-disable-next-line complete/no-mutable-return
|
|
11
|
+
export function objectFilter<K extends string | number | symbol, V>(
|
|
12
|
+
object: ReadonlyRecord<K, V>,
|
|
13
|
+
predicate: (value: V) => boolean,
|
|
14
|
+
): V[] {
|
|
15
|
+
const array: V[] = [];
|
|
16
|
+
|
|
17
|
+
// eslint-disable-next-line complete/no-for-in
|
|
18
|
+
for (const key in object) {
|
|
19
|
+
const value = object[key];
|
|
20
|
+
const match = predicate(value);
|
|
21
|
+
if (match) {
|
|
22
|
+
array.push(value);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return array;
|
|
27
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ReadonlySet } from "../types/ReadonlySet.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This returns a random integer between min and max. It is inclusive on both ends.
|
|
5
|
+
*
|
|
6
|
+
* For example:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const oneTwoOrThree = getRandomInt(1, 3);
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* @param min The lower bound for the random number (inclusive).
|
|
13
|
+
* @param max The upper bound for the random number (inclusive).
|
|
14
|
+
* @param exceptions Optional. An array of elements that will be skipped over when getting the
|
|
15
|
+
* random integer. For example, a min of 1, a max of 4, and an exceptions array of
|
|
16
|
+
* `[2]` would cause the function to return either 1, 3, or 4. Default is an empty
|
|
17
|
+
* array.
|
|
18
|
+
*/
|
|
19
|
+
export function getRandomInt(
|
|
20
|
+
min: number,
|
|
21
|
+
max: number,
|
|
22
|
+
exceptions: readonly number[] = [],
|
|
23
|
+
): number {
|
|
24
|
+
min = Math.ceil(min); // eslint-disable-line no-param-reassign
|
|
25
|
+
max = Math.floor(max); // eslint-disable-line no-param-reassign
|
|
26
|
+
|
|
27
|
+
if (min > max) {
|
|
28
|
+
const oldMin = min;
|
|
29
|
+
const oldMax = max;
|
|
30
|
+
|
|
31
|
+
min = oldMax; // eslint-disable-line no-param-reassign
|
|
32
|
+
max = oldMin; // eslint-disable-line no-param-reassign
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const exceptionsSet = new ReadonlySet(exceptions);
|
|
36
|
+
|
|
37
|
+
let randomInt: number;
|
|
38
|
+
do {
|
|
39
|
+
randomInt = Math.floor(Math.random() * (max - min + 1)) + min;
|
|
40
|
+
} while (exceptionsSet.has(randomInt));
|
|
41
|
+
|
|
42
|
+
return randomInt;
|
|
43
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to add all of the values in one set to another set. The first set passed will be
|
|
3
|
+
* modified in place.
|
|
4
|
+
*
|
|
5
|
+
* This function is variadic, meaning that you can specify N sets to add to the first set.
|
|
6
|
+
*/
|
|
7
|
+
export function addSetsToSet<T>(
|
|
8
|
+
// eslint-disable-next-line complete/prefer-readonly-parameter-types
|
|
9
|
+
mainSet: Set<T>,
|
|
10
|
+
...setsToAdd: ReadonlyArray<ReadonlySet<T>>
|
|
11
|
+
): void {
|
|
12
|
+
for (const set of setsToAdd) {
|
|
13
|
+
for (const value of set) {
|
|
14
|
+
mainSet.add(value);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Helper function to create a new set that is the composition of two or more sets.
|
|
21
|
+
*
|
|
22
|
+
* This function is variadic, meaning that you can specify N sets.
|
|
23
|
+
*/
|
|
24
|
+
// eslint-disable-next-line complete/no-mutable-return
|
|
25
|
+
export function combineSets<T>(...sets: ReadonlyArray<ReadonlySet<T>>): Set<T> {
|
|
26
|
+
const newSet = new Set<T>();
|
|
27
|
+
for (const set of sets) {
|
|
28
|
+
for (const value of set) {
|
|
29
|
+
newSet.add(value);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return newSet;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Helper function to copy a set. (You can also use a Set constructor to accomplish this task.) */
|
|
37
|
+
// eslint-disable-next-line complete/no-mutable-return
|
|
38
|
+
export function copySet<T>(oldSet: ReadonlySet<T>): Set<T> {
|
|
39
|
+
const newSet = new Set<T>();
|
|
40
|
+
for (const value of oldSet) {
|
|
41
|
+
newSet.add(value);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return newSet;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Helper function to convert the keys of an object to a read-only set.
|
|
49
|
+
*
|
|
50
|
+
* Also see the `objectKeysToSet` function.
|
|
51
|
+
*/
|
|
52
|
+
export function objectKeysToReadonlySet<K extends string | number | symbol, V>(
|
|
53
|
+
object: Record<K, V>,
|
|
54
|
+
): ReadonlySet<K> {
|
|
55
|
+
return objectKeysToSet(object);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Helper function to convert the keys of an object to a set.
|
|
60
|
+
*
|
|
61
|
+
* Also see the `objectKeysToReadonlySet` function.
|
|
62
|
+
*/
|
|
63
|
+
// eslint-disable-next-line complete/no-mutable-return
|
|
64
|
+
export function objectKeysToSet<K extends string | number | symbol, V>(
|
|
65
|
+
object: Record<K, V>,
|
|
66
|
+
): Set<K> {
|
|
67
|
+
const set = new Set<K>();
|
|
68
|
+
|
|
69
|
+
for (const key of Object.keys(object)) {
|
|
70
|
+
set.add(key as K);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return set;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Helper function to convert the values of an object to a read-only set.
|
|
78
|
+
*
|
|
79
|
+
* Also see the `objectValuesToSet` function.
|
|
80
|
+
*/
|
|
81
|
+
export function objectValuesToReadonlySet<
|
|
82
|
+
K extends string | number | symbol,
|
|
83
|
+
V,
|
|
84
|
+
>(object: Record<K, V>): ReadonlySet<V> {
|
|
85
|
+
return objectValuesToSet(object);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Helper function to convert the values of an object to a set.
|
|
90
|
+
*
|
|
91
|
+
* Also see the `objectValuesToReadonlySet` function.
|
|
92
|
+
*/
|
|
93
|
+
// eslint-disable-next-line complete/no-mutable-return
|
|
94
|
+
export function objectValuesToSet<K extends string | number | symbol, V>(
|
|
95
|
+
object: Record<K, V>,
|
|
96
|
+
): Set<V> {
|
|
97
|
+
const set = new Set<V>();
|
|
98
|
+
|
|
99
|
+
for (const key of Object.values(object)) {
|
|
100
|
+
set.add(key as V);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return set;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Helper function to add one or more elements to a set at once without having to repeatedly call
|
|
108
|
+
* the `Set.add` method.
|
|
109
|
+
*
|
|
110
|
+
* This function is variadic, meaning that you can pass as many things as you want to add.
|
|
111
|
+
*/
|
|
112
|
+
// eslint-disable-next-line complete/prefer-readonly-parameter-types
|
|
113
|
+
export function setAdd<T>(set: Set<T>, ...elements: readonly T[]): void {
|
|
114
|
+
for (const element of elements) {
|
|
115
|
+
set.add(element);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Helper function to check for one or more elements in a set at once without having to repeatedly
|
|
121
|
+
* call the `Set.has` method.
|
|
122
|
+
*
|
|
123
|
+
* This function is variadic, meaning that you can pass as many things as you want to check for. It
|
|
124
|
+
* will return true if one or more elements are found.
|
|
125
|
+
*/
|
|
126
|
+
export function setHas<T>(
|
|
127
|
+
set: ReadonlySet<T>,
|
|
128
|
+
...elements: readonly T[]
|
|
129
|
+
): boolean {
|
|
130
|
+
return elements.some((element) => set.has(element));
|
|
131
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to perform a case insensitive sort. This will copy the provided array and return
|
|
3
|
+
* the sorted copy.
|
|
4
|
+
*
|
|
5
|
+
* From:
|
|
6
|
+
* https://stackoverflow.com/questions/8996963/how-to-perform-case-insensitive-sorting-array-of-string-in-javascript
|
|
7
|
+
*/
|
|
8
|
+
// eslint-disable-next-line complete/no-mutable-return
|
|
9
|
+
export function sortCaseInsensitive(array: readonly string[]): string[] {
|
|
10
|
+
const newArray = [...array];
|
|
11
|
+
newArray.sort((a, b) =>
|
|
12
|
+
a.localeCompare(b, undefined, {
|
|
13
|
+
sensitivity: "base",
|
|
14
|
+
}),
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
return newArray;
|
|
18
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { equal } from "node:assert";
|
|
2
|
+
import test, { describe } from "node:test";
|
|
3
|
+
import { hasDiacritic, hasEmoji } from "./string.js";
|
|
4
|
+
|
|
5
|
+
describe("hasEmoji", () => {
|
|
6
|
+
test("should return true for string with emoji", () => {
|
|
7
|
+
equal(hasEmoji("Hello ๐ World"), true);
|
|
8
|
+
equal(hasEmoji("This is a ๐ test"), true);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("should return false for string without emoji", () => {
|
|
12
|
+
equal(hasEmoji("Hello World"), false);
|
|
13
|
+
equal(hasEmoji("No emoji here!"), false);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("should handle empty string", () => {
|
|
17
|
+
equal(hasEmoji(""), false);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("should handle strings with only emoji", () => {
|
|
21
|
+
equal(hasEmoji("๐"), true);
|
|
22
|
+
equal(hasEmoji("๐"), true);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe("hasDiacritic", () => {
|
|
27
|
+
test("should return true for diacritic character", () => {
|
|
28
|
+
equal(hasDiacritic("รก"), true);
|
|
29
|
+
equal(hasDiacritic("รจ"), true);
|
|
30
|
+
equal(hasDiacritic("รด"), true);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("should return false for non-diacritic character", () => {
|
|
34
|
+
equal(hasDiacritic("A"), false);
|
|
35
|
+
equal(hasDiacritic("1"), false);
|
|
36
|
+
equal(hasDiacritic("!"), false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("should handle empty string", () => {
|
|
40
|
+
equal(hasDiacritic(""), false);
|
|
41
|
+
});
|
|
42
|
+
});
|