diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bd1d00..0449694 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## [1.3.18](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.3.17) (2025-02-17) + - Fix: Added fix for html injection + ## [1.3.17](https://github.com/contentstack/contentstack-utils-javascript/tree/v1.3.17) (2025-02-11) - Enh: updateAssetURLForGQL update for multilpe entries - Fix: Added support of br tag (\n) after just enter diff --git a/__test__/json-to-html.test.ts b/__test__/json-to-html.test.ts index 720feac..de20842 100644 --- a/__test__/json-to-html.test.ts +++ b/__test__/json-to-html.test.ts @@ -33,7 +33,8 @@ import { orderListJson2, testJsonRte, testJsonAsset, - embeddedAssetAsLinkJsonEntry} from './mock/json-element-mock' + embeddedAssetAsLinkJsonEntry, + escapeJsonHtml } from './mock/json-element-mock' import { blockquoteHtml, codeHtml, @@ -60,7 +61,8 @@ import { styleObjHtml, referenceObjHtml, referenceObjHtmlBlock, - imagetags} from './mock/json-element-mock-result' + imagetags, + escapeHtml } from './mock/json-element-mock-result' describe('Node parser paragraph content', () => { it('Should accept proper values', done => { const entry = { uid: 'uid'} @@ -122,6 +124,15 @@ describe('Node parser paragraph content', () => { expect(entry.rich_text_editor).toEqual([paragraphHtml]) done() }) + + it('Should render Json To html', done => { + const entry = {...escapeJsonHtml} + + jsonToHTML({entry, paths: ['rich_text_editor']}) + + expect(entry.rich_text_editor).toEqual(escapeHtml) + done() + }) }) diff --git a/__test__/mock/gql-asset-url-update-mock.ts b/__test__/mock/gql-asset-url-update-mock.ts index 671ca5f..bc9fdb3 100644 --- a/__test__/mock/gql-asset-url-update-mock.ts +++ b/__test__/mock/gql-asset-url-update-mock.ts @@ -264,21 +264,13 @@ export const gqlResponseForAssetUpdateMultipleEntries = { "title": "merry-marketplace.png", "url": "actual_asset_url.png", "content_type": "image/png", - "description": null, + "description": "null", "file_size": 273858, "filename": "merry-marketplace.png", - "permanent_url": "Permanent URL Not Defined!" - } - }, - { - "node": { - "title": "Screenshot.png", - "url": "https://azure-na-images.contentstack.com/v3/assets/folder_uid/asset_uid_2/folder_uid_4/Screenshot_2024-12-09_at_7.28.28_PM.png?branch=test2", - "content_type": "image/png", - "description": "", - "file_size": 287954, - "filename": "Screenshot_2024-12-09_at_7.28.28_PM.png", - "permanent_url": "Permanent URL Not Defined!" + "permanent_url": "Permanent URL Not Defined!", + "system" : { + "uid": "asset_uid_1" + } } }, { @@ -289,7 +281,10 @@ export const gqlResponseForAssetUpdateMultipleEntries = { "description": "", "file_size": 1050317, "filename": "Aadhaar.pdf", - "permanent_url": "Permanent URL Not Defined!" + "permanent_url": "Permanent URL Not Defined!", + "system" : { + "uid": "asset_uid_2" + } } } ] diff --git a/__test__/mock/json-element-mock-result.ts b/__test__/mock/json-element-mock-result.ts index 7b1b349..800d991 100644 --- a/__test__/mock/json-element-mock-result.ts +++ b/__test__/mock/json-element-mock-result.ts @@ -23,8 +23,8 @@ const classAndIdAttrsHtml = " const styleObjHtml = "

heading1

heading2

heading3

heading4

heading5
heading6
" const referenceObjHtml = "

Embed entry as a link

Open entry as a link in new tab

Bold entry

Bold entry open in new tab

" const referenceObjHtmlBlock = "

Embed entry as a link

Embed entry as a link open in new tab

" - const imagetags = "
\"batman\"
The Batman
" +const escapeHtml = "

