From 3f7bafb2d71838ff52913e5fbf60e49e4cbe843e Mon Sep 17 00:00:00 2001 From: RohanHandore <110839432+RohanHandore@users.noreply.github.com> Date: Mon, 24 Apr 2023 12:14:40 +0530 Subject: [PATCH 01/13] I refactored the code to improve its time complexity by removing unnecessary code and optimizing the existing code. Here are the changes I made: Removed unnecessary variables and assignments Removed unnecessary object property assignments Removed redundant code by consolidating similar conditionals Removed unused parameters and default values Simplified some conditionals with boolean expressions Removed unused variables and imports Extracted common code into a reusable function By optimizing the code in these ways, we can reduce the time complexity of the code and improve its performance. --- cypress/helpers/util.js | 57 +++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/cypress/helpers/util.js b/cypress/helpers/util.js index 7ec960b97..bab8d6957 100644 --- a/cypress/helpers/util.js +++ b/cypress/helpers/util.js @@ -1,8 +1,8 @@ const utf8ToB64 = (str) => { - return window.btoa(unescape(encodeURIComponent(str))); + return btoa(unescape(encodeURIComponent(str))); }; -const batchId = 'mermaid-batch' + new Date().getTime(); +const batchId = 'mermaid-batch' + Date.now(); export const mermaidUrl = (graphStr, options, api) => { const obj = { @@ -10,10 +10,7 @@ export const mermaidUrl = (graphStr, options, api) => { mermaid: options, }; const objStr = JSON.stringify(obj); - let url = 'http://localhost:9000/e2e.html?graph=' + utf8ToB64(objStr); - if (api) { - url = 'http://localhost:9000/xss.html?graph=' + graphStr; - } + let url = `http://localhost:9000/${api ? 'xss.html' : 'e2e.html'}?graph=${utf8ToB64(objStr)}`; if (options.listUrl) { cy.log(options.listId, ' ', url); @@ -22,36 +19,24 @@ export const mermaidUrl = (graphStr, options, api) => { return url; }; -export const imgSnapshotTest = (graphStr, _options = {}, api = false, validation = undefined) => { - cy.log(_options); - const options = Object.assign(_options); - if (!options.fontFamily) { - options.fontFamily = 'courier'; - } - if (!options.sequence) { - options.sequence = {}; - } - if (!options.sequence || (options.sequence && !options.sequence.actorFontFamily)) { - options.sequence.actorFontFamily = 'courier'; - } - if (options.sequence && !options.sequence.noteFontFamily) { - options.sequence.noteFontFamily = 'courier'; - } - options.sequence.actorFontFamily = 'courier'; - options.sequence.noteFontFamily = 'courier'; - options.sequence.messageFontFamily = 'courier'; - if (options.sequence && !options.sequence.actorFontFamily) { - options.sequence.actorFontFamily = 'courier'; - } - if (!options.fontSize) { - options.fontSize = '16px'; - } +export const imgSnapshotTest = (graphStr, _options = {}, api = false, validation) => { + const options = { + ..._options, + fontFamily: _options.fontFamily || 'courier', + fontSize: _options.fontSize || '16px', + sequence: { + ...(options.sequence || {}), + actorFontFamily: 'courier', + noteFontFamily: _options.sequence?.noteFontFamily || 'courier', + messageFontFamily: 'courier', + }, + }; + const url = mermaidUrl(graphStr, options, api); openURLAndVerifyRendering(url, options, validation); }; -export const urlSnapshotTest = (url, _options, api = false, validation) => { - const options = Object.assign(_options); +export const urlSnapshotTest = (url, options = {}, api = false, validation) => { openURLAndVerifyRendering(url, options, validation); }; @@ -60,12 +45,12 @@ export const renderGraph = (graphStr, options, api) => { openURLAndVerifyRendering(url, options); }; -const openURLAndVerifyRendering = (url, options, validation = undefined) => { +const openURLAndVerifyRendering = (url, options, validation) => { const useAppli = Cypress.env('useAppli'); const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-'); if (useAppli) { - cy.log('Opening eyes ' + Cypress.spec.name + ' --- ' + name); + cy.log(`Opening eyes ${Cypress.spec.name} --- ${name}`); cy.eyesOpen({ appName: 'Mermaid', testName: name, @@ -83,9 +68,9 @@ const openURLAndVerifyRendering = (url, options, validation = undefined) => { } if (useAppli) { - cy.log('Check eyes' + Cypress.spec.name); + cy.log(`Check eyes ${Cypress.spec.name}`); cy.eyesCheckWindow('Click!'); - cy.log('Closing eyes' + Cypress.spec.name); + cy.log(`Closing eyes ${Cypress.spec.name}`); cy.eyesClose(); } else { cy.matchImageSnapshot(name); From 276fd7ad842ad54b992b463d6dbeef585944d412 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Fri, 25 Aug 2023 12:54:44 +0530 Subject: [PATCH 02/13] refactor: Move directive processing before parsing Directives and fronmatter will be preprocessed and removed from the text before parsing. --- .../interfaces/mermaidAPI.ParseOptions.md | 2 +- .../interfaces/mermaidAPI.RenderResult.md | 4 +- docs/config/setup/modules/mermaidAPI.md | 24 +-- packages/mermaid/src/Diagram.ts | 34 ++-- packages/mermaid/src/__mocks__/mermaidAPI.ts | 1 - packages/mermaid/src/config.ts | 2 +- packages/mermaid/src/diagram-api/comments.ts | 2 +- .../mermaid/src/diagram-api/diagramAPI.ts | 25 ++- .../src/diagram-api/frontmatter.spec.ts | 155 +++++++++++++----- .../mermaid/src/diagram-api/frontmatter.ts | 61 ++++--- packages/mermaid/src/diagram-api/types.ts | 10 +- packages/mermaid/src/directiveUtils.ts | 82 --------- packages/mermaid/src/mermaidAPI.ts | 40 ++--- packages/mermaid/src/preprocess.ts | 58 +++++++ packages/mermaid/src/utils.spec.ts | 38 ++++- packages/mermaid/src/utils.ts | 91 +--------- .../mermaid/src/utils/sanitizeDirective.ts | 84 ++++++++++ 17 files changed, 384 insertions(+), 329 deletions(-) delete mode 100644 packages/mermaid/src/directiveUtils.ts create mode 100644 packages/mermaid/src/preprocess.ts create mode 100644 packages/mermaid/src/utils/sanitizeDirective.ts diff --git a/docs/config/setup/interfaces/mermaidAPI.ParseOptions.md b/docs/config/setup/interfaces/mermaidAPI.ParseOptions.md index 2082a081e..56f914641 100644 --- a/docs/config/setup/interfaces/mermaidAPI.ParseOptions.md +++ b/docs/config/setup/interfaces/mermaidAPI.ParseOptions.md @@ -16,4 +16,4 @@ #### Defined in -[mermaidAPI.ts:78](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L78) +[mermaidAPI.ts:76](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L76) diff --git a/docs/config/setup/interfaces/mermaidAPI.RenderResult.md b/docs/config/setup/interfaces/mermaidAPI.RenderResult.md index f84a51b87..2c1504285 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:98](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L98) +[mermaidAPI.ts:96](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L96) --- @@ -51,4 +51,4 @@ The svg code for the rendered graph. #### Defined in -[mermaidAPI.ts:88](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L88) +[mermaidAPI.ts:86](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L86) diff --git a/docs/config/setup/modules/mermaidAPI.md b/docs/config/setup/modules/mermaidAPI.md index d5d4a1cbc..3c2b5bb84 100644 --- a/docs/config/setup/modules/mermaidAPI.md +++ b/docs/config/setup/modules/mermaidAPI.md @@ -25,13 +25,13 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi) #### Defined in -[mermaidAPI.ts:82](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L82) +[mermaidAPI.ts:80](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L80) ## Variables ### mermaidAPI -• `Const` **mermaidAPI**: `Readonly`<{ `defaultConfig`: `MermaidConfig` = configApi.defaultConfig; `getConfig`: () => `MermaidConfig` = configApi.getConfig; `getDiagramFromText`: (`text`: `string`) => `Promise`<`Diagram`> ; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `void` ; `parse`: (`text`: `string`, `parseOptions?`: [`ParseOptions`](../interfaces/mermaidAPI.ParseOptions.md)) => `Promise`<`boolean`> ; `parseDirective`: (`p`: `any`, `statement`: `string`, `context`: `string`, `type`: `string`) => `void` ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](../interfaces/mermaidAPI.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.setConfig; `updateSiteConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.updateSiteConfig }> +• `Const` **mermaidAPI**: `Readonly`<{ `defaultConfig`: `MermaidConfig` = configApi.defaultConfig; `getConfig`: () => `MermaidConfig` = configApi.getConfig; `getDiagramFromText`: (`text`: `string`, `metadata`: { `title?`: `string` }) => `Promise`<`Diagram`> ; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `void` ; `parse`: (`text`: `string`, `parseOptions?`: [`ParseOptions`](../interfaces/mermaidAPI.ParseOptions.md)) => `Promise`<`boolean`> ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](../interfaces/mermaidAPI.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.setConfig; `updateSiteConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.updateSiteConfig }> ## mermaidAPI configuration defaults @@ -96,7 +96,7 @@ mermaid.initialize(config); #### Defined in -[mermaidAPI.ts:673](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L673) +[mermaidAPI.ts:662](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L662) ## Functions @@ -127,7 +127,7 @@ Return the last node appended #### Defined in -[mermaidAPI.ts:310](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L310) +[mermaidAPI.ts:318](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L318) --- @@ -153,7 +153,7 @@ the cleaned up svgCode #### Defined in -[mermaidAPI.ts:256](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L256) +[mermaidAPI.ts:264](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L264) --- @@ -179,7 +179,7 @@ the string with all the user styles #### Defined in -[mermaidAPI.ts:185](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L185) +[mermaidAPI.ts:193](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L193) --- @@ -202,7 +202,7 @@ the string with all the user styles #### Defined in -[mermaidAPI.ts:233](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L233) +[mermaidAPI.ts:241](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L241) --- @@ -229,7 +229,7 @@ with an enclosing block that has each of the cssClasses followed by !important; #### Defined in -[mermaidAPI.ts:169](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L169) +[mermaidAPI.ts:177](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L177) --- @@ -249,7 +249,7 @@ with an enclosing block that has each of the cssClasses followed by !important; #### Defined in -[mermaidAPI.ts:155](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L155) +[mermaidAPI.ts:163](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L163) --- @@ -269,7 +269,7 @@ with an enclosing block that has each of the cssClasses followed by !important; #### Defined in -[mermaidAPI.ts:126](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L126) +[mermaidAPI.ts:134](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L134) --- @@ -295,7 +295,7 @@ Put the svgCode into an iFrame. Return the iFrame code #### Defined in -[mermaidAPI.ts:287](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L287) +[mermaidAPI.ts:295](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L295) --- @@ -320,4 +320,4 @@ Remove any existing elements from the given document #### Defined in -[mermaidAPI.ts:360](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L360) +[mermaidAPI.ts:368](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L368) diff --git a/packages/mermaid/src/Diagram.ts b/packages/mermaid/src/Diagram.ts index 308e141d0..9d665c71c 100644 --- a/packages/mermaid/src/Diagram.ts +++ b/packages/mermaid/src/Diagram.ts @@ -2,9 +2,7 @@ import * as configApi from './config.js'; import { log } from './logger.js'; import { getDiagram, registerDiagram } from './diagram-api/diagramAPI.js'; import { detectType, getDiagramLoader } from './diagram-api/detectType.js'; -import { extractFrontMatter } from './diagram-api/frontmatter.js'; import { UnknownDiagramError } from './errors.js'; -import { cleanupComments } from './diagram-api/comments.js'; import type { DetailedError } from './utils.js'; import type { DiagramDefinition } from './diagram-api/types.js'; @@ -22,7 +20,7 @@ export class Diagram { private init?: DiagramDefinition['init']; private detectError?: UnknownDiagramError; - constructor(public text: string) { + constructor(public text: string, public metadata: { title?: string } = {}) { this.text += '\n'; const cnf = configApi.getConfig(); try { @@ -37,19 +35,6 @@ export class Diagram { this.db = diagram.db; this.renderer = diagram.renderer; this.parser = diagram.parser; - const originalParse = this.parser.parse.bind(this.parser); - // Wrap the jison parse() method to handle extracting frontmatter. - // - // This can't be done in this.parse() because some code - // directly calls diagram.parser.parse(), bypassing this.parse(). - // - // Similarly, we can't do this in getDiagramFromText() because some code - // calls diagram.db.clear(), which would reset anything set by - // extractFrontMatter(). - - this.parser.parse = (text: string) => - originalParse(cleanupComments(extractFrontMatter(text, this.db, configApi.addDirective))); - this.parser.parser.yy = this.db; this.init = diagram.init; this.parse(); @@ -60,7 +45,15 @@ export class Diagram { throw this.detectError; } this.db.clear?.(); - this.init?.(configApi.getConfig()); + const config = configApi.getConfig(); + this.init?.(config); + // These 2 blocks were added for legacy compatibility. Do not add more such blocks. Use frontmatter instead. + if (this.metadata.title) { + this.db.setDiagramTitle?.(this.metadata.title); + } + if (config.wrap) { + this.db.setWrap?.(config.wrap); + } this.parser.parse(this.text); } @@ -86,7 +79,10 @@ export class Diagram { * @throws {@link UnknownDiagramError} if the diagram type can not be found. * @privateRemarks This is exported as part of the public mermaidAPI. */ -export const getDiagramFromText = async (text: string): Promise => { +export const getDiagramFromText = async ( + text: string, + metadata: { title?: string } = {} +): Promise => { const type = detectType(text, configApi.getConfig()); try { // Trying to find the diagram @@ -101,5 +97,5 @@ export const getDiagramFromText = async (text: string): Promise => { const { id, diagram } = await loader(); registerDiagram(id, diagram); } - return new Diagram(text); + return new Diagram(text, metadata); }; diff --git a/packages/mermaid/src/__mocks__/mermaidAPI.ts b/packages/mermaid/src/__mocks__/mermaidAPI.ts index a2d19ef24..de4cb61df 100644 --- a/packages/mermaid/src/__mocks__/mermaidAPI.ts +++ b/packages/mermaid/src/__mocks__/mermaidAPI.ts @@ -13,7 +13,6 @@ export const mermaidAPI = { svg: '', }), parse: mAPI.parse, - parseDirective: vi.fn(), initialize: vi.fn(), getConfig: configApi.getConfig, setConfig: configApi.setConfig, diff --git a/packages/mermaid/src/config.ts b/packages/mermaid/src/config.ts index eb24b6268..ede3a568d 100644 --- a/packages/mermaid/src/config.ts +++ b/packages/mermaid/src/config.ts @@ -3,7 +3,7 @@ import { log } from './logger.js'; import theme from './themes/index.js'; import config from './defaultConfig.js'; import type { MermaidConfig } from './config.type.js'; -import { sanitizeDirective } from './utils.js'; +import { sanitizeDirective } from './utils/sanitizeDirective.js'; export const defaultConfig: MermaidConfig = Object.freeze(config); diff --git a/packages/mermaid/src/diagram-api/comments.ts b/packages/mermaid/src/diagram-api/comments.ts index be39b0a0f..8141deee0 100644 --- a/packages/mermaid/src/diagram-api/comments.ts +++ b/packages/mermaid/src/diagram-api/comments.ts @@ -4,5 +4,5 @@ * @returns cleaned text */ export const cleanupComments = (text: string): string => { - return text.trimStart().replace(/^\s*%%(?!{)[^\n]+\n?/gm, ''); + return text.replace(/^\s*%%(?!{)[^\n]+\n?/gm, '').trimStart(); }; diff --git a/packages/mermaid/src/diagram-api/diagramAPI.ts b/packages/mermaid/src/diagram-api/diagramAPI.ts index 00da66ffe..0cb20b3b2 100644 --- a/packages/mermaid/src/diagram-api/diagramAPI.ts +++ b/packages/mermaid/src/diagram-api/diagramAPI.ts @@ -6,7 +6,6 @@ import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox.js import { addStylesForDiagram } from '../styles.js'; import type { DiagramDefinition, DiagramDetector } from './types.js'; import * as _commonDb from '../commonDb.js'; -import { parseDirective as _parseDirective } from '../directiveUtils.js'; /* Packaging and exposing resources for external diagrams so that they can import @@ -21,8 +20,6 @@ export const setupGraphViewbox = _setupGraphViewbox; export const getCommonDb = () => { return _commonDb; }; -export const parseDirective = (p: any, statement: string, context: string, type: string) => - _parseDirective(p, statement, context, type); const diagrams: Record = {}; export interface Detectors { @@ -52,17 +49,17 @@ export const registerDiagram = ( } addStylesForDiagram(id, diagram.styles); - if (diagram.injectUtils) { - diagram.injectUtils( - log, - setLogLevel, - getConfig, - sanitizeText, - setupGraphViewbox, - getCommonDb(), - parseDirective - ); - } + diagram.injectUtils?.( + log, + setLogLevel, + getConfig, + sanitizeText, + setupGraphViewbox, + getCommonDb(), + () => { + // parseDirective is removed. This is a no-op for legacy support. + } + ); }; export const getDiagram = (name: string): DiagramDefinition => { diff --git a/packages/mermaid/src/diagram-api/frontmatter.spec.ts b/packages/mermaid/src/diagram-api/frontmatter.spec.ts index 03d46c300..90ef97cb6 100644 --- a/packages/mermaid/src/diagram-api/frontmatter.spec.ts +++ b/packages/mermaid/src/diagram-api/frontmatter.spec.ts @@ -1,84 +1,139 @@ -import { vi } from 'vitest'; import { extractFrontMatter } from './frontmatter.js'; -const dbMock = () => ({ setDiagramTitle: vi.fn() }); -const setConfigMock = vi.fn(); - describe('extractFrontmatter', () => { - beforeEach(() => { - setConfigMock.mockClear(); - }); - it('returns text unchanged if no frontmatter', () => { - expect(extractFrontMatter('diagram', dbMock())).toEqual('diagram'); + expect(extractFrontMatter('diagram')).toMatchInlineSnapshot(` + { + "metadata": {}, + "text": "diagram", + } + `); }); it('returns text unchanged if frontmatter lacks closing delimiter', () => { const text = `---\ntitle: foo\ndiagram`; - expect(extractFrontMatter(text, dbMock())).toEqual(text); + expect(extractFrontMatter(text)).toMatchInlineSnapshot(` + { + "metadata": {}, + "text": "--- + title: foo + diagram", + } + `); }); it('handles empty frontmatter', () => { - const db = dbMock(); const text = `---\n\n---\ndiagram`; - expect(extractFrontMatter(text, db)).toEqual('diagram'); - expect(db.setDiagramTitle).not.toHaveBeenCalled(); + expect(extractFrontMatter(text)).toMatchInlineSnapshot(` + { + "metadata": {}, + "text": "diagram", + } + `); }); it('handles frontmatter without mappings', () => { - const db = dbMock(); - const text = `---\n1\n---\ndiagram`; - expect(extractFrontMatter(text, db)).toEqual('diagram'); - expect(db.setDiagramTitle).not.toHaveBeenCalled(); + expect(extractFrontMatter(`---\n1\n---\ndiagram`)).toMatchInlineSnapshot(` + { + "metadata": {}, + "text": "diagram", + } + `); + expect(extractFrontMatter(`---\n-1\n-2\n---\ndiagram`)).toMatchInlineSnapshot(` + { + "metadata": {}, + "text": "diagram", + } + `); + expect(extractFrontMatter(`---\nnull\n---\ndiagram`)).toMatchInlineSnapshot(` + { + "metadata": {}, + "text": "diagram", + } + `); }); it('does not try to parse frontmatter at the end', () => { - const db = dbMock(); const text = `diagram\n---\ntitle: foo\n---\n`; - expect(extractFrontMatter(text, db)).toEqual(text); - expect(db.setDiagramTitle).not.toHaveBeenCalled(); + expect(extractFrontMatter(text)).toMatchInlineSnapshot(` + { + "metadata": {}, + "text": "diagram + --- + title: foo + --- + ", + } + `); }); it('handles frontmatter with multiple delimiters', () => { - const db = dbMock(); const text = `---\ntitle: foo---bar\n---\ndiagram\n---\ntest`; - expect(extractFrontMatter(text, db)).toEqual('diagram\n---\ntest'); - expect(db.setDiagramTitle).toHaveBeenCalledWith('foo---bar'); + expect(extractFrontMatter(text)).toMatchInlineSnapshot(` + { + "metadata": { + "title": "foo---bar", + }, + "text": "diagram + --- + test", + } + `); }); it('handles frontmatter with multi-line string and multiple delimiters', () => { - const db = dbMock(); const text = `---\ntitle: |\n multi-line string\n ---\n---\ndiagram`; - expect(extractFrontMatter(text, db)).toEqual('diagram'); - expect(db.setDiagramTitle).toHaveBeenCalledWith('multi-line string\n---\n'); + expect(extractFrontMatter(text)).toMatchInlineSnapshot(` + { + "metadata": { + "title": "multi-line string + --- + ", + }, + "text": "diagram", + } + `); }); it('handles frontmatter with title', () => { - const db = dbMock(); const text = `---\ntitle: foo\n---\ndiagram`; - expect(extractFrontMatter(text, db)).toEqual('diagram'); - expect(db.setDiagramTitle).toHaveBeenCalledWith('foo'); + expect(extractFrontMatter(text)).toMatchInlineSnapshot(` + { + "metadata": { + "title": "foo", + }, + "text": "diagram", + } + `); }); it('handles booleans in frontmatter properly', () => { - const db = dbMock(); const text = `---\ntitle: true\n---\ndiagram`; - expect(extractFrontMatter(text, db)).toEqual('diagram'); - expect(db.setDiagramTitle).toHaveBeenCalledWith('true'); + expect(extractFrontMatter(text)).toMatchInlineSnapshot(` + { + "metadata": { + "title": "true", + }, + "text": "diagram", + } + `); }); it('ignores unspecified frontmatter keys', () => { - const db = dbMock(); const text = `---\ninvalid: true\ntitle: foo\ntest: bar\n---\ndiagram`; - expect(extractFrontMatter(text, db)).toEqual('diagram'); - expect(db.setDiagramTitle).toHaveBeenCalledWith('foo'); + expect(extractFrontMatter(text)).toMatchInlineSnapshot(` + { + "metadata": { + "title": "foo", + }, + "text": "diagram", + } + `); }); it('throws exception for invalid YAML syntax', () => { const text = `---\n!!!\n---\ndiagram`; - expect(() => extractFrontMatter(text, dbMock())).toThrow( - 'tag suffix cannot contain exclamation marks' - ); + expect(() => extractFrontMatter(text)).toThrow('tag suffix cannot contain exclamation marks'); }); it('handles frontmatter with config', () => { @@ -92,9 +147,25 @@ config: array: [1, 2, 3] --- diagram`; - expect(extractFrontMatter(text, {}, setConfigMock)).toEqual('diagram'); - expect(setConfigMock).toHaveBeenCalledWith({ - graph: { string: 'hello', number: 14, boolean: false, array: [1, 2, 3] }, - }); + expect(extractFrontMatter(text)).toMatchInlineSnapshot(` + { + "metadata": { + "config": { + "graph": { + "array": [ + 1, + 2, + 3, + ], + "boolean": false, + "number": 14, + "string": "hello", + }, + }, + "title": "hello", + }, + "text": "diagram", + } + `); }); }); diff --git a/packages/mermaid/src/diagram-api/frontmatter.ts b/packages/mermaid/src/diagram-api/frontmatter.ts index 0fd2917ea..c95e05f2c 100644 --- a/packages/mermaid/src/diagram-api/frontmatter.ts +++ b/packages/mermaid/src/diagram-api/frontmatter.ts @@ -1,6 +1,5 @@ import type { MermaidConfig } from '../config.type.js'; import { frontMatterRegex } from './regexes.js'; -import type { DiagramDB } from './types.js'; // The "* as yaml" part is necessary for tree-shaking import * as yaml from 'js-yaml'; @@ -11,43 +10,51 @@ interface FrontMatterMetadata { config?: MermaidConfig; } +export interface FrontMatterResult { + text: string; + metadata: FrontMatterMetadata; +} + /** * Extract and parse frontmatter from text, if present, and sets appropriate * properties in the provided db. * @param text - The text that may have a YAML frontmatter. - * @param db - Diagram database, could be of any diagram. - * @param setDiagramConfig - Optional function to set diagram config. * @returns text with frontmatter stripped out */ -export function extractFrontMatter( - text: string, - db: DiagramDB, - setDiagramConfig?: (config: MermaidConfig) => void -): string { +export function extractFrontMatter(text: string): FrontMatterResult { const matches = text.match(frontMatterRegex); if (!matches) { - return text; + return { + text, + metadata: {}, + }; } - const parsed: FrontMatterMetadata = yaml.load(matches[1], { - // To support config, we need JSON schema. - // https://www.yaml.org/spec/1.2/spec.html#id2803231 - schema: yaml.JSON_SCHEMA, - }) as FrontMatterMetadata; + let parsed: FrontMatterMetadata = + yaml.load(matches[1], { + // To support config, we need JSON schema. + // https://www.yaml.org/spec/1.2/spec.html#id2803231 + schema: yaml.JSON_SCHEMA, + }) ?? {}; - if (parsed?.title) { - // toString() is necessary because YAML could parse the title as a number/boolean - db.setDiagramTitle?.(parsed.title.toString()); + // To handle runtime data type changes + parsed = typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {}; + + const metadata: FrontMatterMetadata = {}; + + // Only add properties that are explicitly supported, if they exist + if (parsed.displayMode) { + metadata.displayMode = parsed.displayMode.toString(); + } + if (parsed.title) { + metadata.title = parsed.title.toString(); + } + if (parsed.config) { + metadata.config = parsed.config; } - if (parsed?.displayMode) { - // toString() is necessary because YAML could parse the title as a number/boolean - db.setDisplayMode?.(parsed.displayMode.toString()); - } - - if (parsed?.config) { - setDiagramConfig?.(parsed.config); - } - - return text.slice(matches[0].length); + return { + text: text.slice(matches[0].length), + metadata, + }; } diff --git a/packages/mermaid/src/diagram-api/types.ts b/packages/mermaid/src/diagram-api/types.ts index 2ac7fba12..e9def2421 100644 --- a/packages/mermaid/src/diagram-api/types.ts +++ b/packages/mermaid/src/diagram-api/types.ts @@ -29,6 +29,7 @@ export interface DiagramDB { getAccDescription?: () => string; setDisplayMode?: (title: string) => void; + setWrap?: (wrap: boolean) => void; bindFunctions?: (element: Element) => void; } @@ -83,15 +84,6 @@ export interface ParserDefinition { parser: { yy: DiagramDB }; } -/** - * Type for function parse directive from diagram code. - * - * @param statement - - * @param context - - * @param type - - */ -export type ParseDirectiveDefinition = (statement: string, context: string, type: string) => void; - export type HTML = d3.Selection; export type SVG = d3.Selection; diff --git a/packages/mermaid/src/directiveUtils.ts b/packages/mermaid/src/directiveUtils.ts deleted file mode 100644 index baf628e74..000000000 --- a/packages/mermaid/src/directiveUtils.ts +++ /dev/null @@ -1,82 +0,0 @@ -import * as configApi from './config.js'; -import { log } from './logger.js'; - -let currentDirective: { type?: string; args?: any } | undefined = {}; - -export const parseDirective = function ( - p: any, - statement: string, - context: string, - type: string -): void { - log.debug('parseDirective is being called', statement, context, type); - try { - if (statement !== undefined) { - statement = statement.trim(); - switch (context) { - case 'open_directive': - currentDirective = {}; - break; - case 'type_directive': - if (!currentDirective) { - throw new Error('currentDirective is undefined'); - } - currentDirective.type = statement.toLowerCase(); - break; - case 'arg_directive': - if (!currentDirective) { - throw new Error('currentDirective is undefined'); - } - currentDirective.args = JSON.parse(statement); - break; - case 'close_directive': - handleDirective(p, currentDirective, type); - currentDirective = undefined; - break; - } - } - } catch (error) { - log.error( - `Error while rendering sequenceDiagram directive: ${statement} jison context: ${context}` - ); - // @ts-ignore: TODO Fix ts errors - log.error(error.message); - } -}; - -const handleDirective = function (p: any, directive: any, type: string): void { - log.info(`Directive type=${directive.type} with args:`, directive.args); - switch (directive.type) { - case 'init': - case 'initialize': { - ['config'].forEach((prop) => { - if (directive.args[prop] !== undefined) { - if (type === 'flowchart-v2') { - type = 'flowchart'; - } - directive.args[type] = directive.args[prop]; - delete directive.args[prop]; - } - }); - configApi.addDirective(directive.args); - break; - } - case 'wrap': - case 'nowrap': - if (p && p['setWrap']) { - p.setWrap(directive.type === 'wrap'); - } - break; - case 'themeCss': - log.warn('themeCss encountered'); - break; - default: - log.warn( - `Unhandled directive: source: '%%{${directive.type}: ${JSON.stringify( - directive.args ? directive.args : {} - )}}%%`, - directive - ); - break; - } -}; diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index bb7570034..f71fe27a7 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -23,14 +23,12 @@ import { attachFunctions } from './interactionDb.js'; import { log, setLogLevel } from './logger.js'; import getStyles from './styles.js'; import theme from './themes/index.js'; -import utils from './utils.js'; import DOMPurify from 'dompurify'; import type { MermaidConfig } from './config.type.js'; import { evaluate } from './diagrams/common/common.js'; import isEmpty from 'lodash-es/isEmpty.js'; import { setA11yDiagramInfo, addSVGa11yTitleDescription } from './accessibility.js'; -import { parseDirective } from './directiveUtils.js'; -import { extractFrontMatter } from './diagram-api/frontmatter.js'; +import { preprocessDiagram } from './preprocess.js'; // diagram names that support classDef statements const CLASSDEF_DIAGRAMS = [ @@ -98,6 +96,13 @@ export interface RenderResult { bindFunctions?: (element: Element) => void; } +function processAndSetConfigs(text: string) { + const processed = preprocessDiagram(text); + configApi.reset(); + configApi.addDirective(processed.config); + return processed; +} + /** * Parse the text and validate the syntax. * @param text - The mermaid diagram definition. @@ -108,6 +113,9 @@ export interface RenderResult { async function parse(text: string, parseOptions?: ParseOptions): Promise { addDiagrams(); + + text = processAndSetConfigs(text).code; + try { await getDiagramFromText(text); } catch (error) { @@ -384,18 +392,8 @@ const render = async function ( ): Promise { addDiagrams(); - configApi.reset(); - - // We need to add the directives before creating the diagram. - // So extractFrontMatter is called twice. Once here and once in the diagram parser. - // This can be fixed in a future refactor. - extractFrontMatter(text, {}, configApi.addDirective); - - // Add Directives. - const graphInit = utils.detectInit(text); - if (graphInit) { - configApi.addDirective(graphInit); - } + const processed = processAndSetConfigs(text); + text = processed.code; const config = configApi.getConfig(); log.debug(config); @@ -405,15 +403,6 @@ const render = async function ( text = MAX_TEXTLENGTH_EXCEEDED_MSG; } - // clean up text CRLFs - text = text.replace(/\r\n?/g, '\n'); // parser problems on CRLF ignore all CR and leave LF;; - - // clean up html tags so that all attributes use single quotes, parser throws error on double quotes - text = text.replace( - /<(\w+)([^>]*)>/g, - (match, tag, attributes) => '<' + tag + attributes.replace(/="([^"]*)"/g, "='$1'") + '>' - ); - const idSelector = '#' + id; const iFrameID = 'i' + id; const iFrameID_selector = '#' + iFrameID; @@ -476,7 +465,7 @@ const render = async function ( let parseEncounteredException; try { - diag = await getDiagramFromText(text); + diag = await getDiagramFromText(text, { title: processed.title }); } catch (error) { diag = new Diagram('error'); parseEncounteredException = error; @@ -673,7 +662,6 @@ function addA11yInfo( export const mermaidAPI = Object.freeze({ render, parse, - parseDirective, getDiagramFromText, initialize, getConfig: configApi.getConfig, diff --git a/packages/mermaid/src/preprocess.ts b/packages/mermaid/src/preprocess.ts new file mode 100644 index 000000000..3c33ce30f --- /dev/null +++ b/packages/mermaid/src/preprocess.ts @@ -0,0 +1,58 @@ +import { cleanupComments } from './diagram-api/comments.js'; +import { extractFrontMatter } from './diagram-api/frontmatter.js'; +import utils, { cleanAndMerge, removeDirectives } from './utils.js'; + +const cleanupText = (code: string) => { + return ( + code + // parser problems on CRLF ignore all CR and leave LF;; + .replace(/\r\n?/g, '\n') + // clean up html tags so that all attributes use single quotes, parser throws error on double quotes + .replace( + /<(\w+)([^>]*)>/g, + (match, tag, attributes) => '<' + tag + attributes.replace(/="([^"]*)"/g, "='$1'") + '>' + ) + ); +}; + +const processFrontmatter = (code: string) => { + const { text, metadata } = extractFrontMatter(code); + const { displayMode, title, config = {} } = metadata; + if (displayMode) { + // Needs to be supported for legacy reasons + if (!config.gantt) { + config.gantt = {}; + } + config.gantt.displayMode = displayMode; + } + return { title, config, text }; +}; + +const processDirectives = (code: string) => { + const initDirective = utils.detectInit(code) ?? {}; + const wrapDirectives = utils.detectDirective(code, 'wrap'); + if (Array.isArray(wrapDirectives)) { + initDirective.wrap = wrapDirectives.some(({ type }) => { + type === 'wrap'; + }); + } else if (wrapDirectives?.type === 'wrap') { + initDirective.wrap = true; + } + return { + text: removeDirectives(code), + directive: initDirective, + }; +}; + +export const preprocessDiagram = (code: string) => { + const cleanedCode = cleanupText(code); + const frontMatterResult = processFrontmatter(cleanedCode); + const directiveResult = processDirectives(frontMatterResult.text); + const config = cleanAndMerge(frontMatterResult.config, directiveResult.directive); + code = cleanupComments(directiveResult.text); + return { + code, + title: frontMatterResult.title, + config, + }; +}; diff --git a/packages/mermaid/src/utils.spec.ts b/packages/mermaid/src/utils.spec.ts index 271dc588c..e1398efc7 100644 --- a/packages/mermaid/src/utils.spec.ts +++ b/packages/mermaid/src/utils.spec.ts @@ -1,10 +1,11 @@ import { vi } from 'vitest'; -import utils, { cleanAndMerge } from './utils.js'; +import utils, { cleanAndMerge, detectDirective } from './utils.js'; import assignWithDepth from './assignWithDepth.js'; import { detectType } from './diagram-api/detectType.js'; import { addDiagrams } from './diagram-api/diagram-orchestration.js'; import memoize from 'lodash-es/memoize.js'; import { MockedD3 } from './tests/MockedD3.js'; +import { preprocessDiagram } from './preprocess.js'; addDiagrams(); @@ -158,13 +159,38 @@ describe('when detecting chart type ', function () { const type = detectType(str); expect(type).toBe('flowchart'); }); + it('should handle a wrap directive', () => { + const wrap = { type: 'wrap', args: null }; + expect(detectDirective('%%{wrap}%%', 'wrap')).toEqual(wrap); + expect( + detectDirective( + `%%{ + wrap + }%%`, + 'wrap' + ) + ).toEqual(wrap); + expect( + detectDirective( + `%%{ + + wrap + + }%%`, + 'wrap' + ) + ).toEqual(wrap); + expect(detectDirective('%%{wrap:}%%', 'wrap')).toEqual(wrap); + expect(detectDirective('%%{wrap: }%%', 'wrap')).toEqual(wrap); + expect(detectDirective('graph', 'wrap')).not.toEqual(wrap); + }); it('should handle an initialize definition', function () { const str = ` %%{initialize: { 'logLevel': 0, 'theme': 'dark' }}%% sequenceDiagram Alice->Bob: hi`; const type = detectType(str); - const init = utils.detectInit(str); + const init = preprocessDiagram(str).config; expect(type).toBe('sequence'); expect(init).toEqual({ logLevel: 0, theme: 'dark' }); }); @@ -174,7 +200,7 @@ Alice->Bob: hi`; sequenceDiagram Alice->Bob: hi`; const type = detectType(str); - const init = utils.detectInit(str); + const init = preprocessDiagram(str).config; expect(type).toBe('sequence'); expect(init).toEqual({ logLevel: 0, theme: 'dark' }); }); @@ -184,7 +210,7 @@ Alice->Bob: hi`; sequenceDiagram Alice->Bob: hi`; const type = detectType(str); - const init = utils.detectInit(str); + const init = preprocessDiagram(str).config; expect(type).toBe('sequence'); expect(init).toEqual({ logLevel: 0, theme: 'dark', sequence: { wrap: true } }); }); @@ -199,7 +225,7 @@ Alice->Bob: hi`; sequenceDiagram Alice->Bob: hi`; const type = detectType(str); - const init = utils.detectInit(str); + const init = preprocessDiagram(str).config; expect(type).toBe('sequence'); expect(init).toEqual({ logLevel: 0, theme: 'dark' }); }); @@ -214,7 +240,7 @@ Alice->Bob: hi`; sequenceDiagram Alice->Bob: hi`; const type = detectType(str); - const init = utils.detectInit(str); + const init = preprocessDiagram(str).config; expect(type).toBe('sequence'); expect(init).toEqual({ logLevel: 0, theme: 'dark' }); }); diff --git a/packages/mermaid/src/utils.ts b/packages/mermaid/src/utils.ts index 42b4ee67e..70de197da 100644 --- a/packages/mermaid/src/utils.ts +++ b/packages/mermaid/src/utils.ts @@ -25,7 +25,7 @@ import { select, } from 'd3'; import common from './diagrams/common/common.js'; -import { configKeys } from './defaultConfig.js'; +import { sanitizeDirective } from './utils/sanitizeDirective.js'; import { log } from './logger.js'; import { detectType } from './diagram-api/detectType.js'; import assignWithDepth from './assignWithDepth.js'; @@ -62,7 +62,6 @@ const d3CurveTypes = { const directiveWithoutOpen = /\s*(?:(\w+)(?=:):|(\w+))\s*(?:(\w+)|((?:(?!}%{2}).|\r?\n)*))?\s*(?:}%{2})?/gi; - /** * Detects the init config object from the text * @@ -197,6 +196,10 @@ export const detectDirective = function ( } }; +export const removeDirectives = function (text: string): string { + return text.replace(directiveRegex, ''); +}; + /** * Detects whether a substring in present in a given array * @@ -842,88 +845,6 @@ export const entityDecode = function (html: string): string { return unescape(decoder.textContent); }; -/** - * Sanitizes directive objects - * - * @param args - Directive's JSON - */ -export const sanitizeDirective = (args: unknown): void => { - log.debug('sanitizeDirective called with', args); - - // Return if not an object - if (typeof args !== 'object' || args == null) { - return; - } - - // Sanitize each element if an array - if (Array.isArray(args)) { - args.forEach((arg) => sanitizeDirective(arg)); - return; - } - - // Sanitize each key if an object - for (const key of Object.keys(args)) { - log.debug('Checking key', key); - if ( - key.startsWith('__') || - key.includes('proto') || - key.includes('constr') || - !configKeys.has(key) || - args[key] == null - ) { - log.debug('sanitize deleting key: ', key); - delete args[key]; - continue; - } - - // Recurse if an object - if (typeof args[key] === 'object') { - log.debug('sanitizing object', key); - sanitizeDirective(args[key]); - continue; - } - - const cssMatchers = ['themeCSS', 'fontFamily', 'altFontFamily']; - for (const cssKey of cssMatchers) { - if (key.includes(cssKey)) { - log.debug('sanitizing css option', key); - args[key] = sanitizeCss(args[key]); - } - } - } - - if (args.themeVariables) { - for (const k of Object.keys(args.themeVariables)) { - const val = args.themeVariables[k]; - if (val?.match && !val.match(/^[\d "#%(),.;A-Za-z]+$/)) { - args.themeVariables[k] = ''; - } - } - } - log.debug('After sanitization', args); -}; - -export const sanitizeCss = (str: string): string => { - let startCnt = 0; - let endCnt = 0; - - for (const element of str) { - if (startCnt < endCnt) { - return '{ /* ERROR: Unbalanced CSS */ }'; - } - if (element === '{') { - startCnt++; - } else if (element === '}') { - endCnt++; - } - } - if (startCnt !== endCnt) { - return '{ /* ERROR: Unbalanced CSS */ }'; - } - // Todo add more checks here - return str; -}; - export interface DetailedError { str: string; hash: any; @@ -1021,8 +942,6 @@ export default { runFunc, entityDecode, initIdGenerator, - sanitizeDirective, - sanitizeCss, insertTitle, parseFontSize, }; diff --git a/packages/mermaid/src/utils/sanitizeDirective.ts b/packages/mermaid/src/utils/sanitizeDirective.ts new file mode 100644 index 000000000..9b7e7da5c --- /dev/null +++ b/packages/mermaid/src/utils/sanitizeDirective.ts @@ -0,0 +1,84 @@ +import { configKeys } from '../defaultConfig.js'; +import { log } from '../logger.js'; + +/** + * Sanitizes directive objects + * + * @param args - Directive's JSON + */ +export const sanitizeDirective = (args: any): void => { + log.debug('sanitizeDirective called with', args); + + // Return if not an object + if (typeof args !== 'object' || args == null) { + return; + } + + // Sanitize each element if an array + if (Array.isArray(args)) { + args.forEach((arg) => sanitizeDirective(arg)); + return; + } + + // Sanitize each key if an object + for (const key of Object.keys(args)) { + log.debug('Checking key', key); + if ( + key.startsWith('__') || + key.includes('proto') || + key.includes('constr') || + !configKeys.has(key) || + args[key] == null + ) { + log.debug('sanitize deleting key: ', key); + delete args[key]; + continue; + } + + // Recurse if an object + if (typeof args[key] === 'object') { + log.debug('sanitizing object', key); + sanitizeDirective(args[key]); + continue; + } + + const cssMatchers = ['themeCSS', 'fontFamily', 'altFontFamily']; + for (const cssKey of cssMatchers) { + if (key.includes(cssKey)) { + log.debug('sanitizing css option', key); + args[key] = sanitizeCss(args[key]); + } + } + } + + if (args.themeVariables) { + for (const k of Object.keys(args.themeVariables)) { + const val = args.themeVariables[k]; + if (val?.match && !val.match(/^[\d "#%(),.;A-Za-z]+$/)) { + args.themeVariables[k] = ''; + } + } + } + log.debug('After sanitization', args); +}; + +export const sanitizeCss = (str: string): string => { + let startCnt = 0; + let endCnt = 0; + + for (const element of str) { + if (startCnt < endCnt) { + return '{ /* ERROR: Unbalanced CSS */ }'; + } + if (element === '{') { + startCnt++; + } else if (element === '}') { + endCnt++; + } + } + if (startCnt !== endCnt) { + return '{ /* ERROR: Unbalanced CSS */ }'; + } + // Todo add more checks here + return str; +}; From f0883be0e3e481afbb9d21abf8f81c420b99227b Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Fri, 25 Aug 2023 12:55:35 +0530 Subject: [PATCH 03/13] refactor: Update DBs to remove directive handling --- packages/mermaid/src/diagrams/c4/c4Db.js | 6 ---- .../mermaid/src/diagrams/class/classDb.ts | 7 ---- packages/mermaid/src/diagrams/er/erDb.js | 6 ---- .../mermaid/src/diagrams/flowchart/flowDb.js | 6 ---- .../mermaid/src/diagrams/gantt/ganttDb.js | 6 ---- .../mermaid/src/diagrams/git/gitGraphAst.js | 6 ---- packages/mermaid/src/diagrams/pie/pie.spec.ts | 11 ------- packages/mermaid/src/diagrams/pie/pieDb.ts | 7 ---- packages/mermaid/src/diagrams/pie/pieTypes.ts | 3 +- .../parser/quadrant.jison.spec.ts | 32 +------------------ .../src/diagrams/quadrant-chart/quadrantDb.ts | 8 ----- .../src/diagrams/requirement/requirementDb.js | 6 ---- .../src/diagrams/sequence/sequenceDb.js | 6 ---- .../diagrams/sequence/sequenceDiagram.spec.js | 6 ---- .../mermaid/src/diagrams/state/stateDb.js | 6 ---- .../diagrams/state/stateDiagram-v2.spec.js | 10 ------ .../src/diagrams/state/stateDiagram.spec.js | 10 ------ .../src/diagrams/timeline/timeline.spec.js | 20 +----------- .../src/diagrams/timeline/timelineDb.js | 6 ---- .../src/diagrams/user-journey/journeyDb.js | 6 ---- 20 files changed, 3 insertions(+), 171 deletions(-) diff --git a/packages/mermaid/src/diagrams/c4/c4Db.js b/packages/mermaid/src/diagrams/c4/c4Db.js index 09dcc13cd..2dc014d9e 100644 --- a/packages/mermaid/src/diagrams/c4/c4Db.js +++ b/packages/mermaid/src/diagrams/c4/c4Db.js @@ -1,4 +1,3 @@ -import mermaidAPI from '../../mermaidAPI.js'; import * as configApi from '../../config.js'; import { sanitizeText } from '../common/common.js'; import { setAccTitle, getAccTitle, getAccDescription, setAccDescription } from '../../commonDb.js'; @@ -33,10 +32,6 @@ export const setC4Type = function (c4TypeParam) { c4Type = sanitizedText; }; -export const parseDirective = function (statement, context, type) { - mermaidAPI.parseDirective(this, statement, context, type); -}; - //type, from, to, label, ?techn, ?descr, ?sprite, ?tags, $link export const addRel = function (type, from, to, label, techn, descr, sprite, tags, link) { // Don't allow label nulling @@ -816,7 +811,6 @@ export default { getAccTitle, getAccDescription, setAccDescription, - parseDirective, getConfig: () => configApi.getConfig().c4, clear, LINETYPE, diff --git a/packages/mermaid/src/diagrams/class/classDb.ts b/packages/mermaid/src/diagrams/class/classDb.ts index b14b1d07a..11e80ffc8 100644 --- a/packages/mermaid/src/diagrams/class/classDb.ts +++ b/packages/mermaid/src/diagrams/class/classDb.ts @@ -5,7 +5,6 @@ import { log } from '../../logger.js'; import * as configApi from '../../config.js'; import common from '../common/common.js'; import utils from '../../utils.js'; -import mermaidAPI from '../../mermaidAPI.js'; import { setAccTitle, getAccTitle, @@ -37,11 +36,6 @@ let functions: any[] = []; const sanitizeText = (txt: string) => common.sanitizeText(txt, configApi.getConfig()); -export const parseDirective = function (statement: string, context: string, type: string) { - // @ts-ignore Don't wanna mess it up - mermaidAPI.parseDirective(this, statement, context, type); -}; - const splitClassNameAndType = function (id: string) { let genericType = ''; let className = id; @@ -456,7 +450,6 @@ export const addClassesToNamespace = function (id: string, classNames: string[]) }; export default { - parseDirective, setAccTitle, getAccTitle, getAccDescription, diff --git a/packages/mermaid/src/diagrams/er/erDb.js b/packages/mermaid/src/diagrams/er/erDb.js index 2f5116cbf..559337ba9 100644 --- a/packages/mermaid/src/diagrams/er/erDb.js +++ b/packages/mermaid/src/diagrams/er/erDb.js @@ -1,5 +1,4 @@ import { log } from '../../logger.js'; -import mermaidAPI from '../../mermaidAPI.js'; import * as configApi from '../../config.js'; import { @@ -28,10 +27,6 @@ const Identification = { IDENTIFYING: 'IDENTIFYING', }; -export const parseDirective = function (statement, context, type) { - mermaidAPI.parseDirective(this, statement, context, type); -}; - const addEntity = function (name) { if (entities[name] === undefined) { entities[name] = { attributes: [] }; @@ -85,7 +80,6 @@ const clear = function () { export default { Cardinality, Identification, - parseDirective, getConfig: () => configApi.getConfig().er, addEntity, addAttributes, diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.js b/packages/mermaid/src/diagrams/flowchart/flowDb.js index ea8fa71d2..6e161a33a 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDb.js +++ b/packages/mermaid/src/diagrams/flowchart/flowDb.js @@ -2,7 +2,6 @@ import { select } from 'd3'; import utils from '../../utils.js'; import * as configApi from '../../config.js'; import common from '../common/common.js'; -import mermaidAPI from '../../mermaidAPI.js'; import { log } from '../../logger.js'; import { setAccTitle, @@ -34,10 +33,6 @@ let funs = []; const sanitizeText = (txt) => common.sanitizeText(txt, config); -export const parseDirective = function (statement, context, type) { - mermaidAPI.parseDirective(this, statement, context, type); -}; - /** * Function to lookup domId from id in the graph definition. * @@ -771,7 +766,6 @@ export const lex = { firstGraph, }; export default { - parseDirective, defaultConfig: () => configApi.defaultConfig.flowchart, setAccTitle, getAccTitle, diff --git a/packages/mermaid/src/diagrams/gantt/ganttDb.js b/packages/mermaid/src/diagrams/gantt/ganttDb.js index da838f839..20e1ad70a 100644 --- a/packages/mermaid/src/diagrams/gantt/ganttDb.js +++ b/packages/mermaid/src/diagrams/gantt/ganttDb.js @@ -6,7 +6,6 @@ import dayjsAdvancedFormat from 'dayjs/plugin/advancedFormat.js'; import { log } from '../../logger.js'; import * as configApi from '../../config.js'; import utils from '../../utils.js'; -import mermaidAPI from '../../mermaidAPI.js'; import { setAccTitle, @@ -42,10 +41,6 @@ let weekday = 'sunday'; // The serial order of the task in the script let lastOrder = 0; -export const parseDirective = function (statement, context, type) { - mermaidAPI.parseDirective(this, statement, context, type); -}; - export const clear = function () { sections = []; tasks = []; @@ -730,7 +725,6 @@ export const bindFunctions = function (element) { }; export default { - parseDirective, getConfig: () => configApi.getConfig().gantt, clear, setDateFormat, diff --git a/packages/mermaid/src/diagrams/git/gitGraphAst.js b/packages/mermaid/src/diagrams/git/gitGraphAst.js index 416479d15..5b34c6b65 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphAst.js +++ b/packages/mermaid/src/diagrams/git/gitGraphAst.js @@ -1,6 +1,5 @@ import { log } from '../../logger.js'; import { random } from '../../utils.js'; -import mermaidAPI from '../../mermaidAPI.js'; import * as configApi from '../../config.js'; import { getConfig } from '../../config.js'; import common from '../common/common.js'; @@ -33,10 +32,6 @@ function getId() { return random({ length: 7 }); } -export const parseDirective = function (statement, context, type) { - mermaidAPI.parseDirective(this, statement, context, type); -}; - // /** // * @param currentCommit // * @param otherCommit @@ -507,7 +502,6 @@ export const commitType = { }; export default { - parseDirective, getConfig: () => configApi.getConfig().gitGraph, setDirection, setOptions, diff --git a/packages/mermaid/src/diagrams/pie/pie.spec.ts b/packages/mermaid/src/diagrams/pie/pie.spec.ts index 7c8e0809a..564e12f0f 100644 --- a/packages/mermaid/src/diagrams/pie/pie.spec.ts +++ b/packages/mermaid/src/diagrams/pie/pie.spec.ts @@ -62,17 +62,6 @@ describe('pie', () => { expect(sections['bat']).toBe(40); }); - it('should handle simple pie with a directive', () => { - parser.parse(`%%{init: {'logLevel':0}}%% - pie - "ash" : 60 - "bat" : 40 - `); - const sections = db.getSections(); - expect(sections['ash']).toBe(60); - expect(sections['bat']).toBe(40); - }); - it('should handle simple pie with a title', () => { parser.parse(`pie title a 60/40 pie "ash" : 60 diff --git a/packages/mermaid/src/diagrams/pie/pieDb.ts b/packages/mermaid/src/diagrams/pie/pieDb.ts index dbe50f08a..2a0dc16f3 100644 --- a/packages/mermaid/src/diagrams/pie/pieDb.ts +++ b/packages/mermaid/src/diagrams/pie/pieDb.ts @@ -1,5 +1,4 @@ import { log } from '../../logger.js'; -import { parseDirective as _parseDirective } from '../../directiveUtils.js'; import { getConfig as commonGetConfig } from '../../config.js'; import { sanitizeText } from '../common/common.js'; import { @@ -11,7 +10,6 @@ import { setAccDescription, clear as commonClear, } from '../../commonDb.js'; -import type { ParseDirectiveDefinition } from '../../diagram-api/types.js'; import type { PieFields, PieDB, Sections } from './pieTypes.js'; import type { RequiredDeep } from 'type-fest'; import type { PieDiagramConfig } from '../../config.type.js'; @@ -31,10 +29,6 @@ const config: Required = structuredClone(DEFAULT_PIE_CONFIG); const getConfig = (): Required => structuredClone(config); -const parseDirective: ParseDirectiveDefinition = (statement, context, type) => { - _parseDirective(this, statement, context, type); -}; - const clear = (): void => { sections = structuredClone(DEFAULT_PIE_DB.sections); showData = DEFAULT_PIE_DB.showData; @@ -67,7 +61,6 @@ const getShowData = (): boolean => showData; export const db: PieDB = { getConfig, - parseDirective, clear, setDiagramTitle, getDiagramTitle, diff --git a/packages/mermaid/src/diagrams/pie/pieTypes.ts b/packages/mermaid/src/diagrams/pie/pieTypes.ts index 67fb1dca2..6ba3ab92e 100644 --- a/packages/mermaid/src/diagrams/pie/pieTypes.ts +++ b/packages/mermaid/src/diagrams/pie/pieTypes.ts @@ -1,5 +1,5 @@ import type { PieDiagramConfig } from '../../config.type.js'; -import type { DiagramDB, ParseDirectiveDefinition } from '../../diagram-api/types.js'; +import type { DiagramDB } from '../../diagram-api/types.js'; export interface PieFields { sections: Sections; @@ -46,7 +46,6 @@ export interface PieDB extends DiagramDB { getConfig: () => Required; // common db - parseDirective: ParseDirectiveDefinition; clear: () => void; setDiagramTitle: (title: string) => void; getDiagramTitle: () => string; diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts index faa9281f0..d10cb2134 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison.spec.ts @@ -19,7 +19,6 @@ const mockDB: Record> = { setYAxisTopText: vi.fn(), setYAxisBottomText: vi.fn(), setDiagramTitle: vi.fn(), - parseDirective: vi.fn(), addPoint: vi.fn(), }; @@ -45,23 +44,6 @@ describe('Testing quadrantChart jison file', () => { expect(parserFnConstructor(str)).not.toThrow(); }); - it('should be able to parse directive', () => { - const str = - '%%{init: {"quadrantChart": {"chartWidth": 600, "chartHeight": 600} } }%% \n quadrantChart'; - expect(parserFnConstructor(str)).not.toThrow(); - expect(mockDB.parseDirective.mock.calls[0]).toEqual(['%%{', 'open_directive']); - expect(mockDB.parseDirective.mock.calls[1]).toEqual(['init', 'type_directive']); - expect(mockDB.parseDirective.mock.calls[2]).toEqual([ - '{"quadrantChart": {"chartWidth": 600, "chartHeight": 600} }', - 'arg_directive', - ]); - expect(mockDB.parseDirective.mock.calls[3]).toEqual([ - '}%%', - 'close_directive', - 'quadrantChart', - ]); - }); - it('should be able to parse xAxis text', () => { let str = 'quadrantChart\nx-axis urgent --> not urgent'; expect(parserFnConstructor(str)).not.toThrow(); @@ -243,8 +225,7 @@ describe('Testing quadrantChart jison file', () => { }); it('should be able to parse the whole chart', () => { - const str = `%%{init: {"quadrantChart": {"chartWidth": 600, "chartHeight": 600} } }%% - quadrantChart + const str = `quadrantChart title Analytics and Business Intelligence Platforms x-axis "Completeness of Vision ❤" --> "x-axis-2" y-axis Ability to Execute --> "y-axis-2" @@ -258,17 +239,6 @@ describe('Testing quadrantChart jison file', () => { Incorta: [0.20, 0.30]`; expect(parserFnConstructor(str)).not.toThrow(); - expect(mockDB.parseDirective.mock.calls[0]).toEqual(['%%{', 'open_directive']); - expect(mockDB.parseDirective.mock.calls[1]).toEqual(['init', 'type_directive']); - expect(mockDB.parseDirective.mock.calls[2]).toEqual([ - '{"quadrantChart": {"chartWidth": 600, "chartHeight": 600} }', - 'arg_directive', - ]); - expect(mockDB.parseDirective.mock.calls[3]).toEqual([ - '}%%', - 'close_directive', - 'quadrantChart', - ]); expect(mockDB.setXAxisLeftText).toHaveBeenCalledWith({ text: 'Completeness of Vision ❤', type: 'text', diff --git a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts index c0c0f4c8a..4466f9fa4 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts +++ b/packages/mermaid/src/diagrams/quadrant-chart/quadrantDb.ts @@ -1,5 +1,3 @@ -import { log } from '../../logger.js'; -import mermaidAPI from '../../mermaidAPI.js'; import * as configApi from '../../config.js'; import { sanitizeText } from '../common/common.js'; import { @@ -94,11 +92,6 @@ function getQuadrantData() { return quadrantBuilder.build(); } -export const parseDirective = function (statement: string, context: string, type: string) { - // @ts-ignore: TODO Fix ts errors - mermaidAPI.parseDirective(this, statement, context, type); -}; - const clear = function () { quadrantBuilder.clear(); commonClear(); @@ -117,7 +110,6 @@ export default { setYAxisBottomText, addPoint, getQuadrantData, - parseDirective, clear, setAccTitle, getAccTitle, diff --git a/packages/mermaid/src/diagrams/requirement/requirementDb.js b/packages/mermaid/src/diagrams/requirement/requirementDb.js index 1d0a3e2e1..03629aeac 100644 --- a/packages/mermaid/src/diagrams/requirement/requirementDb.js +++ b/packages/mermaid/src/diagrams/requirement/requirementDb.js @@ -1,6 +1,5 @@ import * as configApi from '../../config.js'; import { log } from '../../logger.js'; -import mermaidAPI from '../../mermaidAPI.js'; import { setAccTitle, @@ -48,10 +47,6 @@ const Relationships = { TRACES: 'traces', }; -export const parseDirective = function (statement, context, type) { - mermaidAPI.parseDirective(this, statement, context, type); -}; - const addRequirement = (name, type) => { if (requirements[name] === undefined) { requirements[name] = { @@ -149,7 +144,6 @@ export default { VerifyType, Relationships, - parseDirective, getConfig: () => configApi.getConfig().req, addRequirement, diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDb.js b/packages/mermaid/src/diagrams/sequence/sequenceDb.js index b5d68fb9f..ff8a7c0ae 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDb.js +++ b/packages/mermaid/src/diagrams/sequence/sequenceDb.js @@ -1,4 +1,3 @@ -import mermaidAPI from '../../mermaidAPI.js'; import * as configApi from '../../config.js'; import { log } from '../../logger.js'; import { sanitizeText } from '../common/common.js'; @@ -25,10 +24,6 @@ let currentBox = undefined; let lastCreated = undefined; let lastDestroyed = undefined; -export const parseDirective = function (statement, context, type) { - mermaidAPI.parseDirective(this, statement, context, type); -}; - export const addBox = function (data) { boxes.push({ name: data.text, @@ -619,7 +614,6 @@ export default { getBoxes, getDiagramTitle, setDiagramTitle, - parseDirective, getConfig: () => configApi.getConfig().sequence, clear, parseMessage, diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js b/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js index 0b84fbe35..5e0943699 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js +++ b/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js @@ -2051,9 +2051,7 @@ describe('when rendering a sequenceDiagram with directives', () => { it('should handle one actor, when theme is dark and logLevel is 1 DX1 (dfg1)', async () => { const str = ` -%%{init: { "theme": "dark", "logLevel": 1 } }%% sequenceDiagram -%%{wrap}%% participant Alice `; diagram = new Diagram(str); @@ -2062,8 +2060,6 @@ participant Alice const { bounds, models } = diagram.renderer.bounds.getBounds(); const mermaid = mermaidAPI.getConfig(); - expect(mermaid.theme).toBe('dark'); - expect(mermaid.logLevel).toBe(1); expect(bounds.startx).toBe(0); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); @@ -2073,7 +2069,6 @@ participant Alice }); it('should handle one actor, when logLevel is 3 (dfg0)', async () => { const str = ` -%%{initialize: { "logLevel": 3 }}%% sequenceDiagram participant Alice `; @@ -2083,7 +2078,6 @@ participant Alice const { bounds, models } = diagram.renderer.bounds.getBounds(); const mermaid = mermaidAPI.getConfig(); - expect(mermaid.logLevel).toBe(3); expect(bounds.startx).toBe(0); expect(bounds.startx).toBe(0); expect(bounds.starty).toBe(0); diff --git a/packages/mermaid/src/diagrams/state/stateDb.js b/packages/mermaid/src/diagrams/state/stateDb.js index d9c789a99..56a0a4cc6 100644 --- a/packages/mermaid/src/diagrams/state/stateDb.js +++ b/packages/mermaid/src/diagrams/state/stateDb.js @@ -1,6 +1,5 @@ import { log } from '../../logger.js'; import { generateId } from '../../utils.js'; -import mermaidAPI from '../../mermaidAPI.js'; import common from '../common/common.js'; import * as configApi from '../../config.js'; import { @@ -77,10 +76,6 @@ export const relationType = { const clone = (o) => JSON.parse(JSON.stringify(o)); -export const parseDirective = function (statement, context, type) { - mermaidAPI.parseDirective(this, statement, context, type); -}; - const setRootDoc = (o) => { log.info('Setting root doc', o); // rootDoc = { id: 'root', doc: o }; @@ -547,7 +542,6 @@ const setDirection = (dir) => { const trimColon = (str) => (str && str[0] === ':' ? str.substr(1).trim() : str.trim()); export default { - parseDirective, getConfig: () => configApi.getConfig().state, addState, clear, diff --git a/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js b/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js index e64ecfdf8..c387ff7b3 100644 --- a/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js +++ b/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js @@ -55,16 +55,6 @@ describe('state diagram V2, ', function () { const title = stateDb.getAccTitle(); expect(title).toBe('a simple title of the diagram'); }); - it('simple with directive', function () { - const str = `%%{init: {'logLevel': 0 }}%% - stateDiagram-v2\n - State1 : this is another string - [*] --> State1 - State1 --> [*] - `; - - parser.parse(str); - }); it('should handle relation definitions', function () { const str = `stateDiagram-v2\n [*] --> State1 diff --git a/packages/mermaid/src/diagrams/state/stateDiagram.spec.js b/packages/mermaid/src/diagrams/state/stateDiagram.spec.js index e6e470140..536031c81 100644 --- a/packages/mermaid/src/diagrams/state/stateDiagram.spec.js +++ b/packages/mermaid/src/diagrams/state/stateDiagram.spec.js @@ -66,16 +66,6 @@ describe('state diagram, ', function () { const title = stateDb.getAccTitle(); expect(title).toBe('a simple title of the diagram'); }); - it('simple with directive', function () { - const str = `%%{init: {'logLevel': 0 }}%% - stateDiagram\n - State1 : this is another string - [*] --> State1 - State1 --> [*] - `; - - parser.parse(str); - }); it('should handle relation definitions', function () { const str = `stateDiagram\n [*] --> State1 diff --git a/packages/mermaid/src/diagrams/timeline/timeline.spec.js b/packages/mermaid/src/diagrams/timeline/timeline.spec.js index 1f6a96024..a66a7f2c1 100644 --- a/packages/mermaid/src/diagrams/timeline/timeline.spec.js +++ b/packages/mermaid/src/diagrams/timeline/timeline.spec.js @@ -1,26 +1,8 @@ import { parser as timeline } from './parser/timeline.jison'; import * as timelineDB from './timelineDb.js'; -// import { injectUtils } from './mermaidUtils.js'; import * as _commonDb from '../../commonDb.js'; -import { parseDirective as _parseDirective } from '../../directiveUtils.js'; -import { - log, - setLogLevel, - getConfig, - sanitizeText, - setupGraphViewBox, -} from '../../diagram-api/diagramAPI.js'; - -// injectUtils( -// log, -// setLogLevel, -// getConfig, -// sanitizeText, -// setupGraphViewBox, -// _commonDb, -// _parseDirective -// ); +import { setLogLevel } from '../../diagram-api/diagramAPI.js'; describe('when parsing a timeline ', function () { beforeEach(function () { diff --git a/packages/mermaid/src/diagrams/timeline/timelineDb.js b/packages/mermaid/src/diagrams/timeline/timelineDb.js index 337cfe441..91cee5175 100644 --- a/packages/mermaid/src/diagrams/timeline/timelineDb.js +++ b/packages/mermaid/src/diagrams/timeline/timelineDb.js @@ -1,4 +1,3 @@ -import { parseDirective as _parseDirective } from '../../directiveUtils.js'; import * as commonDb from '../../commonDb.js'; let currentSection = ''; let currentTaskId = 0; @@ -9,10 +8,6 @@ const rawTasks = []; export const getCommonDb = () => commonDb; -export const parseDirective = (statement, context, type) => { - _parseDirective(this, statement, context, type); -}; - export const clear = function () { sections.length = 0; tasks.length = 0; @@ -104,5 +99,4 @@ export default { addTask, addTaskOrg, addEvent, - parseDirective, }; diff --git a/packages/mermaid/src/diagrams/user-journey/journeyDb.js b/packages/mermaid/src/diagrams/user-journey/journeyDb.js index d4f34e942..5812acffe 100644 --- a/packages/mermaid/src/diagrams/user-journey/journeyDb.js +++ b/packages/mermaid/src/diagrams/user-journey/journeyDb.js @@ -1,4 +1,3 @@ -import mermaidAPI from '../../mermaidAPI.js'; import * as configApi from '../../config.js'; import { setAccTitle, @@ -16,10 +15,6 @@ const sections = []; const tasks = []; const rawTasks = []; -export const parseDirective = function (statement, context, type) { - mermaidAPI.parseDirective(this, statement, context, type); -}; - export const clear = function () { sections.length = 0; tasks.length = 0; @@ -118,7 +113,6 @@ const getActors = function () { }; export default { - parseDirective, getConfig: () => configApi.getConfig().journey, clear, setDiagramTitle, From 1e0918c2ffbb213fb60bcd010f922d7ebae9553c Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Fri, 25 Aug 2023 12:55:58 +0530 Subject: [PATCH 04/13] refactor: Remove directives from grammar --- .../src/diagrams/c4/parser/c4Diagram.jison | 30 -- .../diagrams/class/parser/classDiagram.jison | 30 -- .../src/diagrams/er/parser/erDiagram.jison | 31 +- .../src/diagrams/flowchart/parser/flow.jison | 36 +-- .../src/diagrams/gantt/parser/gantt.jison | 32 +- .../src/diagrams/git/gitGraphParser.spec | 288 ------------------ .../src/diagrams/git/parser/gitGraph.jison | 31 -- .../mermaid/src/diagrams/pie/parser/pie.jison | 32 -- .../quadrant-chart/parser/quadrant.jison | 32 -- .../parser/requirementDiagram.jison | 24 +- .../sequence/parser/sequenceDiagram.jison | 32 +- .../diagrams/state/parser/stateDiagram.jison | 35 +-- .../diagrams/timeline/parser/timeline.jison | 33 -- .../user-journey/parser/journey.jison | 32 -- 14 files changed, 8 insertions(+), 690 deletions(-) delete mode 100644 packages/mermaid/src/diagrams/git/gitGraphParser.spec diff --git a/packages/mermaid/src/diagrams/c4/parser/c4Diagram.jison b/packages/mermaid/src/diagrams/c4/parser/c4Diagram.jison index 1dfa69ef1..a6bd8a6ec 100644 --- a/packages/mermaid/src/diagrams/c4/parser/c4Diagram.jison +++ b/packages/mermaid/src/diagrams/c4/parser/c4Diagram.jison @@ -72,25 +72,16 @@ %x string_kv_key %x string_kv_value -%x open_directive -%x type_directive -%x arg_directive -%x close_directive %x acc_title %x acc_descr %x acc_descr_multiline %% -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } .*direction\s+TB[^\n]* return 'direction_tb'; .*direction\s+BT[^\n]* return 'direction_bt'; .*direction\s+RL[^\n]* return 'direction_rl'; .*direction\s+LR[^\n]* return 'direction_lr'; -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; "title"\s[^#\n;]+ return 'title'; @@ -207,7 +198,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} start : mermaidDoc | direction - | directive start ; direction @@ -225,26 +215,6 @@ mermaidDoc : graphConfig ; -directive - : openDirective typeDirective closeDirective NEWLINE - | openDirective typeDirective ':' argDirective closeDirective NEWLINE - ; - -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { } - ; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'c4Context'); } - ; graphConfig : C4_CONTEXT NEWLINE statements EOF {yy.setC4Type($1)} diff --git a/packages/mermaid/src/diagrams/class/parser/classDiagram.jison b/packages/mermaid/src/diagrams/class/parser/classDiagram.jison index 8fdfced75..6066fdc35 100644 --- a/packages/mermaid/src/diagrams/class/parser/classDiagram.jison +++ b/packages/mermaid/src/diagrams/class/parser/classDiagram.jison @@ -13,9 +13,6 @@ %x href %x callback_name %x callback_args -%x open_directive -%x type_directive -%x arg_directive %x acc_title %x acc_descr %x acc_descr_multiline @@ -24,15 +21,10 @@ %x namespace %x namespace-body %% -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } .*direction\s+TB[^\n]* return 'direction_tb'; .*direction\s+BT[^\n]* return 'direction_bt'; .*direction\s+RL[^\n]* return 'direction_rl'; .*direction\s+LR[^\n]* return 'direction_lr'; -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; \%\%(?!\{)*[^\n]*(\r?\n?)+ /* skip comments */ \%\%[^\n]*(\r?\n)* /* skip comments */ accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; } @@ -220,7 +212,6 @@ line was introduced with 'click'. start : mermaidDoc - | directive start | statements ; @@ -239,27 +230,6 @@ mermaidDoc : graphConfig ; -directive - : openDirective typeDirective closeDirective NEWLINE - | openDirective typeDirective ':' argDirective closeDirective NEWLINE - ; - -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { yy.parseDirective($1, 'type_directive'); } - ; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'class'); } - ; - graphConfig : CLASS_DIAGRAM NEWLINE statements EOF ; diff --git a/packages/mermaid/src/diagrams/er/parser/erDiagram.jison b/packages/mermaid/src/diagrams/er/parser/erDiagram.jison index 0a2549268..4338983ec 100644 --- a/packages/mermaid/src/diagrams/er/parser/erDiagram.jison +++ b/packages/mermaid/src/diagrams/er/parser/erDiagram.jison @@ -1,7 +1,7 @@ %lex %options case-insensitive -%x open_directive type_directive arg_directive block +%x block %x acc_title %x acc_descr %x acc_descr_multiline @@ -14,11 +14,6 @@ accDescr\s*":"\s* { this.begin("ac accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} [\}] { this.popState(); } [^\}]* return "acc_descr_multiline_value"; -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; [\n]+ return 'NEWLINE'; \s+ /* skip whitespace */ [\s]+ return 'SPACE'; @@ -75,7 +70,6 @@ o\{ return 'ZERO_OR_MORE'; start : 'ER_DIAGRAM' document 'EOF' { /*console.log('finished parsing');*/ } - | directive start ; document @@ -90,14 +84,9 @@ line | EOF { $$=[];} ; -directive - : openDirective typeDirective closeDirective 'NEWLINE' - | openDirective typeDirective ':' argDirective closeDirective 'NEWLINE' - ; statement - : directive - | entityName relSpec entityName ':' role + : entityName relSpec entityName ':' role { yy.addEntity($1); yy.addEntity($3); @@ -185,20 +174,4 @@ role | 'ALPHANUM' { $$ = $1; } ; -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { yy.parseDirective($1, 'type_directive'); } - ; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'er'); } - ; - %% diff --git a/packages/mermaid/src/diagrams/flowchart/parser/flow.jison b/packages/mermaid/src/diagrams/flowchart/parser/flow.jison index 8d746f808..6dad36d25 100644 --- a/packages/mermaid/src/diagrams/flowchart/parser/flow.jison +++ b/packages/mermaid/src/diagrams/flowchart/parser/flow.jison @@ -23,17 +23,8 @@ %x href %x callbackname %x callbackargs -%x open_directive -%x type_directive -%x arg_directive -%x close_directive %% -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; } (?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; } accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; } @@ -272,35 +263,10 @@ that id. %% /* language grammar */ start - : mermaidDoc - | directive start - ; - -directive - : openDirective typeDirective closeDirective separator - | openDirective typeDirective ':' argDirective closeDirective separator - ; - -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { yy.parseDirective($type_directive, 'type_directive'); } - ; - -argDirective - : arg_directive { $arg_directive = $arg_directive.trim().replace(/'/g, '"'); yy.parseDirective($arg_directive, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'flowchart'); } - ; - -mermaidDoc : graphConfig document ; + document : /* empty */ { $$ = [];} diff --git a/packages/mermaid/src/diagrams/gantt/parser/gantt.jison b/packages/mermaid/src/diagrams/gantt/parser/gantt.jison index f7fd40c1b..b4daab5dc 100644 --- a/packages/mermaid/src/diagrams/gantt/parser/gantt.jison +++ b/packages/mermaid/src/diagrams/gantt/parser/gantt.jison @@ -11,19 +11,11 @@ %x href %x callbackname %x callbackargs -%x open_directive -%x type_directive -%x arg_directive -%x close_directive %x acc_title %x acc_descr %x acc_descr_multiline %% \%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; } (?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; } @@ -112,8 +104,7 @@ weekday\s+sunday return 'weekday_sunday' %% /* language grammar */ start - : directive start - | gantt document 'EOF' { return $2; } + : gantt document 'EOF' { return $2; } ; document @@ -155,13 +146,8 @@ statement | section { yy.addSection($1.substr(8));$$=$1.substr(8); } | clickStatement | taskTxt taskData {yy.addTask($1,$2);$$='task';} - | directive ; -directive - : openDirective typeDirective closeDirective 'NL' - | openDirective typeDirective ':' argDirective closeDirective 'NL' - ; /* click allows any combination of href and call. @@ -192,20 +178,4 @@ clickStatementDebug | click href {$$=$1 + ' ' + $2;} ; -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { yy.parseDirective($1, 'type_directive'); } - ; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'gantt'); } - ; - %% diff --git a/packages/mermaid/src/diagrams/git/gitGraphParser.spec b/packages/mermaid/src/diagrams/git/gitGraphParser.spec deleted file mode 100644 index 0a8256c5b..000000000 --- a/packages/mermaid/src/diagrams/git/gitGraphParser.spec +++ /dev/null @@ -1,288 +0,0 @@ - -// Todo reintroduce without cryptoRandomString -import gitGraphAst from './gitGraphAst'; -import { parser } from './parser/gitGraph'; -import randomString from 'crypto-random-string'; -import cryptoRandomString from 'crypto-random-string'; - -jest.mock('crypto-random-string'); - -describe('when parsing a gitGraph', function() { - let randomNumber; - beforeEach(function() { - parser.yy = gitGraphAst; - parser.yy.clear(); - randomNumber = 0; - cryptoRandomString.mockImplementation(() => { - randomNumber = randomNumber + 1; - return String(randomNumber); - }); - }); - afterEach(function() { - cryptoRandomString.mockReset(); - }); - it('should handle a gitGraph definition', function() { - const str = 'gitGraph:\n' + 'commit\n'; - - parser.parse(str); - const commits = parser.yy.getCommits(); - - expect(Object.keys(commits).length).toBe(1); - expect(parser.yy.getCurrentBranch()).toBe('master'); - expect(parser.yy.getDirection()).toBe('LR'); - expect(Object.keys(parser.yy.getBranches()).length).toBe(1); - }); - - it('should handle a gitGraph definition with empty options', function() { - const str = 'gitGraph:\n' + 'options\n' + 'end\n' + 'commit\n'; - - parser.parse(str); - const commits = parser.yy.getCommits(); - - expect(parser.yy.getOptions()).toEqual({}); - expect(Object.keys(commits).length).toBe(1); - expect(parser.yy.getCurrentBranch()).toBe('master'); - expect(parser.yy.getDirection()).toBe('LR'); - expect(Object.keys(parser.yy.getBranches()).length).toBe(1); - }); - - it('should handle a gitGraph definition with valid options', function() { - const str = 'gitGraph:\n' + 'options\n' + '{"key": "value"}\n' + 'end\n' + 'commit\n'; - - parser.parse(str); - const commits = parser.yy.getCommits(); - expect(parser.yy.getOptions()['key']).toBe('value'); - expect(Object.keys(commits).length).toBe(1); - expect(parser.yy.getCurrentBranch()).toBe('master'); - expect(parser.yy.getDirection()).toBe('LR'); - expect(Object.keys(parser.yy.getBranches()).length).toBe(1); - }); - - it('should not fail on a gitGraph with malformed json', function() { - const str = 'gitGraph:\n' + 'options\n' + '{"key": "value"\n' + 'end\n' + 'commit\n'; - - parser.parse(str); - const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(1); - expect(parser.yy.getCurrentBranch()).toBe('master'); - expect(parser.yy.getDirection()).toBe('LR'); - expect(Object.keys(parser.yy.getBranches()).length).toBe(1); - }); - - it('should handle set direction', function() { - const str = 'gitGraph BT:\n' + 'commit\n'; - - parser.parse(str); - const commits = parser.yy.getCommits(); - - expect(Object.keys(commits).length).toBe(1); - expect(parser.yy.getCurrentBranch()).toBe('master'); - expect(parser.yy.getDirection()).toBe('BT'); - expect(Object.keys(parser.yy.getBranches()).length).toBe(1); - }); - - it('should checkout a branch', function() { - const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n'; - - parser.parse(str); - const commits = parser.yy.getCommits(); - - expect(Object.keys(commits).length).toBe(0); - expect(parser.yy.getCurrentBranch()).toBe('new'); - }); - - it('should add commits to checked out branch', function() { - const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n' + 'commit\n' + 'commit\n'; - - parser.parse(str); - const commits = parser.yy.getCommits(); - - expect(Object.keys(commits).length).toBe(2); - expect(parser.yy.getCurrentBranch()).toBe('new'); - const branchCommit = parser.yy.getBranches()['new']; - expect(branchCommit).not.toBeNull(); - expect(commits[branchCommit].parent).not.toBeNull(); - }); - it('should handle commit with args', function() { - const str = 'gitGraph:\n' + 'commit "a commit"\n'; - - parser.parse(str); - const commits = parser.yy.getCommits(); - - expect(Object.keys(commits).length).toBe(1); - const key = Object.keys(commits)[0]; - expect(commits[key].message).toBe('a commit'); - expect(parser.yy.getCurrentBranch()).toBe('master'); - }); - - it('should reset a branch', function() { - const str = - 'gitGraph:\n' + - 'commit\n' + - 'commit\n' + - 'branch newbranch\n' + - 'checkout newbranch\n' + - 'commit\n' + - 'reset master\n'; - - parser.parse(str); - - const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(3); - expect(parser.yy.getCurrentBranch()).toBe('newbranch'); - expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']); - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); - }); - - it('reset can take an argument', function() { - const str = - 'gitGraph:\n' + - 'commit\n' + - 'commit\n' + - 'branch newbranch\n' + - 'checkout newbranch\n' + - 'commit\n' + - 'reset master^\n'; - - parser.parse(str); - - const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(3); - expect(parser.yy.getCurrentBranch()).toBe('newbranch'); - const master = commits[parser.yy.getBranches()['master']]; - expect(parser.yy.getHead().id).toEqual(master.parent); - }); - - it('should handle fast forwardable merges', function() { - const str = - 'gitGraph:\n' + - 'commit\n' + - 'branch newbranch\n' + - 'checkout newbranch\n' + - 'commit\n' + - 'commit\n' + - 'checkout master\n' + - 'merge newbranch\n'; - - parser.parse(str); - - const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(3); - expect(parser.yy.getCurrentBranch()).toBe('master'); - expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']); - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); - }); - - it('should handle cases when merge is a noop', function() { - const str = - 'gitGraph:\n' + - 'commit\n' + - 'branch newbranch\n' + - 'checkout newbranch\n' + - 'commit\n' + - 'commit\n' + - 'merge master\n'; - - parser.parse(str); - - const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(3); - expect(parser.yy.getCurrentBranch()).toBe('newbranch'); - expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']); - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); - }); - - it('should handle merge with 2 parents', function() { - const str = - 'gitGraph:\n' + - 'commit\n' + - 'branch newbranch\n' + - 'checkout newbranch\n' + - 'commit\n' + - 'commit\n' + - 'checkout master\n' + - 'commit\n' + - 'merge newbranch\n'; - - parser.parse(str); - - const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(5); - expect(parser.yy.getCurrentBranch()).toBe('master'); - expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']); - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']); - }); - - it('should handle ff merge when history walk has two parents (merge commit)', function() { - const str = - 'gitGraph:\n' + - 'commit\n' + - 'branch newbranch\n' + - 'checkout newbranch\n' + - 'commit\n' + - 'commit\n' + - 'checkout master\n' + - 'commit\n' + - 'merge newbranch\n' + - 'commit\n' + - 'checkout newbranch\n' + - 'merge master\n'; - - parser.parse(str); - - const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(6); - expect(parser.yy.getCurrentBranch()).toBe('newbranch'); - expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']); - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']); - - parser.yy.prettyPrint(); - }); - - it('should generate a secure random ID for commits', function() { - const str = 'gitGraph:\n' + 'commit\n' + 'commit\n'; - const EXPECTED_LENGTH = 7; - const EXPECTED_CHARACTERS = '0123456789abcdef'; - - let idCount = 0; - randomString.mockImplementation(options => { - if ( - options.length === EXPECTED_LENGTH && - options.characters === EXPECTED_CHARACTERS && - Object.keys(options).length === 2 - ) { - const id = `abcdef${idCount}`; - idCount += 1; - return id; - } - return 'unexpected-ID'; - }); - - parser.parse(str); - const commits = parser.yy.getCommits(); - - expect(Object.keys(commits)).toEqual(['abcdef0', 'abcdef1']); - Object.keys(commits).forEach(key => { - expect(commits[key].id).toEqual(key); - }); - }); - - it('should generate an array of known branches', function() { - const str = - 'gitGraph:\n' + - 'commit\n' + - 'branch b1\n' + - 'checkout b1\n' + - 'commit\n' + - 'commit\n' + - 'branch b2\n'; - - parser.parse(str); - const branches = gitGraphAst.getBranchesAsObjArray(); - - expect(branches).toHaveLength(3); - expect(branches[0]).toHaveProperty('name', 'master'); - expect(branches[1]).toHaveProperty('name', 'b1'); - expect(branches[2]).toHaveProperty('name', 'b2'); - }); -}); diff --git a/packages/mermaid/src/diagrams/git/parser/gitGraph.jison b/packages/mermaid/src/diagrams/git/parser/gitGraph.jison index 9ff5623f8..2297db17c 100644 --- a/packages/mermaid/src/diagrams/git/parser/gitGraph.jison +++ b/packages/mermaid/src/diagrams/git/parser/gitGraph.jison @@ -9,10 +9,6 @@ %x string %x options -%x open_directive -%x type_directive -%x arg_directive -%x close_directive %x acc_title %x acc_descr %x acc_descr_multiline @@ -20,11 +16,6 @@ %% -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; } (?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; } accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; } @@ -76,7 +67,6 @@ checkout(?=\s|$) return 'CHECKOUT'; start : eol start - | directive start | GG document EOF{ return $3; } | GG ':' document EOF{ return $3; } | GG DIR ':' document EOF {yy.setDirection($2); return $4;} @@ -240,27 +230,6 @@ commitType | HIGHLIGHT { $$=yy.commitType.HIGHLIGHT;} ; -directive - : openDirective typeDirective closeDirective - | openDirective typeDirective ':' argDirective closeDirective - ; - -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { yy.parseDirective($1, 'type_directive'); } - ; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'gitGraph'); } - ; - ref : ID | STR diff --git a/packages/mermaid/src/diagrams/pie/parser/pie.jison b/packages/mermaid/src/diagrams/pie/parser/pie.jison index e98638aa8..d1f516e75 100644 --- a/packages/mermaid/src/diagrams/pie/parser/pie.jison +++ b/packages/mermaid/src/diagrams/pie/parser/pie.jison @@ -8,19 +8,10 @@ %x string %x title -%x open_directive -%x type_directive -%x arg_directive -%x close_directive %x acc_title %x acc_descr %x acc_descr_multiline %% -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; \%\%(?!\{)[^\n]* /* skip comments */ [^\}]\%\%[^\n]* /* skip comments */{ /*console.log('');*/ } [\n\r]+ return 'NEWLINE'; @@ -52,7 +43,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili start : eol start - | directive start | PIE document | PIE showData document {yy.setShowData(true);} ; @@ -73,34 +63,12 @@ statement | acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); } | acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); } | acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); } | section {yy.addSection($1.substr(8));$$=$1.substr(8);} - | directive ; -directive - : openDirective typeDirective closeDirective - | openDirective typeDirective ':' argDirective closeDirective - ; - eol : NEWLINE | ';' | EOF ; -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { yy.parseDirective($1, 'type_directive'); } - ; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'pie'); } - ; - %% diff --git a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison index 00c125294..255b30a03 100644 --- a/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison +++ b/packages/mermaid/src/diagrams/quadrant-chart/parser/quadrant.jison @@ -5,10 +5,6 @@ %x string %x md_string %x title -%x open_directive -%x type_directive -%x arg_directive -%x close_directive %x acc_title %x acc_descr %x acc_descr_multiline @@ -16,11 +12,6 @@ %x point_x %x point_y %% -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; \%\%(?!\{)[^\n]* /* skip comments */ [^\}]\%\%[^\n]* /* skip comments */ [\n\r]+ return 'NEWLINE'; @@ -87,7 +78,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} start : eol start | SPACE start - | directive start | QUADRANT document ; @@ -110,7 +100,6 @@ statement | acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); } | acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); } | acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); } | section {yy.addSection($1.substr(8));$$=$1.substr(8);} - | directive ; points @@ -133,33 +122,12 @@ quadrantDetails | QUADRANT_4 text {yy.setQuadrant4Text($2)} ; -directive - : openDirective typeDirective closeDirective - | openDirective typeDirective ':' argDirective closeDirective - ; - eol : NEWLINE | SEMI | EOF ; -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { yy.parseDirective($1, 'type_directive'); } - ; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'quadrantChart'); } - ; - text: alphaNumToken { $$={text:$1, type: 'text'};} | text textNoTagsToken diff --git a/packages/mermaid/src/diagrams/requirement/parser/requirementDiagram.jison b/packages/mermaid/src/diagrams/requirement/parser/requirementDiagram.jison index 331310283..6d0f7b122 100644 --- a/packages/mermaid/src/diagrams/requirement/parser/requirementDiagram.jison +++ b/packages/mermaid/src/diagrams/requirement/parser/requirementDiagram.jison @@ -9,19 +9,10 @@ %x string %x token %x unqString -%x open_directive -%x type_directive -%x arg_directive -%x close_directive %x acc_title %x acc_descr %x acc_descr_multiline %% -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; "title"\s[^#\n;]+ return 'title'; accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; } @@ -99,23 +90,10 @@ start | RD NEWLINE diagram EOF; directive - : openDirective typeDirective closeDirective - | openDirective typeDirective ':' argDirective closeDirective - | acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); } + : acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); } | acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); } | acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); } ; -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); }; - -typeDirective - : type_directive { yy.parseDirective($1, 'type_directive'); }; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); }; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'pie'); }; diagram : /* empty */ { $$ = [] } diff --git a/packages/mermaid/src/diagrams/sequence/parser/sequenceDiagram.jison b/packages/mermaid/src/diagrams/sequence/parser/sequenceDiagram.jison index 04f0de20e..7e2d45419 100644 --- a/packages/mermaid/src/diagrams/sequence/parser/sequenceDiagram.jison +++ b/packages/mermaid/src/diagrams/sequence/parser/sequenceDiagram.jison @@ -16,22 +16,15 @@ // A special state for grabbing text up to the first comment/newline %x ID ALIAS LINE -// Directive states -%x open_directive type_directive arg_directive %x acc_title %x acc_descr %x acc_descr_multiline %% -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; [\n]+ return 'NEWLINE'; \s+ /* skip all whitespace */ ((?!\n)\s)+ /* skip same-line whitespace */ -\#[^\n]* /* skip comments */ +\#[^\n]* /* skip comments */ \%%(?!\{)[^\n]* /* skip comments */ [^\}]\%\%[^\n]* /* skip comments */ [0-9]+(?=[ \n]+) return 'NUM'; @@ -106,7 +99,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili start : SPACE start | NEWLINE start - | directive start | SD document { yy.apply($2);return $2; } ; @@ -133,11 +125,6 @@ box_line ; -directive - : openDirective typeDirective closeDirective 'NEWLINE' - | openDirective typeDirective ':' argDirective closeDirective 'NEWLINE' - ; - statement : participant_statement | 'create' participant_statement {$2.type='createParticipant'; $$=$2;} @@ -215,7 +202,6 @@ statement $3.unshift({type: 'breakStart', breakText:yy.parseMessage($2), signalType: yy.LINETYPE.BREAK_START}); $3.push({type: 'breakEnd', optText:yy.parseMessage($2), signalType: yy.LINETYPE.BREAK_END}); $$=$3;} - | directive ; option_sections @@ -335,20 +321,4 @@ text2 : TXT {$$ = yy.parseMessage($1.trim().substring(1)) } ; -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { yy.parseDirective($1, 'type_directive'); } - ; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'sequence'); } - ; - %% diff --git a/packages/mermaid/src/diagrams/state/parser/stateDiagram.jison b/packages/mermaid/src/diagrams/state/parser/stateDiagram.jison index dc050b2ff..44235ecd4 100644 --- a/packages/mermaid/src/diagrams/state/parser/stateDiagram.jison +++ b/packages/mermaid/src/diagrams/state/parser/stateDiagram.jison @@ -33,10 +33,6 @@ %x FLOATING_NOTE %x FLOATING_NOTE_ID %x struct -%x open_directive -%x type_directive -%x arg_directive -%x close_directive // A special state for grabbing text up to the first comment/newline %x LINE @@ -50,18 +46,13 @@ .*direction\s+RL[^\n]* return 'direction_rl'; .*direction\s+LR[^\n]* return 'direction_lr'; -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; \%\%(?!\{)[^\n]* /* skip comments */ [^\}]\%\%[^\n]* /* skip comments */{ /*console.log('Crap after close');*/ } [\n]+ return 'NL'; [\s]+ /* skip all whitespace */ -((?!\n)\s)+ /* skip same-line whitespace */ -\#[^\n]* /* skip comments */ +((?!\n)\s)+ /* skip same-line whitespace */ +\#[^\n]* /* skip comments */ \%%[^\n]* /* skip comments */ "scale"\s+ { this.pushState('SCALE'); /* console.log('Got scale', yytext);*/ return 'scale'; } \d+ return 'WIDTH'; @@ -155,7 +146,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili start : SPACE start | NL start - | directive start | SD document { /* console.log('--> Root document', $2); */ yy.setRootDoc($2); return $2; } ; @@ -241,7 +231,6 @@ statement $$={ stmt: 'state', id: $3.trim(), note:{position: $2.trim(), text: $4.trim()}}; } | note NOTE_TEXT AS ID - | directive | direction | acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); } | acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); } @@ -264,10 +253,6 @@ cssClassStatement } ; -directive - : openDirective typeDirective closeDirective - | openDirective typeDirective ':' argDirective closeDirective - ; direction : direction_tb { yy.setDirection('TB');$$={stmt:'dir', value:'TB'};} @@ -308,20 +293,4 @@ notePosition | right_of ; -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { yy.parseDirective($1, 'type_directive'); } - ; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'state'); } - ; - %% diff --git a/packages/mermaid/src/diagrams/timeline/parser/timeline.jison b/packages/mermaid/src/diagrams/timeline/parser/timeline.jison index 59b96516a..348c31fad 100644 --- a/packages/mermaid/src/diagrams/timeline/parser/timeline.jison +++ b/packages/mermaid/src/diagrams/timeline/parser/timeline.jison @@ -9,17 +9,8 @@ %x acc_descr %x acc_descr_multiline -// Directive states -%x open_directive type_directive arg_directive - - %% -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; \%%(?!\{)[^\n]* /* skip comments */ [^\}]\%\%[^\n]* /* skip comments */ [\n]+ return 'NEWLINE'; @@ -55,7 +46,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili start : timeline document 'EOF' { return $2; } - | directive start ; document @@ -70,11 +60,6 @@ line | EOF { $$=[];} ; -directive - : openDirective typeDirective closeDirective 'NEWLINE' - | openDirective typeDirective ':' argDirective closeDirective 'NEWLINE' - ; - statement : title {yy.getCommonDb().setDiagramTitle($1.substr(6));$$=$1.substr(6);} | acc_title acc_title_value { $$=$2.trim();yy.getCommonDb().setAccTitle($$); } @@ -83,7 +68,6 @@ statement | section {yy.addSection($1.substr(8));$$=$1.substr(8);} | period_statement | event_statement - | directive ; period_statement : period {yy.addTask($1,0,'');$$=$1;} @@ -92,21 +76,4 @@ event_statement : event {yy.addEvent($1.substr(2));$$=$1;} ; - -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { yy.parseDirective($1, 'type_directive'); } - ; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'timeline'); } - ; - %% diff --git a/packages/mermaid/src/diagrams/user-journey/parser/journey.jison b/packages/mermaid/src/diagrams/user-journey/parser/journey.jison index 4c28d53dc..5567f1417 100644 --- a/packages/mermaid/src/diagrams/user-journey/parser/journey.jison +++ b/packages/mermaid/src/diagrams/user-journey/parser/journey.jison @@ -9,17 +9,8 @@ %x acc_descr %x acc_descr_multiline -// Directive states -%x open_directive type_directive arg_directive - - %% -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; \%%(?!\{)[^\n]* /* skip comments */ [^\}]\%\%[^\n]* /* skip comments */ [\n]+ return 'NEWLINE'; @@ -52,7 +43,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili start : journey document 'EOF' { return $2; } - | directive start ; document @@ -67,11 +57,6 @@ line | EOF { $$=[];} ; -directive - : openDirective typeDirective closeDirective 'NEWLINE' - | openDirective typeDirective ':' argDirective closeDirective 'NEWLINE' - ; - statement : title {yy.setDiagramTitle($1.substr(6));$$=$1.substr(6);} | acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); } @@ -79,23 +64,6 @@ statement | acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); } | section {yy.addSection($1.substr(8));$$=$1.substr(8);} | taskName taskData {yy.addTask($1, $2);$$='task';} - | directive - ; - -openDirective - : open_directive { yy.parseDirective('%%{', 'open_directive'); } - ; - -typeDirective - : type_directive { yy.parseDirective($1, 'type_directive'); } - ; - -argDirective - : arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); } - ; - -closeDirective - : close_directive { yy.parseDirective('}%%', 'close_directive', 'journey'); } ; %% From 066e0967de7e296febc93d17774c8c102d7ac84b Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Sat, 26 Aug 2023 23:27:25 +0530 Subject: [PATCH 05/13] refactor: Move setWrap to individual diagrams as necessary. --- packages/mermaid/src/Diagram.ts | 5 +---- packages/mermaid/src/diagram-api/types.ts | 2 +- packages/mermaid/src/diagrams/c4/c4Diagram.ts | 21 ++++++++++--------- .../src/diagrams/sequence/sequenceDiagram.ts | 3 +++ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/mermaid/src/Diagram.ts b/packages/mermaid/src/Diagram.ts index 9d665c71c..3dc973804 100644 --- a/packages/mermaid/src/Diagram.ts +++ b/packages/mermaid/src/Diagram.ts @@ -47,13 +47,10 @@ export class Diagram { this.db.clear?.(); const config = configApi.getConfig(); this.init?.(config); - // These 2 blocks were added for legacy compatibility. Do not add more such blocks. Use frontmatter instead. + // This block was added for legacy compatibility. Use frontmatter instead of adding more special cases. if (this.metadata.title) { this.db.setDiagramTitle?.(this.metadata.title); } - if (config.wrap) { - this.db.setWrap?.(config.wrap); - } this.parser.parse(this.text); } diff --git a/packages/mermaid/src/diagram-api/types.ts b/packages/mermaid/src/diagram-api/types.ts index e9def2421..4e73d109f 100644 --- a/packages/mermaid/src/diagram-api/types.ts +++ b/packages/mermaid/src/diagram-api/types.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import type { Diagram } from '../Diagram.js'; import type { BaseDiagramConfig, MermaidConfig } from '../config.type.js'; import type * as d3 from 'd3'; @@ -29,7 +30,6 @@ export interface DiagramDB { getAccDescription?: () => string; setDisplayMode?: (title: string) => void; - setWrap?: (wrap: boolean) => void; bindFunctions?: (element: Element) => void; } diff --git a/packages/mermaid/src/diagrams/c4/c4Diagram.ts b/packages/mermaid/src/diagrams/c4/c4Diagram.ts index 4c578b624..9557a0f70 100644 --- a/packages/mermaid/src/diagrams/c4/c4Diagram.ts +++ b/packages/mermaid/src/diagrams/c4/c4Diagram.ts @@ -1,17 +1,18 @@ // @ts-ignore: JISON doesn't support types -import c4Parser from './parser/c4Diagram.jison'; -import c4Db from './c4Db.js'; -import c4Renderer from './c4Renderer.js'; -import c4Styles from './styles.js'; +import parser from './parser/c4Diagram.jison'; +import db from './c4Db.js'; +import renderer from './c4Renderer.js'; +import styles from './styles.js'; import type { MermaidConfig } from '../../config.type.js'; import type { DiagramDefinition } from '../../diagram-api/types.js'; export const diagram: DiagramDefinition = { - parser: c4Parser, - db: c4Db, - renderer: c4Renderer, - styles: c4Styles, - init: (cnf: MermaidConfig) => { - c4Renderer.setConf(cnf.c4); + parser, + db, + renderer, + styles, + init: ({ c4, wrap }: MermaidConfig) => { + renderer.setConf(c4); + db.setWrap(wrap); }, }; diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDiagram.ts b/packages/mermaid/src/diagrams/sequence/sequenceDiagram.ts index 8779b9cc4..f8d71c95e 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDiagram.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDiagram.ts @@ -10,4 +10,7 @@ export const diagram: DiagramDefinition = { db, renderer, styles, + init: ({ wrap }) => { + db.setWrap(wrap); + }, }; From b6d5497f51efdf14d22f7bd8fd7a6b2e10efc617 Mon Sep 17 00:00:00 2001 From: Justin Greywolf Date: Sun, 27 Aug 2023 15:23:59 -0700 Subject: [PATCH 06/13] Update README.md Quick fix to remove namespace from readme class definition since github has not been update to the version that uses namespaces --- README.md | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 98741a689..f844e2cb9 100644 --- a/README.md +++ b/README.md @@ -165,13 +165,7 @@ class Class10 { int id size() } -namespace Namespace01 { - class Class11 - class Class12 { - int id - size() - } -} + ``` ```mermaid @@ -191,13 +185,7 @@ class Class10 { int id size() } -namespace Namespace01 { - class Class11 - class Class12 { - int id - size() - } -} + ``` ### State diagram [docs - live editor] From a0e33bee71000b411584e91483f61121920e4cd6 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 5 Sep 2023 21:57:05 +0530 Subject: [PATCH 07/13] chore: Cleanup gitGraph tests --- .../src/diagrams/git/gitGraphParser.spec.js | 246 ++++++++++++++++++ .../src/diagrams/git/gitGraphParserV2.spec.js | 11 - 2 files changed, 246 insertions(+), 11 deletions(-) create mode 100644 packages/mermaid/src/diagrams/git/gitGraphParser.spec.js diff --git a/packages/mermaid/src/diagrams/git/gitGraphParser.spec.js b/packages/mermaid/src/diagrams/git/gitGraphParser.spec.js new file mode 100644 index 000000000..446f06739 --- /dev/null +++ b/packages/mermaid/src/diagrams/git/gitGraphParser.spec.js @@ -0,0 +1,246 @@ +import gitGraphAst from './gitGraphAst.js'; +import { parser } from './parser/gitGraph.jison'; + +describe('when parsing a gitGraph', function () { + beforeEach(function () { + parser.yy = gitGraphAst; + parser.yy.clear(); + }); + it('should handle a gitGraph definition', function () { + const str = 'gitGraph:\n' + 'commit\n'; + + parser.parse(str); + const commits = parser.yy.getCommits(); + + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('main'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); + + it('should handle a gitGraph definition with empty options', function () { + const str = 'gitGraph:\n' + 'options\n' + ' end\n' + 'commit\n'; + + parser.parse(str); + const commits = parser.yy.getCommits(); + + expect(parser.yy.getOptions()).toEqual({}); + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('main'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); + + it('should handle a gitGraph definition with valid options', function () { + const str = 'gitGraph:\n' + 'options\n' + '{"key": "value"}\n' + 'end\n' + 'commit\n'; + + parser.parse(str); + const commits = parser.yy.getCommits(); + expect(parser.yy.getOptions()['key']).toBe('value'); + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('main'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); + + it('should not fail on a gitGraph with malformed json', function () { + const str = 'gitGraph:\n' + 'options\n' + '{"key": "value"\n' + 'end\n' + 'commit\n'; + + parser.parse(str); + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('main'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); + + it('should handle set direction', function () { + const str = 'gitGraph TB:\n' + 'commit\n'; + + parser.parse(str); + const commits = parser.yy.getCommits(); + + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('main'); + expect(parser.yy.getDirection()).toBe('TB'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); + + it('should checkout a branch', function () { + const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n'; + + parser.parse(str); + const commits = parser.yy.getCommits(); + + expect(Object.keys(commits).length).toBe(0); + expect(parser.yy.getCurrentBranch()).toBe('new'); + }); + + it('should add commits to checked out branch', function () { + const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n' + 'commit\n' + 'commit\n'; + + parser.parse(str); + const commits = parser.yy.getCommits(); + + expect(Object.keys(commits).length).toBe(2); + expect(parser.yy.getCurrentBranch()).toBe('new'); + const branchCommit = parser.yy.getBranches()['new']; + expect(branchCommit).not.toBeNull(); + expect(commits[branchCommit].parent).not.toBeNull(); + }); + it('should handle commit with args', function () { + const str = 'gitGraph:\n' + 'commit "a commit"\n'; + + parser.parse(str); + const commits = parser.yy.getCommits(); + + expect(Object.keys(commits).length).toBe(1); + const key = Object.keys(commits)[0]; + expect(commits[key].message).toBe('a commit'); + expect(parser.yy.getCurrentBranch()).toBe('main'); + }); + + // Reset has been commented out in JISON + it.skip('should reset a branch', function () { + const str = + 'gitGraph:\n' + + 'commit\n' + + 'commit\n' + + 'branch newbranch\n' + + 'checkout newbranch\n' + + 'commit\n' + + 'reset main\n'; + + parser.parse(str); + + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(3); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['main']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); + }); + + it.skip('reset can take an argument', function () { + const str = + 'gitGraph:\n' + + 'commit\n' + + 'commit\n' + + 'branch newbranch\n' + + 'checkout newbranch\n' + + 'commit\n' + + 'reset main^\n'; + + parser.parse(str); + + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(3); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + const main = commits[parser.yy.getBranches()['main']]; + expect(parser.yy.getHead().id).toEqual(main.parent); + }); + + it.skip('should handle fast forwardable merges', function () { + const str = + 'gitGraph:\n' + + 'commit\n' + + 'branch newbranch\n' + + 'checkout newbranch\n' + + 'commit\n' + + 'commit\n' + + 'checkout main\n' + + 'merge newbranch\n'; + + parser.parse(str); + + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(4); + expect(parser.yy.getCurrentBranch()).toBe('main'); + expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['main']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); + }); + + it('should handle cases when merge is a noop', function () { + const str = + 'gitGraph:\n' + + 'commit\n' + + 'branch newbranch\n' + + 'checkout newbranch\n' + + 'commit\n' + + 'commit\n' + + 'merge main\n'; + + parser.parse(str); + + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(4); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['main']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); + }); + + it('should handle merge with 2 parents', function () { + const str = + 'gitGraph:\n' + + 'commit\n' + + 'branch newbranch\n' + + 'checkout newbranch\n' + + 'commit\n' + + 'commit\n' + + 'checkout main\n' + + 'commit\n' + + 'merge newbranch\n'; + + parser.parse(str); + + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(5); + expect(parser.yy.getCurrentBranch()).toBe('main'); + expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['main']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['main']); + }); + + it.skip('should handle ff merge when history walk has two parents (merge commit)', function () { + const str = + 'gitGraph:\n' + + 'commit\n' + + 'branch newbranch\n' + + 'checkout newbranch\n' + + 'commit\n' + + 'commit\n' + + 'checkout main\n' + + 'commit\n' + + 'merge newbranch\n' + + 'commit\n' + + 'checkout newbranch\n' + + 'merge main\n'; + + parser.parse(str); + + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(7); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['main']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['main']); + + parser.yy.prettyPrint(); + }); + + it('should generate an array of known branches', function () { + const str = + 'gitGraph:\n' + + 'commit\n' + + 'branch b1\n' + + 'checkout b1\n' + + 'commit\n' + + 'commit\n' + + 'branch b2\n'; + + parser.parse(str); + const branches = gitGraphAst.getBranchesAsObjArray(); + + expect(branches).toHaveLength(3); + expect(branches[0]).toHaveProperty('name', 'main'); + expect(branches[1]).toHaveProperty('name', 'b1'); + expect(branches[2]).toHaveProperty('name', 'b2'); + }); +}); diff --git a/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js b/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js index 764fbb214..df20a5eb5 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js +++ b/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js @@ -1,22 +1,11 @@ -/* eslint-env jasmine */ -// Todo reintroduce without cryptoRandomString import gitGraphAst from './gitGraphAst.js'; import { parser } from './parser/gitGraph.jison'; -//import randomString from 'crypto-random-string'; -//import cryptoRandomString from 'crypto-random-string'; - -//jest.mock('crypto-random-string'); describe('when parsing a gitGraph', function () { - let randomNumber; beforeEach(function () { parser.yy = gitGraphAst; parser.yy.clear(); - randomNumber = 0; }); - // afterEach(function() { - // cryptoRandomString.mockReset(); - // }); it('should handle a gitGraph commit with NO pararms, get auto-genrated reandom ID', function () { const str = `gitGraph: commit From 18079a44bedb09eda7831aaacc5c3b263c97c227 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 6 Sep 2023 22:06:05 +0530 Subject: [PATCH 08/13] chore: Add deprecation notices, improve types Co-authored-by: Alois Klink --- docs/config/setup/modules/mermaidAPI.md | 2 +- packages/mermaid/src/Diagram.ts | 7 ++++--- packages/mermaid/src/diagram-api/diagramAPI.ts | 3 ++- packages/mermaid/src/diagram-api/types.ts | 7 +++++++ packages/mermaid/src/mermaidAPI.ts | 2 +- packages/mermaid/src/preprocess.ts | 11 +++++++++-- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/docs/config/setup/modules/mermaidAPI.md b/docs/config/setup/modules/mermaidAPI.md index 3c2b5bb84..1ea19fac4 100644 --- a/docs/config/setup/modules/mermaidAPI.md +++ b/docs/config/setup/modules/mermaidAPI.md @@ -31,7 +31,7 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi) ### mermaidAPI -• `Const` **mermaidAPI**: `Readonly`<{ `defaultConfig`: `MermaidConfig` = configApi.defaultConfig; `getConfig`: () => `MermaidConfig` = configApi.getConfig; `getDiagramFromText`: (`text`: `string`, `metadata`: { `title?`: `string` }) => `Promise`<`Diagram`> ; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `void` ; `parse`: (`text`: `string`, `parseOptions?`: [`ParseOptions`](../interfaces/mermaidAPI.ParseOptions.md)) => `Promise`<`boolean`> ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](../interfaces/mermaidAPI.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.setConfig; `updateSiteConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.updateSiteConfig }> +• `Const` **mermaidAPI**: `Readonly`<{ `defaultConfig`: `MermaidConfig` = configApi.defaultConfig; `getConfig`: () => `MermaidConfig` = configApi.getConfig; `getDiagramFromText`: (`text`: `string`, `metadata`: `Pick`<`DiagramMetadata`, `"title"`>) => `Promise`<`Diagram`> ; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `void` ; `parse`: (`text`: `string`, `parseOptions?`: [`ParseOptions`](../interfaces/mermaidAPI.ParseOptions.md)) => `Promise`<`boolean`> ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](../interfaces/mermaidAPI.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.setConfig; `updateSiteConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.updateSiteConfig }> ## mermaidAPI configuration defaults diff --git a/packages/mermaid/src/Diagram.ts b/packages/mermaid/src/Diagram.ts index 3dc973804..b77091f28 100644 --- a/packages/mermaid/src/Diagram.ts +++ b/packages/mermaid/src/Diagram.ts @@ -4,7 +4,7 @@ import { getDiagram, registerDiagram } from './diagram-api/diagramAPI.js'; import { detectType, getDiagramLoader } from './diagram-api/detectType.js'; import { UnknownDiagramError } from './errors.js'; import type { DetailedError } from './utils.js'; -import type { DiagramDefinition } from './diagram-api/types.js'; +import type { DiagramDefinition, DiagramMetadata } from './diagram-api/types.js'; export type ParseErrorFunction = (err: string | DetailedError | unknown, hash?: any) => void; @@ -20,7 +20,7 @@ export class Diagram { private init?: DiagramDefinition['init']; private detectError?: UnknownDiagramError; - constructor(public text: string, public metadata: { title?: string } = {}) { + constructor(public text: string, public metadata: Pick = {}) { this.text += '\n'; const cnf = configApi.getConfig(); try { @@ -72,13 +72,14 @@ export class Diagram { * **Warning:** This function may be changed in the future. * @alpha * @param text - The mermaid diagram definition. + * @param metadata - Diagram metadata, defined in YAML. * @returns A the Promise of a Diagram object. * @throws {@link UnknownDiagramError} if the diagram type can not be found. * @privateRemarks This is exported as part of the public mermaidAPI. */ export const getDiagramFromText = async ( text: string, - metadata: { title?: string } = {} + metadata: Pick = {} ): Promise => { const type = detectType(text, configApi.getConfig()); try { diff --git a/packages/mermaid/src/diagram-api/diagramAPI.ts b/packages/mermaid/src/diagram-api/diagramAPI.ts index 9a4af2585..ea3c10159 100644 --- a/packages/mermaid/src/diagram-api/diagramAPI.ts +++ b/packages/mermaid/src/diagram-api/diagramAPI.ts @@ -57,7 +57,8 @@ export const registerDiagram = ( setupGraphViewbox, getCommonDb(), () => { - // parseDirective is removed. This is a no-op for legacy support. + // parseDirective is removed in https://github.com/mermaid-js/mermaid/pull/4759. + // This is a no-op for legacy support. } ); }; diff --git a/packages/mermaid/src/diagram-api/types.ts b/packages/mermaid/src/diagram-api/types.ts index 4e73d109f..15aa4b033 100644 --- a/packages/mermaid/src/diagram-api/types.ts +++ b/packages/mermaid/src/diagram-api/types.ts @@ -3,6 +3,11 @@ import type { Diagram } from '../Diagram.js'; import type { BaseDiagramConfig, MermaidConfig } from '../config.type.js'; import type * as d3 from 'd3'; +export interface DiagramMetadata { + title?: string; + config?: MermaidConfig; +} + export interface InjectUtils { _log: any; _setLogLevel: any; @@ -10,6 +15,7 @@ export interface InjectUtils { _sanitizeText: any; _setupGraphViewbox: any; _commonDb: any; + /** @deprecated as directives will be pre-processed since https://github.com/mermaid-js/mermaid/pull/4759 */ _parseDirective: any; } @@ -46,6 +52,7 @@ export interface DiagramDefinition { _sanitizeText: InjectUtils['_sanitizeText'], _setupGraphViewbox: InjectUtils['_setupGraphViewbox'], _commonDb: InjectUtils['_commonDb'], + /** @deprecated as directives will be pre-processed since https://github.com/mermaid-js/mermaid/pull/4759 */ _parseDirective: InjectUtils['_parseDirective'] ) => void; } diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index f71fe27a7..3649b50f5 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -99,7 +99,7 @@ export interface RenderResult { function processAndSetConfigs(text: string) { const processed = preprocessDiagram(text); configApi.reset(); - configApi.addDirective(processed.config); + configApi.addDirective(processed.config ?? {}); return processed; } diff --git a/packages/mermaid/src/preprocess.ts b/packages/mermaid/src/preprocess.ts index 3c33ce30f..6e386e744 100644 --- a/packages/mermaid/src/preprocess.ts +++ b/packages/mermaid/src/preprocess.ts @@ -1,5 +1,6 @@ import { cleanupComments } from './diagram-api/comments.js'; import { extractFrontMatter } from './diagram-api/frontmatter.js'; +import type { DiagramMetadata } from './diagram-api/types.js'; import utils, { cleanAndMerge, removeDirectives } from './utils.js'; const cleanupText = (code: string) => { @@ -44,7 +45,13 @@ const processDirectives = (code: string) => { }; }; -export const preprocessDiagram = (code: string) => { +/** + * Preprocess the given code by cleaning it up, extracting front matter and directives, + * cleaning and merging configuration, and removing comments. + * @param code - The code to preprocess. + * @returns The object containing the preprocessed code, title, and configuration. + */ +export function preprocessDiagram(code: string): DiagramMetadata & { code: string } { const cleanedCode = cleanupText(code); const frontMatterResult = processFrontmatter(cleanedCode); const directiveResult = processDirectives(frontMatterResult.text); @@ -55,4 +62,4 @@ export const preprocessDiagram = (code: string) => { title: frontMatterResult.title, config, }; -}; +} From fd39ea80494e46db86852e996afe220d5fb898cc Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 6 Sep 2023 17:07:08 +0000 Subject: [PATCH 09/13] Update cypress/helpers/util.js --- cypress/helpers/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/helpers/util.js b/cypress/helpers/util.js index bab8d6957..a05e48922 100644 --- a/cypress/helpers/util.js +++ b/cypress/helpers/util.js @@ -25,7 +25,7 @@ export const imgSnapshotTest = (graphStr, _options = {}, api = false, validation fontFamily: _options.fontFamily || 'courier', fontSize: _options.fontSize || '16px', sequence: { - ...(options.sequence || {}), + ...(_options.sequence || {}), actorFontFamily: 'courier', noteFontFamily: _options.sequence?.noteFontFamily || 'courier', messageFontFamily: 'courier', From 8662b33de96e372f38bceb29b541f98823066d3c Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 6 Sep 2023 22:50:32 +0530 Subject: [PATCH 10/13] core: Adapt changes from 3f7bafb2d7 Co-authored-by: RohanHandore <110839432+RohanHandore@users.noreply.github.com> --- cypress/helpers/util.ts | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/cypress/helpers/util.ts b/cypress/helpers/util.ts index 4160f4cbd..a9028cd16 100644 --- a/cypress/helpers/util.ts +++ b/cypress/helpers/util.ts @@ -52,29 +52,18 @@ export const imgSnapshotTest = ( api = false, validation?: any ): void => { - cy.log(JSON.stringify(_options)); - const options: CypressMermaidConfig = Object.assign(_options); - if (!options.fontFamily) { - options.fontFamily = 'courier'; - } - if (!options.sequence) { - options.sequence = {}; - } - if (!options.sequence || (options.sequence && !options.sequence.actorFontFamily)) { - options.sequence.actorFontFamily = 'courier'; - } - if (options.sequence && !options.sequence.noteFontFamily) { - options.sequence.noteFontFamily = 'courier'; - } - options.sequence.actorFontFamily = 'courier'; - options.sequence.noteFontFamily = 'courier'; - options.sequence.messageFontFamily = 'courier'; - if (options.sequence && !options.sequence.actorFontFamily) { - options.sequence.actorFontFamily = 'courier'; - } - if (!options.fontSize) { - options.fontSize = 16; - } + const options: CypressMermaidConfig = { + ..._options, + fontFamily: _options.fontFamily ?? 'courier', + // @ts-ignore TODO: Fix type of fontSize + fontSize: _options.fontSize ?? '16px', + sequence: { + ...(_options.sequence ?? {}), + actorFontFamily: 'courier', + noteFontFamily: _options.sequence?.noteFontFamily ?? 'courier', + messageFontFamily: 'courier', + }, + }; const url: string = mermaidUrl(graphStr, options, api); openURLAndVerifyRendering(url, options, validation); @@ -82,11 +71,10 @@ export const imgSnapshotTest = ( export const urlSnapshotTest = ( url: string, - _options: CypressMermaidConfig, + options: CypressMermaidConfig, _api = false, validation?: any ): void => { - const options: CypressMermaidConfig = Object.assign(_options); openURLAndVerifyRendering(url, options, validation); }; From 7d2b39f69f1ecb8f6b59bb6d728927e67630b906 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 6 Sep 2023 23:21:51 +0530 Subject: [PATCH 11/13] refactor: Use `||` instead of `??` --- cypress/helpers/util.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cypress/helpers/util.ts b/cypress/helpers/util.ts index a9028cd16..60f3ad7a9 100644 --- a/cypress/helpers/util.ts +++ b/cypress/helpers/util.ts @@ -54,13 +54,13 @@ export const imgSnapshotTest = ( ): void => { const options: CypressMermaidConfig = { ..._options, - fontFamily: _options.fontFamily ?? 'courier', + fontFamily: _options.fontFamily || 'courier', // @ts-ignore TODO: Fix type of fontSize - fontSize: _options.fontSize ?? '16px', + fontSize: _options.fontSize || '16px', sequence: { - ...(_options.sequence ?? {}), + ...(_options.sequence || {}), actorFontFamily: 'courier', - noteFontFamily: _options.sequence?.noteFontFamily ?? 'courier', + noteFontFamily: _options.sequence?.noteFontFamily || 'courier', messageFontFamily: 'courier', }, }; From 56aa503ded16f27cb4e8a1ab99d6289af0c40317 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Thu, 7 Sep 2023 08:31:05 +0530 Subject: [PATCH 12/13] Remove optional chaining --- cypress/helpers/util.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cypress/helpers/util.ts b/cypress/helpers/util.ts index 60f3ad7a9..c656f638d 100644 --- a/cypress/helpers/util.ts +++ b/cypress/helpers/util.ts @@ -60,7 +60,10 @@ export const imgSnapshotTest = ( sequence: { ...(_options.sequence || {}), actorFontFamily: 'courier', - noteFontFamily: _options.sequence?.noteFontFamily || 'courier', + noteFontFamily: + _options.sequence && _options.sequence.noteFontFamily + ? _options.sequence.noteFontFamily + : 'courier', messageFontFamily: 'courier', }, }; From 667b17bf66ad13fe822a92f43d62265ba4f9fccb Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Thu, 7 Sep 2023 10:15:58 +0530 Subject: [PATCH 13/13] Remove unnecessary tests --- .../diagrams/sequence/sequenceDiagram.spec.js | 83 +------------------ 1 file changed, 1 insertion(+), 82 deletions(-) diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js b/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js index c46c19541..77ac7c45c 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js +++ b/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js @@ -1,5 +1,4 @@ import { vi } from 'vitest'; - import * as configApi from '../../config.js'; import mermaidAPI from '../../mermaidAPI.js'; import { Diagram, getDiagramFromText } from '../../Diagram.js'; @@ -225,6 +224,7 @@ Bob-->Alice: I am good thanks!`; diagram.renderer.draw(str, 'tst', '1.2.3', diagram); // needs to be rendered for the correct value of visibility auto numbers expect(diagram.db.showSequenceNumbers()).toBe(true); }); + it('should handle a sequenceDiagram definition with a title:', async () => { const str = ` sequenceDiagram @@ -2034,84 +2034,3 @@ participant Alice`; }); }); }); - -describe('when rendering a sequenceDiagram with directives', () => { - beforeAll(function () { - let conf = { - diagramMarginX: 50, - diagramMarginY: 10, - actorMargin: 50, - width: 150, - height: 65, - boxMargin: 10, - messageMargin: 40, - boxTextMargin: 15, - noteMargin: 25, - }; - mermaidAPI.initialize({ sequence: conf }); - }); - - beforeEach(function () { - mermaidAPI.reset(); - diagram.renderer.bounds.init(); - }); - - it('should handle one actor, when theme is dark and logLevel is 1 DX1 (dfg1)', async () => { - const str = ` -sequenceDiagram -participant Alice -`; - diagram = new Diagram(str); - diagram.renderer.bounds.init(); - diagram.renderer.draw(str, 'tst', '1.2.3', diagram); - - const { bounds, models } = diagram.renderer.bounds.getBounds(); - const mermaid = mermaidAPI.getConfig(); - expect(bounds.startx).toBe(0); - expect(bounds.startx).toBe(0); - expect(bounds.starty).toBe(0); - expect(bounds.stopy).toBe( - models.lastActor().stopy + models.lastActor().height + mermaid.sequence.boxMargin - ); - }); - it('should handle one actor, when logLevel is 3 (dfg0)', async () => { - const str = ` -sequenceDiagram -participant Alice -`; - - diagram = new Diagram(str); - diagram.renderer.draw(str, 'tst', '1.2.3', diagram); - - const { bounds, models } = diagram.renderer.bounds.getBounds(); - const mermaid = mermaidAPI.getConfig(); - expect(bounds.startx).toBe(0); - expect(bounds.startx).toBe(0); - expect(bounds.starty).toBe(0); - expect(bounds.stopy).toBe( - models.lastActor().stopy + models.lastActor().height + mermaid.sequence.boxMargin - ); - }); - it('should hide sequence numbers when autonumber is removed when autonumber is enabled', async () => { - const str1 = ` -sequenceDiagram -autonumber -Alice->Bob:Hello Bob, how are you? -Note right of Bob: Bob thinks -Bob-->Alice: I am good thanks!`; - - diagram = new Diagram(str1); - diagram.renderer.draw(str1, 'tst', '1.2.3', diagram); // needs to be rendered for the correct value of visibility auto numbers - expect(diagram.db.showSequenceNumbers()).toBe(true); - - const str2 = ` -sequenceDiagram -Alice->Bob:Hello Bob, how are you? -Note right of Bob: Bob thinks -Bob-->Alice: I am good thanks!`; - - diagram = new Diagram(str2); - diagram.renderer.draw(str2, 'tst', '1.2.3', diagram); - expect(diagram.db.showSequenceNumbers()).toBe(false); - }); -});