From f7120063b195af244f7a514f8965d0c8eb9d042e Mon Sep 17 00:00:00 2001 From: csAyushDubey Date: Mon, 1 Sep 2025 11:04:31 +0530 Subject: [PATCH 1/7] fix: cslp generation for variant-resolved entries --- src/entry-editable.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/entry-editable.ts b/src/entry-editable.ts index 156de0c..9d1de74 100644 --- a/src/entry-editable.ts +++ b/src/entry-editable.ts @@ -115,12 +115,27 @@ function getTag(content: object, prefix: string, tagsAsObject: boolean, locale: } function getTagsValue(dataValue: string, tagsAsObject: boolean, appliedVariants: { _applied_variants: { [key: string]: any }, shouldApplyVariant: boolean, metaKey: string }): any { - if (appliedVariants.shouldApplyVariant && appliedVariants._applied_variants && appliedVariants._applied_variants[appliedVariants.metaKey]) { + if (appliedVariants.shouldApplyVariant && appliedVariants._applied_variants) { + const isFieldVariantised = appliedVariants._applied_variants[appliedVariants.metaKey]; + if(isFieldVariantised) { const variant = appliedVariants._applied_variants[appliedVariants.metaKey] // Adding v2 prefix to the cslp tag. New cslp tags are in v2 format. ex: v2:content_type_uid.entry_uid.locale.title const newDataValueArray = ('v2:' + dataValue).split('.'); newDataValueArray[1] = newDataValueArray[1] + '_' + variant; dataValue = newDataValueArray.join('.'); + } + else { + const variantisedFieldPaths = Object.keys(appliedVariants._applied_variants).sort((a, b) => { + return b.length - a.length; + }); + const variantisedParentPath = variantisedFieldPaths.find(path => appliedVariants.metaKey.startsWith(path)); + if(variantisedParentPath) { + const variant = appliedVariants._applied_variants[variantisedParentPath]; + const newDataValueArray = ('v2:' + dataValue).split('.'); + newDataValueArray[1] = newDataValueArray[1] + '_' + variant; + dataValue = newDataValueArray.join('.'); + } + } } if (tagsAsObject) { return { "data-cslp": dataValue }; From e4236e087597d2f8b0db21863f050570af00c15c Mon Sep 17 00:00:00 2001 From: csAyushDubey Date: Wed, 3 Sep 2025 17:10:35 +0530 Subject: [PATCH 2/7] fix: added test cases --- __test__/entry-editable.test.ts | 138 ++++++++++++++++++++++++++- __test__/mock/entry-editable-mock.ts | 69 +++++++++++++- 2 files changed, 203 insertions(+), 4 deletions(-) diff --git a/__test__/entry-editable.test.ts b/__test__/entry-editable.test.ts index 53a4882..d988ddd 100644 --- a/__test__/entry-editable.test.ts +++ b/__test__/entry-editable.test.ts @@ -1,7 +1,5 @@ -import { EntryModel } from '../src' import { addTags } from '../src/entry-editable' -import { entry_global_field, entry_global_field_multiple, entry_modular_block, entry_reference, entry_with_text } from './mock/entry-editable-mock' -import { entryMultipleContent } from './mock/entry-multiple-rich-text-content' +import { entry_global_field, entry_global_field_multiple, entry_modular_block, entry_reference, entry_with_text, entry_with_applied_variants, entry_with_system_variants, entry_with_parent_path_variants } from './mock/entry-editable-mock' describe('Entry editable test', () => { it('Entry with text test', done => { @@ -129,4 +127,138 @@ describe('Entry editable test', () => { done() }) + // Tests for applied variants functionality + describe('Applied Variants Tests', () => { + it('Entry with applied variants should generate v2 tags with variant suffix', done => { + addTags(entry_with_applied_variants, 'entry_asset', false) + + // Field with direct variant match should get v2 prefix and variant suffix + expect((entry_with_applied_variants as any)['$']['rich_text_editor']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_1.en-us.rich_text_editor') + expect((entry_with_applied_variants as any)['$']['rich_text_editor_multiple']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_1.en-us.rich_text_editor_multiple') + + // Nested field with direct variant match + expect((entry_with_applied_variants as any)['nested']['$']['field']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_2.en-us.nested.field') + + // Field without variant should not have v2 prefix + expect((entry_with_applied_variants as any)['nested']['$']['other_field']).toEqual('data-cslp=entry_asset.entry_uid_1.en-us.nested.other_field') + + done() + }) + + it('Entry with applied variants should return v2 objects when tagsAsObject is true', done => { + addTags(entry_with_applied_variants, 'entry_asset', true) + + // Field with direct variant match should get v2 prefix and variant suffix as object + expect((entry_with_applied_variants as any)['$']['rich_text_editor']).toEqual({'data-cslp': 'v2:entry_asset.entry_uid_1_variant_1.en-us.rich_text_editor'}) + expect((entry_with_applied_variants as any)['$']['rich_text_editor_multiple']).toEqual({'data-cslp': 'v2:entry_asset.entry_uid_1_variant_1.en-us.rich_text_editor_multiple'}) + + // Nested field with direct variant match + expect((entry_with_applied_variants as any)['nested']['$']['field']).toEqual({'data-cslp': 'v2:entry_asset.entry_uid_1_variant_2.en-us.nested.field'}) + + // Field without variant should not have v2 prefix + expect((entry_with_applied_variants as any)['nested']['$']['other_field']).toEqual({'data-cslp': 'entry_asset.entry_uid_1.en-us.nested.other_field'}) + + done() + }) + + it('Entry with system-level applied variants should work correctly', done => { + addTags(entry_with_system_variants, 'entry_asset', false) + + // Fields with system variants should get v2 prefix and variant suffix + expect((entry_with_system_variants as any)['$']['title']).toEqual('data-cslp=v2:entry_asset.entry_uid_2_system_variant.en-us.title') + expect((entry_with_system_variants as any)['$']['description']).toEqual('data-cslp=v2:entry_asset.entry_uid_2_desc_variant.en-us.description') + + done() + }) + + it('Entry with parent path variants should find correct variant', done => { + addTags(entry_with_parent_path_variants, 'entry_asset', false) + + // Field under 'group' parent should get parent variant + expect((entry_with_parent_path_variants as any)['group']['$']['other']).toEqual('data-cslp=v2:entry_asset.entry_uid_3_parent_variant.en-us.group.other') + + // Field under 'group.nested' should get parent variant (group is longer match) + expect((entry_with_parent_path_variants as any)['group']['nested']['$']['field']).toEqual('data-cslp=v2:entry_asset.entry_uid_3_parent_variant.en-us.group.nested.field') + + // Field with exact deep path match should get deep variant + expect((entry_with_parent_path_variants as any)['group']['nested']['deep']['$']['field']).toEqual('data-cslp=v2:entry_asset.entry_uid_3_deep_variant.en-us.group.nested.deep.field') + + done() + }) + + it('Entry with modular block variants should apply variants correctly', done => { + addTags(entry_with_applied_variants, 'entry_asset', false) + + // Modular block content with variant should get v2 prefix and variant suffix + expect((entry_with_applied_variants as any)['modular_blocks'][0]['$']['content']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_3.en-us.modular_blocks.0.content') + + // Modular block field without variant should not have v2 prefix + expect((entry_with_applied_variants as any)['modular_blocks'][0]['$']['title']).toEqual('data-cslp=entry_asset.entry_uid_1.en-us.modular_blocks.0.title') + + done() + }) + + it('Entry without applied variants should work normally', done => { + addTags(entry_with_text, 'entry_asset', false) + + // Should not have v2 prefix when no variants are applied + expect((entry_with_text as any)['$']['rich_text_editor']).toEqual('data-cslp=entry_asset.entry_uid_1.en-us.rich_text_editor') + expect((entry_with_text as any)['$']['rich_text_editor_multiple']).toEqual('data-cslp=entry_asset.entry_uid_1.en-us.rich_text_editor_multiple') + + done() + }) + + it('Entry with empty applied variants should work normally', done => { + const entryWithEmptyVariants = { + ...entry_with_text, + _applied_variants: {} + } + + addTags(entryWithEmptyVariants, 'entry_asset', false) + + // Should not have v2 prefix when variants object is empty + expect((entryWithEmptyVariants as any)['$']['rich_text_editor']).toEqual('data-cslp=entry_asset.entry_uid_1.en-us.rich_text_editor') + expect((entryWithEmptyVariants as any)['$']['rich_text_editor_multiple']).toEqual('data-cslp=entry_asset.entry_uid_1.en-us.rich_text_editor_multiple') + + done() + }) + + it('Variant path sorting should work correctly for nested paths', done => { + const entryWithComplexVariants = { + "_version": 10, + "locale": "en-us", + "uid": "entry_uid_test", + "ACL": {}, + "_applied_variants": { + "a": "variant_a", + "a.b": "variant_ab", + "a.b.c": "variant_abc", + "a.b.c.d": "variant_abcd" + }, + "a": { + "b": { + "c": { + "d": { + "field": "deep field" + }, + "field": "c field" + }, + "field": "b field" + }, + "field": "a field" + } + } + + addTags(entryWithComplexVariants, 'entry_asset', false) + + // Should use the longest matching path variant + expect((entryWithComplexVariants as any)['a']['b']['c']['d']['$']['field']).toEqual('data-cslp=v2:entry_asset.entry_uid_test_variant_abcd.en-us.a.b.c.d.field') + expect((entryWithComplexVariants as any)['a']['b']['c']['$']['field']).toEqual('data-cslp=v2:entry_asset.entry_uid_test_variant_abc.en-us.a.b.c.field') + expect((entryWithComplexVariants as any)['a']['b']['$']['field']).toEqual('data-cslp=v2:entry_asset.entry_uid_test_variant_ab.en-us.a.b.field') + expect((entryWithComplexVariants as any)['a']['$']['field']).toEqual('data-cslp=v2:entry_asset.entry_uid_test_variant_a.en-us.a.field') + + done() + }) + }) + }) \ No newline at end of file diff --git a/__test__/mock/entry-editable-mock.ts b/__test__/mock/entry-editable-mock.ts index 590c131..fc0811c 100644 --- a/__test__/mock/entry-editable-mock.ts +++ b/__test__/mock/entry-editable-mock.ts @@ -150,10 +150,77 @@ const entry_global_field_multiple = { } ] } +// Mock entry with applied variants for testing variant functionality +const entry_with_applied_variants = { + "_version": 10, + "locale": "en-us", + "uid": "entry_uid_1", + "ACL": {}, + "_applied_variants": { + "rich_text_editor": "variant_1", + "nested.field": "variant_2", + "modular_blocks.content": "variant_3" + }, + "rich_text_editor": "

Content with variant

", + "rich_text_editor_multiple": [ + "

Multiple content with variant

" + ], + "nested": { + "field": "nested field content", + "other_field": "other nested content" + }, + "modular_blocks": [ + { + "content": "modular content", + "title": "modular title" + } + ] +} + +// Mock entry with system-level applied variants +const entry_with_system_variants = { + "_version": 10, + "locale": "en-us", + "uid": "entry_uid_2", + "ACL": {}, + "system": { + "applied_variants": { + "title": "system_variant", + "description": "desc_variant" + } + }, + "title": "System variant title", + "description": "System variant description" +} + +// Mock entry with nested parent path variants +const entry_with_parent_path_variants = { + "_version": 10, + "locale": "en-us", + "uid": "entry_uid_3", + "ACL": {}, + "_applied_variants": { + "group": "parent_variant", + "group.nested.deep": "deep_variant" + }, + "group": { + "nested": { + "field": "nested field", + "deep": { + "field": "deep field" + } + }, + "other": "other field" + } +} + export { entry_with_text, entry_reference, entry_global_field, entry_modular_block, - entry_global_field_multiple + entry_global_field_multiple, + entry_with_applied_variants, + entry_with_system_variants, + entry_with_parent_path_variants } \ No newline at end of file From dadd536a36b09177553ecc5149a5850814fa892e Mon Sep 17 00:00:00 2001 From: Aravind Kumar Date: Mon, 8 Sep 2025 22:20:17 +0530 Subject: [PATCH 3/7] Delete secrets-scan.yml --- .github/workflows/secrets-scan.yml | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 .github/workflows/secrets-scan.yml diff --git a/.github/workflows/secrets-scan.yml b/.github/workflows/secrets-scan.yml deleted file mode 100644 index 049c02f..0000000 --- a/.github/workflows/secrets-scan.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Secrets Scan -on: - pull_request: - types: [opened, synchronize, reopened] -jobs: - security-secrets: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: '2' - ref: '${{ github.event.pull_request.head.ref }}' - - run: | - git reset --soft HEAD~1 - - name: Install Talisman - run: | - # Download Talisman - wget https://github.com/thoughtworks/talisman/releases/download/v1.37.0/talisman_linux_amd64 -O talisman - - # Checksum verification - checksum=$(sha256sum ./talisman | awk '{print $1}') - if [ "$checksum" != "8e0ae8bb7b160bf10c4fa1448beb04a32a35e63505b3dddff74a092bccaaa7e4" ]; then exit 1; fi - - # Make it executable - chmod +x talisman - - name: Run talisman - run: | - # Run Talisman with the pre-commit hook - ./talisman --githook pre-commit \ No newline at end of file From 472dd01060768ecc8fcd3a0c5efaec4341303c0c Mon Sep 17 00:00:00 2001 From: Aravind Kumar Date: Mon, 8 Sep 2025 22:20:21 +0530 Subject: [PATCH 4/7] Updated codeowners --- CODEOWNERS | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 1be7e0d..0496bc6 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1,11 @@ -* @contentstack/security-admin +* @contentstack/devex-pr-reviewers + +.github/workflows/sca-scan.yml @contentstack/security-admin + +.github/workflows/codeql-anaylsis.yml @contentstack/security-admin + +**/.snyk @contentstack/security-admin + +.github/workflows/policy-scan.yml @contentstack/security-admin + +.github/workflows/issues-jira.yml @contentstack/security-admin From 53a045743912c23abb6fe5df3539efc82e235221 Mon Sep 17 00:00:00 2001 From: csAyushDubey Date: Tue, 9 Sep 2025 00:59:03 +0530 Subject: [PATCH 5/7] test: fixed tests as requested --- __test__/entry-editable.test.ts | 17 ++------------ __test__/mock/entry-editable-mock.ts | 33 +++++++++++----------------- 2 files changed, 15 insertions(+), 35 deletions(-) diff --git a/__test__/entry-editable.test.ts b/__test__/entry-editable.test.ts index d988ddd..a8ae39a 100644 --- a/__test__/entry-editable.test.ts +++ b/__test__/entry-editable.test.ts @@ -1,5 +1,5 @@ import { addTags } from '../src/entry-editable' -import { entry_global_field, entry_global_field_multiple, entry_modular_block, entry_reference, entry_with_text, entry_with_applied_variants, entry_with_system_variants, entry_with_parent_path_variants } from './mock/entry-editable-mock' +import { entry_global_field, entry_global_field_multiple, entry_modular_block, entry_reference, entry_with_text, entry_with_applied_variants, entry_with_parent_path_variants } from './mock/entry-editable-mock' describe('Entry editable test', () => { it('Entry with text test', done => { @@ -134,7 +134,6 @@ describe('Entry editable test', () => { // Field with direct variant match should get v2 prefix and variant suffix expect((entry_with_applied_variants as any)['$']['rich_text_editor']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_1.en-us.rich_text_editor') - expect((entry_with_applied_variants as any)['$']['rich_text_editor_multiple']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_1.en-us.rich_text_editor_multiple') // Nested field with direct variant match expect((entry_with_applied_variants as any)['nested']['$']['field']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_2.en-us.nested.field') @@ -150,7 +149,6 @@ describe('Entry editable test', () => { // Field with direct variant match should get v2 prefix and variant suffix as object expect((entry_with_applied_variants as any)['$']['rich_text_editor']).toEqual({'data-cslp': 'v2:entry_asset.entry_uid_1_variant_1.en-us.rich_text_editor'}) - expect((entry_with_applied_variants as any)['$']['rich_text_editor_multiple']).toEqual({'data-cslp': 'v2:entry_asset.entry_uid_1_variant_1.en-us.rich_text_editor_multiple'}) // Nested field with direct variant match expect((entry_with_applied_variants as any)['nested']['$']['field']).toEqual({'data-cslp': 'v2:entry_asset.entry_uid_1_variant_2.en-us.nested.field'}) @@ -161,16 +159,6 @@ describe('Entry editable test', () => { done() }) - it('Entry with system-level applied variants should work correctly', done => { - addTags(entry_with_system_variants, 'entry_asset', false) - - // Fields with system variants should get v2 prefix and variant suffix - expect((entry_with_system_variants as any)['$']['title']).toEqual('data-cslp=v2:entry_asset.entry_uid_2_system_variant.en-us.title') - expect((entry_with_system_variants as any)['$']['description']).toEqual('data-cslp=v2:entry_asset.entry_uid_2_desc_variant.en-us.description') - - done() - }) - it('Entry with parent path variants should find correct variant', done => { addTags(entry_with_parent_path_variants, 'entry_asset', false) @@ -191,9 +179,8 @@ describe('Entry editable test', () => { // Modular block content with variant should get v2 prefix and variant suffix expect((entry_with_applied_variants as any)['modular_blocks'][0]['$']['content']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_3.en-us.modular_blocks.0.content') - // Modular block field without variant should not have v2 prefix - expect((entry_with_applied_variants as any)['modular_blocks'][0]['$']['title']).toEqual('data-cslp=entry_asset.entry_uid_1.en-us.modular_blocks.0.title') + expect((entry_with_applied_variants as any)['modular_blocks'][0]['content']['$']['title']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_3.en-us.modular_blocks.0.content.title') done() }) diff --git a/__test__/mock/entry-editable-mock.ts b/__test__/mock/entry-editable-mock.ts index fc0811c..f44e085 100644 --- a/__test__/mock/entry-editable-mock.ts +++ b/__test__/mock/entry-editable-mock.ts @@ -171,27 +171,13 @@ const entry_with_applied_variants = { }, "modular_blocks": [ { - "content": "modular content", - "title": "modular title" + "content": { + "title": "modular title" + } } ] } -// Mock entry with system-level applied variants -const entry_with_system_variants = { - "_version": 10, - "locale": "en-us", - "uid": "entry_uid_2", - "ACL": {}, - "system": { - "applied_variants": { - "title": "system_variant", - "description": "desc_variant" - } - }, - "title": "System variant title", - "description": "System variant description" -} // Mock entry with nested parent path variants const entry_with_parent_path_variants = { @@ -201,7 +187,8 @@ const entry_with_parent_path_variants = { "ACL": {}, "_applied_variants": { "group": "parent_variant", - "group.nested.deep": "deep_variant" + "group.nested.deep": "deep_variant", + "modular_blocks.content": "parent_variant" }, "group": { "nested": { @@ -211,7 +198,14 @@ const entry_with_parent_path_variants = { } }, "other": "other field" - } + }, + "modular_blocks": [ + { + "content": { + "title": "modular title" + } + } + ] } export { @@ -221,6 +215,5 @@ export { entry_modular_block, entry_global_field_multiple, entry_with_applied_variants, - entry_with_system_variants, entry_with_parent_path_variants } \ No newline at end of file From 2210ed256d41289a3ed88adbbc04584178e28912 Mon Sep 17 00:00:00 2001 From: csAyushDubey Date: Tue, 9 Sep 2025 18:47:32 +0530 Subject: [PATCH 6/7] fix: requested logic changes --- __test__/entry-editable.test.ts | 38 ++++++++++++++---- __test__/mock/entry-editable-mock.ts | 60 +++++++++++++++++++++------- src/entry-editable.ts | 39 ++++++++++++++---- 3 files changed, 108 insertions(+), 29 deletions(-) diff --git a/__test__/entry-editable.test.ts b/__test__/entry-editable.test.ts index a8ae39a..39d72e4 100644 --- a/__test__/entry-editable.test.ts +++ b/__test__/entry-editable.test.ts @@ -131,7 +131,7 @@ describe('Entry editable test', () => { describe('Applied Variants Tests', () => { it('Entry with applied variants should generate v2 tags with variant suffix', done => { addTags(entry_with_applied_variants, 'entry_asset', false) - + // Field with direct variant match should get v2 prefix and variant suffix expect((entry_with_applied_variants as any)['$']['rich_text_editor']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_1.en-us.rich_text_editor') @@ -140,6 +140,7 @@ describe('Entry editable test', () => { // Field without variant should not have v2 prefix expect((entry_with_applied_variants as any)['nested']['$']['other_field']).toEqual('data-cslp=entry_asset.entry_uid_1.en-us.nested.other_field') + expect((entry_with_applied_variants as any)['$']['rich_text_editor_multiple']).toEqual('data-cslp=entry_asset.entry_uid_1.en-us.rich_text_editor_multiple') done() }) @@ -155,32 +156,53 @@ describe('Entry editable test', () => { // Field without variant should not have v2 prefix expect((entry_with_applied_variants as any)['nested']['$']['other_field']).toEqual({'data-cslp': 'entry_asset.entry_uid_1.en-us.nested.other_field'}) + expect((entry_with_applied_variants as any)['$']['rich_text_editor_multiple']).toEqual({'data-cslp': 'entry_asset.entry_uid_1.en-us.rich_text_editor_multiple'}) done() }) it('Entry with parent path variants should find correct variant', done => { addTags(entry_with_parent_path_variants, 'entry_asset', false) - + + // Group field should get parent variant + expect((entry_with_parent_path_variants as any)['$']['group']).toEqual('data-cslp=v2:entry_asset.entry_uid_3_parent_variant.en-us.group') // Field under 'group' parent should get parent variant expect((entry_with_parent_path_variants as any)['group']['$']['other']).toEqual('data-cslp=v2:entry_asset.entry_uid_3_parent_variant.en-us.group.other') - // Field under 'group.nested' should get parent variant (group is longer match) expect((entry_with_parent_path_variants as any)['group']['nested']['$']['field']).toEqual('data-cslp=v2:entry_asset.entry_uid_3_parent_variant.en-us.group.nested.field') - // Field with exact deep path match should get deep variant expect((entry_with_parent_path_variants as any)['group']['nested']['deep']['$']['field']).toEqual('data-cslp=v2:entry_asset.entry_uid_3_deep_variant.en-us.group.nested.deep.field') + // Field with the same starting path should not get parent variant + expect((entry_with_parent_path_variants as any)['$']['group_multiple']).toEqual('data-cslp=entry_asset.entry_uid_3.en-us.group_multiple') + + // Modular block content with variant should get v2 prefix and variant suffix + expect((entry_with_parent_path_variants as any)['modular_blocks'][0]['$']['content']).toEqual('data-cslp=v2:entry_asset.entry_uid_3_parent_variant.en-us.modular_blocks.0.content') + // Modular block field inside a variantised parent should get v2 prefix and variant suffix + expect((entry_with_parent_path_variants as any)['modular_blocks'][0]['content']['$']['title']).toEqual('data-cslp=v2:entry_asset.entry_uid_3_parent_variant.en-us.modular_blocks.0.content.title') + + // Modular block content without variant should not have v2 prefix and variant suffix + expect((entry_with_parent_path_variants as any)['modular_blocks'][1]['$']['content']).toEqual('data-cslp=entry_asset.entry_uid_3.en-us.modular_blocks.1.content') + // Modular block field inside a non variantised parent should not get v2 prefix and variant suffix + expect((entry_with_parent_path_variants as any)['modular_blocks'][1]['content']['$']['title']).toEqual('data-cslp=entry_asset.entry_uid_3.en-us.modular_blocks.1.content.title') + done() }) it('Entry with modular block variants should apply variants correctly', done => { addTags(entry_with_applied_variants, 'entry_asset', false) - + // Modular block content with variant should get v2 prefix and variant suffix - expect((entry_with_applied_variants as any)['modular_blocks'][0]['$']['content']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_3.en-us.modular_blocks.0.content') - // Modular block field without variant should not have v2 prefix - expect((entry_with_applied_variants as any)['modular_blocks'][0]['content']['$']['title']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_3.en-us.modular_blocks.0.content.title') + expect((entry_with_applied_variants as any)['modular_blocks'][1]['$']['content_from_variant']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_3.en-us.modular_blocks.1.content_from_variant') + // Modular block field inside a variantised parent should get v2 prefix and variant suffix + expect((entry_with_applied_variants as any)['modular_blocks'][1]['content_from_variant']['$']['title']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_3.en-us.modular_blocks.1.content_from_variant.title') + // Field inside a variantised parent with a different variant should get v2 prefix and variant suffix of that variant + expect((entry_with_applied_variants as any)['modular_blocks'][1]['content_from_variant']['$']['different_from_parent_variant']).toEqual('data-cslp=v2:entry_asset.entry_uid_1_variant_4.en-us.modular_blocks.1.content_from_variant.different_from_parent_variant') + + // Modular block content without variant should get v2 prefix and variant suffix + expect((entry_with_applied_variants as any)['modular_blocks'][0]['$']['content']).toEqual('data-cslp=entry_asset.entry_uid_1.en-us.modular_blocks.0.content') + // Modular block field without variant should not have v2 prefix and variant suffix + expect((entry_with_applied_variants as any)['modular_blocks'][0]['content']['$']['title']).toEqual('data-cslp=entry_asset.entry_uid_1.en-us.modular_blocks.0.content.title') done() }) diff --git a/__test__/mock/entry-editable-mock.ts b/__test__/mock/entry-editable-mock.ts index f44e085..05b4659 100644 --- a/__test__/mock/entry-editable-mock.ts +++ b/__test__/mock/entry-editable-mock.ts @@ -22,9 +22,9 @@ const entry_modular_block = { "

module 2 

" ], "_metadata": { - "uid": "metadata_uid" + "uid": "metadata_uid_1" } - } + }, }, { "global_modular": { @@ -46,13 +46,13 @@ const entry_modular_block = { "

Module 2

" ], "_metadata": { - "uid": "metadata_uid" + "uid": "metadata_uid_1" } - } + }, } ], "_metadata": { - "uid": "metadata_uid" + "uid": "metadata_uid_2" } } } @@ -106,9 +106,9 @@ const entry_global_field = { "

global modular 2

" ], "_metadata": { - "uid": "metadata_uid" + "uid": "metadata_uid_1" } - } + }, } ] }, @@ -139,13 +139,13 @@ const entry_global_field_multiple = { "

Global multiple modular

\n

2

" ], "_metadata": { - "uid": "metadata_uid" + "uid": "metadata_uid_1" } - } + }, } ], "_metadata": { - "uid": "metadata_uid" + "uid": "metadata_uid_1" } } ] @@ -159,7 +159,8 @@ const entry_with_applied_variants = { "_applied_variants": { "rich_text_editor": "variant_1", "nested.field": "variant_2", - "modular_blocks.content": "variant_3" + "modular_blocks.content_from_variant.metadata_uid_2": "variant_3", + "modular_blocks.content_from_variant.metadata_uid_2.different_from_parent_variant": "variant_4" }, "rich_text_editor": "

Content with variant

", "rich_text_editor_multiple": [ @@ -172,7 +173,19 @@ const entry_with_applied_variants = { "modular_blocks": [ { "content": { - "title": "modular title" + "title": "modular title", + "_metadata": { + "uid": "metadata_uid_1" + } + } + }, + { + "content_from_variant": { + "title": "modular title from variant", + "different_from_parent_variant": "different from parent variant", + "_metadata": { + "uid": "metadata_uid_2" + } } } ] @@ -188,7 +201,7 @@ const entry_with_parent_path_variants = { "_applied_variants": { "group": "parent_variant", "group.nested.deep": "deep_variant", - "modular_blocks.content": "parent_variant" + "modular_blocks.content.metadata_uid_1": "parent_variant" }, "group": { "nested": { @@ -202,7 +215,26 @@ const entry_with_parent_path_variants = { "modular_blocks": [ { "content": { - "title": "modular title" + "title": "modular title", + "_metadata": { + "uid": "metadata_uid_1" + } + }, + }, + { + "content": { + "title": "modular title 2", + "_metadata": { + "uid": "metadata_uid_2" + } + }, + } + ], + "group_multiple": [ + { + "other": "other field", + "_metadata": { + "uid": "metadata_uid_1" } } ] diff --git a/src/entry-editable.ts b/src/entry-editable.ts index ff2c23b..5cf9bd1 100644 --- a/src/entry-editable.ts +++ b/src/entry-editable.ts @@ -1,5 +1,11 @@ import { EntryModel } from "." +interface AppliedVariants { + _applied_variants: { [key: string]: any } + shouldApplyVariant: boolean + metaKey: string +} + export function addTags(entry: EntryModel, contentTypeUid: string, tagsAsObject: boolean, locale: string = 'en-us'): void { if (entry) { // handle case senstivity for contentTypeUid and locale @@ -11,7 +17,7 @@ export function addTags(entry: EntryModel, contentTypeUid: string, tagsAsObject: } } -function getTag(content: object, prefix: string, tagsAsObject: boolean, locale: string, appliedVariants: { _applied_variants: { [key: string]: any }, shouldApplyVariant: boolean, metaKey: string }): object { +function getTag(content: object, prefix: string, tagsAsObject: boolean, locale: string, appliedVariants: AppliedVariants): object { const tags: any = {} const { metaKey, shouldApplyVariant, _applied_variants } = appliedVariants Object.entries(content).forEach(([key, value]) => { @@ -125,12 +131,9 @@ function getTagsValue(dataValue: string, tagsAsObject: boolean, appliedVariants: dataValue = newDataValueArray.join('.'); } else { - const variantisedFieldPaths = Object.keys(appliedVariants._applied_variants).sort((a, b) => { - return b.length - a.length; - }); - const variantisedParentPath = variantisedFieldPaths.find(path => appliedVariants.metaKey.startsWith(path)); - if(variantisedParentPath) { - const variant = appliedVariants._applied_variants[variantisedParentPath]; + const parentVariantisedPath = getParentVariantisedPath(appliedVariants); + if(parentVariantisedPath) { + const variant = appliedVariants._applied_variants[parentVariantisedPath]; const newDataValueArray = ('v2:' + dataValue).split('.'); newDataValueArray[1] = newDataValueArray[1] + '_' + variant; dataValue = newDataValueArray.join('.'); @@ -150,4 +153,26 @@ function getParentTagsValue(dataValue: string, tagsAsObject: boolean): any { } else { return `data-cslp-parent-field=${dataValue}`; } +} + +function getParentVariantisedPath(appliedVariants: AppliedVariants) { + try { + // Safety fallback + if(!appliedVariants._applied_variants) return ''; + const variantisedFieldPaths = Object.keys(appliedVariants._applied_variants).sort((a, b) => { + return b.length - a.length; + }); + const childPathFragments = appliedVariants.metaKey.split('.'); + // Safety fallback + if(childPathFragments.length === 0 || variantisedFieldPaths.length === 0) return ''; + const parentVariantisedPath = variantisedFieldPaths.find(path => { + const parentFragments = path.split('.'); + if(parentFragments.length > childPathFragments.length) return false; + return parentFragments.every((fragment, index) => childPathFragments[index] === fragment); + }) ?? ''; + return parentVariantisedPath; + } + catch(e) { + return ''; + } } \ No newline at end of file From ca32c0b434eb592d5c0ccdcff78d8a1604133007 Mon Sep 17 00:00:00 2001 From: csAyushDubey Date: Thu, 11 Sep 2025 11:25:31 +0530 Subject: [PATCH 7/7] chore : resolved merge conflicts --- .github/workflows/secrets-scan.yml | 29 +++++++++++++++++++++++++++++ CODEOWNERS | 12 +----------- 2 files changed, 30 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/secrets-scan.yml diff --git a/.github/workflows/secrets-scan.yml b/.github/workflows/secrets-scan.yml new file mode 100644 index 0000000..f9db69f --- /dev/null +++ b/.github/workflows/secrets-scan.yml @@ -0,0 +1,29 @@ +name: Secrets Scan +on: + pull_request: + types: [opened, synchronize, reopened] +jobs: + security-secrets: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: '2' + ref: '${{ github.event.pull_request.head.ref }}' + - run: | + git reset --soft HEAD~1 + - name: Install Talisman + run: | + # Download Talisman + wget https://github.com/thoughtworks/talisman/releases/download/v1.37.0/talisman_linux_amd64 -O talisman + + # Checksum verification + checksum=$(sha256sum ./talisman | awk '{print $1}') + if [ "$checksum" != "8e0ae8bb7b160bf10c4fa1448beb04a32a35e63505b3dddff74a092bccaaa7e4" ]; then exit 1; fi + + # Make it executable + chmod +x talisman + - name: Run talisman + run: | + # Run Talisman with the pre-commit hook + ./talisman --githook pre-commit \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS index 0496bc6..0773923 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,11 +1 @@ -* @contentstack/devex-pr-reviewers - -.github/workflows/sca-scan.yml @contentstack/security-admin - -.github/workflows/codeql-anaylsis.yml @contentstack/security-admin - -**/.snyk @contentstack/security-admin - -.github/workflows/policy-scan.yml @contentstack/security-admin - -.github/workflows/issues-jira.yml @contentstack/security-admin +* @contentstack/security-admin \ No newline at end of file