From 8322a6359847e3b7a65391d5d33f9955bf4685ae Mon Sep 17 00:00:00 2001 From: darshanr0107 Date: Mon, 25 Aug 2025 16:17:04 +0530 Subject: [PATCH 1/4] feat: add helper to differentiate user-defined layout from default on-behalf-of: @Mermaid-Chart --- docs/config/setup/config/README.md | 1 + .../setup/config/functions/getLayoutInfo.md | 27 +++++++++++++++++++ packages/mermaid/src/config.ts | 16 +++++++++++ 3 files changed, 44 insertions(+) create mode 100644 docs/config/setup/config/functions/getLayoutInfo.md diff --git a/docs/config/setup/config/README.md b/docs/config/setup/config/README.md index 67fca78eb..6b17a38ad 100644 --- a/docs/config/setup/config/README.md +++ b/docs/config/setup/config/README.md @@ -18,6 +18,7 @@ - [addDirective](functions/addDirective.md) - [getConfig](functions/getConfig.md) +- [getLayoutInfo](functions/getLayoutInfo.md) - [getSiteConfig](functions/getSiteConfig.md) - [reset](functions/reset.md) - [sanitize](functions/sanitize.md) diff --git a/docs/config/setup/config/functions/getLayoutInfo.md b/docs/config/setup/config/functions/getLayoutInfo.md new file mode 100644 index 000000000..044c6f96b --- /dev/null +++ b/docs/config/setup/config/functions/getLayoutInfo.md @@ -0,0 +1,27 @@ +> **Warning** +> +> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. +> +> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/setup/config/functions/getLayoutInfo.md](../../../../../packages/mermaid/src/docs/config/setup/config/functions/getLayoutInfo.md). + +[**mermaid**](../../README.md) + +--- + +# Function: getLayoutInfo() + +> **getLayoutInfo**(): `object` + +Defined in: [packages/mermaid/src/config.ts:260](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.ts#L260) + +## Returns + +`object` + +### isUserDefined + +> **isUserDefined**: `boolean` + +### layout + +> **layout**: `string` diff --git a/packages/mermaid/src/config.ts b/packages/mermaid/src/config.ts index 9468a3e46..295432ed3 100644 --- a/packages/mermaid/src/config.ts +++ b/packages/mermaid/src/config.ts @@ -248,3 +248,19 @@ const checkConfig = (config: MermaidConfig) => { issueWarning('LAZY_LOAD_DEPRECATED'); } }; + +const isUserDefinedLayout = (): boolean => { + if (configFromInitialize?.layout) { + return true; + } + + return directives.some((d) => !!d.layout); +}; + +export const getLayoutInfo = () => { + const cfg = getConfig(); + return { + layout: cfg.layout ?? 'dagre', + isUserDefined: isUserDefinedLayout(), + }; +}; From 31ecf31c2e35bbe7e3bec02b0ce50723a8d9ddee Mon Sep 17 00:00:00 2001 From: darshanr0107 Date: Mon, 25 Aug 2025 18:26:03 +0530 Subject: [PATCH 2/4] refactor: remove layout-specific checks and create generic function on-behalf-of: @Mermaid-Chart --- docs/config/setup/config/README.md | 2 +- .../setup/config/functions/getLayoutInfo.md | 27 ------------------- .../config/functions/getUserDefinedConfig.md | 19 +++++++++++++ packages/mermaid/src/config.ts | 20 +++++++------- 4 files changed, 29 insertions(+), 39 deletions(-) delete mode 100644 docs/config/setup/config/functions/getLayoutInfo.md create mode 100644 docs/config/setup/config/functions/getUserDefinedConfig.md diff --git a/docs/config/setup/config/README.md b/docs/config/setup/config/README.md index 6b17a38ad..c811c7b08 100644 --- a/docs/config/setup/config/README.md +++ b/docs/config/setup/config/README.md @@ -18,8 +18,8 @@ - [addDirective](functions/addDirective.md) - [getConfig](functions/getConfig.md) -- [getLayoutInfo](functions/getLayoutInfo.md) - [getSiteConfig](functions/getSiteConfig.md) +- [getUserDefinedConfig](functions/getUserDefinedConfig.md) - [reset](functions/reset.md) - [sanitize](functions/sanitize.md) - [saveConfigFromInitialize](functions/saveConfigFromInitialize.md) diff --git a/docs/config/setup/config/functions/getLayoutInfo.md b/docs/config/setup/config/functions/getLayoutInfo.md deleted file mode 100644 index 044c6f96b..000000000 --- a/docs/config/setup/config/functions/getLayoutInfo.md +++ /dev/null @@ -1,27 +0,0 @@ -> **Warning** -> -> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. -> -> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/setup/config/functions/getLayoutInfo.md](../../../../../packages/mermaid/src/docs/config/setup/config/functions/getLayoutInfo.md). - -[**mermaid**](../../README.md) - ---- - -# Function: getLayoutInfo() - -> **getLayoutInfo**(): `object` - -Defined in: [packages/mermaid/src/config.ts:260](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.ts#L260) - -## Returns - -`object` - -### isUserDefined - -> **isUserDefined**: `boolean` - -### layout - -> **layout**: `string` diff --git a/docs/config/setup/config/functions/getUserDefinedConfig.md b/docs/config/setup/config/functions/getUserDefinedConfig.md new file mode 100644 index 000000000..ed39f1337 --- /dev/null +++ b/docs/config/setup/config/functions/getUserDefinedConfig.md @@ -0,0 +1,19 @@ +> **Warning** +> +> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. +> +> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/setup/config/functions/getUserDefinedConfig.md](../../../../../packages/mermaid/src/docs/config/setup/config/functions/getUserDefinedConfig.md). + +[**mermaid**](../../README.md) + +--- + +# Function: getUserDefinedConfig() + +> **getUserDefinedConfig**(): [`MermaidConfig`](../../mermaid/interfaces/MermaidConfig.md) + +Defined in: [packages/mermaid/src/config.ts:252](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.ts#L252) + +## Returns + +[`MermaidConfig`](../../mermaid/interfaces/MermaidConfig.md) diff --git a/packages/mermaid/src/config.ts b/packages/mermaid/src/config.ts index 295432ed3..4fcb3224d 100644 --- a/packages/mermaid/src/config.ts +++ b/packages/mermaid/src/config.ts @@ -249,18 +249,16 @@ const checkConfig = (config: MermaidConfig) => { } }; -const isUserDefinedLayout = (): boolean => { - if (configFromInitialize?.layout) { - return true; +export const getUserDefinedConfig = (): MermaidConfig => { + let userConfig: MermaidConfig = {}; + + if (configFromInitialize) { + userConfig = assignWithDepth(userConfig, configFromInitialize); } - return directives.some((d) => !!d.layout); -}; + for (const d of directives) { + userConfig = assignWithDepth(userConfig, d); + } -export const getLayoutInfo = () => { - const cfg = getConfig(); - return { - layout: cfg.layout ?? 'dagre', - isUserDefined: isUserDefinedLayout(), - }; + return userConfig; }; From 4760ed88937f17d6c7b191fb8f588f364e6195e8 Mon Sep 17 00:00:00 2001 From: darshanr0107 Date: Mon, 25 Aug 2025 19:13:58 +0530 Subject: [PATCH 3/4] fix: add unit tests for getUserDefinedConfig across different scenarios on-behalf-of: @Mermaid-Chart --- packages/mermaid/src/config.spec.ts | 163 ++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/packages/mermaid/src/config.spec.ts b/packages/mermaid/src/config.spec.ts index 000be1282..2cacfebbf 100644 --- a/packages/mermaid/src/config.spec.ts +++ b/packages/mermaid/src/config.spec.ts @@ -78,3 +78,166 @@ describe('when working with site config', () => { expect(config_4.altFontFamily).toBeUndefined(); }); }); + +describe('getUserDefinedConfig', () => { + beforeEach(() => { + configApi.reset(); + }); + + it('should return empty object when no user config is defined', () => { + const userConfig = configApi.getUserDefinedConfig(); + expect(userConfig).toEqual({}); + }); + + it('should return config from initialize only', () => { + const initConfig: MermaidConfig = { theme: 'dark', fontFamily: 'Arial' }; + configApi.saveConfigFromInitialize(initConfig); + + const userConfig = configApi.getUserDefinedConfig(); + expect(userConfig).toEqual(initConfig); + }); + + it('should return config from directives only', () => { + const directive1: MermaidConfig = { layout: 'elk', fontSize: 14 }; + const directive2: MermaidConfig = { theme: 'forest' }; + + configApi.addDirective(directive1); + configApi.addDirective(directive2); + + const userConfig = configApi.getUserDefinedConfig(); + expect(userConfig.layout).toBe('elk'); + expect(userConfig.fontSize).toBe(14); + expect(userConfig.theme).toBe('forest'); + }); + + it('should combine initialize config and directives', () => { + const initConfig: MermaidConfig = { theme: 'dark', fontFamily: 'Arial', layout: 'dagre' }; + const directive1: MermaidConfig = { layout: 'elk', fontSize: 14 }; + const directive2: MermaidConfig = { theme: 'forest' }; + + configApi.saveConfigFromInitialize(initConfig); + configApi.addDirective(directive1); + configApi.addDirective(directive2); + + const userConfig = configApi.getUserDefinedConfig(); + expect(userConfig.theme).toBe('forest'); + expect(userConfig.fontFamily).toBe('Arial'); + expect(userConfig.layout).toBe('elk'); + expect(userConfig.fontSize).toBe(14); + }); + + it('should handle nested config objects properly', () => { + const initConfig: MermaidConfig = { + flowchart: { nodeSpacing: 50, rankSpacing: 100 }, + theme: 'default', + }; + const directive: MermaidConfig = { + flowchart: { nodeSpacing: 75, curve: 'basis' }, + mindmap: { padding: 20 }, + }; + + configApi.saveConfigFromInitialize(initConfig); + configApi.addDirective(directive); + + const userConfig = configApi.getUserDefinedConfig(); + expect(userConfig).toEqual({ + theme: 'default', + flowchart: { + nodeSpacing: 75, + rankSpacing: 100, + curve: 'basis', + }, + mindmap: { + padding: 20, + }, + }); + }); + + it('should handle complex nested overrides', () => { + const initConfig: MermaidConfig = { + flowchart: { + nodeSpacing: 50, + rankSpacing: 100, + curve: 'linear', + }, + theme: 'default', + }; + const directive1: MermaidConfig = { + flowchart: { + nodeSpacing: 75, + }, + fontSize: 12, + }; + const directive2: MermaidConfig = { + flowchart: { + curve: 'basis', + nodeSpacing: 100, + }, + mindmap: { + padding: 15, + }, + }; + + configApi.saveConfigFromInitialize(initConfig); + configApi.addDirective(directive1); + configApi.addDirective(directive2); + + const userConfig = configApi.getUserDefinedConfig(); + expect(userConfig).toEqual({ + theme: 'default', + fontSize: 12, + flowchart: { + nodeSpacing: 100, + rankSpacing: 100, + curve: 'basis', + }, + mindmap: { + padding: 15, + }, + }); + }); + + it('should return independent copies (not references)', () => { + const initConfig: MermaidConfig = { theme: 'dark', flowchart: { nodeSpacing: 50 } }; + configApi.saveConfigFromInitialize(initConfig); + + const userConfig1 = configApi.getUserDefinedConfig(); + const userConfig2 = configApi.getUserDefinedConfig(); + + userConfig1.theme = 'neutral'; + userConfig1.flowchart!.nodeSpacing = 999; + + expect(userConfig2.theme).toBe('dark'); + expect(userConfig2.flowchart!.nodeSpacing).toBe(50); + }); + + it('should handle edge cases with undefined values', () => { + const initConfig: MermaidConfig = { theme: 'dark', layout: undefined }; + const directive: MermaidConfig = { fontSize: 14, fontFamily: undefined }; + + configApi.saveConfigFromInitialize(initConfig); + configApi.addDirective(directive); + + const userConfig = configApi.getUserDefinedConfig(); + expect(userConfig.theme).toBe('dark'); + expect(userConfig.layout).toBeUndefined(); + expect(userConfig.fontFamily).toBeUndefined(); + expect(userConfig.fontSize).toBe(14); + }); + + it('should work correctly after reset', () => { + const initConfig: MermaidConfig = { theme: 'dark' }; + const directive: MermaidConfig = { layout: 'elk' }; + + configApi.saveConfigFromInitialize(initConfig); + configApi.addDirective(directive); + + let userConfig = configApi.getUserDefinedConfig(); + expect(userConfig).toEqual({ theme: 'dark', layout: 'elk' }); + + configApi.reset(); + + userConfig = configApi.getUserDefinedConfig(); + expect(userConfig).toEqual({ theme: 'dark' }); + }); +}); From 50127f3ffe3d8a9e66cf263e1159b72785e848ee Mon Sep 17 00:00:00 2001 From: darshanr0107 Date: Tue, 26 Aug 2025 13:17:38 +0530 Subject: [PATCH 4/4] fix: review comments related to getUserDefinedConfig tests on-behalf-of: @Mermaid-Chart --- packages/mermaid/src/config.spec.ts | 109 +++++++++++++++++----------- 1 file changed, 65 insertions(+), 44 deletions(-) diff --git a/packages/mermaid/src/config.spec.ts b/packages/mermaid/src/config.spec.ts index 2cacfebbf..7fbae03af 100644 --- a/packages/mermaid/src/config.spec.ts +++ b/packages/mermaid/src/config.spec.ts @@ -104,10 +104,14 @@ describe('getUserDefinedConfig', () => { configApi.addDirective(directive1); configApi.addDirective(directive2); - const userConfig = configApi.getUserDefinedConfig(); - expect(userConfig.layout).toBe('elk'); - expect(userConfig.fontSize).toBe(14); - expect(userConfig.theme).toBe('forest'); + expect(configApi.getUserDefinedConfig()).toMatchInlineSnapshot(` + { + "fontFamily": "Arial", + "fontSize": 14, + "layout": "elk", + "theme": "forest", + } + `); }); it('should combine initialize config and directives', () => { @@ -120,10 +124,14 @@ describe('getUserDefinedConfig', () => { configApi.addDirective(directive2); const userConfig = configApi.getUserDefinedConfig(); - expect(userConfig.theme).toBe('forest'); - expect(userConfig.fontFamily).toBe('Arial'); - expect(userConfig.layout).toBe('elk'); - expect(userConfig.fontSize).toBe(14); + expect(userConfig).toMatchInlineSnapshot(` + { + "fontFamily": "Arial", + "fontSize": 14, + "layout": "elk", + "theme": "forest", + } + `); }); it('should handle nested config objects properly', () => { @@ -140,17 +148,19 @@ describe('getUserDefinedConfig', () => { configApi.addDirective(directive); const userConfig = configApi.getUserDefinedConfig(); - expect(userConfig).toEqual({ - theme: 'default', - flowchart: { - nodeSpacing: 75, - rankSpacing: 100, - curve: 'basis', - }, - mindmap: { - padding: 20, - }, - }); + expect(userConfig).toMatchInlineSnapshot(` + { + "flowchart": { + "curve": "basis", + "nodeSpacing": 75, + "rankSpacing": 100, + }, + "mindmap": { + "padding": 20, + }, + "theme": "default", + } + `); }); it('should handle complex nested overrides', () => { @@ -183,18 +193,20 @@ describe('getUserDefinedConfig', () => { configApi.addDirective(directive2); const userConfig = configApi.getUserDefinedConfig(); - expect(userConfig).toEqual({ - theme: 'default', - fontSize: 12, - flowchart: { - nodeSpacing: 100, - rankSpacing: 100, - curve: 'basis', - }, - mindmap: { - padding: 15, - }, - }); + expect(userConfig).toMatchInlineSnapshot(` + { + "flowchart": { + "curve": "basis", + "nodeSpacing": 100, + "rankSpacing": 100, + }, + "fontSize": 12, + "mindmap": { + "padding": 15, + }, + "theme": "default", + } + `); }); it('should return independent copies (not references)', () => { @@ -207,8 +219,14 @@ describe('getUserDefinedConfig', () => { userConfig1.theme = 'neutral'; userConfig1.flowchart!.nodeSpacing = 999; - expect(userConfig2.theme).toBe('dark'); - expect(userConfig2.flowchart!.nodeSpacing).toBe(50); + expect(userConfig2).toMatchInlineSnapshot(` + { + "flowchart": { + "nodeSpacing": 50, + }, + "theme": "dark", + } + `); }); it('should handle edge cases with undefined values', () => { @@ -218,26 +236,29 @@ describe('getUserDefinedConfig', () => { configApi.saveConfigFromInitialize(initConfig); configApi.addDirective(directive); - const userConfig = configApi.getUserDefinedConfig(); - expect(userConfig.theme).toBe('dark'); - expect(userConfig.layout).toBeUndefined(); - expect(userConfig.fontFamily).toBeUndefined(); - expect(userConfig.fontSize).toBe(14); + expect(configApi.getUserDefinedConfig()).toMatchInlineSnapshot(` + { + "fontSize": 14, + "layout": undefined, + "theme": "dark", + } + `); }); - it('should work correctly after reset', () => { + it('should retain config from initialize after reset', () => { const initConfig: MermaidConfig = { theme: 'dark' }; const directive: MermaidConfig = { layout: 'elk' }; configApi.saveConfigFromInitialize(initConfig); configApi.addDirective(directive); - let userConfig = configApi.getUserDefinedConfig(); - expect(userConfig).toEqual({ theme: 'dark', layout: 'elk' }); + expect(configApi.getUserDefinedConfig()).toMatchInlineSnapshot(` + { + "layout": "elk", + "theme": "dark", + } + `); configApi.reset(); - - userConfig = configApi.getUserDefinedConfig(); - expect(userConfig).toEqual({ theme: 'dark' }); }); });