Skip to content

Commit 2776804

Browse files
Merge pull request #195 from contentstack/staging
DX | 27-10-2025 | Release
2 parents b560395 + 99c2379 commit 2776804

File tree

8 files changed

+539
-297
lines changed

8 files changed

+539
-297
lines changed

.github/workflows/secrets-scan.yml

Lines changed: 0 additions & 29 deletions
This file was deleted.

.talismanrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ fileignoreconfig:
33
ignore_detectors:
44
- filecontent
55
- filename: package-lock.json
6-
checksum: f5a5aba11ae3778465d1c001151fefa136629e136a7037fbb70fc7c738cb9d36
6+
checksum: fb18e620409c9476503edb301ef7b1360681e7d03d8c9b93c2e7a6453c744631
77
- filename: src/entry-editable.ts
88
checksum: 3ba7af9ed1c1adef2e2bd5610099716562bebb8ba750d4b41ddda99fc9eaf115
99
- filename: .husky/pre-commit

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [1.5.0](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.4.5) (2025-10-27)
4+
- fix: handle null and undefined values in getTag function
5+
- fix: refernce variant cslp generation fix
6+
7+
## [1.4.4](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.4.4) (2025-09-24)
8+
-Enhance break and newline handling, update dependencies
9+
310
## [1.4.3](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.4.3) (2025-09-22)
411
- Fix data-cslp generation logic in case of applied_variants
512

CODEOWNERS

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,11 @@
1-
* @contentstack/security-admin
1+
* @contentstack/devex-pr-reviewers
2+
3+
.github/workflows/sca-scan.yml @contentstack/security-admin
4+
5+
.github/workflows/codeql-anaylsis.yml @contentstack/security-admin
6+
7+
**/.snyk @contentstack/security-admin
8+
9+
.github/workflows/policy-scan.yml @contentstack/security-admin
10+
11+
.github/workflows/issues-jira.yml @contentstack/security-admin

__test__/entry-editable.test.ts

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,110 @@ describe('Entry editable test', () => {
232232
done()
233233
})
234234

