Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 28 additions & 28 deletions .github/workflows/secrets-scan.yml
Original file line number Diff line number Diff line change
@@ -1,29 +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
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
2 changes: 1 addition & 1 deletion .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ fileignoreconfig:
ignore_detectors:
- filecontent
- filename: package-lock.json
checksum: 030162c3c72502ccac30f3ce0172f1c2ae31a794544e0e1096771326780ea21b
checksum: 88174adc8b9dcedecf549defe09988aa4ca95940801e923d829123ba2f3ef6f4
- filename: src/entry-editable.ts
checksum: f9c4694229205fca252bb087482a3e408c6ad3b237cd108e337bcff49458db5c
- filename: .husky/pre-commit
Expand Down
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Changelog

## [1.5.0](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.4.1) (2025-09-01)
## [1.4.3](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.4.3) (2025-09-22)
- Fix data-cslp generation logic in case of applied_variants

## [1.4.2](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.4.2) (2025-09-01)
- Improve null checks in find embedded entry and find embedded asset functions

## [1.4.1](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.4.1) (2025-05-26)
Expand Down
2 changes: 1 addition & 1 deletion CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @contentstack/security-admin
* @contentstack/security-admin
147 changes: 144 additions & 3 deletions __test__/entry-editable.test.ts
Original file line number Diff line number Diff line change
@@ -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_parent_path_variants } from './mock/entry-editable-mock'

describe('Entry editable test', () => {
it('Entry with text test', done => {
Expand Down Expand Up @@ -129,4 +127,147 @@ 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')

// 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')
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 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'})

// 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'})
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'][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()
})

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()
})
})

})
Loading
Loading