diff --git a/cypress/integration/other/interaction.spec.js b/cypress/integration/other/interaction.spec.js index b253d0389..857141b5b 100644 --- a/cypress/integration/other/interaction.spec.js +++ b/cypress/integration/other/interaction.spec.js @@ -1,266 +1,180 @@ describe('Interaction', () => { - describe('Interaction - security level loose', () => { - it('Graph: should handle a click on a node with a bound function', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g#flowchart-Function-4').click(); + describe('Security level loose', () => { + beforeEach(() => { + cy.visit('http://localhost:9000/click_security_loose.html'); + }); + it('Graph: should handle a click on a node with a bound function', () => { + cy.contains('FunctionTest1').parents('.node').click(); cy.get('.created-by-click').should('have.text', 'Clicked By Flow'); }); + it('Graph: should handle a click on a node with a bound function with args', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g#flowchart-FunctionArg-28').click(); - + cy.contains('FunctionArgTest2').parents('.node').click(); cy.get('.created-by-click-2').should('have.text', 'Clicked By Flow: ARGUMENT'); }); + it('Flowchart: should handle a click on a node with a bound function where the node starts with a number', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g[id="flowchart-FunctionArg-34"]').click(); - + cy.contains('2FunctionArg').parents('.node').click(); cy.get('.created-by-click-2').should('have.text', 'Clicked By Flow: ARGUMENT'); }); - it('Graph: should handle a click on a node with a bound url', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('#flowchart-URL-5').click(); - cy.location().should((location) => { - expect(location.href).to.eq('http://localhost:9000/webpackUsage.html'); + it('Graph: should handle a click on a node with a bound url', () => { + // When there is a URL, cy.contains selects the a tag instead of the span. The .node is a child of a, so we have to use find instead of parent. + cy.contains('URLTest1').find('.node').click(); + cy.location().should(({ href }) => { + expect(href).to.eq('http://localhost:9000/empty.html'); }); }); - it('Graph: should handle a click on a node with a bound url where the node starts with a number', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g[id="flowchart-2URL-11"]').click(); - cy.location().should((location) => { - expect(location.href).to.eq('http://localhost:9000/webpackUsage.html'); + it('Graph: should handle a click on a node with a bound url where the node starts with a number', () => { + cy.contains('2URL').find('.node').click(); + cy.location().should(({ href }) => { + expect(href).to.eq('http://localhost:9000/empty.html'); }); }); it('Flowchart-v2: should handle a click on a node with a bound function', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g#flowchart-Function-16').click(); - + cy.contains('FunctionTest2').parents('.node').click(); cy.get('.created-by-click').should('have.text', 'Clicked By Flow'); }); + it('Flowchart-v2: should handle a click on a node with a bound function where the node starts with a number', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g[id="flowchart-1Function-22"]').click(); - + cy.contains('10Function').parents('.node').click(); cy.get('.created-by-click').should('have.text', 'Clicked By Flow'); }); - it('Flowchart-v2: should handle a click on a node with a bound url', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('#flowchart-URL-17').click(); - cy.location().should((location) => { - expect(location.href).to.eq('http://localhost:9000/webpackUsage.html'); + it('Flowchart-v2: should handle a click on a node with a bound url', () => { + cy.contains('URLTest2').find('.node').click(); + cy.location().should(({ href }) => { + expect(href).to.eq('http://localhost:9000/empty.html'); }); }); - it('Flowchart-v2: should handle a click on a node with a bound url where the node starts with a number', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g[id="flowchart-2URL-23"]').click(); - cy.location().should((location) => { - expect(location.href).to.eq('http://localhost:9000/webpackUsage.html'); + it('Flowchart-v2: should handle a click on a node with a bound url where the node starts with a number', () => { + cy.contains('20URL').find('.node').click(); + cy.location().should(({ href }) => { + expect(href).to.eq('http://localhost:9000/empty.html'); }); }); it('should handle a click on a task with a bound URL clicking on the rect', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('rect#cl1').click({ force: true }); - - cy.location().should((location) => { - expect(location.href).to.eq('http://localhost:9000/webpackUsage.html'); + cy.get('rect#cl1').click({ force: true }); + cy.location().should(({ href }) => { + expect(href).to.eq('http://localhost:9000/empty.html'); }); }); + it('should handle a click on a task with a bound URL clicking on the text', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('text#cl1-text').click({ force: true }); - - cy.location().should((location) => { - expect(location.href).to.eq('http://localhost:9000/webpackUsage.html'); + cy.get('text#cl1-text').click({ force: true }); + cy.location().should(({ href }) => { + expect(href).to.eq('http://localhost:9000/empty.html'); }); }); - it('should handle a click on a task with a bound function without args', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('rect#cl2').click({ force: true }); + it('should handle a click on a task with a bound function without args', () => { + cy.get('rect#cl2').click({ force: true }); cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant cl2'); }); - it('should handle a click on a task with a bound function with args', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('rect#cl3').click({ force: true }); + it('should handle a click on a task with a bound function with args', () => { + cy.get('rect#cl3').click({ force: true }); cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant test1 test2 test3'); }); it('should handle a click on a task with a bound function without args', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('text#cl2-text').click({ force: true }); - + cy.get('text#cl2-text').click({ force: true }); cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant cl2'); }); - it('should handle a click on a task with a bound function with args ', () => { - const url = 'http://localhost:9000/click_security_loose.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('text#cl3-text').click({ force: true }); + it('should handle a click on a task with a bound function with args ', () => { + cy.get('text#cl3-text').click({ force: true }); cy.get('.created-by-gant-click').should('have.text', 'Clicked By Gant test1 test2 test3'); }); }); describe('Interaction - security level tight', () => { + beforeEach(() => { + cy.visit('http://localhost:9000/click_security_strict.html'); + }); it('should handle a click on a node without a bound function', () => { - const url = 'http://localhost:9000/click_security_strict.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g#flowchart-Function-4').click(); - + cy.contains('Function1').parents('.node').click(); cy.get('.created-by-click').should('not.exist'); - // cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow'); }); + it('should handle a click on a node with a bound function where the node starts with a number', () => { - const url = 'http://localhost:9000/click_security_strict.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g[id="flowchart-1Function-10"]').click(); - - // cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow'); + cy.contains('1Function').parents('.node').click(); cy.get('.created-by-click').should('not.exist'); }); - it('should handle a click on a node with a bound url', () => { - const url = 'http://localhost:9000/click_security_strict.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g#flowchart-URL-5').click(); - cy.location().should((location) => { - expect(location.href).to.eq('http://localhost:9000/webpackUsage.html'); + it('should handle a click on a node with a bound url', () => { + cy.contains('URL1').find('.node').click(); + cy.location().should(({ href }) => { + expect(href).to.eq('http://localhost:9000/empty.html'); }); }); - it('should handle a click on a node with a bound url where the node starts with a number', () => { - const url = 'http://localhost:9000/click_security_strict.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g[id="flowchart-2URL-11"]').click(); - cy.location().should((location) => { - expect(location.href).to.eq('http://localhost:9000/webpackUsage.html'); + it('should handle a click on a node with a bound url where the node starts with a number', () => { + cy.contains('2URL').find('.node').click(); + cy.location().should(({ href }) => { + expect(href).to.eq('http://localhost:9000/empty.html'); }); }); it('should handle a click on a task with a bound URL clicking on the rect', () => { - const url = 'http://localhost:9000/click_security_strict.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('rect#cl1').click({ force: true }); - - cy.location().should((location) => { - expect(location.href).to.eq('http://localhost:9000/webpackUsage.html'); + cy.get('rect#cl1').click({ force: true }); + cy.location().should(({ href }) => { + expect(href).to.eq('http://localhost:9000/empty.html'); }); }); + it('should handle a click on a task with a bound URL clicking on the text', () => { - const url = 'http://localhost:9000/click_security_strict.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('text#cl1-text').click({ force: true }); - - cy.location().should((location) => { - expect(location.href).to.eq('http://localhost:9000/webpackUsage.html'); + cy.get('text#cl1-text').click({ force: true }); + cy.location().should(({ href }) => { + expect(href).to.eq('http://localhost:9000/empty.html'); }); }); - it('should handle a click on a task with a bound function', () => { - const url = 'http://localhost:9000/click_security_strict.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('rect#cl2').click({ force: true }); - // cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2'); + it('should handle a click on a task with a bound function', () => { + cy.get('rect#cl2').click({ force: true }); cy.get('.created-by-gant-click').should('not.exist'); }); - it('should handle a click on a task with a bound function', () => { - const url = 'http://localhost:9000/click_security_strict.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('text#cl2-text').click({ force: true }); - // cy.get('.created-by-gant-click').should('not.have.text', 'Clicked By Gant cl2'); + it('should handle a click on a task with a bound function', () => { + cy.get('text#cl2-text').click({ force: true }); cy.get('.created-by-gant-click').should('not.exist'); }); }); describe('Interaction - security level other, missspelling', () => { + beforeEach(() => { + cy.visit('http://localhost:9000/click_security_other.html'); + }); + it('should handle a click on a node with a bound function', () => { - const url = 'http://localhost:9000/click_security_other.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g#flowchart-Function-4').click(); - - // cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow'); + cy.contains('Function1').parents('.node').click(); cy.get('.created-by-click').should('not.exist'); }); + it('should handle a click on a node with a bound function where the node starts with a number', () => { - const url = 'http://localhost:9000/click_security_other.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g[id="flowchart-1Function-10"]').click(); - - cy.get('.created-by-click').should('not.exist'); + cy.contains('1Function').parents('.node').click(); cy.get('.created-by-click').should('not.exist'); }); - it('should handle a click on a node with a bound url', () => { - const url = 'http://localhost:9000/click_security_other.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('g#flowchart-URL-5').click(); - cy.location().should((location) => { - expect(location.href).to.eq('http://localhost:9000/webpackUsage.html'); + it('should handle a click on a node with a bound url', () => { + cy.contains('URL1').find('.node').click(); + cy.location().should(({ href }) => { + expect(href).to.eq('http://localhost:9000/empty.html'); }); }); it('should handle a click on a task with a bound function', () => { - const url = 'http://localhost:9000/click_security_other.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('rect#cl2').click({ force: true }); - + cy.get('rect#cl2').click({ force: true }); cy.get('.created-by-gant-click').should('not.exist'); }); - it('should handle a click on a task with a bound function', () => { - const url = 'http://localhost:9000/click_security_other.html'; - cy.viewport(1440, 1024); - cy.visit(url); - cy.get('body').find('text#cl2-text').click({ force: true }); + it('should handle a click on a task with a bound function', () => { + cy.get('text#cl2-text').click({ force: true }); cy.get('.created-by-gant-click').should('not.exist'); }); }); diff --git a/cypress/platform/click_security_loose.html b/cypress/platform/click_security_loose.html index 6c77e90af..459c14e85 100644 --- a/cypress/platform/click_security_loose.html +++ b/cypress/platform/click_security_loose.html @@ -13,42 +13,42 @@
+graph TB - Function-->URL - click Function clickByFlow "Add a div" - click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + FunctionTest1-->URLTest1 + click FunctionTest1 clickByFlow "Add a div" + click URLTest1 "http://localhost:9000/empty.html" "Visit mermaid docs"-+graph TB 1Function--->2URL click 1Function clickByFlow "Add a div" - click 2URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + click 2URL "http://localhost:9000/empty.html" "Visit mermaid docs"-+flowchart TB - Function-->URL - click Function clickByFlow "Add a div" - click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" _self + FunctionTest2-->URLTest2 + click FunctionTest2 clickByFlow "Add a div" + click URLTest2 "http://localhost:9000/empty.html" "Visit mermaid docs" _self-+flowchart TB - 1Function--->2URL - click 1Function clickByFlow "Add a div" - click 2URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" _self + 10Function--->20URL + click 10Function clickByFlow "Add a div" + click 20URL "http://localhost:9000/empty.html" "Visit mermaid docs" _self-+classDiagram class ShapeLink - link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link" + link ShapeLink "http://localhost:9000/empty.html" "This is a tooltip for a link" class ShapeCallback callback ShapeCallback "clickByClass" "This is a tooltip for a callback"-+classDiagram-v2 class ShapeLink2 - link ShapeLink2 "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link" + link ShapeLink2 "http://localhost:9000/empty.html" "This is a tooltip for a link" class ShapeCallback2 callback ShapeCallback2 "clickByClass" "This is a tooltip for a callback"@@ -85,7 +85,7 @@ Calling a Callback (look at the console log) :cl2, after cl1, 3d Calling a Callback with args :cl3, after cl1, 3d - click cl1 href "http://localhost:9000/webpackUsage.html" + click cl1 href "http://localhost:9000/empty.html" click cl2 call clickByGantt() click cl3 call clickByGantt("test1", test2, test3) @@ -95,31 +95,31 @@ Add another diagram to demo page : 48h-+graph TB - FunctionArg-->URL - click FunctionArg call clickByFlowArg(ARGUMENT) "Add a div" - click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + FunctionArgTest2-->URL + click FunctionArgTest2 call clickByFlowArg(ARGUMENT) "Add a div" + click URL "http://localhost:9000/empty.html" "Visit mermaid docs"-+flowchart TB - FunctionArg-->URL - click FunctionArg call clickByFlowArg(ARGUMENT) "Add a div" - click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + 2FunctionArg-->URL + click 2FunctionArg call clickByFlowArg(ARGUMENT) "Add a div" + click URL "http://localhost:9000/empty.html" "Visit mermaid docs"-+classDiagram class ShapeLink - link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link" + link ShapeLink "http://localhost:9000/empty.html" "This is a tooltip for a link" class ShapeCallback click ShapeCallback call clickByClass(123) "This is a tooltip for a callback"-+classDiagram-v2 class ShapeLink2 - link ShapeLink2 "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link" + link ShapeLink2 "http://localhost:9000/empty.html" "This is a tooltip for a link" class ShapeCallback2 click ShapeCallback2 call clickByClass(123) "This is a tooltip for a callback"diff --git a/cypress/platform/click_security_other.html b/cypress/platform/click_security_other.html index 20bfd5293..5338cac06 100644 --- a/cypress/platform/click_security_other.html +++ b/cypress/platform/click_security_other.html @@ -9,15 +9,15 @@graph TB - Function-->URL - click Function clickByFlow "Add a div" - click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + Function1-->URL1 + click Function1 clickByFlow "Add a div" + click URL1 "http://localhost:9000/empty.html" "Visit mermaid docs"graph TB 1Function-->2URL click 1Function clickByFlow "Add a div" - click 2URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + click 2URL "http://localhost:9000/empty.html" "Visit mermaid docs"@@ -50,7 +50,7 @@ Visit mermaidjs :active, cl1, 2014-01-07,2014-01-10 Calling a Callback (look at the console log) :cl2, after cl1, 3d - click cl1 href "http://localhost:9000/webpackUsage.html" + click cl1 href "http://localhost:9000/empty.html" click cl2 call clickByGantt("test", test, test) section Last section diff --git a/cypress/platform/click_security_sandbox.html b/cypress/platform/click_security_sandbox.html index 94229500c..49c5d71c0 100644 --- a/cypress/platform/click_security_sandbox.html +++ b/cypress/platform/click_security_sandbox.html @@ -17,38 +17,38 @@ graph TB Function-->URL click Function clickByFlow "Add a div" - click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + click URL "http://localhost:9000/empty.html" "Visit mermaid docs"graph TB 1Function--->2URL click 1Function clickByFlow "Add a div" - click 2URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + click 2URL "http://localhost:9000/empty.html" "Visit mermaid docs"flowchart TB Function-->URL click Function clickByFlow "Add a div" - click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" _self + click URL "http://localhost:9000/empty.html" "Visit mermaid docs" _selfflowchart TB 1Function--->2URL click 1Function clickByFlow "Add a div" - click 2URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" _self + click 2URL "http://localhost:9000/empty.html" "Visit mermaid docs" _selfclassDiagram class ShapeLink - link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link" + link ShapeLink "http://localhost:9000/empty.html" "This is a tooltip for a link" class ShapeCallback callback ShapeCallback "clickByClass" "This is a tooltip for a callback"classDiagram-v2 class ShapeLink2 - link ShapeLink2 "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link" + link ShapeLink2 "http://localhost:9000/empty.html" "This is a tooltip for a link" class ShapeCallback2 callback ShapeCallback2 "clickByClass" "This is a tooltip for a callback"@@ -85,7 +85,7 @@ Calling a Callback (look at the console log) :cl2, after cl1, 3d Calling a Callback with args :cl3, after cl1, 3d - click cl1 href "http://localhost:9000/webpackUsage.html" + click cl1 href "http://localhost:9000/empty.html" click cl2 call clickByGantt() click cl3 call clickByGantt("test1", test2, test3) @@ -99,19 +99,19 @@ graph TB FunctionArg-->URL click FunctionArg call clickByFlowArg(ARGUMENT) "Add a div" - click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + click URL "http://localhost:9000/empty.html" "Visit mermaid docs"flowchart TB FunctionArg-->URL click FunctionArg call clickByFlowArg(ARGUMENT) "Add a div" - click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + click URL "http://localhost:9000/empty.html" "Visit mermaid docs"classDiagram class ShapeLink - link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link" + link ShapeLink "http://localhost:9000/empty.html" "This is a tooltip for a link" class ShapeCallback click ShapeCallback call clickByClass(123) "This is a tooltip for a callback"@@ -119,7 +119,7 @@classDiagram-v2 class ShapeLink2 - link ShapeLink2 "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link" + link ShapeLink2 "http://localhost:9000/empty.html" "This is a tooltip for a link" class ShapeCallback2 click ShapeCallback2 call clickByClass(123) "This is a tooltip for a callback"diff --git a/cypress/platform/click_security_strict.html b/cypress/platform/click_security_strict.html index 00c6d9c6a..26605ddf9 100644 --- a/cypress/platform/click_security_strict.html +++ b/cypress/platform/click_security_strict.html @@ -9,15 +9,15 @@graph TB - Function-->URL - click Function clickByFlow "Add a div" - click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + Function1-->URL1 + click Function1 clickByFlow "Add a div" + click URL1 "http://localhost:9000/empty.html" "Visit mermaid docs"graph TB 1Function-->2URL click 1Function clickByFlow "Add a div" - click 2URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" + click 2URL "http://localhost:9000/empty.html" "Visit mermaid docs"@@ -51,7 +51,7 @@ Calling a Callback (look at the console log) :cl2, after cl1, 3d Calling a Callback with args :cl3, after cl1, 3d - click cl1 href "http://localhost:9000/webpackUsage.html" + click cl1 href "http://localhost:9000/empty.html" click cl2 call clickByGantt() click cl3 call clickByGantt("test1", test2, test3) diff --git a/cypress/platform/empty.html b/cypress/platform/empty.html new file mode 100644 index 000000000..2961644d6 --- /dev/null +++ b/cypress/platform/empty.html @@ -0,0 +1,10 @@ + + + + + + +- - + + + diff --git a/cypress/platform/viewer.js b/cypress/platform/viewer.js index 8f1ccfdab..ff70e0abe 100644 --- a/cypress/platform/viewer.js +++ b/cypress/platform/viewer.js @@ -36,6 +36,8 @@ const contentLoaded = function () { document.getElementsByTagName('body')[0].appendChild(div); } + graphObj.mermaid.extraDiagrams = ['/mermaid-mindmap-detector.core.mjs']; + mermaid2.initialize(graphObj.mermaid); mermaid2.init(); } diff --git a/packages/mermaid-mindmap/src/add-diagram.ts b/packages/mermaid-mindmap/src/add-diagram.ts index 873d55232..c8ade1bfa 100644 --- a/packages/mermaid-mindmap/src/add-diagram.ts +++ b/packages/mermaid-mindmap/src/add-diagram.ts @@ -5,13 +5,10 @@ import mindmapRenderer from './mindmapRenderer'; import mindmapStyles from './styles'; import { injectUtils } from './mermaidUtils'; -window.mermaid.connectDiagram( - 'mindmap', - { - db: mindmapDb, - renderer: mindmapRenderer, - parser: mindmapParser, - styles: mindmapStyles, - }, - injectUtils -); +export const mindmap = { + db: mindmapDb, + renderer: mindmapRenderer, + parser: mindmapParser, + styles: mindmapStyles, + injectUtils, +}; diff --git a/packages/mermaid-mindmap/src/mindmapDetector.ts b/packages/mermaid-mindmap/src/mindmapDetector.ts index 9a3f6f426..e69de29bb 100644 --- a/packages/mermaid-mindmap/src/mindmapDetector.ts +++ b/packages/mermaid-mindmap/src/mindmapDetector.ts @@ -1,3 +0,0 @@ -export const mindmapDetector = (txt: string) => { - return txt.match(/^\s*mindmap/) !== null; -}; diff --git a/packages/mermaid-mindmap/src/registry.ts b/packages/mermaid-mindmap/src/registry.ts index e70967ba6..a76a3627f 100644 --- a/packages/mermaid-mindmap/src/registry.ts +++ b/packages/mermaid-mindmap/src/registry.ts @@ -1,34 +1,10 @@ -// @ts-ignore: TODO Fix ts errors -import { mindmapDetector } from './mindmapDetector'; +export const id = 'mindmap'; -const scriptElement = document.currentScript as HTMLScriptElement; -const path = scriptElement.src; -const lastSlash = path.lastIndexOf('/'); -const baseFolder = lastSlash < 0 ? path : path.substring(0, lastSlash + 1); +export const detector = (txt: string) => { + return txt.match(/^\s*mindmap/) !== null; +}; -if (typeof document !== 'undefined') { - if (window.mermaid && typeof window.mermaid.detectors === 'object') { - window.mermaid.detectors.push({ id: 'mindmap', detector: mindmapDetector }); - } else { - window.mermaid = {}; - window.mermaid.detectors = [{ id: 'mindmap', detector: mindmapDetector }]; - } - - /*! - * Wait for document loaded before starting the execution. - */ - window.addEventListener( - 'load', - () => { - if (window.mermaid && typeof window.mermaid.detectors === 'object') { - window.mermaid.detectors.push({ - id: 'mindmap', - detector: mindmapDetector, - path: baseFolder, - }); - console.error(window.mermaid.detectors); // eslint-disable-line no-console - } - }, - false - ); -} +export const loadDiagram = async () => { + const { mindmap } = await import('./add-diagram'); + return { id, diagram: mindmap }; +}; diff --git a/packages/mermaid-mindmap/tsconfig.json b/packages/mermaid-mindmap/tsconfig.json index 45076b7b5..310137cc0 100644 --- a/packages/mermaid-mindmap/tsconfig.json +++ b/packages/mermaid-mindmap/tsconfig.json @@ -1,5 +1,6 @@ { "extends": "../../tsconfig.json", + "module": "esnext", "compilerOptions": { "rootDir": "./src", "outDir": "./dist" diff --git a/packages/mermaid/src/Diagram.ts b/packages/mermaid/src/Diagram.ts index 231a78af6..9bdc92079 100644 --- a/packages/mermaid/src/Diagram.ts +++ b/packages/mermaid/src/Diagram.ts @@ -1,7 +1,7 @@ import * as configApi from './config'; import { log } from './logger'; -import { getDiagram, loadDiagram } from './diagram-api/diagramAPI'; -import { detectType, getPathForDiagram } from './diagram-api/detectType'; +import { getDiagram, registerDiagram } from './diagram-api/diagramAPI'; +import { detectType, getDiagramLoader } from './diagram-api/detectType'; import { isDetailedError } from './utils'; export class Diagram { type = 'graph'; @@ -75,10 +75,25 @@ export const getDiagramFromText = async (txt: string, parseError?: Function) => // Trying to find the diagram getDiagram(type); } catch (error) { + const loader = getDiagramLoader(type); + if (!loader) { + throw new Error(`Diagram ${type} not found.`); + } // Diagram not avaiable, loading it - const path = getPathForDiagram(type); + // const path = getPathForDiagram(type); + const { diagram } = await loader(); // eslint-disable-line @typescript-eslint/no-explicit-any + registerDiagram( + type, + { + db: diagram.db, + renderer: diagram.renderer, + parser: diagram.parser, + styles: diagram.styles, + }, + diagram.injectUtils + ); // await loadDiagram('./packages/mermaid-mindmap/dist/mermaid-mindmap.js'); - await loadDiagram(path + 'mermaid-' + type + '.js'); + // await loadDiagram(path + 'mermaid-' + type + '.js'); // new diagram will try getDiagram again and if fails then it is a valid throw } // If either of the above worked, we have the diagram diff --git a/packages/mermaid/src/config.type.ts b/packages/mermaid/src/config.type.ts index d9d94226f..b757eb8de 100644 --- a/packages/mermaid/src/config.type.ts +++ b/packages/mermaid/src/config.type.ts @@ -3,6 +3,7 @@ import DOMPurify from 'dompurify'; export interface MermaidConfig { + extraDiagrams?: any; theme?: string; themeVariables?: any; themeCSS?: string; diff --git a/packages/mermaid/src/defaultConfig.ts b/packages/mermaid/src/defaultConfig.ts index 681fda60c..a90001874 100644 --- a/packages/mermaid/src/defaultConfig.ts +++ b/packages/mermaid/src/defaultConfig.ts @@ -115,7 +115,7 @@ const config: PartialEmpty + + + diff --git a/cypress/platform/knsv.html b/cypress/platform/knsv.html index d4ffa0c0c..8bd8d7c79 100644 --- a/cypress/platform/knsv.html +++ b/cypress/platform/knsv.html @@ -368,7 +368,6 @@ flowchart TD= { * Default value: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize'] */ secure: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize'], - + extraDiagrams: [], /** * This option controls if the generated ids of nodes in the SVG are generated randomly or based * on a seed. If set to false, the IDs are generated based on the current date and thus are not diff --git a/packages/mermaid/src/diagram-api/detectType.ts b/packages/mermaid/src/diagram-api/detectType.ts index afb9a9078..6a31dd1a9 100644 --- a/packages/mermaid/src/diagram-api/detectType.ts +++ b/packages/mermaid/src/diagram-api/detectType.ts @@ -1,8 +1,8 @@ import { MermaidConfig } from '../config.type'; export type DiagramDetector = (text: string, config?: MermaidConfig) => boolean; -export type DetectorRecord = { detector: DiagramDetector; path: string }; - +export type DiagramLoader = (() => any) | null; +export type DetectorRecord = { detector: DiagramDetector; loader: DiagramLoader }; const directive = /[%]{2}[{]\s*(?:(?:(\w+)\s*:|(\w+))\s*(?:(?:(\w+))|((?:(?![}][%]{2}).|\r?\n)*))?\s*)(?:[}][%]{2})?/gi; const anyComment = /\s*%%.*\n/gm; @@ -37,8 +37,9 @@ export const detectType = function (text: string, config?: MermaidConfig): strin // console.log(detectors); - for (const [key, detectorRecord] of Object.entries(detectors)) { - if (detectorRecord.detector(text, config)) { + for (const [key, { detector }] of Object.entries(detectors)) { + const diagram = detector(text, config); + if (diagram) { return key; } } @@ -47,13 +48,15 @@ export const detectType = function (text: string, config?: MermaidConfig): strin return 'flowchart'; }; -export const addDetector = (key: string, detector: DiagramDetector, path: string) => { - detectors[key] = { detector, path }; +export const addDetector = ( + key: string, + detector: DiagramDetector, + loader: DiagramLoader | null +) => { + detectors[key] = { detector, loader }; + // TODO: Remove + // eslint-disable-next-line no-console + console.log(detectors); }; -export const getPathForDiagram = (id: string) => { - const detectorRecord = detectors[id]; - if (detectorRecord) { - return detectorRecord.path; - } -}; +export const getDiagramLoader = (key: string) => detectors[key].loader; diff --git a/packages/mermaid/src/diagram-api/diagram-orchestration.ts b/packages/mermaid/src/diagram-api/diagram-orchestration.ts index 912559c90..1693f4f51 100644 --- a/packages/mermaid/src/diagram-api/diagram-orchestration.ts +++ b/packages/mermaid/src/diagram-api/diagram-orchestration.ts @@ -112,7 +112,7 @@ const registerDiagramAndDetector = ( detector: DiagramDetector ) => { registerDiagram(id, diagram); - registerDetector(id, detector, ''); + registerDetector(id, detector); }; export const addDiagrams = () => { diff --git a/packages/mermaid/src/diagram-api/diagramAPI.spec.ts b/packages/mermaid/src/diagram-api/diagramAPI.spec.ts index 018e72bd4..584a36fa3 100644 --- a/packages/mermaid/src/diagram-api/diagramAPI.spec.ts +++ b/packages/mermaid/src/diagram-api/diagramAPI.spec.ts @@ -19,17 +19,13 @@ describe('DiagramAPI', () => { const detector: DiagramDetector = (str: string) => { return str.match('loki') !== null; }; - registerDetector('loki', detector, ''); - registerDiagram( - 'loki', - { - db: {}, - parser: {}, - renderer: {}, - styles: {}, - }, - (text: string) => text.includes('loki') - ); + registerDetector('loki', detector); + registerDiagram('loki', { + db: {}, + parser: {}, + renderer: {}, + styles: {}, + }); expect(getDiagram('loki')).not.toBeNull(); expect(detectType('loki diagram')).toBe('loki'); }); diff --git a/packages/mermaid/src/diagram-api/diagramAPI.ts b/packages/mermaid/src/diagram-api/diagramAPI.ts index beb770f31..002619bbb 100644 --- a/packages/mermaid/src/diagram-api/diagramAPI.ts +++ b/packages/mermaid/src/diagram-api/diagramAPI.ts @@ -18,12 +18,21 @@ export const getConfig = _getConfig; export const sanitizeText = (text: string) => _sanitizeText(text, getConfig()); export const setupGraphViewbox = _setupGraphViewbox; +export interface InjectUtils { + _log: any; + _setLogLevel: any; + _getConfig: any; + _sanitizeText: any; + _setupGraphViewbox: any; +} + export interface DiagramDefinition { db: any; renderer: any; parser: any; styles: any; init?: (config: MermaidConfig) => void; + injectUtils?: (utils: InjectUtils) => void; } const diagrams: Record = {}; @@ -32,8 +41,8 @@ export interface Detectors { [key: string]: DiagramDetector; } -export const registerDetector = (id: string, detector: DiagramDetector, path: string) => { - addDetector(id, detector, path); +export const registerDetector = (id: string, detector: DiagramDetector) => { + addDetector(id, detector, null); }; export const registerDiagram = ( @@ -52,7 +61,9 @@ export const registerDiagram = ( } diagrams[id] = diagram; addStylesForDiagram(id, diagram.styles); - connectCallbacks[id] = callback; + if (typeof callback !== 'undefined') { + callback(log, setLogLevel, getConfig, sanitizeText, setupGraphViewbox); + } }; export const getDiagram = (name: string): DiagramDefinition => { diff --git a/packages/mermaid/src/mermaid.ts b/packages/mermaid/src/mermaid.ts index 6a709dd32..d59c43ec7 100644 --- a/packages/mermaid/src/mermaid.ts +++ b/packages/mermaid/src/mermaid.ts @@ -45,7 +45,7 @@ import { isDetailedError } from './utils'; * @param nodes * @param callback */ -const init = function ( +const init = async function ( config?: MermaidConfig, // eslint-disable-next-line no-undef nodes?: string | HTMLElement | NodeListOf , @@ -54,10 +54,20 @@ const init = function ( ) { try { log.info('Detectors in init', mermaid.detectors); // eslint-disable-line + const conf = mermaidAPI.getConfig(); + if (typeof conf.extraDiagrams !== 'undefined' && conf.extraDiagrams.length > 0) { + // config.extraDiagrams.forEach(async (diagram: string) => { + const { id, detector, loadDiagram } = await import(conf.extraDiagrams[0]); + // TODO: Remove + // eslint-disable-next-line no-console + console.log(id, detector, loadDiagram); + addDetector(id, detector, loadDiagram); + // }); + } mermaid.detectors.forEach(({ id, detector, path }) => { addDetector(id, detector, path); }); - initThrowsErrors(config, nodes, callback); + await initThrowsErrors(config, nodes, callback); } catch (e) { log.warn('Syntax Error rendering'); if (isDetailedError(e)) { @@ -69,7 +79,7 @@ const init = function ( } }; -const initThrowsErrors = function ( +const initThrowsErrors = async function ( config?: MermaidConfig, // eslint-disable-next-line no-undef nodes?: string | HTMLElement | NodeListOf , @@ -108,7 +118,7 @@ const initThrowsErrors = function ( // generate the id of the diagram const idGenerator = new utils.initIdGenerator(conf.deterministicIds, conf.deterministicIDSeed); - let txt; + let txt: string; const errors = []; // element is the current div with mermaid class @@ -136,7 +146,7 @@ const initThrowsErrors = function ( log.debug('Detected early reinit: ', init); } try { - mermaidAPI.render( + await mermaidAPI.render( id, txt, (svgCode: string, bindFunctions?: (el: Element) => void) => { @@ -164,8 +174,8 @@ const initThrowsErrors = function ( } }; -const initialize = function (config: MermaidConfig) { - mermaidAPI.initialize(config); +const initialize = async function (config: MermaidConfig) { + await mermaidAPI.initialize(config); }; /** diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index 50eb51ec5..f9544ee44 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -18,6 +18,7 @@ import { compile, serialize, stringify } from 'stylis'; import pkg from '../package.json'; import * as configApi from './config'; import { addDiagrams } from './diagram-api/diagram-orchestration'; +import { addDetector } from './diagram-api/detectType'; import classDb from './diagrams/class/classDb'; import flowDb from './diagrams/flowchart/flowDb'; import flowRenderer from './diagrams/flowchart/flowRenderer'; @@ -461,7 +462,7 @@ const handleDirective = function (p: any, directive: any, type: string): void { }; /** @param {MermaidConfig} options */ -function initialize(options: MermaidConfig) { +async function initialize(options: MermaidConfig) { // Handle legacy location of font-family configuration if (options?.fontFamily) { if (!options.themeVariables?.fontFamily) { @@ -485,6 +486,7 @@ function initialize(options: MermaidConfig) { typeof options === 'object' ? configApi.setSiteConfig(options) : configApi.getSiteConfig(); setLogLevel(config.logLevel); + if (!hasLoadedDiagrams) { addDiagrams(); hasLoadedDiagrams = true; diff --git a/tsconfig.json b/tsconfig.json index 99feb5bda..fe107f205 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,7 +27,7 @@ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ /* Modules */ - "module": "ES6" /* Specify what module code is generated. */, + "module": "es2022" /* Specify what module code is generated. */, // "rootDir": "./packages" /* Specify the root folder within your source files. */, "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, // "baseUrl": "./src" /* Specify the base directory to resolve non-relative module names. */, diff --git a/vite.config.ts b/vite.config.ts index 8d34e6184..e79295425 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -15,4 +15,12 @@ export default defineConfig({ reporter: ['text', 'json', 'html', 'lcov'], }, }, + build: { + /** If you set esmExternals to true, this plugins assumes that + all external dependencies are ES modules */ + + commonjsOptions: { + esmExternals: true, + }, + }, });