@startinblox/components-ds4go 2.2.4 → 3.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/.gitlab-ci.yml +8 -2
- package/AGENTS.md +516 -0
- package/cypress/component/no-component-test.cy.ts +9 -0
- package/cypress/e2e/helpers/components/setupCacheInvalidation.cy.ts +512 -0
- package/cypress/e2e/helpers/components/setupCacheOnResourceReady.cy.ts +483 -0
- package/cypress/e2e/helpers/components/setupComponentSubscriptions.cy.ts +239 -0
- package/cypress/e2e/helpers/components/setupOnSaveReset.cy.ts +380 -0
- package/cypress/e2e/helpers/datas/checkValueInIntervalRecursive.cy.ts +563 -0
- package/cypress/e2e/helpers/datas/dataBuilder.cy.ts +508 -0
- package/cypress/e2e/helpers/datas/filterGenerator.cy.ts +285 -0
- package/cypress/e2e/helpers/datas/filterObjectByDateAfter.cy.ts +389 -0
- package/cypress/e2e/helpers/datas/filterObjectByDateInterval.cy.ts +613 -0
- package/cypress/e2e/helpers/datas/filterObjectById.cy.ts +276 -0
- package/cypress/e2e/helpers/datas/filterObjectByInterval.cy.ts +237 -0
- package/cypress/e2e/helpers/datas/filterObjectByNamedValue.cy.ts +299 -0
- package/cypress/e2e/helpers/datas/filterObjectByType.cy.ts +307 -0
- package/cypress/e2e/helpers/datas/filterObjectByValue.cy.ts +375 -0
- package/cypress/e2e/helpers/datas/sort.cy.ts +293 -0
- package/cypress/e2e/helpers/ui/formatDate.cy.ts +233 -0
- package/cypress/e2e/helpers/utils/requestNavigation.cy.ts +257 -0
- package/cypress/e2e/helpers/utils/uniq.cy.ts +160 -0
- package/cypress/support/e2e.ts +1 -0
- package/cypress.config.ts +2 -0
- package/dist/index.js +932 -734
- package/locales/en.xlf +75 -0
- package/package.json +10 -10
- package/src/components/solid-boilerplate.ts +76 -0
- package/src/components/solid-fact-bundle-creation.ts +202 -59
- package/src/helpers/components/componentObjectHandler.ts +5 -7
- package/src/helpers/components/componentObjectsHandler.ts +8 -3
- package/src/helpers/components/orbitComponent.ts +87 -68
- package/src/helpers/components/setupCacheInvalidation.ts +50 -23
- package/src/helpers/components/setupCacheOnResourceReady.ts +42 -23
- package/src/helpers/components/setupComponentSubscriptions.ts +10 -9
- package/src/helpers/components/setupOnSaveReset.ts +27 -5
- package/src/helpers/datas/checkValueInIntervalRecursive.ts +66 -0
- package/src/helpers/datas/dataBuilder.ts +4 -4
- package/src/helpers/datas/filterGenerator.ts +13 -10
- package/src/helpers/datas/filterObjectByDateAfter.ts +3 -3
- package/src/helpers/datas/filterObjectByDateInterval.ts +44 -0
- package/src/helpers/datas/filterObjectById.ts +7 -6
- package/src/helpers/datas/filterObjectByInterval.ts +6 -110
- package/src/helpers/datas/filterObjectByNamedValue.ts +35 -33
- package/src/helpers/datas/filterObjectByType.ts +3 -3
- package/src/helpers/datas/filterObjectByValue.ts +17 -16
- package/src/helpers/datas/sort.ts +50 -23
- package/src/helpers/index.ts +2 -0
- package/src/helpers/ui/formatDate.ts +14 -1
- package/src/helpers/utils/requestNavigation.ts +5 -2
- package/src/helpers/utils/uniq.ts +1 -1
- package/src/styles/fact-bundle-creation.scss +102 -0
- package/cypress/component/solid-boilerplate.cy.ts +0 -9
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import filterObjectByNamedValue from "@helpers/datas/filterObjectByNamedValue";
|
|
2
|
+
|
|
3
|
+
describe("filterObjectByNamedValue helper function", () => {
|
|
4
|
+
describe("Basic functionality", () => {
|
|
5
|
+
it("should filter objects by property value matching search string", () => {
|
|
6
|
+
const objects = [
|
|
7
|
+
{ name: "Alice Johnson", age: 30 },
|
|
8
|
+
{ name: "Bob Smith", age: 25 },
|
|
9
|
+
{ name: "Charlie Brown", age: 35 },
|
|
10
|
+
];
|
|
11
|
+
const result = filterObjectByNamedValue(objects, "name", "alice");
|
|
12
|
+
expect(result).to.have.length(1);
|
|
13
|
+
expect(result[0].name).to.equal("Alice Johnson");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should return all objects when propName is empty", () => {
|
|
17
|
+
const objects = [{ name: "Alice" }, { name: "Bob" }];
|
|
18
|
+
const result = filterObjectByNamedValue(objects, "", "alice");
|
|
19
|
+
expect(result).to.have.length(2);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should return all objects when searchString is empty", () => {
|
|
23
|
+
const objects = [{ name: "Alice" }, { name: "Bob" }];
|
|
24
|
+
const result = filterObjectByNamedValue(objects, "name", "");
|
|
25
|
+
expect(result).to.have.length(2);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should return all objects when searchString is only whitespace", () => {
|
|
29
|
+
const objects = [{ name: "Alice" }, { name: "Bob" }];
|
|
30
|
+
const result = filterObjectByNamedValue(objects, "name", " ");
|
|
31
|
+
expect(result).to.have.length(2);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should return empty array when no match found", () => {
|
|
35
|
+
const objects = [{ name: "Alice" }, { name: "Bob" }];
|
|
36
|
+
const result = filterObjectByNamedValue(objects, "name", "xyz");
|
|
37
|
+
expect(result).to.have.length(0);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("Search scoring", () => {
|
|
42
|
+
it("should prioritize whole word matches", () => {
|
|
43
|
+
const objects = [
|
|
44
|
+
{ name: "Alice" },
|
|
45
|
+
{ name: "Alice Johnson" },
|
|
46
|
+
{ name: "Alice Wonderland" },
|
|
47
|
+
{ name: "Alicia" },
|
|
48
|
+
];
|
|
49
|
+
const result = filterObjectByNamedValue(objects, "name", "alice");
|
|
50
|
+
expect(result).to.have.length(3);
|
|
51
|
+
expect(result[0].name).to.equal("Alice");
|
|
52
|
+
expect(result[1].name).to.equal("Alice Johnson");
|
|
53
|
+
expect(result[2].name).to.equal("Alice Wonderland");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should score partial matches lower than whole word matches", () => {
|
|
57
|
+
const objects = [{ name: "Alice Wonderland" }, { name: "Bob" }];
|
|
58
|
+
const result = filterObjectByNamedValue(objects, "name", "alice");
|
|
59
|
+
expect(result).to.have.length(1);
|
|
60
|
+
expect(result[0].name).to.equal("Alice Wonderland");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should sort results by relevance score descending", () => {
|
|
64
|
+
const objects = [
|
|
65
|
+
{ name: "Alice" },
|
|
66
|
+
{ name: "Alice Wonderland" },
|
|
67
|
+
{ name: "Bob Alice" },
|
|
68
|
+
];
|
|
69
|
+
const result = filterObjectByNamedValue(objects, "name", "alice");
|
|
70
|
+
expect(result[0].name).to.equal("Alice");
|
|
71
|
+
expect(result[1].name).to.equal("Alice Wonderland");
|
|
72
|
+
expect(result[2].name).to.equal("Bob Alice");
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe("Case sensitivity", () => {
|
|
77
|
+
it("should be case insensitive", () => {
|
|
78
|
+
const objects = [{ name: "Alice" }, { name: "BOB" }, { name: "Charlie" }];
|
|
79
|
+
const result = filterObjectByNamedValue(objects, "name", "alice");
|
|
80
|
+
expect(result).to.have.length(1);
|
|
81
|
+
expect(result[0].name).to.equal("Alice");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should match uppercase search with lowercase data", () => {
|
|
85
|
+
const objects = [{ name: "alice" }, { name: "bob" }];
|
|
86
|
+
const result = filterObjectByNamedValue(objects, "name", "ALICE");
|
|
87
|
+
expect(result).to.have.length(1);
|
|
88
|
+
expect(result[0].name).to.equal("alice");
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe("Nested property handling", () => {
|
|
93
|
+
it("should filter by nested property using dot notation", () => {
|
|
94
|
+
const objects = [
|
|
95
|
+
{ name: "Alice", profile: { bio: "Software engineer" } },
|
|
96
|
+
{ name: "Bob", profile: { bio: "Designer" } },
|
|
97
|
+
{ name: "Charlie", profile: { bio: "Software developer" } },
|
|
98
|
+
];
|
|
99
|
+
const result = filterObjectByNamedValue(
|
|
100
|
+
objects,
|
|
101
|
+
"profile.bio",
|
|
102
|
+
"software",
|
|
103
|
+
);
|
|
104
|
+
expect(result).to.have.length(2);
|
|
105
|
+
expect(result.map((r) => r.name)).to.deep.equal(["Alice", "Charlie"]);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should filter by deeply nested property", () => {
|
|
109
|
+
const objects = [
|
|
110
|
+
{ name: "Alice", user: { profile: { bio: "Software engineer" } } },
|
|
111
|
+
{ name: "Bob", user: { profile: { bio: "Designer" } } },
|
|
112
|
+
];
|
|
113
|
+
const result = filterObjectByNamedValue(
|
|
114
|
+
objects,
|
|
115
|
+
"user.profile.bio",
|
|
116
|
+
"software",
|
|
117
|
+
);
|
|
118
|
+
expect(result).to.have.length(1);
|
|
119
|
+
expect(result[0].name).to.equal("Alice");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should return empty array when nested property does not exist", () => {
|
|
123
|
+
const objects = [
|
|
124
|
+
{ name: "Alice", profile: { bio: "Software" } },
|
|
125
|
+
{ name: "Bob", profile: { bio: "Designer" } },
|
|
126
|
+
];
|
|
127
|
+
const result = filterObjectByNamedValue(
|
|
128
|
+
objects,
|
|
129
|
+
"nonexistent.property",
|
|
130
|
+
"software",
|
|
131
|
+
);
|
|
132
|
+
expect(result).to.have.length(0);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe("Recursive search within property", () => {
|
|
137
|
+
it("should search recursively within nested objects", () => {
|
|
138
|
+
const objects = [
|
|
139
|
+
{
|
|
140
|
+
name: "Alice",
|
|
141
|
+
profile: { bio: "Software engineer with Python experience" },
|
|
142
|
+
},
|
|
143
|
+
{ name: "Bob", profile: { bio: "Designer" } },
|
|
144
|
+
];
|
|
145
|
+
const result = filterObjectByNamedValue(objects, "profile", "python");
|
|
146
|
+
expect(result).to.have.length(1);
|
|
147
|
+
expect(result[0].name).to.equal("Alice");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("should search recursively within arrays", () => {
|
|
151
|
+
const objects = [
|
|
152
|
+
{ name: "Alice", skills: ["Python", "JavaScript"] },
|
|
153
|
+
{ name: "Bob", skills: ["Java", "C++"] },
|
|
154
|
+
];
|
|
155
|
+
const result = filterObjectByNamedValue(objects, "skills", "python");
|
|
156
|
+
expect(result).to.have.length(1);
|
|
157
|
+
expect(result[0].name).to.equal("Alice");
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("should search recursively within array of objects", () => {
|
|
161
|
+
const objects = [
|
|
162
|
+
{ name: "Alice", skills: [{ name: "Python" }, { name: "JavaScript" }] },
|
|
163
|
+
{ name: "Bob", skills: [{ name: "Java" }, { name: "C++" }] },
|
|
164
|
+
];
|
|
165
|
+
const result = filterObjectByNamedValue(objects, "skills", "python");
|
|
166
|
+
expect(result).to.have.length(1);
|
|
167
|
+
expect(result[0].name).to.equal("Alice");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should find match at any depth in nested structure", () => {
|
|
171
|
+
const objects = [
|
|
172
|
+
{ name: "Alice", data: { level1: { level2: { level3: "Python" } } } },
|
|
173
|
+
{ name: "Bob", data: { level1: { level2: { level3: "Java" } } } },
|
|
174
|
+
];
|
|
175
|
+
const result = filterObjectByNamedValue(objects, "data", "python");
|
|
176
|
+
expect(result).to.have.length(1);
|
|
177
|
+
expect(result[0].name).to.equal("Alice");
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe("Special characters in search", () => {
|
|
182
|
+
it("should handle regex special characters in search string", () => {
|
|
183
|
+
const objects = [{ name: "C++ Developer" }, { name: "Java Developer" }];
|
|
184
|
+
const result = filterObjectByNamedValue(objects, "name", "c++");
|
|
185
|
+
expect(result).to.have.length(1);
|
|
186
|
+
expect(result[0].name).to.equal("C++ Developer");
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it("should handle dots in search string", () => {
|
|
190
|
+
const objects = [{ name: "version.1.0" }, { name: "version.2.0" }];
|
|
191
|
+
const result = filterObjectByNamedValue(objects, "name", "version.1");
|
|
192
|
+
expect(result).to.have.length(1);
|
|
193
|
+
expect(result[0].name).to.equal("version.1.0");
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("should handle asterisks in search string", () => {
|
|
197
|
+
const objects = [{ name: "item*1" }, { name: "item*2" }];
|
|
198
|
+
const result = filterObjectByNamedValue(objects, "name", "item*1");
|
|
199
|
+
expect(result).to.have.length(1);
|
|
200
|
+
expect(result[0].name).to.equal("item*1");
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
describe("Edge cases", () => {
|
|
205
|
+
it("should handle empty array", () => {
|
|
206
|
+
const result = filterObjectByNamedValue([], "name", "test");
|
|
207
|
+
expect(result).to.deep.equal([]);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("should handle objects with null property", () => {
|
|
211
|
+
const objects = [{ name: null }, { name: "Alice" }];
|
|
212
|
+
const result = filterObjectByNamedValue(objects, "name", "alice");
|
|
213
|
+
expect(result).to.have.length(1);
|
|
214
|
+
expect(result[0].name).to.equal("Alice");
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("should handle objects with undefined property", () => {
|
|
218
|
+
const objects = [{ name: undefined }, { name: "Alice" }];
|
|
219
|
+
const result = filterObjectByNamedValue(objects, "name", "alice");
|
|
220
|
+
expect(result).to.have.length(1);
|
|
221
|
+
expect(result[0].name).to.equal("Alice");
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("should handle property value that is number", () => {
|
|
225
|
+
const objects = [
|
|
226
|
+
{ name: "Alice", score: 100 },
|
|
227
|
+
{ name: "Bob", score: 200 },
|
|
228
|
+
];
|
|
229
|
+
const result = filterObjectByNamedValue(objects, "score", "100");
|
|
230
|
+
expect(result).to.have.length(1);
|
|
231
|
+
expect(result[0].name).to.equal("Alice");
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("should handle property value that is boolean", () => {
|
|
235
|
+
const objects = [
|
|
236
|
+
{ name: "Alice", active: true },
|
|
237
|
+
{ name: "Bob", active: false },
|
|
238
|
+
];
|
|
239
|
+
const result = filterObjectByNamedValue(objects, "active", "true");
|
|
240
|
+
expect(result).to.have.length(1);
|
|
241
|
+
expect(result[0].name).to.equal("Alice");
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe("Mixed data types", () => {
|
|
246
|
+
it("should search through mixed types in nested structure", () => {
|
|
247
|
+
const objects = [
|
|
248
|
+
{
|
|
249
|
+
name: "Alice",
|
|
250
|
+
data: { mixed: ["text", 123, true, { nested: "match" }] },
|
|
251
|
+
},
|
|
252
|
+
{ name: "Bob", data: { mixed: ["other", 456] } },
|
|
253
|
+
];
|
|
254
|
+
const result = filterObjectByNamedValue(objects, "data.mixed", "match");
|
|
255
|
+
expect(result).to.have.length(1);
|
|
256
|
+
expect(result[0].name).to.equal("Alice");
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
describe("Real-world scenarios", () => {
|
|
261
|
+
it("should filter users by name", () => {
|
|
262
|
+
const users = [
|
|
263
|
+
{ "@id": "/user/1", name: "Alice Johnson" },
|
|
264
|
+
{ "@id": "/user/2", name: "Bob Smith" },
|
|
265
|
+
{ "@id": "/user/3", name: "Alice Williams" },
|
|
266
|
+
];
|
|
267
|
+
const result = filterObjectByNamedValue(users, "name", "alice");
|
|
268
|
+
expect(result).to.have.length(2);
|
|
269
|
+
expect(result[0].name).to.equal("Alice Johnson");
|
|
270
|
+
expect(result[1].name).to.equal("Alice Williams");
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("should filter projects by description", () => {
|
|
274
|
+
const projects = [
|
|
275
|
+
{
|
|
276
|
+
"@id": "/project/1",
|
|
277
|
+
name: "Website",
|
|
278
|
+
description: "E-commerce platform",
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"@id": "/project/2",
|
|
282
|
+
name: "Mobile App",
|
|
283
|
+
description: "iOS and Android",
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"@id": "/project/3",
|
|
287
|
+
name: "API",
|
|
288
|
+
description: "REST API for platform",
|
|
289
|
+
},
|
|
290
|
+
];
|
|
291
|
+
const result = filterObjectByNamedValue(
|
|
292
|
+
projects,
|
|
293
|
+
"description",
|
|
294
|
+
"platform",
|
|
295
|
+
);
|
|
296
|
+
expect(result).to.have.length(2);
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
});
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import filterObjectByType from "@helpers/datas/filterObjectByType";
|
|
2
|
+
|
|
3
|
+
describe("filterObjectByType helper function", () => {
|
|
4
|
+
describe("Basic functionality", () => {
|
|
5
|
+
it("should filter objects by @type property", () => {
|
|
6
|
+
const objects = [
|
|
7
|
+
{ "@id": "/resource/1", "@type": "User", name: "Alice" },
|
|
8
|
+
{ "@id": "/resource/2", "@type": "Project", name: "Website" },
|
|
9
|
+
{ "@id": "/resource/3", "@type": "User", name: "Bob" },
|
|
10
|
+
];
|
|
11
|
+
const result = filterObjectByType(objects, "User");
|
|
12
|
+
expect(result).to.have.length(2);
|
|
13
|
+
expect(result.map((r) => r.name)).to.deep.equal(["Alice", "Bob"]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should return all objects when targetType is empty", () => {
|
|
17
|
+
const objects = [
|
|
18
|
+
{ "@id": "/resource/1", "@type": "User", name: "Alice" },
|
|
19
|
+
{ "@id": "/resource/2", "@type": "Project", name: "Website" },
|
|
20
|
+
];
|
|
21
|
+
const result = filterObjectByType(objects, "");
|
|
22
|
+
expect(result).to.have.length(2);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should return empty array when no match found", () => {
|
|
26
|
+
const objects = [
|
|
27
|
+
{ "@id": "/resource/1", "@type": "User", name: "Alice" },
|
|
28
|
+
{ "@id": "/resource/2", "@type": "Project", name: "Website" },
|
|
29
|
+
];
|
|
30
|
+
const result = filterObjectByType(objects, "Task");
|
|
31
|
+
expect(result).to.have.length(0);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe("Array @type handling", () => {
|
|
36
|
+
it("should filter objects with @type as an array", () => {
|
|
37
|
+
const objects = [
|
|
38
|
+
{ "@id": "/resource/1", "@type": ["User", "Admin"], name: "Alice" },
|
|
39
|
+
{ "@id": "/resource/2", "@type": ["Project"], name: "Website" },
|
|
40
|
+
{ "@id": "/resource/3", "@type": ["User", "Member"], name: "Bob" },
|
|
41
|
+
];
|
|
42
|
+
const result = filterObjectByType(objects, "User");
|
|
43
|
+
expect(result).to.have.length(2);
|
|
44
|
+
expect(result.map((r) => r.name)).to.deep.equal(["Alice", "Bob"]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should match any type in the array", () => {
|
|
48
|
+
const objects = [
|
|
49
|
+
{ "@id": "/resource/1", "@type": ["User", "Admin"], name: "Alice" },
|
|
50
|
+
{ "@id": "/resource/2", "@type": ["Project"], name: "Website" },
|
|
51
|
+
];
|
|
52
|
+
const result = filterObjectByType(objects, "Admin");
|
|
53
|
+
expect(result).to.have.length(1);
|
|
54
|
+
expect(result[0].name).to.equal("Alice");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should return empty array when target type not in any array", () => {
|
|
58
|
+
const objects = [
|
|
59
|
+
{ "@id": "/resource/1", "@type": ["User", "Admin"], name: "Alice" },
|
|
60
|
+
{ "@id": "/resource/2", "@type": ["Project"], name: "Website" },
|
|
61
|
+
];
|
|
62
|
+
const result = filterObjectByType(objects, "Task");
|
|
63
|
+
expect(result).to.have.length(0);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should handle arrays with multiple types", () => {
|
|
67
|
+
const objects = [
|
|
68
|
+
{
|
|
69
|
+
"@id": "/resource/1",
|
|
70
|
+
"@type": ["User", "Admin", "Moderator"],
|
|
71
|
+
name: "Alice",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"@id": "/resource/2",
|
|
75
|
+
"@type": ["Project", "Active"],
|
|
76
|
+
name: "Website",
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
const result = filterObjectByType(objects, "Moderator");
|
|
80
|
+
expect(result).to.have.length(1);
|
|
81
|
+
expect(result[0].name).to.equal("Alice");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should handle arrays with duplicate types", () => {
|
|
85
|
+
const objects = [
|
|
86
|
+
{ "@id": "/resource/1", "@type": ["User", "User"], name: "Alice" },
|
|
87
|
+
{ "@id": "/resource/2", "@type": ["Project"], name: "Website" },
|
|
88
|
+
];
|
|
89
|
+
const result = filterObjectByType(objects, "User");
|
|
90
|
+
expect(result).to.have.length(1);
|
|
91
|
+
expect(result[0].name).to.equal("Alice");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("String @type handling", () => {
|
|
96
|
+
it("should filter objects with @type as a string", () => {
|
|
97
|
+
const objects = [
|
|
98
|
+
{ "@id": "/resource/1", "@type": "User", name: "Alice" },
|
|
99
|
+
{ "@id": "/resource/2", "@type": "Project", name: "Website" },
|
|
100
|
+
{ "@id": "/resource/3", "@type": "User", name: "Bob" },
|
|
101
|
+
];
|
|
102
|
+
const result = filterObjectByType(objects, "User");
|
|
103
|
+
expect(result).to.have.length(2);
|
|
104
|
+
expect(result.map((r) => r.name)).to.deep.equal(["Alice", "Bob"]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should match exact string type", () => {
|
|
108
|
+
const objects = [
|
|
109
|
+
{ "@id": "/resource/1", "@type": "User", name: "Alice" },
|
|
110
|
+
{ "@id": "/resource/2", "@type": "UserAdmin", name: "Bob" },
|
|
111
|
+
];
|
|
112
|
+
const result = filterObjectByType(objects, "User");
|
|
113
|
+
expect(result).to.have.length(1);
|
|
114
|
+
expect(result[0].name).to.equal("Alice");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should be case sensitive", () => {
|
|
118
|
+
const objects = [
|
|
119
|
+
{ "@id": "/resource/1", "@type": "User", name: "Alice" },
|
|
120
|
+
{ "@id": "/resource/2", "@type": "user", name: "Bob" },
|
|
121
|
+
];
|
|
122
|
+
const result = filterObjectByType(objects, "User");
|
|
123
|
+
expect(result).to.have.length(1);
|
|
124
|
+
expect(result[0].name).to.equal("Alice");
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe("Edge cases", () => {
|
|
129
|
+
it("should handle empty array", () => {
|
|
130
|
+
const result = filterObjectByType([], "User");
|
|
131
|
+
expect(result).to.deep.equal([]);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("should handle objects without @type property", () => {
|
|
135
|
+
const objects = [
|
|
136
|
+
{ "@id": "/resource/1", name: "Alice" },
|
|
137
|
+
{ "@id": "/resource/2", "@type": "User", name: "Bob" },
|
|
138
|
+
];
|
|
139
|
+
const result = filterObjectByType(objects, "User");
|
|
140
|
+
expect(result).to.have.length(1);
|
|
141
|
+
expect(result[0].name).to.equal("Bob");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("should handle objects with null @type", () => {
|
|
145
|
+
const objects = [
|
|
146
|
+
{ "@id": "/resource/1", "@type": null, name: "Alice" },
|
|
147
|
+
{ "@id": "/resource/2", "@type": "User", name: "Bob" },
|
|
148
|
+
];
|
|
149
|
+
const result = filterObjectByType(objects, "User");
|
|
150
|
+
expect(result).to.have.length(1);
|
|
151
|
+
expect(result[0].name).to.equal("Bob");
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should handle objects with undefined @type", () => {
|
|
155
|
+
const objects = [
|
|
156
|
+
{ "@id": "/resource/1", "@type": undefined, name: "Alice" },
|
|
157
|
+
{ "@id": "/resource/2", "@type": "User", name: "Bob" },
|
|
158
|
+
];
|
|
159
|
+
const result = filterObjectByType(objects, "User");
|
|
160
|
+
expect(result).to.have.length(1);
|
|
161
|
+
expect(result[0].name).to.equal("Bob");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("should handle empty array @type", () => {
|
|
165
|
+
const objects = [
|
|
166
|
+
{ "@id": "/resource/1", "@type": [], name: "Alice" },
|
|
167
|
+
{ "@id": "/resource/2", "@type": ["User"], name: "Bob" },
|
|
168
|
+
];
|
|
169
|
+
const result = filterObjectByType(objects, "User");
|
|
170
|
+
expect(result).to.have.length(1);
|
|
171
|
+
expect(result[0].name).to.equal("Bob");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("should handle objects with non-string/non-array @type", () => {
|
|
175
|
+
const objects = [
|
|
176
|
+
{ "@id": "/resource/1", "@type": 123 as any, name: "Alice" },
|
|
177
|
+
{ "@id": "/resource/2", "@type": "User", name: "Bob" },
|
|
178
|
+
];
|
|
179
|
+
const result = filterObjectByType(objects, "User");
|
|
180
|
+
expect(result).to.have.length(1);
|
|
181
|
+
expect(result[0].name).to.equal("Bob");
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("should handle mixed @type types (string and array)", () => {
|
|
185
|
+
const objects = [
|
|
186
|
+
{ "@id": "/resource/1", "@type": "User", name: "Alice" },
|
|
187
|
+
{ "@id": "/resource/2", "@type": ["User", "Admin"], name: "Bob" },
|
|
188
|
+
{ "@id": "/resource/3", "@type": "Project", name: "Website" },
|
|
189
|
+
];
|
|
190
|
+
const result = filterObjectByType(objects, "User");
|
|
191
|
+
expect(result).to.have.length(2);
|
|
192
|
+
expect(result.map((r) => r.name)).to.deep.equal(["Alice", "Bob"]);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe("Real-world scenarios", () => {
|
|
197
|
+
it("should filter resources by JSON-LD type", () => {
|
|
198
|
+
const resources = [
|
|
199
|
+
{ "@id": "/user/1", "@type": "foaf:Person", name: "Alice" },
|
|
200
|
+
{ "@id": "/project/1", "@type": "doap:Project", name: "Website" },
|
|
201
|
+
{ "@id": "/user/2", "@type": "foaf:Person", name: "Bob" },
|
|
202
|
+
{ "@id": "/task/1", "@type": "schema:Task", name: "Design" },
|
|
203
|
+
];
|
|
204
|
+
const result = filterObjectByType(resources, "foaf:Person");
|
|
205
|
+
expect(result).to.have.length(2);
|
|
206
|
+
expect(result.map((r) => r.name)).to.deep.equal(["Alice", "Bob"]);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("should filter by common RDF types", () => {
|
|
210
|
+
const objects = [
|
|
211
|
+
{ "@id": "/1", "@type": "http://schema.org/Person", name: "Alice" },
|
|
212
|
+
{
|
|
213
|
+
"@id": "/2",
|
|
214
|
+
"@type": "http://schema.org/Organization",
|
|
215
|
+
name: "Company",
|
|
216
|
+
},
|
|
217
|
+
{ "@id": "/3", "@type": "http://schema.org/Person", name: "Bob" },
|
|
218
|
+
];
|
|
219
|
+
const result = filterObjectByType(objects, "http://schema.org/Person");
|
|
220
|
+
expect(result).to.have.length(2);
|
|
221
|
+
expect(result.map((r) => r.name)).to.deep.equal(["Alice", "Bob"]);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("should filter multi-typed resources", () => {
|
|
225
|
+
const resources = [
|
|
226
|
+
{ "@id": "/1", "@type": ["User", "Admin"], name: "Super Admin" },
|
|
227
|
+
{ "@id": "/2", "@type": ["User"], name: "Regular User" },
|
|
228
|
+
{ "@id": "/3", "@type": ["User", "Moderator"], name: "Moderator" },
|
|
229
|
+
];
|
|
230
|
+
const result = filterObjectByType(resources, "User");
|
|
231
|
+
expect(result).to.have.length(3);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
describe("Multiple matching", () => {
|
|
236
|
+
it("should return all matching objects", () => {
|
|
237
|
+
const objects = [
|
|
238
|
+
{ "@id": "/1", "@type": "User", name: "Alice" },
|
|
239
|
+
{ "@id": "/2", "@type": "User", name: "Bob" },
|
|
240
|
+
{ "@id": "/3", "@type": "User", name: "Charlie" },
|
|
241
|
+
];
|
|
242
|
+
const result = filterObjectByType(objects, "User");
|
|
243
|
+
expect(result).to.have.length(3);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("should handle objects with multiple types in array matching same target", () => {
|
|
247
|
+
const objects = [
|
|
248
|
+
{ "@id": "/1", "@type": ["User", "User"], name: "Alice" },
|
|
249
|
+
{ "@id": "/2", "@type": ["User"], name: "Bob" },
|
|
250
|
+
];
|
|
251
|
+
const result = filterObjectByType(objects, "User");
|
|
252
|
+
expect(result).to.have.length(2);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
describe("Type edge cases", () => {
|
|
257
|
+
it("should handle type with special characters", () => {
|
|
258
|
+
const objects = [
|
|
259
|
+
{
|
|
260
|
+
"@id": "/1",
|
|
261
|
+
"@type": "http://example.com/types/User-Profile",
|
|
262
|
+
name: "Alice",
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
"@id": "/2",
|
|
266
|
+
"@type": "http://example.com/types/Project",
|
|
267
|
+
name: "Website",
|
|
268
|
+
},
|
|
269
|
+
];
|
|
270
|
+
const result = filterObjectByType(
|
|
271
|
+
objects,
|
|
272
|
+
"http://example.com/types/User-Profile",
|
|
273
|
+
);
|
|
274
|
+
expect(result).to.have.length(1);
|
|
275
|
+
expect(result[0].name).to.equal("Alice");
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it("should handle type with URI fragments", () => {
|
|
279
|
+
const objects = [
|
|
280
|
+
{
|
|
281
|
+
"@id": "/1",
|
|
282
|
+
"@type": "http://schema.org/Person#User",
|
|
283
|
+
name: "Alice",
|
|
284
|
+
},
|
|
285
|
+
{ "@id": "/2", "@type": "http://schema.org/Person", name: "Bob" },
|
|
286
|
+
];
|
|
287
|
+
const result = filterObjectByType(
|
|
288
|
+
objects,
|
|
289
|
+
"http://schema.org/Person#User",
|
|
290
|
+
);
|
|
291
|
+
expect(result).to.have.length(1);
|
|
292
|
+
expect(result[0].name).to.equal("Alice");
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it("should handle very long type URIs", () => {
|
|
296
|
+
const longUri =
|
|
297
|
+
"http://example.com/very/long/path/to/resource/type/definition/User";
|
|
298
|
+
const objects = [
|
|
299
|
+
{ "@id": "/1", "@type": longUri, name: "Alice" },
|
|
300
|
+
{ "@id": "/2", "@type": "http://example.com/other/type", name: "Bob" },
|
|
301
|
+
];
|
|
302
|
+
const result = filterObjectByType(objects, longUri);
|
|
303
|
+
expect(result).to.have.length(1);
|
|
304
|
+
expect(result[0].name).to.equal("Alice");
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
});
|