• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kiva / ui / 19147367510

06 Nov 2025 07:26PM UTC coverage: 91.443% (+41.5%) from 49.902%
19147367510

push

github

emuvente
test: refactor category-row-arrows-visible-mixin test with runner method

3722 of 3979 branches covered (93.54%)

Branch coverage included in aggregate %.

18923 of 20785 relevant lines covered (91.04%)

78.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.52
/src/util/contentfulUtils.js
1
import { camelCase } from 'change-case';
1✔
2
import kvTokensPrimitives from '@kiva/kv-tokens';
1✔
3

4
/**
1✔
5
 * Takes formatted responsiveImageSet and returns an array of image objects which
1✔
6
 * can be inserted into KvContentfulImg component as source sets
1✔
7
 *
1✔
8
 * @param {object} ResponsiveImage contentful object - output of: formatResponsiveImageSet
1✔
9
 * @returns {array}
1✔
10
 */
1✔
11
export function responsiveImageSetSourceSets(contentfulResponsiveImageObject) {
1✔
12
        const responsiveSizing = contentfulResponsiveImageObject.responsiveSizing || {};
8✔
13
        let formattedArray = contentfulResponsiveImageObject.images.flatMap(entry => {
8✔
14
                /**
24✔
15
         * This filters out images that have 'std' for support of legacy ResponsiveImageSets
24✔
16
         * that had both std and retina images. When all ResponsiveImageSets only have the
24✔
17
         * retina version of images on contentful, this if can be removed
24✔
18
         */
24✔
19

20
                if (entry.title.indexOf('std') !== -1) {
24✔
21
                        return [];
1✔
22
                }
1✔
23

24
                // kvTokensPrimitives.breakpoints:
23✔
25
                // "breakpoints": {
23✔
26
                //         "md": 734,
23✔
27
                //         "lg": 1024,
23✔
28
                //         "xl": 1440
23✔
29
                // },
23✔
30

31
                let mediaSize;
23✔
32
                let width;
23✔
33
                let sortOrder;
23✔
34

35
                const returnWidth = size => {
23✔
36
                        let maxWidthAtBreakpoint;
23✔
37
                        switch (size) {
23✔
38
                                case ('md'):
23✔
39
                                        maxWidthAtBreakpoint = kvTokensPrimitives?.breakpoints?.lg || 1024;
5!
40
                                        break;
5✔
41
                                case ('lg'):
23✔
42
                                        maxWidthAtBreakpoint = kvTokensPrimitives?.breakpoints?.xl || 1440;
8!
43
                                        break;
8✔
44
                                case ('xl'):
23✔
45
                                        // max width at this breakpoint is as large as possible
3✔
46
                                        // lets return image width
3✔
47
                                        maxWidthAtBreakpoint = entry.file?.details?.image?.width;
3✔
48
                                        break;
3✔
49
                                default:
23✔
50
                                        // small  or default
7✔
51
                                        maxWidthAtBreakpoint = kvTokensPrimitives?.breakpoints?.md || 734;
7!
52
                                        break;
7✔
53
                        }
23✔
54
                        // return size or default
23✔
55
                        return responsiveSizing?.[size]?.width || maxWidthAtBreakpoint;
23✔
56
                };
23✔
57

58
                switch (true) {
23✔
59
                        case (entry.title.indexOf('md') !== -1):
24✔
60
                                mediaSize = 'min-width: 734px';
5✔
61
                                width = returnWidth('md');
5✔
62
                                sortOrder = 3;
5✔
63
                                break;
5✔
64
                        case (entry.title.indexOf('lg') !== -1):
24✔
65
                                mediaSize = 'min-width: 1024px';
8✔
66
                                width = returnWidth('lg');
8✔
67
                                sortOrder = 2;
8✔
68
                                break;
8✔
69
                        case (entry.title.indexOf('xl') !== -1):
24✔
70
                                mediaSize = 'min-width: 1440px';
3✔
71
                                width = returnWidth('xl');
3✔
72
                                sortOrder = 1;
3✔
73
                                break;
3✔
74
                        default:
24✔
75
                                // small (entry.title.indexOf('sm') !== -1 ) or default
7✔
76
                                mediaSize = 'min-width: 0';
7✔
77
                                width = returnWidth('sm');
7✔
78
                                sortOrder = 4;
7✔
79
                                break;
7✔
80
                }
24✔
81
                const aspectRatio = (entry.file?.details?.image?.height ?? 0) / (entry.file?.details?.image?.width ?? 1);// eslint-disable-line max-len
24!
82
                const height = aspectRatio ? Math.round(width * aspectRatio) : null;
24!
83

84
                return [{
24✔
85
                        width,
24✔
86
                        height,
24✔
87
                        media: mediaSize,
24✔
88
                        url: entry.file?.url ?? '',
24!
89
                        sortOrder,
24✔
90
                }];
24✔
91
        });
8✔
92
        // Remove duplicate by sortOrder property
8✔
93
        formattedArray = formattedArray.reduce((unique, o) => {
8✔
94
                if (!unique.some(obj => obj.sortOrder === o.sortOrder)) {
23✔
95
                        unique.push(o);
21✔
96
                }
21✔
97
                return unique;
23✔
98
        }, []);
8✔
99

100
        // Sort by sortOrder property
8✔
101
        formattedArray.sort((a, b) => {
8✔
102
                return (a.sortOrder > b.sortOrder) ? 1 : -1;
13!
103
        });
8✔
104
        return formattedArray;
8✔
105
}
8✔
106