235+
it('Entry with array containing null values should skip null elements', done => {
236+
const entryWithNullInArray = {
237+
"locale": "en-us",
238+
"uid": "uid",
239+
"items": [
240+
null,
241+
{ "title": "valid item" },
242+
null
243+
]
244+
}
245+
246+
expect(() => addTags(entryWithNullInArray, 'content_type', false)).not.toThrow()
247+
expect((entryWithNullInArray as any)['items'][1]['$']['title']).toEqual('data-cslp=content_type.uid.en-us.items.1.title')
248+
249+
done()
250+
})
251+
252+
it('Entry with array containing undefined values should skip undefined elements', done => {
253+
const entryWithUndefinedInArray = {
254+
"locale": "en-us",
255+
"uid": "uid",
256+
"items": [
257+
undefined,
258+
{ "title": "valid item" },
259+
undefined
260+
]
261+
}
262+
263+
expect(() => addTags(entryWithUndefinedInArray, 'content_type', false)).not.toThrow()
264+
expect((entryWithUndefinedInArray as any)['items'][1]['$']['title']).toEqual('data-cslp=content_type.uid.en-us.items.1.title')
265+
266+
done()
267+
})
268+
269+
it('Entry with array containing mixed null and undefined values should skip both', done => {
270+
const entryWithMixedNullUndefined = {
271+
"locale": "en-us",
272+
"uid": "uid",
273+
"items": [
274+
null,
275+
undefined,
276+
{ "title": "valid item 1" },
277+
null,
278+
{ "title": "valid item 2" },
279+
undefined
280+
]
281+
}
282+
283+
expect(() => addTags(entryWithMixedNullUndefined, 'content_type', true)).not.toThrow()
284+
expect((entryWithMixedNullUndefined as any)['items'][2]['$']['title']).toEqual({'data-cslp': 'content_type.uid.en-us.items.2.title'})
285+
expect((entryWithMixedNullUndefined as any)['items'][4]['$']['title']).toEqual({'data-cslp': 'content_type.uid.en-us.items.4.title'})
286+
287+
done()
288+
})
289+
290+
it('Entry with _embedded_items containing null values should handle gracefully', done => {
291+
const entryWithEmbeddedNull: any = {
292+
"locale": "en-us",
293+
"uid": "uid",
294+
"blocks": [
295+
{
296+
"items": [
297+
{ "heading": "Item heading" }
298+
]
299+
}
300+
],
301+
"_embedded_items": {
302+
"blocks.items.description": [null]
303+
}
304+
}
305+
306+
expect(() => addTags(entryWithEmbeddedNull, 'content_type', false)).not.toThrow()
307+
expect((entryWithEmbeddedNull as any)['blocks'][0]['items'][0]['$']['heading']).toEqual('data-cslp=content_type.uid.en-us.blocks.0.items.0.heading')
308+
expect((entryWithEmbeddedNull as any)['_embedded_items']['blocks.items.description'][0]).toBeNull()
309+
310+
done()
311+
})
312+
313+
it('Entry with nested arrays containing nulls in complex structure should work', done => {
314+
const entryWithComplexNulls: any = {
315+
"locale": "en-us",
316+
"uid": "uid",
317+
"blocks": [
318+
{
319+
"hero": {
320+
"title": "Hero title",
321+
"items": [null, { "name": "Item name" }, undefined]
322+
}
323+
},
324+
null,
325+
{
326+
"content": "Content text"
327+
}
328+
]
329+
}
330+
331+
expect(() => addTags(entryWithComplexNulls, 'content_type', true)).not.toThrow()
332+
expect((entryWithComplexNulls as any)['blocks'][0]['hero']['$']['title']).toEqual({'data-cslp': 'content_type.uid.en-us.blocks.0.hero.title'})
333+
expect((entryWithComplexNulls as any)['blocks'][0]['hero']['items'][1]['$']['name']).toEqual({'data-cslp': 'content_type.uid.en-us.blocks.0.hero.items.1.name'})
334+
expect((entryWithComplexNulls as any)['blocks'][2]['$']['content']).toEqual({'data-cslp': 'content_type.uid.en-us.blocks.2.content'})
335+
336+
done()
337+
})
338+
235339
it('Variant path sorting should work correctly for nested paths', done => {
236340
const entryWithComplexVariants = {
237341
"_version": 10,
@@ -268,6 +372,151 @@ describe('Entry editable test', () => {
268372

269373
done()
270374
})
375+
376+
it('Reference fields should not inherit parent variants when they have no applied_variants', done => {
377+
const entryWithReferenceAndVariants = {
378+
"title": "home",
379+
"url": "/data/all_test/first",
380+
"single_line": "ssd",
381+
"tags": ["hi"],
382+
"locale": "en-us",
383+
"uid": "blt827e0ad3608248be",
384+
"created_by": "bltf0d59057590e9b09",
385+
"updated_by": "bltf0d59057590e9b09",
386+
"created_at": "2025-08-25T09:43:49.935Z",
387+
"updated_at": "2025-10-09T11:45:19.967Z",
388+
"ACL": [] as any[],
389+
"_version": 40,
390+
"_in_progress": false,
391+
"json_rte": "<p>hisdassf</p>",
392+
"select": "1",
393+
"group": {
394+
"single_line": ""
395+
},
396+
"non_single_line_textbox": "",
397+
"reference": [
398+
{
399+
"title": "base variant",
400+
"single_line": "bases",
401+
"tags": [] as any[],
402+
"locale": "en-us",
403+
"uid": "blt07a6c7258ddba844",
404+
"created_by": "bltf0d59057590e9b09",
405+
"updated_by": "bltf0d59057590e9b09",
406+
"created_at": "2025-10-01T03:10:10.701Z",
407+
"updated_at": "2025-10-09T11:44:44.981Z",
408+
"_content_type_uid": "all_test_3",
409+
"ACL": [] as any[],
410+
"_version": 3,
411+
"_in_progress": false,
412+
"multi_line_reference": "hii\n"
413+
// Note: This reference object has NO _applied_variants
414+
}
415+
],
416+
"taxonomies": [] as any[],
417+
"multi_line": "woek",
418+
"_applied_variants": {
419+
"single_line": "csfff653e89df54e8c",
420+
"tags": "csfff653e89df54e8c",
421+
"multi_line": "csfff653e89df54e8c"
422+
}
423+
}
424+
425+
addTags(entryWithReferenceAndVariants, 'all_test', false)
426+
427+
// Parent entry fields with variants should get v2 prefix
428+
expect((entryWithReferenceAndVariants as any)['$']['single_line']).toEqual('data-cslp=v2:all_test.blt827e0ad3608248be_csfff653e89df54e8c.en-us.single_line')
429+
expect((entryWithReferenceAndVariants as any)['$']['tags']).toEqual('data-cslp=v2:all_test.blt827e0ad3608248be_csfff653e89df54e8c.en-us.tags')
430+
expect((entryWithReferenceAndVariants as any)['$']['multi_line']).toEqual('data-cslp=v2:all_test.blt827e0ad3608248be_csfff653e89df54e8c.en-us.multi_line')
431+
432+
// Reference fields should NOT get v2 prefix since they have no _applied_variants
433+
expect((entryWithReferenceAndVariants as any)['reference'][0]['$']['title']).toEqual('data-cslp=all_test_3.blt07a6c7258ddba844.en-us.title')
434+
expect((entryWithReferenceAndVariants as any)['reference'][0]['$']['single_line']).toEqual('data-cslp=all_test_3.blt07a6c7258ddba844.en-us.single_line')
435+
expect((entryWithReferenceAndVariants as any)['reference'][0]['$']['tags']).toEqual('data-cslp=all_test_3.blt07a6c7258ddba844.en-us.tags')
436+
expect((entryWithReferenceAndVariants as any)['reference'][0]['$']['multi_line_reference']).toEqual('data-cslp=all_test_3.blt07a6c7258ddba844.en-us.multi_line_reference')
437+
438+
done()
439+
})
440+
441+
it('Reference fields with their own applied_variants should use their variants', done => {
442+
const entryWithReferenceHavingVariants = {
443+
"title": "home",
444+
"locale": "en-us",
445+
"uid": "blt827e0ad3608248be",
446+
"ACL": [] as any[],
447+
"_version": 40,
448+
"_in_progress": false,
449+
"single_line": "parent field",
450+
"reference": [
451+
{
452+
"title": "base variant",
453+
"single_line": "reference field",
454+
"locale": "en-us",
455+
"uid": "blt07a6c7258ddba844",
456+
"_content_type_uid": "all_test_3",
457+
"ACL": [] as any[],
458+
"_version": 3,
459+
"_in_progress": false,
460+
"_applied_variants": {
461+
"single_line": "ref_variant_123"
462+
}
463+
}
464+
],
465+
"_applied_variants": {
466+
"single_line": "parent_variant_456"
467+
}
468+
}
469+
470+
addTags(entryWithReferenceHavingVariants, 'all_test', false)
471+
472+
// Parent entry field should get parent variant
473+
expect((entryWithReferenceHavingVariants as any)['$']['single_line']).toEqual('data-cslp=v2:all_test.blt827e0ad3608248be_parent_variant_456.en-us.single_line')
474+
475+
// Reference field should get its own variant, not parent variant
476+
expect((entryWithReferenceHavingVariants as any)['reference'][0]['$']['title']).toEqual('data-cslp=all_test_3.blt07a6c7258ddba844.en-us.title')
477+
expect((entryWithReferenceHavingVariants as any)['reference'][0]['$']['single_line']).toEqual('data-cslp=v2:all_test_3.blt07a6c7258ddba844_ref_variant_123.en-us.single_line')
478+
479+
done()
480+
})
481+
482+
it('Reference fields should work correctly with tagsAsObject=true', done => {
483+
const entryWithReferenceAndVariants = {
484+
"title": "home",
485+
"single_line": "ssd",
486+
"locale": "en-us",
487+
"uid": "blt827e0ad3608248be",
488+
"ACL": [] as any[],
489+
"_version": 40,
490+
"_in_progress": false,
491+
"reference": [
492+
{
493+
"title": "base variant",
494+
"single_line": "bases",
495+
"locale": "en-us",
496+
"uid": "blt07a6c7258ddba844",
497+
"_content_type_uid": "all_test_3",
498+
"ACL": [] as any[],
499+
"_version": 3,
500+
"_in_progress": false
501+
// No _applied_variants
502+
}
503+
],
504+
"_applied_variants": {
505+
"single_line": "csfff653e89df54e8c"
506+
}
507+
}
508+
509+
addTags(entryWithReferenceAndVariants, 'all_test', true)
510+
511+
// Parent entry field with variant should get v2 prefix as object
512+
expect((entryWithReferenceAndVariants as any)['$']['single_line']).toEqual({'data-cslp': 'v2:all_test.blt827e0ad3608248be_csfff653e89df54e8c.en-us.single_line'})
513+
514+
// Reference fields should NOT get v2 prefix as objects
515+
expect((entryWithReferenceAndVariants as any)['reference'][0]['$']['title']).toEqual({'data-cslp': 'all_test_3.blt07a6c7258ddba844.en-us.title'})
516+
expect((entryWithReferenceAndVariants as any)['reference'][0]['$']['single_line']).toEqual({'data-cslp': 'all_test_3.blt07a6c7258ddba844.en-us.single_line'})
517+
518+
done()
519+
})
271520
})
272521

273522
})

0 commit comments

Comments
 (0)