<p>Welcome to Contentstack! <script>console.log(/\"Hello from Contentstack!/\");</script> Explore our platform to create, manage, and publish content seamlessly.</p>

" export { h1Html, @@ -53,5 +53,5 @@ export { referenceObjHtmlBlock, imagetags, paragraphHtmlWithNewLine, - + escapeHtml } \ No newline at end of file diff --git a/__test__/mock/json-element-mock.ts b/__test__/mock/json-element-mock.ts index 1863c3f..463d28e 100644 --- a/__test__/mock/json-element-mock.ts +++ b/__test__/mock/json-element-mock.ts @@ -2394,6 +2394,33 @@ const testJsonAsset={ "_version": 22 } } + +const escapeJsonHtml = { + title: 'entry and assets', + url: '/entry-and-assets', + rich_text_editor: { + uid: "uid", + _version: 13, + attrs: {}, + children: [ + { + type: "p", + attrs: {}, + uid: "0a1b5676aa510e5a", + children: [ + { + text: '

Welcome to Contentstack! Explore our platform to create, manage, and publish content seamlessly.

' + } + ] + } + ], + type: "doc" +}, + locale: 'en-us', + _in_progress: false, + uid: 'asset_uid_10', +} + export { h1Json, h2Json, @@ -2432,5 +2459,6 @@ export { orderListJson2, testJsonRte, testJsonAsset, - paragraphEntryWithNewline + paragraphEntryWithNewline, + escapeJsonHtml } \ No newline at end of file diff --git a/__test__/updateAssetURLForGQL.test.ts b/__test__/updateAssetURLForGQL.test.ts index fc33f5c..a165271 100644 --- a/__test__/updateAssetURLForGQL.test.ts +++ b/__test__/updateAssetURLForGQL.test.ts @@ -3,7 +3,7 @@ import { gqlResponseForAssetUpdate, gqlResponseForAssetUpdateWithoutSystemUid, g describe('updateAssetURLForGQL test', () => { - it.skip('should update the asset URL in the GQL response when proper response is passed', done => { + it('should update the asset URL in the GQL response when proper response is passed', done => { const testResponse = { ...gqlResponseForAssetUpdate }; updateAssetURLForGQL(testResponse); @@ -15,19 +15,19 @@ describe('updateAssetURLForGQL test', () => { done(); }); - it.skip('should update the asset URL in the GQL response when proper response is passed', done => { + it('should update the asset URL in the GQL response with multiple entries when proper response is passed', done => { const testResponse = { ...gqlResponseForAssetUpdateMultipleEntries }; updateAssetURLForGQL(testResponse); const rteField = testResponse.data.page_json_rte.items[0].body_new[0].body.body_12; const assetLink = rteField.json.children[0].attrs['asset-link']; const expectedUrl = rteField.embedded_itemsConnection.edges[0].node.url; - + expect(assetLink).toBe(expectedUrl); done(); }); - it.skip('should throw error when system.uid is not present', done => { + it('should throw error when system.uid is not present', done => { jest.spyOn(console, 'error').mockImplementation(() => {}); const testResponse = { ...gqlResponseForAssetUpdateWithoutSystemUid }; diff --git a/package-lock.json b/package-lock.json index c4d63a0..af29222 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@contentstack/utils", - "version": "1.3.17", + "version": "1.3.18", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@contentstack/utils", - "version": "1.3.17", + "version": "1.3.18", "license": "MIT", "devDependencies": { "@babel/preset-env": "^7.26.0", diff --git a/package.json b/package.json index 5479b66..7dfc8b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/utils", - "version": "1.3.17", + "version": "1.3.18", "description": "Contentstack utilities for Javascript", "main": "dist/index.es.js", "types": "dist/types/index.d.ts", diff --git a/src/helper/enumerate-entries.ts b/src/helper/enumerate-entries.ts index 5e3fd90..c23e5b6 100644 --- a/src/helper/enumerate-entries.ts +++ b/src/helper/enumerate-entries.ts @@ -42,7 +42,7 @@ export function enumerateContents( } export function textNodeToHTML(node: TextNode, renderOption: RenderOption): string { - let text = node.text; + let text = escapeHtml(node.text); if (node.classname || node.id) { text = (renderOption[MarkType.CLASSNAME_OR_ID] as RenderMark)(text, node.classname, node.id); } @@ -158,3 +158,10 @@ function nodeToHTML( } } } + +function escapeHtml(text: string): string { + return text + .replace(/&/g, '&') + .replace(//g, '>') +} \ No newline at end of file diff --git a/src/updateAssetURLForGQL.ts b/src/updateAssetURLForGQL.ts index cde8fb2..29a3e4f 100644 --- a/src/updateAssetURLForGQL.ts +++ b/src/updateAssetURLForGQL.ts @@ -20,21 +20,34 @@ export function updateAssetURLForGQL(gqlResponse:any) { function processEntry(entry:any) { for (let field in entry) { const fieldData = entry[field]; - const rteField = findRTEField(fieldData) - const edges = rteField?.embedded_itemsConnection?.edges; - edges.forEach((edge:any) => { - const node = edge.node; - if (node?.url && node?.filename) { - - if (!node?.system?.uid) throw new Error('Asset UID not found in the response'); - - const correspondingAsset = rteField?.json?.children?.find((child:any) => child.attrs['asset-uid'] === node.system.uid); - correspondingAsset.attrs['asset-link'] = node.url; - } + if (fieldData instanceof Array) { + fieldData.forEach((data:any) => { + findRTEFieldAndUpdateURL(data); }); + } else if (fieldData && typeof fieldData === 'object') { + findRTEFieldAndUpdateURL(fieldData); + } } } +function findRTEFieldAndUpdateURL(fieldData:any) { + const rteField = findRTEField(fieldData); + + if (!rteField) return; + + const edges = rteField?.embedded_itemsConnection?.edges; + edges.forEach((edge:any) => { + const node = edge.node; + if (node?.url && node?.filename) { + + if (!node?.system?.uid) throw new Error('Asset UID not found in the response'); + + const correspondingAsset = rteField?.json?.children?.find((child:any) => child.attrs['asset-uid'] === node.system.uid); + correspondingAsset.attrs['asset-link'] = node.url; + } + }); +} + function findRTEField(fieldData: any): any { if (fieldData && fieldData.embedded_itemsConnection) { return fieldData;