107
/**
1✔
108
 * Format Button (contentful type id: button)
1✔
109
 * Takes raw contentful content object and returns an object with targeted keys/values
1✔
110
 *
1✔
111
 * @param {array} contentfulContent data
1✔
112
 * @returns {object}
1✔
113
 */
1✔
114
export function formatButton(contentfulContent) {
1✔
115
        return {
3✔
116
                description: contentfulContent.fields?.description,
3✔
117
                label: contentfulContent.fields?.label,
3✔
118
                style: contentfulContent.fields?.style,
3✔
119
                subHeadline: contentfulContent.fields?.subHeadline,
3✔
120
                webLink: contentfulContent.fields?.webLink,
3✔
121
                deepLink: contentfulContent.fields?.deepLink,
3✔
122
                analyticsClickEvent: contentfulContent.fields?.analyticsClickEvent,
3✔
123
                webClickEventName: contentfulContent.fields?.webClickEventName,
3✔
124
                filter: contentfulContent.fields?.filter,
3✔
125
        };
3✔
126
}
3✔
127

128
/**
1✔
129
 * Format Generic Content Block (contentful type id: genericContentBlock)
1✔
130
 * Takes raw contentful content object and returns an object with targeted keys/values
1✔
131
 *
1✔
132
 * @param {array} contentfulContent data
1✔
133
 * @returns {object}
1✔
134
 */
1✔
135
export function formatGenericContentBlock(contentfulContent) {
1✔
136
        return {
14✔
137
                key: contentfulContent.fields?.key,
14✔
138
                name: contentfulContent.fields?.name,
14✔
139
                bodyCopy: contentfulContent.fields?.bodyCopy,
14✔
140
                headline: contentfulContent.fields?.headline,
14✔
141
                subHeadline: contentfulContent.fields?.subHeadline,
14✔
142
                primaryCtaLink: contentfulContent.fields?.primaryCtaLink,
14✔
143
                primaryCtaKvTrackEvent: contentfulContent.fields?.primaryCtaKvTrackEvent,
14✔
144
                primaryCtaText: contentfulContent.fields?.primaryCtaText,
14✔
145
        };
14✔
146
}
14✔
147

148
/**
1✔
149
 * Format Generic Content Block (contentful type id: richTextContent)
1✔
150
 * Takes raw contentful content object and returns an object with targeted keys/values
1✔
151
 *
1✔
152
 * @param {array} contentfulContent data
1✔
153
 * @returns {object}
1✔
154
 */
1✔
155
export function formatRichTextContent(contentfulContent) {
1✔
156
        return {
23✔
157
                key: contentfulContent.fields?.key,
23✔
158
                name: contentfulContent.fields?.name,
23✔
159
                richText: contentfulContent.fields?.richText,
23✔
160
        };
23✔
161
}
23✔
162

163
/**
1✔
164
 * Format Ui Setting (contentful type id: uiSetting)
1✔
165
 * Takes raw contentful content object and returns an object with targeted keys/values
1✔
166
 *
1✔
167
 * @param {array} contentfulContent data
1✔
168
 * @returns {object}
1✔
169
 */
