@applicaster/zapp-react-native-utils 14.0.0-alpha.3552323332 → 14.0.0-alpha.3652810444
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/actionsExecutor/ActionExecutorContext.tsx +60 -84
- package/actionsExecutor/ScreenActions.ts +164 -0
- package/actionsExecutor/StorageActions.ts +110 -0
- package/actionsExecutor/feedDecorator.ts +171 -0
- package/actionsExecutor/screenResolver.ts +11 -0
- package/analyticsUtils/AnalyticsEvents/helper.ts +81 -0
- package/analyticsUtils/AnalyticsEvents/sendHeaderClickEvent.ts +1 -1
- package/analyticsUtils/AnalyticsEvents/sendMenuClickEvent.ts +2 -1
- package/analyticsUtils/AnalyticsEvents/sendOnClickEvent.ts +14 -4
- package/analyticsUtils/__tests__/analyticsUtils.test.js +3 -0
- package/analyticsUtils/events.ts +8 -0
- package/analyticsUtils/index.tsx +3 -4
- package/analyticsUtils/manager.ts +1 -1
- package/analyticsUtils/playerAnalyticsTracker.ts +2 -1
- package/appUtils/HooksManager/Hook.ts +4 -4
- package/appUtils/HooksManager/index.ts +11 -1
- package/appUtils/accessibilityManager/index.ts +5 -5
- package/appUtils/contextKeysManager/contextResolver.ts +42 -1
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +5 -0
- package/appUtils/focusManager/__tests__/focusManager.test.js +1 -1
- package/appUtils/focusManager/events.ts +2 -0
- package/appUtils/focusManager/index.ios.ts +10 -0
- package/appUtils/focusManager/index.ts +82 -11
- package/appUtils/focusManager/treeDataStructure/Tree/index.js +1 -1
- package/appUtils/focusManagerAux/utils/index.ts +106 -3
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +0 -15
- package/appUtils/playerManager/useChapterMarker.tsx +0 -1
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +16 -0
- package/arrayUtils/__tests__/isEmptyArray.test.ts +63 -0
- package/arrayUtils/__tests__/isFilledArray.test.ts +1 -1
- package/arrayUtils/index.ts +8 -3
- package/audioPlayerUtils/__tests__/getArtworkImage.test.ts +144 -0
- package/audioPlayerUtils/__tests__/getBackgroundImage.test.ts +72 -0
- package/audioPlayerUtils/__tests__/getImageFromEntry.test.ts +110 -0
- package/audioPlayerUtils/assets/index.ts +2 -0
- package/audioPlayerUtils/index.ts +242 -0
- package/componentsUtils/__tests__/isTabsScreen.test.ts +38 -0
- package/componentsUtils/index.ts +4 -1
- package/conf/player/__tests__/selectors.test.ts +34 -0
- package/conf/player/selectors.ts +10 -0
- package/configurationUtils/__tests__/configurationUtils.test.js +0 -31
- package/configurationUtils/__tests__/getMediaItems.test.ts +65 -0
- package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +34 -0
- package/configurationUtils/__tests__/manifestKeyParser.test.ts +546 -0
- package/configurationUtils/index.ts +63 -34
- package/configurationUtils/manifestKeyParser.ts +57 -32
- package/focusManager/FocusManager.ts +89 -20
- package/focusManager/Tree.ts +25 -21
- package/focusManager/__tests__/FocusManager.test.ts +50 -8
- package/focusManager/aux/index.ts +167 -0
- package/focusManager/utils.ts +12 -6
- package/index.d.ts +0 -9
- package/manifestUtils/_internals/getDefaultConfiguration.js +28 -0
- package/manifestUtils/{_internals.js → _internals/index.js} +2 -25
- package/manifestUtils/createConfig.js +4 -1
- package/manifestUtils/defaultManifestConfigurations/player.js +1239 -200
- package/manifestUtils/progressBar/__tests__/mobileProgressBar.test.js +0 -30
- package/navigationUtils/__tests__/mapContentTypesToRivers.test.ts +130 -0
- package/navigationUtils/index.ts +7 -5
- package/package.json +2 -3
- package/playerUtils/__tests__/configurationUtils.test.ts +1 -65
- package/playerUtils/__tests__/getPlayerActionButtons.test.ts +54 -0
- package/playerUtils/_internals/__tests__/utils.test.ts +71 -0
- package/playerUtils/_internals/index.ts +1 -0
- package/playerUtils/_internals/utils.ts +31 -0
- package/playerUtils/configurationUtils.ts +0 -44
- package/playerUtils/getPlayerActionButtons.ts +17 -0
- package/playerUtils/index.ts +2 -0
- package/playerUtils/useValidatePlayerConfig.tsx +22 -19
- package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +15 -14
- package/reactHooks/cell-click/__tests__/index.test.js +3 -0
- package/reactHooks/cell-click/index.ts +8 -1
- package/reactHooks/debugging/__tests__/index.test.js +0 -1
- package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +47 -90
- package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +71 -31
- package/reactHooks/feed/index.ts +2 -0
- package/reactHooks/feed/useBatchLoading.ts +17 -10
- package/reactHooks/feed/useFeedLoader.tsx +36 -34
- package/reactHooks/feed/useLoadPipesDataDispatch.ts +63 -0
- package/reactHooks/feed/usePipesCacheReset.ts +3 -3
- package/reactHooks/flatList/useSequentialRenderItem.tsx +3 -3
- package/reactHooks/layout/__tests__/index.test.tsx +3 -1
- package/reactHooks/layout/isTablet/index.ts +12 -5
- package/reactHooks/layout/useDimensions/__tests__/useDimensions.test.ts +34 -36
- package/reactHooks/layout/useDimensions/useDimensions.ts +2 -3
- package/reactHooks/layout/useLayoutVersion.ts +5 -5
- package/reactHooks/navigation/index.ts +7 -5
- package/reactHooks/navigation/useIsScreenActive.ts +9 -5
- package/reactHooks/navigation/useRoute.ts +7 -2
- package/reactHooks/navigation/useScreenStateStore.ts +8 -0
- package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +4 -0
- package/reactHooks/screen/useScreenContext.ts +1 -1
- package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +2 -1
- package/reactHooks/state/index.ts +1 -1
- package/reactHooks/state/useHomeRiver.ts +4 -2
- package/reactHooks/state/useRivers.ts +7 -8
- package/riverComponetsMeasurementProvider/index.tsx +1 -1
- package/screenPickerUtils/index.ts +13 -0
- package/services/js2native.ts +1 -0
- package/storage/ScreenSingleValueProvider.ts +204 -0
- package/storage/ScreenStateMultiSelectProvider.ts +293 -0
- package/storage/StorageMultiSelectProvider.ts +192 -0
- package/storage/StorageSingleSelectProvider.ts +108 -0
- package/testUtils/index.tsx +7 -8
- package/time/BackgroundTimer.ts +6 -4
- package/utils/__tests__/endsWith.test.ts +30 -0
- package/utils/__tests__/equals.test.ts +65 -0
- package/utils/__tests__/find.test.ts +36 -0
- package/utils/__tests__/max.test.ts +36 -0
- package/utils/__tests__/omit.test.ts +19 -0
- package/utils/__tests__/path.test.ts +33 -0
- package/utils/__tests__/pathOr.test.ts +37 -0
- package/utils/__tests__/startsWith.test.ts +30 -0
- package/utils/__tests__/take.test.ts +40 -0
- package/utils/__tests__/toLower.test.ts +39 -0
- package/utils/endsWith.ts +9 -0
- package/utils/equals.ts +5 -0
- package/utils/find.ts +3 -0
- package/utils/index.ts +37 -1
- package/utils/max.ts +5 -0
- package/utils/omit.ts +5 -0
- package/utils/path.ts +5 -0
- package/utils/pathOr.ts +5 -0
- package/utils/startsWith.ts +9 -0
- package/utils/take.ts +5 -0
- package/utils/toLower.ts +5 -0
- package/playerUtils/configurationGenerator.ts +0 -2572
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { bridgeLogger } from "../../zapp-react-native-bridge/logger";
|
|
2
|
+
import { BehaviorSubject } from "rxjs";
|
|
3
|
+
import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
|
|
4
|
+
import { getNamespaceAndKey } from "../appUtils/contextKeysManager/utils";
|
|
5
|
+
import { createLogger } from "../logger";
|
|
6
|
+
|
|
7
|
+
export const { log_verbose, log_debug, log_warning, log_info, log_error } =
|
|
8
|
+
createLogger({
|
|
9
|
+
category: "StorageSingleValueProvider",
|
|
10
|
+
subsystem: "zapp-react-native-bridge",
|
|
11
|
+
parent: bridgeLogger,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export interface SingleValueProvider {
|
|
15
|
+
getObservable(): BehaviorSubject<string | null>;
|
|
16
|
+
|
|
17
|
+
setValue(value: string): Promise<void>;
|
|
18
|
+
getValue(): string | null;
|
|
19
|
+
getValueAsync(): Promise<string | null>;
|
|
20
|
+
clearValue(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface StorageListenerArgs {
|
|
24
|
+
value: string | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class StorageSingleValueProvider implements SingleValueProvider {
|
|
28
|
+
// Static cache of providers by namespace
|
|
29
|
+
private static singleValueProviders: Record<
|
|
30
|
+
string,
|
|
31
|
+
StorageSingleValueProvider
|
|
32
|
+
> = {};
|
|
33
|
+
|
|
34
|
+
public static getProvider(keyNamespace: string): SingleValueProvider {
|
|
35
|
+
if (!this.singleValueProviders[keyNamespace]) {
|
|
36
|
+
this.singleValueProviders[keyNamespace] = new StorageSingleValueProvider(
|
|
37
|
+
keyNamespace
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return this.singleValueProviders[keyNamespace];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private valueSubject: BehaviorSubject<string | null>;
|
|
45
|
+
|
|
46
|
+
private readonly key: string;
|
|
47
|
+
private readonly namespace: string;
|
|
48
|
+
|
|
49
|
+
private constructor(keyNamespace: string) {
|
|
50
|
+
const { namespace, key } = getNamespaceAndKey(keyNamespace);
|
|
51
|
+
|
|
52
|
+
if (!key) {
|
|
53
|
+
throw new Error("StorageSingleValueProvider: Key is required");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.key = key;
|
|
57
|
+
this.namespace = namespace;
|
|
58
|
+
localStorage.addListener?.({ key, namespace }, this.reloadValue);
|
|
59
|
+
|
|
60
|
+
this.valueSubject = new BehaviorSubject<string | null>(null);
|
|
61
|
+
|
|
62
|
+
void this.getValueAsync();
|
|
63
|
+
log_debug("StorageSingleValueProvider: Initializing");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private reloadValue = async ({ value }: StorageListenerArgs) => {
|
|
67
|
+
log_debug(`reloadValue: request to reload value: ${value}`);
|
|
68
|
+
|
|
69
|
+
this.valueSubject.next(value);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
public getObservable = (): BehaviorSubject<string | null> =>
|
|
73
|
+
this.valueSubject;
|
|
74
|
+
|
|
75
|
+
private async updateValueAndNotifyObservers(value: string | null) {
|
|
76
|
+
if (value === null) {
|
|
77
|
+
await localStorage.removeItem(this.key, this.namespace);
|
|
78
|
+
} else {
|
|
79
|
+
await localStorage.setItem(this.key, value, this.namespace);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.valueSubject.next(value);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public setValue = async (value: string): Promise<void> => {
|
|
86
|
+
log_debug(`setValue: Setting new value: ${value}`);
|
|
87
|
+
|
|
88
|
+
await this.updateValueAndNotifyObservers(value);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
public clearValue = async (): Promise<void> => {
|
|
92
|
+
await localStorage.removeItem(this.key, this.namespace);
|
|
93
|
+
log_debug("clearValue: Removing value");
|
|
94
|
+
|
|
95
|
+
this.valueSubject.next(null);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
public getValueAsync = async (): Promise<string | null> => {
|
|
99
|
+
const value = await localStorage.getItem(this.key, this.namespace);
|
|
100
|
+
this.valueSubject.next(value);
|
|
101
|
+
|
|
102
|
+
return value;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
public getValue = (): string | null => {
|
|
106
|
+
return this.valueSubject.getValue();
|
|
107
|
+
};
|
|
108
|
+
}
|
package/testUtils/index.tsx
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { SafeAreaProvider } from "react-native-safe-area-context";
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
3
|
import React, { PropsWithChildren } from "react";
|
|
4
|
-
import
|
|
5
|
-
|
|
4
|
+
import configureStore from "redux-mock-store";
|
|
6
5
|
import { Provider } from "react-redux";
|
|
6
|
+
import { View } from "react-native";
|
|
7
7
|
import thunk from "redux-thunk";
|
|
8
|
-
import
|
|
9
|
-
|
|
8
|
+
import * as R from "ramda";
|
|
9
|
+
|
|
10
10
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
11
11
|
|
|
12
|
-
import { render } from "@testing-library/react-native";
|
|
13
|
-
import { AnalyticsProvider } from "../analyticsUtils";
|
|
14
12
|
import { ThemeContext } from "../theme";
|
|
13
|
+
import { AnalyticsProvider } from "../analyticsUtils";
|
|
15
14
|
|
|
16
15
|
export { getByTestId } from "./getByTestId";
|
|
17
16
|
|
package/time/BackgroundTimer.ts
CHANGED
|
@@ -11,15 +11,17 @@ class BackgroundTimer {
|
|
|
11
11
|
this.uniqueId = 0;
|
|
12
12
|
this.callbacks = {};
|
|
13
13
|
|
|
14
|
-
const EventEmitter = platformSelect({
|
|
14
|
+
const EventEmitter: typeof DeviceEventEmitter | undefined = platformSelect({
|
|
15
15
|
android: DeviceEventEmitter,
|
|
16
|
-
|
|
16
|
+
android_tv: DeviceEventEmitter,
|
|
17
|
+
amazon: DeviceEventEmitter, // probably does not exist and uses android_tv
|
|
17
18
|
default: undefined,
|
|
18
19
|
});
|
|
19
20
|
|
|
20
21
|
EventEmitter?.addListener("BackgroundTimer.timer.fired", (id: number) => {
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
const callback = this.callbacks[id];
|
|
23
|
+
|
|
24
|
+
if (callback) {
|
|
23
25
|
delete this.callbacks[id];
|
|
24
26
|
callback();
|
|
25
27
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { endsWith } from "../endsWith";
|
|
2
|
+
|
|
3
|
+
describe("endsWith", () => {
|
|
4
|
+
it("returns false when str is null", () => {
|
|
5
|
+
expect(endsWith("a", null)).toBe(false);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it("returns false when str is undefined", () => {
|
|
9
|
+
expect(endsWith("a", undefined)).toBe(false);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("returns true when string ends with target", () => {
|
|
13
|
+
expect(endsWith("lo", "hello")).toBe(true);
|
|
14
|
+
expect(endsWith("", "hello")).toBe(true); // empty target always matches
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("returns false when string does not end with target", () => {
|
|
18
|
+
expect(endsWith("yo", "hello")).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("works with single character target", () => {
|
|
22
|
+
expect(endsWith("o", "hello")).toBe(true);
|
|
23
|
+
expect(endsWith("x", "hello")).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("is case-sensitive", () => {
|
|
27
|
+
expect(endsWith("Lo", "hello")).toBe(false);
|
|
28
|
+
expect(endsWith("lo", "hello")).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { equals } from "../equals";
|
|
2
|
+
|
|
3
|
+
describe("equals", () => {
|
|
4
|
+
it("returns true for two identical primitive values", () => {
|
|
5
|
+
expect(equals(5, 5)).toBe(true);
|
|
6
|
+
expect(equals("hello", "hello")).toBe(true);
|
|
7
|
+
expect(equals(true, true)).toBe(true);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("returns false for two different primitive values", () => {
|
|
11
|
+
expect(equals(5, 10)).toBe(false);
|
|
12
|
+
expect(equals("hello", "world")).toBe(false);
|
|
13
|
+
expect(equals(true, false)).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("returns true for deeply equal objects", () => {
|
|
17
|
+
const a = { x: 1, y: { z: 2 } };
|
|
18
|
+
const b = { x: 1, y: { z: 2 } };
|
|
19
|
+
expect(equals(a, b)).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("returns false for objects with different values", () => {
|
|
23
|
+
const a = { x: 1, y: { z: 2 } };
|
|
24
|
+
const b = { x: 1, y: { z: 3 } };
|
|
25
|
+
expect(equals(a, b)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("returns true for arrays with same elements", () => {
|
|
29
|
+
expect(equals([1, 2, 3], [1, 2, 3])).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("returns false for arrays with different elements", () => {
|
|
33
|
+
expect(equals([1, 2, 3], [1, 2, 4])).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("returns true for nested arrays/objects", () => {
|
|
37
|
+
const a = [{ id: 1, data: [1, 2, 3] }];
|
|
38
|
+
const b = [{ id: 1, data: [1, 2, 3] }];
|
|
39
|
+
expect(equals(a, b)).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("returns false for arrays with different order", () => {
|
|
43
|
+
expect(equals([1, 2, 3], [3, 2, 1])).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("handles null and undefined correctly", () => {
|
|
47
|
+
expect(equals(null, null)).toBe(true);
|
|
48
|
+
expect(equals(undefined, undefined)).toBe(true);
|
|
49
|
+
expect(equals(null, undefined)).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("handles dates correctly", () => {
|
|
53
|
+
const d1 = new Date("2020-01-01");
|
|
54
|
+
const d2 = new Date("2020-01-01");
|
|
55
|
+
const d3 = new Date("2021-01-01");
|
|
56
|
+
|
|
57
|
+
expect(equals(d1, d2)).toBe(true);
|
|
58
|
+
expect(equals(d1, d3)).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("handles regex correctly", () => {
|
|
62
|
+
expect(equals(/abc/, /abc/)).toBe(true);
|
|
63
|
+
expect(equals(/abc/i, /abc/)).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { find } from "../find";
|
|
2
|
+
|
|
3
|
+
test("example 1", () => {
|
|
4
|
+
const predicate = <T>(_: T, index: number): boolean => index === 0;
|
|
5
|
+
const xs = ["1", "2", "2", "3", "4"];
|
|
6
|
+
|
|
7
|
+
expect(find(predicate, xs)).toBe("1");
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test("example 2", () => {
|
|
11
|
+
const predicate = <T>(_: T, index: number): boolean => index === 0;
|
|
12
|
+
const xs: string[] = [];
|
|
13
|
+
|
|
14
|
+
expect(find(predicate, xs)).toBe(undefined);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("example 3", () => {
|
|
18
|
+
const predicate = () => false;
|
|
19
|
+
const xs = ["1", "2", "2", "3"];
|
|
20
|
+
|
|
21
|
+
expect(find(predicate, xs)).toBe(undefined);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("example 4", () => {
|
|
25
|
+
const predicate = <T>(_: T, index: number): boolean => index === 1;
|
|
26
|
+
const xs = ["1", "2", "2", "3"];
|
|
27
|
+
|
|
28
|
+
expect(find(predicate, xs)).toBe("2");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("example 5", () => {
|
|
32
|
+
const predicate = <T>(_: T, index: number): boolean => index === 2;
|
|
33
|
+
const xs = ["1", "2.1", "2", "3", "2", "4"];
|
|
34
|
+
|
|
35
|
+
expect(find(predicate, xs)).toBe("2");
|
|
36
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { max } from "../max";
|
|
2
|
+
|
|
3
|
+
describe("max", () => {
|
|
4
|
+
describe("for numbers", () => {
|
|
5
|
+
it("returns the first argument when it is greater", () => {
|
|
6
|
+
expect(max(10, 5)).toBe(10);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("returns the second argument when it is greater", () => {
|
|
10
|
+
expect(max(3, 7)).toBe(7);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("returns the same value when both arguments are equal", () => {
|
|
14
|
+
expect(max(4, 4)).toBe(4);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("works with negative numbers", () => {
|
|
18
|
+
expect(max(-2, -5)).toBe(-2);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("works when one argument is negative and the other is positive", () => {
|
|
22
|
+
expect(max(-10, 20)).toBe(20);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("works with zeros", () => {
|
|
26
|
+
expect(max(0, 0)).toBe(0);
|
|
27
|
+
expect(max(0, -1)).toBe(0);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("for letters", () => {
|
|
32
|
+
it("returns the second argument when it is greater", () => {
|
|
33
|
+
expect(max("a", "b")).toBe("b");
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { omit } from "../omit";
|
|
2
|
+
|
|
3
|
+
test("example 1", () => {
|
|
4
|
+
const path = ["a", "b", "c"];
|
|
5
|
+
const record = { a: 1, b: 2, c: 3 };
|
|
6
|
+
|
|
7
|
+
const output = {};
|
|
8
|
+
|
|
9
|
+
expect(omit(path, record)).toEqual(output);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("example 2", () => {
|
|
13
|
+
const path = ["a", "b"];
|
|
14
|
+
const record = { a: 1, b: 2, c: 3 };
|
|
15
|
+
|
|
16
|
+
const output = { c: 3 };
|
|
17
|
+
|
|
18
|
+
expect(omit(path, record)).toEqual(output);
|
|
19
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { path } from "../path";
|
|
2
|
+
|
|
3
|
+
test("example 1", () => {
|
|
4
|
+
const route = ["a", "b", "c"];
|
|
5
|
+
const xs = { a: { b: { c: 1 } } };
|
|
6
|
+
|
|
7
|
+
const output = 1;
|
|
8
|
+
|
|
9
|
+
expect(path(route, xs)).toEqual(output);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("example 2", () => {
|
|
13
|
+
const route = ["a", "b"];
|
|
14
|
+
const xs = { a: { b: { c: 1 } } };
|
|
15
|
+
|
|
16
|
+
const output = { c: 1 };
|
|
17
|
+
|
|
18
|
+
expect(path(route, xs)).toEqual(output);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("example 3", () => {
|
|
22
|
+
const route = ["a", "b", "x"];
|
|
23
|
+
const xs = { a: { b: { c: 1 } } };
|
|
24
|
+
|
|
25
|
+
expect(path(route, xs)).toBeUndefined();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("example 4", () => {
|
|
29
|
+
const route = ["a", "b", "c"];
|
|
30
|
+
const xs = undefined;
|
|
31
|
+
|
|
32
|
+
expect(path(route, xs)).toBeUndefined();
|
|
33
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { pathOr } from "../pathOr";
|
|
2
|
+
|
|
3
|
+
test("example 1", () => {
|
|
4
|
+
const defaultValue = "defaultValue";
|
|
5
|
+
const path = ["a", "b", "c"];
|
|
6
|
+
const xs = { a: { b: { c: 1 } } };
|
|
7
|
+
|
|
8
|
+
const output = 1;
|
|
9
|
+
|
|
10
|
+
expect(pathOr(defaultValue, path, xs)).toEqual(output);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("example 2", () => {
|
|
14
|
+
const defaultValue = "defaultValue";
|
|
15
|
+
const path = ["a", "b"];
|
|
16
|
+
const xs = { a: { b: { c: 1 } } };
|
|
17
|
+
|
|
18
|
+
const output = { c: 1 };
|
|
19
|
+
|
|
20
|
+
expect(pathOr(defaultValue, path, xs)).toEqual(output);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("example 3", () => {
|
|
24
|
+
const defaultValue = "defaultValue";
|
|
25
|
+
const path = ["a", "b", "x"];
|
|
26
|
+
const xs = { a: { b: { c: 1 } } };
|
|
27
|
+
|
|
28
|
+
expect(pathOr(defaultValue, path, xs)).toBe(defaultValue);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("example 4", () => {
|
|
32
|
+
const defaultValue = "defaultValue";
|
|
33
|
+
const path = ["a", "b", "c"];
|
|
34
|
+
const xs = undefined;
|
|
35
|
+
|
|
36
|
+
expect(pathOr(defaultValue, path, xs)).toBe(defaultValue);
|
|
37
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { startsWith } from "../startsWith";
|
|
2
|
+
|
|
3
|
+
describe("startsWith", () => {
|
|
4
|
+
it("returns false when str is null", () => {
|
|
5
|
+
expect(startsWith("a", null)).toBe(false);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it("returns false when str is undefined", () => {
|
|
9
|
+
expect(startsWith("a", undefined)).toBe(false);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("returns true when string starts with target", () => {
|
|
13
|
+
expect(startsWith("he", "hello")).toBe(true);
|
|
14
|
+
expect(startsWith("", "hello")).toBe(true); // empty target always matches
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("returns false when string does not start with target", () => {
|
|
18
|
+
expect(startsWith("yo", "hello")).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("works with single character target", () => {
|
|
22
|
+
expect(startsWith("h", "hello")).toBe(true);
|
|
23
|
+
expect(startsWith("x", "hello")).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("is case-sensitive", () => {
|
|
27
|
+
expect(startsWith("He", "hello")).toBe(false);
|
|
28
|
+
expect(startsWith("he", "hello")).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { take } from "../take";
|
|
2
|
+
|
|
3
|
+
describe("take", () => {
|
|
4
|
+
it("takes n elements from the beginning", () => {
|
|
5
|
+
expect(take(2, [1, 2, 3])).toEqual([1, 2]);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it("returns the whole array if n is larger than length", () => {
|
|
9
|
+
expect(take(5, [1, 2, 3])).toEqual([1, 2, 3]);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("returns empty array if n is 0", () => {
|
|
13
|
+
expect(take(0, [1, 2, 3])).toEqual([]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("returns empty array for empty input array", () => {
|
|
17
|
+
expect(take(2, [])).toEqual([]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("returns empty array if n is negative", () => {
|
|
21
|
+
expect(take(-1, [1, 2, 3])).toEqual([]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("works with strings in array", () => {
|
|
25
|
+
expect(take(2, ["a", "b", "c"])).toEqual(["a", "b"]);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("works with objects in array", () => {
|
|
29
|
+
const arr = [{ id: 1 }, { id: 2 }];
|
|
30
|
+
expect(take(1, arr)).toEqual([{ id: 1 }]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("returns empty array if input is not an array", () => {
|
|
34
|
+
// @ts-expect-error testing non-array input
|
|
35
|
+
expect(take(2, null)).toEqual([]);
|
|
36
|
+
|
|
37
|
+
// @ts-expect-error testing non-array input
|
|
38
|
+
expect(take(2, undefined)).toEqual([]);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { toLower } from "../toLower";
|
|
2
|
+
|
|
3
|
+
describe("toLower", () => {
|
|
4
|
+
it("converts mixed case string to lowercase", () => {
|
|
5
|
+
expect(toLower("--Foo-Bar--")).toBe("--foo-bar--");
|
|
6
|
+
expect(toLower("fooBar")).toBe("foobar");
|
|
7
|
+
expect(toLower("__FOO_BAR__")).toBe("__foo_bar__");
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("returns the same string if already lowercase", () => {
|
|
11
|
+
expect(toLower("hello")).toBe("hello");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("converts uppercase string to lowercase", () => {
|
|
15
|
+
expect(toLower("HELLO")).toBe("hello");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("handles empty string", () => {
|
|
19
|
+
expect(toLower("")).toBe("");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("converts string with numbers and symbols", () => {
|
|
23
|
+
expect(toLower("123-ABC-xyz")).toBe("123-abc-xyz");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("handles null and undefined gracefully", () => {
|
|
27
|
+
// @ts-expect-error testing null input
|
|
28
|
+
expect(toLower(null)).toBe("");
|
|
29
|
+
// @ts-expect-error testing undefined input
|
|
30
|
+
expect(toLower(undefined)).toBe("");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("coerces non-string values to string before lowercasing", () => {
|
|
34
|
+
// @ts-expect-error testing number input
|
|
35
|
+
expect(toLower(12345)).toBe("12345");
|
|
36
|
+
// @ts-expect-error testing boolean input
|
|
37
|
+
expect(toLower(true)).toBe("true");
|
|
38
|
+
});
|
|
39
|
+
});
|
package/utils/equals.ts
ADDED
package/utils/find.ts
ADDED
package/utils/index.ts
CHANGED
|
@@ -2,4 +2,40 @@ export { chunk } from "./chunk";
|
|
|
2
2
|
|
|
3
3
|
export { times } from "./times";
|
|
4
4
|
|
|
5
|
-
export {
|
|
5
|
+
export { startsWith } from "./startsWith";
|
|
6
|
+
|
|
7
|
+
export { find } from "./find";
|
|
8
|
+
|
|
9
|
+
export { pathOr } from "./pathOr";
|
|
10
|
+
|
|
11
|
+
export { path } from "./path";
|
|
12
|
+
|
|
13
|
+
export { omit } from "./omit";
|
|
14
|
+
|
|
15
|
+
export { endsWith } from "./endsWith";
|
|
16
|
+
|
|
17
|
+
export { max } from "./max";
|
|
18
|
+
|
|
19
|
+
export { equals } from "./equals";
|
|
20
|
+
|
|
21
|
+
export { take } from "./take";
|
|
22
|
+
|
|
23
|
+
export { toLower } from "./toLower";
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
cloneDeep as clone,
|
|
27
|
+
flatten,
|
|
28
|
+
drop,
|
|
29
|
+
size,
|
|
30
|
+
isNil,
|
|
31
|
+
isEmpty,
|
|
32
|
+
get,
|
|
33
|
+
has,
|
|
34
|
+
flatMap,
|
|
35
|
+
difference,
|
|
36
|
+
pick,
|
|
37
|
+
map,
|
|
38
|
+
trim,
|
|
39
|
+
toString,
|
|
40
|
+
last,
|
|
41
|
+
} from "lodash";
|
package/utils/max.ts
ADDED
package/utils/omit.ts
ADDED
package/utils/path.ts
ADDED
package/utils/pathOr.ts
ADDED
package/utils/take.ts
ADDED