@applicaster/zapp-react-native-utils 14.0.0-alpha.3514550494 → 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/analyticsUtils/playerAnalyticsTracker.ts +2 -1
- package/appUtils/accessibilityManager/const.ts +0 -13
- package/appUtils/accessibilityManager/hooks.ts +1 -35
- package/appUtils/accessibilityManager/index.ts +30 -151
- package/appUtils/focusManager/events.ts +2 -0
- package/appUtils/platform/platformUtils.ts +1 -31
- package/focusManager/FocusManager.ts +63 -4
- package/focusManager/aux/index.ts +167 -0
- package/focusManager/utils.ts +12 -6
- package/manifestUtils/defaultManifestConfigurations/player.js +2 -16
- package/navigationUtils/index.ts +1 -1
- package/package.json +2 -2
- package/playerUtils/getPlayerActionButtons.ts +1 -1
- package/reactHooks/feed/useLoadPipesDataDispatch.ts +7 -1
- package/screenPickerUtils/index.ts +6 -0
- package/utils/__tests__/endsWith.test.ts +30 -0
- package/utils/__tests__/equals.test.ts +65 -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__/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/index.ts +14 -1
- package/utils/max.ts +5 -0
- package/utils/omit.ts +5 -0
- package/utils/path.ts +5 -0
- package/utils/take.ts +5 -0
- package/utils/toLower.ts +5 -0
- package/appUtils/accessibilityManager/utils.ts +0 -24
- package/playerUtils/PlayerTTS/PlayerTTS.ts +0 -359
- package/playerUtils/PlayerTTS/index.ts +0 -1
- package/playerUtils/usePlayerTTS.ts +0 -21
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isNil,
|
|
3
|
+
startsWith,
|
|
4
|
+
find,
|
|
5
|
+
pathOr,
|
|
6
|
+
} from "@applicaster/zapp-react-native-utils/utils";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
QUICK_BRICK_CONTENT,
|
|
10
|
+
QUICK_BRICK_NAVBAR,
|
|
11
|
+
QUICK_BRICK_NAVBAR_SECTIONS,
|
|
12
|
+
} from "@applicaster/quick-brick-core/const";
|
|
13
|
+
|
|
14
|
+
const isNavBar = (node) => startsWith(QUICK_BRICK_NAVBAR, node?.id);
|
|
15
|
+
const isContent = (node) => startsWith(QUICK_BRICK_CONTENT, node?.id);
|
|
16
|
+
|
|
17
|
+
// SCREEN_PICKER_SELECTOR_CONTAINER(we assume there is only one SCREEN_PICKER)
|
|
18
|
+
let screenPickerSelectorContainerId;
|
|
19
|
+
|
|
20
|
+
export const onRegisterScreenPickerSelectorContainer = (id) => {
|
|
21
|
+
screenPickerSelectorContainerId = id;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const onUnregisterScreenPickerSelectorContainer = (id) => {
|
|
25
|
+
// reset screenSelectorId on unregistration
|
|
26
|
+
if (screenPickerSelectorContainerId === id) {
|
|
27
|
+
screenPickerSelectorContainerId = undefined;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
// SCREEN_PICKER_SELECTOR_CONTAINER
|
|
31
|
+
|
|
32
|
+
// SCREEN_PICKER_CONTENT_CONTAINER(we assume there is only one SCREEN_PICKER)
|
|
33
|
+
let screenPickerContentContainerId;
|
|
34
|
+
|
|
35
|
+
export const onRegisterScreenPickerContentContainer = (id) => {
|
|
36
|
+
screenPickerContentContainerId = id;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const onUnregisterScreenPickerContentContainer = (id) => {
|
|
40
|
+
// reset screenSelectorId on unregistration
|
|
41
|
+
if (screenPickerContentContainerId === id) {
|
|
42
|
+
screenPickerContentContainerId = undefined;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const isScreenPickerContentContainer = (node) =>
|
|
47
|
+
screenPickerContentContainerId === node?.id;
|
|
48
|
+
|
|
49
|
+
// SCREEN_PICKER_CONTENT_CONTAINER
|
|
50
|
+
|
|
51
|
+
const findSelectedMenuIdInSection = (focusableTree, section) => {
|
|
52
|
+
const children = pathOr([], ["children"], focusableTree.find(section));
|
|
53
|
+
|
|
54
|
+
return find((child) => child.component.current.props.isSelected(), children)
|
|
55
|
+
?.id;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const findSelectedMenuId = (focusableTree) => {
|
|
59
|
+
const selectedMenuItemIdInLeftSection = findSelectedMenuIdInSection(
|
|
60
|
+
focusableTree,
|
|
61
|
+
QUICK_BRICK_NAVBAR_SECTIONS.left
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (selectedMenuItemIdInLeftSection) {
|
|
65
|
+
return selectedMenuItemIdInLeftSection;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const selectedMenuItemIdInMenuSection = findSelectedMenuIdInSection(
|
|
69
|
+
focusableTree,
|
|
70
|
+
QUICK_BRICK_NAVBAR_SECTIONS.menu
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
if (selectedMenuItemIdInMenuSection) {
|
|
74
|
+
return selectedMenuItemIdInMenuSection;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const selectedMenuItemIdInRightSection = findSelectedMenuIdInSection(
|
|
78
|
+
focusableTree,
|
|
79
|
+
QUICK_BRICK_NAVBAR_SECTIONS.right
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
if (selectedMenuItemIdInRightSection) {
|
|
83
|
+
return selectedMenuItemIdInRightSection;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return undefined;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const findSelectedTabId = (focusableTree, item: ZappEntry): string => {
|
|
90
|
+
const screenSelectorContainerNode = focusableTree.find(
|
|
91
|
+
screenPickerSelectorContainerId
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const selectedTabId = find(
|
|
95
|
+
(child) => child.component.current.props.isSelected(item.id),
|
|
96
|
+
screenSelectorContainerNode.children
|
|
97
|
+
)?.id;
|
|
98
|
+
|
|
99
|
+
return selectedTabId;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const isTabsScreenContentFocused = (focusableTree, id) => {
|
|
103
|
+
const node = focusableTree.find(id);
|
|
104
|
+
|
|
105
|
+
if (isNil(node)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (isNavBar(node)) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (isContent(node)) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (isScreenPickerContentContainer(node)) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return isTabsScreenContentFocused(focusableTree, node.parentId);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const isCurrentFocusOnMenu = (focusableTree, id): boolean => {
|
|
125
|
+
const node = focusableTree.find(id);
|
|
126
|
+
|
|
127
|
+
if (isNil(node)) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (isNavBar(node)) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (isContent(node)) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return isCurrentFocusOnMenu(focusableTree, node.parentId);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const isCurrentFocusOnContent = (focusableTree, id) => {
|
|
143
|
+
const node = focusableTree.find(id);
|
|
144
|
+
|
|
145
|
+
if (isNil(node)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (isNavBar(node)) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (isContent(node)) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return isCurrentFocusOnContent(focusableTree, node.parentId);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const contextWithoutScrolling = (
|
|
161
|
+
source: FocusManager.FocusContext["source"]
|
|
162
|
+
): FocusManager.FocusContext => {
|
|
163
|
+
return {
|
|
164
|
+
source,
|
|
165
|
+
preserveScroll: true,
|
|
166
|
+
};
|
|
167
|
+
};
|
package/focusManager/utils.ts
CHANGED
|
@@ -4,11 +4,11 @@ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/he
|
|
|
4
4
|
|
|
5
5
|
export const getFocusableId = (ref) => ref?.current?.props.id;
|
|
6
6
|
|
|
7
|
-
type Direction = "up" | "down" | "left" | "right";
|
|
8
|
-
|
|
9
7
|
const normalizeDirection = (direction) => direction.toLowerCase();
|
|
10
8
|
|
|
11
|
-
const checkDirection = (
|
|
9
|
+
const checkDirection = (
|
|
10
|
+
direction: FocusManager.Android.FocusNavigationDirections
|
|
11
|
+
) => {
|
|
12
12
|
invariant(!isNilOrEmpty(direction), "direction should not be empty");
|
|
13
13
|
|
|
14
14
|
invariant(
|
|
@@ -17,19 +17,25 @@ const checkDirection = (direction: Direction) => {
|
|
|
17
17
|
);
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
export const toFocusDirection = (
|
|
20
|
+
export const toFocusDirection = (
|
|
21
|
+
direction: FocusManager.Android.FocusNavigationDirections
|
|
22
|
+
) => {
|
|
21
23
|
checkDirection(direction);
|
|
22
24
|
|
|
23
25
|
return `nextFocus${capitalize(normalizeDirection(direction))}`;
|
|
24
26
|
};
|
|
25
27
|
|
|
26
|
-
export const isHorizontalDirection = (
|
|
28
|
+
export const isHorizontalDirection = (
|
|
29
|
+
direction: FocusManager.Android.FocusNavigationDirections
|
|
30
|
+
) => {
|
|
27
31
|
checkDirection(direction);
|
|
28
32
|
|
|
29
33
|
return ["left", "right"].includes(normalizeDirection(direction));
|
|
30
34
|
};
|
|
31
35
|
|
|
32
|
-
export const isVerticalDirection = (
|
|
36
|
+
export const isVerticalDirection = (
|
|
37
|
+
direction: FocusManager.Android.FocusNavigationDirections
|
|
38
|
+
) => {
|
|
33
39
|
checkDirection(direction);
|
|
34
40
|
|
|
35
41
|
return ["up", "down"].includes(normalizeDirection(direction));
|
|
@@ -208,7 +208,7 @@ function getPlayerConfiguration({ platform, version }) {
|
|
|
208
208
|
{
|
|
209
209
|
key: "accessibility_forward_label",
|
|
210
210
|
label: "Accessibility forward label",
|
|
211
|
-
initial_value: "
|
|
211
|
+
initial_value: "Forward button",
|
|
212
212
|
label_tooltip: "Label for forward button accessibility",
|
|
213
213
|
type: "text_input",
|
|
214
214
|
},
|
|
@@ -292,7 +292,7 @@ function getPlayerConfiguration({ platform, version }) {
|
|
|
292
292
|
{
|
|
293
293
|
key: "accessibility_back_label",
|
|
294
294
|
label: "Accessibility back label",
|
|
295
|
-
initial_value: "
|
|
295
|
+
initial_value: "Back button",
|
|
296
296
|
label_tooltip: "Label for back button accessibility",
|
|
297
297
|
type: "text_input",
|
|
298
298
|
},
|
|
@@ -317,20 +317,6 @@ function getPlayerConfiguration({ platform, version }) {
|
|
|
317
317
|
label_tooltip: "Hint for fullscreen button accessibility",
|
|
318
318
|
type: "text_input",
|
|
319
319
|
},
|
|
320
|
-
{
|
|
321
|
-
key: "accessibility_skip_intro_label",
|
|
322
|
-
label: "Accessibility skip intro label",
|
|
323
|
-
initial_value: "Skip intro - button",
|
|
324
|
-
label_tooltip: "Label for skip intro button accessibility",
|
|
325
|
-
type: "text_input",
|
|
326
|
-
},
|
|
327
|
-
{
|
|
328
|
-
key: "accessibility_skip_intro_hint",
|
|
329
|
-
label: "Accessibility skip intro hint",
|
|
330
|
-
initial_value: "Press to skip intro",
|
|
331
|
-
label_tooltip: "Hint for skip intro button accessibility",
|
|
332
|
-
type: "text_input",
|
|
333
|
-
},
|
|
334
320
|
],
|
|
335
321
|
};
|
|
336
322
|
|
package/navigationUtils/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "14.0.0-alpha.
|
|
3
|
+
"version": "14.0.0-alpha.3652810444",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@applicaster/applicaster-types": "14.0.0-alpha.
|
|
30
|
+
"@applicaster/applicaster-types": "14.0.0-alpha.3652810444",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
@@ -30,7 +30,13 @@ export const useLoadPipesDataDispatch = () => {
|
|
|
30
30
|
return React.useCallback(
|
|
31
31
|
(
|
|
32
32
|
url: string,
|
|
33
|
-
options
|
|
33
|
+
options: {
|
|
34
|
+
callback?: (data: unknown, error?: Error | null | undefined) => void;
|
|
35
|
+
riverId?: string;
|
|
36
|
+
clearCache?: boolean;
|
|
37
|
+
silentRefresh?: boolean;
|
|
38
|
+
parentFeed?: string;
|
|
39
|
+
} = {},
|
|
34
40
|
{
|
|
35
41
|
withResolvers = false,
|
|
36
42
|
withScreenRouteMapping = false,
|
|
@@ -5,3 +5,9 @@ export const getPickerSelectorId = (id) => `PickerSelector.${id}`;
|
|
|
5
5
|
export const SCREEN_PICKER_CONTAINER = "ScreenPickerContainer";
|
|
6
6
|
|
|
7
7
|
export const getScreenPickerId = (id) => `${SCREEN_PICKER_CONTAINER}.${id}`;
|
|
8
|
+
|
|
9
|
+
export const getScreenPickerSelectorContainerId = (id) =>
|
|
10
|
+
`${SCREEN_PICKER_CONTAINER}.${id}-screen-selector`;
|
|
11
|
+
|
|
12
|
+
export const getScreenPickerContentContainerId = (id) =>
|
|
13
|
+
`${SCREEN_PICKER_CONTAINER}.${id}-screen-container`;
|
|
@@ -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 { 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,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/index.ts
CHANGED
|
@@ -8,6 +8,20 @@ export { find } from "./find";
|
|
|
8
8
|
|
|
9
9
|
export { pathOr } from "./pathOr";
|
|
10
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
|
+
|
|
11
25
|
export {
|
|
12
26
|
cloneDeep as clone,
|
|
13
27
|
flatten,
|
|
@@ -19,7 +33,6 @@ export {
|
|
|
19
33
|
has,
|
|
20
34
|
flatMap,
|
|
21
35
|
difference,
|
|
22
|
-
take,
|
|
23
36
|
pick,
|
|
24
37
|
map,
|
|
25
38
|
trim,
|
package/utils/max.ts
ADDED
package/utils/omit.ts
ADDED
package/utils/path.ts
ADDED
package/utils/take.ts
ADDED