1✔
170
export function formatUiSetting(contentfulContent) {
1✔
171
        return {
10✔
172
                key: contentfulContent.fields?.key,
10✔
173
                active: contentfulContent.fields?.active,
10✔
174
                startDate: contentfulContent.fields?.startDate,
10✔
175
                endDate: contentfulContent.fields?.endDate,
10✔
176
                // eslint-disable-next-line no-use-before-define
10✔
177
                contents: formatContentTypes(contentfulContent.fields?.content),
10✔
178
                dataObject: contentfulContent.fields?.dataObject,
10✔
179
        };
10✔
180
}
10✔
181

182
/**
1✔
183
 * Format Background (contentful type id: background)
1✔
184
 * Takes raw contentful content object and returns an object with targeted keys/values
1✔
185
 *
1✔
186
 * @param {array} contentfulContent data
1✔
187
 * @returns {object}
1✔
188
 */
1✔
189
export function formatBackground(contentfulContent) {
1✔
190
        return {
3✔
191
                key: contentfulContent.fields?.key,
3✔
192
                name: contentfulContent.fields?.name,
3✔
193
                backgroundColor: contentfulContent.fields?.backgroundColor,
3✔
194
                backgroundMedia: contentfulContent.fields?.backgroundMedia?.fields,
3✔
195
        };
3✔
196
}
3✔
197

198
/**
1✔
199
 * Format Carousel (contentful type id: carousel)
1✔
200
 * Takes raw contentful content object and returns an object with targeted keys/values
1✔
201
 *
1✔
202
 * @param {array} contentfulContent data
1✔
203
 * @returns {object}
1✔
204
 */
1✔
205
export function formatCarousel(contentfulContent) {
1✔
206
        return {
3✔
207
                key: contentfulContent.fields?.key,
3✔
208
                // eslint-disable-next-line no-use-before-define
3✔
209
                slides: formatContentTypes(contentfulContent.fields?.slides),
3✔
210
                slidesToShow: contentfulContent.fields?.slidesToShow,
3✔
211

212
        };
3✔
213
}
3✔
214

215
/**
1✔
216
 * Format StoryCard (contentful type id: storyCard)
1✔
217
 * Takes raw contentful content object and returns an object with targeted keys/values
1✔
218
 *
1✔
219
 * Default alignment value is center. This is enforced in the contentful UI,
1✔
220
 * but legacy story cards before the alignment field was added may have a null value
1✔
221
 *
1✔
222
 * @param {array} contentfulContent data
1✔
223
 * @returns {object}
1✔
224
 */
1✔
225
export function formatStoryCard(contentfulContent) {
1✔
226
        return {
3✔
227
                backgroundMedia: contentfulContent.fields?.backgroundMedia?.fields,
3✔
228
                cardTitle: contentfulContent.fields?.cardTitle,
3✔
229
                cardContent: contentfulContent.fields?.cardContent,
3✔
230
                footer: contentfulContent.fields?.footer,
3✔
231
                key: contentfulContent.fields?.key,
3✔
232
                theme: contentfulContent.fields?.theme,
3✔
233
                alignment: contentfulContent.fields?.alignment ?? 'center',
3✔
234
                link: contentfulContent.fields?.link,
3✔
235
                analyticsClickEvent: contentfulContent.fields?.analyticsClickEvent
3✔
236
        };
3✔
237
}
3✔
238

239
/**
1✔
240
 * Format Ui Setting (contentful type id: globalPromoBanner)
1✔
241
 * Takes raw contentful content object and returns an object with targeted keys/values
1✔
242
 *
1✔
243
 * @param {array} contentfulContent data
1✔
244
 * @returns {object}
1✔
245
 */
1✔
246
export function formatGlobalPromoBanner(contentfulContent) {
1✔
247
        return {
11✔
248
                bannerName: contentfulContent.fields?.bannerName,
11✔
249
                richText: contentfulContent.fields?.richText,
11✔
250
                startDate: contentfulContent.fields?.startDate,
11✔
251
                endDate: contentfulContent.fields?.endDate,
11✔
252
                active: contentfulContent.fields?.active,
11✔
253
                iconKey: contentfulContent.fields?.iconKey,
11✔
254
                hiddenUrls: contentfulContent.fields?.hiddenUrls,
11✔
255
        };
11✔
256
}
11✔
257

258
/**
1✔
259
 * Format Media Asset (contentful Native type id: Asset)
1✔
260
 * Takes raw contentful content object and returns an object with targeted keys/values
1✔
261
 *
1✔
262
 * @param {array} mediaArray data
1✔
263
 * @returns {object}
1✔
264
 */
