From dfa71317adf91ab2ad49109e5c5e868ffd56bef9 Mon Sep 17 00:00:00 2001 From: Ian Sanders Date: Tue, 14 May 2024 13:57:32 -0400 Subject: [PATCH 1/8] Encode string to UTF-8 before encoding to Base64 --- packages/mermaid/src/mermaidAPI.spec.ts | 2 +- packages/mermaid/src/mermaidAPI.ts | 4 ++-- packages/mermaid/src/utils/base64.ts | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 packages/mermaid/src/utils/base64.ts diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts index 40efd776b..6e7765c49 100644 --- a/packages/mermaid/src/mermaidAPI.spec.ts +++ b/packages/mermaid/src/mermaidAPI.spec.ts @@ -176,7 +176,7 @@ describe('mermaidAPI', () => { }); describe('putIntoIFrame', () => { - const inputSvgCode = 'this is the SVG code'; + const inputSvgCode = 'this is the SVG code ⛵'; it('uses the default SVG iFrame height is used if no svgElement given', () => { const result = putIntoIFrame(inputSvgCode); diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index fc5eb77dc..4c635f84b 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -31,6 +31,7 @@ import { setA11yDiagramInfo, addSVGa11yTitleDescription } from './accessibility. import type { DiagramMetadata, DiagramStyleClassDef } from './diagram-api/types.js'; import { preprocessDiagram } from './preprocess.js'; import { decodeEntities } from './utils.js'; +import {toBase64} from './utils/base64.js'; const MAX_TEXTLENGTH = 50_000; const MAX_TEXTLENGTH_EXCEEDED_MSG = @@ -249,13 +250,12 @@ export const cleanUpSvgCode = ( * @param svgCode - the svg code to put inside the iFrame * @param svgElement - the d3 node that has the current svgElement so we can get the height from it * @returns - the code with the iFrame that now contains the svgCode - * TODO replace btoa(). Replace with buf.toString('base64')? */ export const putIntoIFrame = (svgCode = '', svgElement?: D3Element): string => { const height = svgElement?.viewBox?.baseVal?.height ? svgElement.viewBox.baseVal.height + 'px' : IFRAME_HEIGHT; - const base64encodedSrc = btoa('' + svgCode + ''); + const base64encodedSrc = toBase64('' + svgCode + ''); return ``; diff --git a/packages/mermaid/src/utils/base64.ts b/packages/mermaid/src/utils/base64.ts new file mode 100644 index 000000000..4a0f5b295 --- /dev/null +++ b/packages/mermaid/src/utils/base64.ts @@ -0,0 +1,6 @@ +export function toBase64(str: string) { + // ref: https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem + const utf8Bytes = new TextEncoder().encode(str); + const utf8Str = Array.from(utf8Bytes, (byte) => String.fromCodePoint(byte)).join(''); + return btoa(utf8Str); +} From 56c4f10607467c4003993f95e3b3e0c9fa6f94e5 Mon Sep 17 00:00:00 2001 From: Ian Sanders Date: Tue, 14 May 2024 14:08:35 -0400 Subject: [PATCH 2/8] Add charset=UTF-8 --- packages/mermaid/src/mermaidAPI.spec.ts | 2 +- packages/mermaid/src/mermaidAPI.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts index 6e7765c49..e9a214f61 100644 --- a/packages/mermaid/src/mermaidAPI.spec.ts +++ b/packages/mermaid/src/mermaidAPI.spec.ts @@ -200,7 +200,7 @@ describe('mermaidAPI', () => { it('sets src to base64 version of svgCode', () => { const base64encodedSrc = btoa('' + inputSvgCode + ''); - const expectedRegExp = new RegExp('src="data:text/html;base64,' + base64encodedSrc + '"'); + const expectedRegExp = new RegExp('src="data:text/html;charset=UTF-8;base64,' + base64encodedSrc + '"'); const result = putIntoIFrame(inputSvgCode); expect(result).toMatch(expectedRegExp); diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index 4c635f84b..34e022ff9 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -256,7 +256,7 @@ export const putIntoIFrame = (svgCode = '', svgElement?: D3Element): string => { ? svgElement.viewBox.baseVal.height + 'px' : IFRAME_HEIGHT; const base64encodedSrc = toBase64('' + svgCode + ''); - return ``; }; From 6f56d94c64b2c24a0036f7e9fb002bb7fd2dadf5 Mon Sep 17 00:00:00 2001 From: Ian Sanders Date: Tue, 14 May 2024 14:30:13 -0400 Subject: [PATCH 3/8] Fix test --- packages/mermaid/src/mermaidAPI.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts index e9a214f61..5aafe13fd 100644 --- a/packages/mermaid/src/mermaidAPI.spec.ts +++ b/packages/mermaid/src/mermaidAPI.spec.ts @@ -69,6 +69,7 @@ vi.mock('stylis', () => { import { compile, serialize } from 'stylis'; import { decodeEntities, encodeEntities } from './utils.js'; import { Diagram } from './Diagram.js'; +import {toBase64} from './utils/base64.js'; /** * @see https://vitest.dev/guide/mocking.html Mock part of a module @@ -199,7 +200,7 @@ describe('mermaidAPI', () => { }); it('sets src to base64 version of svgCode', () => { - const base64encodedSrc = btoa('' + inputSvgCode + ''); + const base64encodedSrc = toBase64('' + inputSvgCode + ''); const expectedRegExp = new RegExp('src="data:text/html;charset=UTF-8;base64,' + base64encodedSrc + '"'); const result = putIntoIFrame(inputSvgCode); From df94d3994dac4b62c6ec55377c0aed2c61d3a547 Mon Sep 17 00:00:00 2001 From: Ian Sanders Date: Tue, 14 May 2024 14:34:10 -0400 Subject: [PATCH 4/8] Format --- packages/mermaid/src/mermaidAPI.spec.ts | 10 +++++++--- packages/mermaid/src/mermaidAPI.ts | 6 ++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts index 5aafe13fd..1e030fab9 100644 --- a/packages/mermaid/src/mermaidAPI.spec.ts +++ b/packages/mermaid/src/mermaidAPI.spec.ts @@ -69,7 +69,7 @@ vi.mock('stylis', () => { import { compile, serialize } from 'stylis'; import { decodeEntities, encodeEntities } from './utils.js'; import { Diagram } from './Diagram.js'; -import {toBase64} from './utils/base64.js'; +import { toBase64 } from './utils/base64.js'; /** * @see https://vitest.dev/guide/mocking.html Mock part of a module @@ -200,8 +200,12 @@ describe('mermaidAPI', () => { }); it('sets src to base64 version of svgCode', () => { - const base64encodedSrc = toBase64('' + inputSvgCode + ''); - const expectedRegExp = new RegExp('src="data:text/html;charset=UTF-8;base64,' + base64encodedSrc + '"'); + const base64encodedSrc = toBase64( + '' + inputSvgCode + '' + ); + const expectedRegExp = new RegExp( + 'src="data:text/html;charset=UTF-8;base64,' + base64encodedSrc + '"' + ); const result = putIntoIFrame(inputSvgCode); expect(result).toMatch(expectedRegExp); diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index 34e022ff9..12a7f176f 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -31,7 +31,7 @@ import { setA11yDiagramInfo, addSVGa11yTitleDescription } from './accessibility. import type { DiagramMetadata, DiagramStyleClassDef } from './diagram-api/types.js'; import { preprocessDiagram } from './preprocess.js'; import { decodeEntities } from './utils.js'; -import {toBase64} from './utils/base64.js'; +import { toBase64 } from './utils/base64.js'; const MAX_TEXTLENGTH = 50_000; const MAX_TEXTLENGTH_EXCEEDED_MSG = @@ -255,7 +255,9 @@ export const putIntoIFrame = (svgCode = '', svgElement?: D3Element): string => { const height = svgElement?.viewBox?.baseVal?.height ? svgElement.viewBox.baseVal.height + 'px' : IFRAME_HEIGHT; - const base64encodedSrc = toBase64('' + svgCode + ''); + const base64encodedSrc = toBase64( + '' + svgCode + '' + ); return ``; From 3b2b8dacd8878062f3b139498b83cb2352424198 Mon Sep 17 00:00:00 2001 From: Ian Sanders Date: Tue, 14 May 2024 15:02:14 -0400 Subject: [PATCH 5/8] Replace regex with contain match --- packages/mermaid/src/mermaidAPI.spec.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts index 1e030fab9..9d8df3c0f 100644 --- a/packages/mermaid/src/mermaidAPI.spec.ts +++ b/packages/mermaid/src/mermaidAPI.spec.ts @@ -203,12 +203,10 @@ describe('mermaidAPI', () => { const base64encodedSrc = toBase64( '' + inputSvgCode + '' ); - const expectedRegExp = new RegExp( - 'src="data:text/html;charset=UTF-8;base64,' + base64encodedSrc + '"' - ); + const expectedSrc = 'src="data:text/html;charset=UTF-8;base64,' + base64encodedSrc + '"' const result = putIntoIFrame(inputSvgCode); - expect(result).toMatch(expectedRegExp); + expect(result).toContain(expectedSrc); }); it('uses the height and appends px from the svgElement given', () => { From e26dea6416b03d16b952368eb54673310d8fdd06 Mon Sep 17 00:00:00 2001 From: Ian Sanders Date: Tue, 14 May 2024 15:07:31 -0400 Subject: [PATCH 6/8] Format --- packages/mermaid/src/mermaidAPI.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts index 9d8df3c0f..223753b93 100644 --- a/packages/mermaid/src/mermaidAPI.spec.ts +++ b/packages/mermaid/src/mermaidAPI.spec.ts @@ -203,7 +203,7 @@ describe('mermaidAPI', () => { const base64encodedSrc = toBase64( '' + inputSvgCode + '' ); - const expectedSrc = 'src="data:text/html;charset=UTF-8;base64,' + base64encodedSrc + '"' + const expectedSrc = 'src="data:text/html;charset=UTF-8;base64,' + base64encodedSrc + '"'; const result = putIntoIFrame(inputSvgCode); expect(result).toContain(expectedSrc); From 81d8b9d02ea71b878064427f14231ba6f1eb7099 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Thu, 20 Jun 2024 18:41:11 +0530 Subject: [PATCH 7/8] chore: Fix docs --- .../setup/interfaces/mermaidAPI.ParseOptions.md | 2 +- .../setup/interfaces/mermaidAPI.ParseResult.md | 2 +- .../setup/interfaces/mermaidAPI.RenderResult.md | 6 +++--- docs/config/setup/modules/mermaidAPI.md | 17 ++++++++--------- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/config/setup/interfaces/mermaidAPI.ParseOptions.md b/docs/config/setup/interfaces/mermaidAPI.ParseOptions.md index fa100744e..c388a4f26 100644 --- a/docs/config/setup/interfaces/mermaidAPI.ParseOptions.md +++ b/docs/config/setup/interfaces/mermaidAPI.ParseOptions.md @@ -19,4 +19,4 @@ The `parseError` function will not be called. #### Defined in -[mermaidAPI.ts:64](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L64) +[mermaidAPI.ts:65](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L65) diff --git a/docs/config/setup/interfaces/mermaidAPI.ParseResult.md b/docs/config/setup/interfaces/mermaidAPI.ParseResult.md index 9f912cc8c..376f29346 100644 --- a/docs/config/setup/interfaces/mermaidAPI.ParseResult.md +++ b/docs/config/setup/interfaces/mermaidAPI.ParseResult.md @@ -18,4 +18,4 @@ The diagram type, e.g. 'flowchart', 'sequence', etc. #### Defined in -[mermaidAPI.ts:71](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L71) +[mermaidAPI.ts:72](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L72) diff --git a/docs/config/setup/interfaces/mermaidAPI.RenderResult.md b/docs/config/setup/interfaces/mermaidAPI.RenderResult.md index b5cc48038..52ef3ec0c 100644 --- a/docs/config/setup/interfaces/mermaidAPI.RenderResult.md +++ b/docs/config/setup/interfaces/mermaidAPI.RenderResult.md @@ -39,7 +39,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present. #### Defined in -[mermaidAPI.ts:94](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L94) +[mermaidAPI.ts:95](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L95) --- @@ -51,7 +51,7 @@ The diagram type, e.g. 'flowchart', 'sequence', etc. #### Defined in -[mermaidAPI.ts:84](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L84) +[mermaidAPI.ts:85](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L85) --- @@ -63,4 +63,4 @@ The svg code for the rendered graph. #### Defined in -[mermaidAPI.ts:80](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L80) +[mermaidAPI.ts:81](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L81) diff --git a/docs/config/setup/modules/mermaidAPI.md b/docs/config/setup/modules/mermaidAPI.md index d17533a03..7bdd94775 100644 --- a/docs/config/setup/modules/mermaidAPI.md +++ b/docs/config/setup/modules/mermaidAPI.md @@ -26,7 +26,7 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi) #### Defined in -[mermaidAPI.ts:74](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L74) +[mermaidAPI.ts:75](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L75) ## Variables @@ -98,7 +98,7 @@ mermaid.initialize(config); #### Defined in -[mermaidAPI.ts:634](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L634) +[mermaidAPI.ts:636](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L636) ## Functions @@ -129,7 +129,7 @@ Return the last node appended #### Defined in -[mermaidAPI.ts:276](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L276) +[mermaidAPI.ts:278](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L278) --- @@ -155,7 +155,7 @@ the cleaned up svgCode #### Defined in -[mermaidAPI.ts:222](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L222) +[mermaidAPI.ts:223](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L223) --- @@ -180,7 +180,7 @@ the string with all the user styles #### Defined in -[mermaidAPI.ts:153](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L153) +[mermaidAPI.ts:154](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L154) --- @@ -203,7 +203,7 @@ the string with all the user styles #### Defined in -[mermaidAPI.ts:199](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L199) +[mermaidAPI.ts:200](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L200) --- @@ -230,7 +230,7 @@ with an enclosing block that has each of the cssClasses followed by !important; #### Defined in -[mermaidAPI.ts:138](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L138) +[mermaidAPI.ts:139](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L139) --- @@ -252,7 +252,6 @@ Put the svgCode into an iFrame. Return the iFrame code `string` - the code with the iFrame that now contains the svgCode - TODO replace btoa(). Replace with buf.toString('base64')? #### Defined in @@ -281,4 +280,4 @@ Remove any existing elements from the given document #### Defined in -[mermaidAPI.ts:326](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L326) +[mermaidAPI.ts:328](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L328) From 9bbd3cab3cfb0685e7e7d7bbd2c7287f46568a13 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Thu, 20 Jun 2024 22:48:28 +0530 Subject: [PATCH 8/8] chore: Use string templates --- docs/config/setup/modules/mermaidAPI.md | 6 +++--- packages/mermaid/src/mermaidAPI.spec.ts | 7 ++----- packages/mermaid/src/mermaidAPI.ts | 4 +--- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/docs/config/setup/modules/mermaidAPI.md b/docs/config/setup/modules/mermaidAPI.md index 7bdd94775..d7bfe68ef 100644 --- a/docs/config/setup/modules/mermaidAPI.md +++ b/docs/config/setup/modules/mermaidAPI.md @@ -98,7 +98,7 @@ mermaid.initialize(config); #### Defined in -[mermaidAPI.ts:636](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L636) +[mermaidAPI.ts:634](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L634) ## Functions @@ -129,7 +129,7 @@ Return the last node appended #### Defined in -[mermaidAPI.ts:278](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L278) +[mermaidAPI.ts:276](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L276) --- @@ -280,4 +280,4 @@ Remove any existing elements from the given document #### Defined in -[mermaidAPI.ts:328](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L328) +[mermaidAPI.ts:326](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L326) diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts index 6c220b9e1..1134f8635 100644 --- a/packages/mermaid/src/mermaidAPI.spec.ts +++ b/packages/mermaid/src/mermaidAPI.spec.ts @@ -200,11 +200,8 @@ describe('mermaidAPI', () => { }); it('sets src to base64 version of svgCode', () => { - const base64encodedSrc = toBase64( - '' + inputSvgCode + '' - ); - const expectedSrc = 'src="data:text/html;charset=UTF-8;base64,' + base64encodedSrc + '"'; - + const base64encodedSrc = toBase64(`${inputSvgCode}`); + const expectedSrc = `src="data:text/html;charset=UTF-8;base64,${base64encodedSrc}"`; const result = putIntoIFrame(inputSvgCode); expect(result).toContain(expectedSrc); }); diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index a7daa6ca2..ee6696af9 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -254,9 +254,7 @@ export const putIntoIFrame = (svgCode = '', svgElement?: D3Element): string => { const height = svgElement?.viewBox?.baseVal?.height ? svgElement.viewBox.baseVal.height + 'px' : IFRAME_HEIGHT; - const base64encodedSrc = toBase64( - '' + svgCode + '' - ); + const base64encodedSrc = toBase64(`${svgCode}`); return ``;