1✔
265
export function formatMediaAssetArray(mediaArray) {
1✔
266
        if (!mediaArray || !mediaArray.length) return [];
19✔
267

268
        const mediaAssets = [];
13✔
269

270
        mediaArray.forEach(media => {
13✔
271
                const mediaEntry = {
94✔
272
                        title: media.fields?.title,
94✔
273
                        description: media.fields?.description,
94✔
274
                        file: media.fields?.file,
94✔
275
                };
94✔
276
                mediaAssets.push(mediaEntry);
94✔
277
        });
13✔
278
        return mediaAssets;
13✔
279
}
13✔
280

281
/**
1✔
282
 * Format ResponsiveImageSet (contentful type id: responsiveImageSet)
1✔
283
 * Takes raw contentful content object and returns an object with targeted keys/values
1✔
284
 *
1✔
285
 * @param {array} contentfulContent data
1✔
286
 * @returns {object}
1✔
287
 */
1✔
288
export function formatResponsiveImageSet(contentfulContent) {
1✔
289
        const imageSet = {
11✔
290
                name: contentfulContent.fields?.name,
11✔
291
                description: contentfulContent.fields?.description,
11✔
292
                images: [],
11✔
293
                responsiveSizing: contentfulContent.fields?.responsiveSizing
11✔
294
        };
11✔
295
        const rawImages = contentfulContent.fields?.images;
11✔
296
        imageSet.images = formatMediaAssetArray(rawImages);
11✔
297

298
        return imageSet;
11✔
299
}
11✔
300

301
/**
1✔
302
 * Format ContentGroup (contentful type id: contentGroup)
1✔
303
 * Takes raw contentful content object and returns an object with targeted keys/values
1✔
304
 *
1✔
305
 * @param {array} contentfulContent data
1✔
306
 * @returns {object}
1✔
307
 */
1✔
308
export function formatContentGroupsFlat(contentfulContent) {
1✔
309
        const contentGroupsFlat = {};
12✔
310
        const cleanedContentGroups = [];
12✔
311

312
        contentfulContent.forEach((entry, index) => {
12✔
313
                const isContentGroup = entry.sys?.contentType?.sys?.id === 'contentGroup';
18✔
314
                if (!isContentGroup) {
18✔
315
                        cleanedContentGroups.push({
1✔
316
                                error: 'Entry is not a Content Group'
1✔
317
                        });
1✔
318
                } else {
18✔
319
                        const contentGroupFields = {
17✔
320
                                key: entry.fields?.key,
17✔
321
                                name: entry.fields?.name,
17✔
322
                                type: entry.fields?.type ?? null,
17✔
323
                                title: entry.fields?.title ?? null,
17✔
324
                                // eslint-disable-next-line no-use-before-define
17✔
325
                                contents: formatContentTypes(entry.fields?.contents)
17✔
326
                        };
17✔
327
                        if (entry.fields?.media?.length) {
17✔
328
                                contentGroupFields.media = formatMediaAssetArray(entry.fields?.media);
1✔
329
                        }
1✔
330
                        cleanedContentGroups.push(contentGroupFields);
17✔
331

332
                        const cgType = entry.fields?.type ? camelCase(entry.fields?.type) : null;
17✔
333
                        contentGroupsFlat[
17✔
334
                                cgType
17✔
335
                || camelCase(entry.fields?.key)
17✔
336
                || `cg${index}`
17!
337
                        ] = contentGroupFields;
17✔
338
                }
17✔
339
        });
12✔
340

341
        return contentGroupsFlat;
12✔
342
}
12✔
343

344
/**
1✔
345
 * Takes raw contentful content level object along with it's type, then calls it's helper method returning the content
1✔
346
 *
1✔
347
 * @param {object} contentfulContent data
1✔
348
 * @param {string} contentType data
1✔
349
 * @returns {object}
1✔
350
 */
1✔
351
export function formatContentType(contentfulContent, contentType) {
1✔
352
        // console.log(JSON.stringify(contentfulContent), contentType);
69✔
353
        switch (contentType) {
69✔
354
                case 'genericContentBlock':
69✔
355
                        return {
13✔
356
                                ...formatGenericContentBlock(contentfulContent),
13✔
357
                                contentType
13✔
358
                        };
13✔
359
                case 'uiSetting':
69✔
360
                        return {
9✔
361
                                ...formatUiSetting(contentfulContent),
9✔
362
                                contentType
9✔
363
                        };
9✔
364
                case 'globalPromoBanner':
69✔
365
                        return {
10✔
366
                                ...formatGlobalPromoBanner(contentfulContent),
10✔
367
                                contentType
10✔
368
                        };
10✔
369
                case 'responsiveImageSet':
69✔
370
                        return {
9✔
371
                                ...formatResponsiveImageSet(contentfulContent),
9✔
372
                                contentType
9✔
373
                        };
9✔
374
                case 'richTextContent':
69✔
375
                        return {
23✔
376
                                ...formatRichTextContent(contentfulContent),
23✔
377
                                contentType
23✔
378
                        };
23✔
379
                case 'background':
69✔
380
                        return {
1✔
381
                                ...formatBackground(contentfulContent),
1✔
382
                                contentType
1✔
383
                        };
1✔
384
                case 'button':
69✔
385
                        return {
1✔
386
                                ...formatButton(contentfulContent),
1✔
387
                                contentType
1✔
388
                        };
1✔
389
                case 'storyCard':
69✔
390
                        return {
1✔
391
                                ...formatStoryCard(contentfulContent),
1✔
392
                                contentType
1✔
393
                        };
1✔
394
                case 'carousel':
69✔
395
                        return {
1✔
396
                                ...formatCarousel(contentfulContent),
1✔
397
                                contentType
1✔
398
                        };
1✔
399
                default:
69✔
400
                        return { error: 'Unrecognized Content Type' };
1✔
401
        }
69✔
402
}
69✔
403

404
/**
1✔
405
 * Takes raw contentful content level objects and returns an array keys mapped for each content type.
1✔
406
 *
1✔
407
 * @param {array} contentfulContent data
1✔
408
 * @returns {array}
1✔
409
 */
1✔
410
export function formatContentTypes(contentfulContent) {
1✔
411
        const contents = contentfulContent?.length ? contentfulContent : [];
43✔
412
        const formattedContent = [];
43✔
413

414
        contents.forEach(item => {
43✔
415
                const contentType = item.sys?.contentType?.sys?.id;
63✔
416
                formattedContent.push(formatContentType(item, contentType));
63✔
417
        });
43✔
418

419
        return formattedContent;
43✔
420
}
43✔
421

422
/**
1✔
423
 * Takes raw contentful content page entry, and returns an object with keys mapped to page structured content types.
1✔
424
 *
1✔
425
 * @param {object} entryItem data
1✔
426
 * @returns {object}
1✔
427
 */
1✔
428
export function processPageContent(entryItem) {
1✔
429
        const contentfulContentObject = {};
4✔
430
        // verify we have a content type page object
4✔
431
        const isPage = entryItem.sys?.contentType?.sys?.id === 'page';
4✔
432
        if (!isPage) return { error: 'Non-Page Type Contentful Response' };
4✔
433

434
        // extract top level items in the Page, initialize pageLayout and settings
3✔
435
        contentfulContentObject.page = {
3✔
436
                key: entryItem.fields?.key,
4✔
437
                path: entryItem.fields?.path,
4✔
438
                pageTitle: entryItem.fields?.pageTitle,
4✔
439
                pageType: entryItem.fields?.pageType,
4✔
440
                pageDescription: entryItem.fields?.pageDescription,
4✔
441
                canonicalUrl: entryItem.fields?.canonicalUrl,
4✔
442
                pageLayout: {
4✔
443
                        name: entryItem.fields?.pageLayout?.fields?.name,
4✔
444
                        pageTitle: entryItem.fields?.pageLayout?.fields?.pageTitle,
4✔
445
                        pageBackgroundColor: entryItem.fields?.pageLayout?.fields?.pageBackgroundColor,
4✔
446
                        pageDescription: entryItem.fields?.pageLayout?.fields?.pageDescription
4✔
447
                },
4✔
448
                settings: entryItem.fields?.settings
4✔
449
                        ? formatContentTypes(entryItem.fields?.settings) : []
4!
450
        };
4✔
451

452
        // extract content groups for parsing
4✔
453
        const contentGroups = entryItem.fields?.pageLayout?.fields?.contentGroups ?? [];
4!
454
        const cleanedContentGroups = [];
4✔
455

456
        if (contentGroups.length <= 0) {
4!
457
                contentfulContentObject.page.pageLayout.contentGroups = {
×
458
                        error: 'Non-Page Type Contentful Response'
×
459
                };
×
460
        } else {
4✔
461
                contentGroups.forEach(item => {
3✔
462
                        const contentGroupFields = {
3✔
463
                                key: item.fields?.key,
3✔
464
                                name: item.fields?.name,
3✔
465
                                type: item.fields?.type ?? null,
3!
466
                                title: item.fields?.title ?? null,
3!
467
                                contents: formatContentTypes(item.fields?.contents),
3✔
468
                                media: formatMediaAssetArray(item.fields?.media),
3✔
469
                        };
3✔
470
                        cleanedContentGroups.push(contentGroupFields);
3✔
471
                });
3✔
472

473
                contentfulContentObject.page.pageLayout.contentGroups = cleanedContentGroups;
3✔
474
        }
3✔
475

476
        return contentfulContentObject;
3✔
477
}
3✔
478

479
/**
1✔
480
 * Takes raw contentful content page entry, and returns an object with keys mapped to page structured content types.
1✔
481
 *
1✔
482
 * @param {object} entryItem data
1✔
483
 * @returns {object}
1✔
484
 */
1✔
485
export function processPageContentFlat(entryItem) {
1✔
486
        const contentfulContentObject = {};
12✔
487
        // verify we have a content type page object
12✔
488
        const isPage = entryItem.sys?.contentType?.sys?.id === 'page';
12✔
489
        if (!isPage) return { error: 'Non-Page Type Contentful Response' };
12✔
490

491
        // extract top level items in the Page, initialize pageLayout and settings
9✔
492

493
        contentfulContentObject.page = {
9✔
494
                key: entryItem.fields?.key,
12✔
495
                path: entryItem.fields?.path,
12✔
496
                pageTitle: entryItem.fields?.pageTitle,
12✔
497
                pageType: entryItem.fields?.pageType,
12✔
498
                pageDescription: entryItem.fields?.pageDescription,
12✔
499
                canonicalUrl: entryItem.fields?.canonicalUrl,
12✔
500
                pageLayout: {
12✔
501
                        name: entryItem.fields?.pageLayout?.fields?.name,
12✔
502
                        pageTitle: entryItem.fields?.pageLayout?.fields?.pageTitle,
12✔
503
                        pageDescription: entryItem.fields?.pageLayout?.fields?.pageDescription
12✔
504
                },
12✔
505
                settings: entryItem.fields?.settings
12✔
506
                        ? formatContentTypes(entryItem.fields?.settings) : []
12✔
507
        };
12✔
508

509
        // extract content groups for parsing
12✔
510
        const contentGroups = entryItem.fields?.pageLayout?.fields?.contentGroups ?? [];
12!
511

512
        if (contentGroups.length <= 0) {
12!
513
                contentfulContentObject.page.pageLayout.contentGroups = {
×
514
                        error: 'Missing Content Groups in Contentful Response'
×
515
                };
×
516
        } else {
12✔
517
                contentfulContentObject.page.contentGroups = formatContentGroupsFlat(contentGroups);
9✔
518
        }
9✔
519

520
        return contentfulContentObject;
9✔
521
}
9✔
522

523
/**
1✔
524
 *  Takes the following (sourceString, splitKey, [dynamicValues])
1✔
525
 *
1✔
526
 * - sourceString = String of text to be .split at the location of the splitKey
1✔
527
 * - splitKey = is the value to look for in the string to preform the .split
1✔
528
 * - [dynamicValues] are the values you want to concat to the string at location of the splitKey
1✔
529
 *
1✔
530
 */
1✔
531
export function buildDynamicString(sourceString = '', splitKey = '', dynamicValues = []) {
1✔
532
        if (typeof sourceString !== 'string') {
6✔
533
                return '';
2✔
534
        }
2✔
535
        // if the split key is not found in the source string, return the source string
4✔
536
        if (sourceString.indexOf(splitKey) === -1) {
6✔
537
                return sourceString;
2✔
538
        }
2✔
539

540
        let finalString = '';
2✔
541
        // split the source string where it finds the splitKey
2✔
542
        const stringSplit = sourceString.split(splitKey);
2✔
543
        // forEach with index of the sourceString
2✔
544
        stringSplit.forEach((item, index) => {
2✔
545
                finalString = finalString.concat(item);
5✔
546
                // if there's a dyanmic value at the current index, proceed adding it
5✔
547
                // to the finalString
5✔
548
                if (dynamicValues[index]) {
5✔
549
                        finalString = finalString.concat(dynamicValues[index]);
3✔
550
                }
3✔
551
        });
2✔
552
        return finalString;
2✔
553
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc