diff --git a/cypress/integration/rendering/theme.spec.js b/cypress/integration/rendering/theme.spec.js index f42dd0c2f..30a7efb7f 100644 --- a/cypress/integration/rendering/theme.spec.js +++ b/cypress/integration/rendering/theme.spec.js @@ -1,5 +1,30 @@ import { imgSnapshotTest } from '../../helpers/util.js'; +describe('themeCSS balancing, it', () => { + it('should not allow unbalanced CSS definitions', () => { + imgSnapshotTest( + ` + %%{init: { 'themeCSS': '} * { background: red }' } }%% + flowchart TD + a --> b + `, + {} + ); + cy.get('svg'); + }); + it('should not allow unbalanced CSS definitions 2', () => { + imgSnapshotTest( + ` + %%{init: { 'themeCSS': '\u007D * { background: red }' } }%% + flowchart TD + a2 --> b2 + `, + {} + ); + cy.get('svg'); + }); +}); + describe('Pie Chart', () => { // beforeEach(()=>{ // cy.clock((new Date('2014-06-09')).getTime()); diff --git a/cypress/platform/css1.html b/cypress/platform/css1.html new file mode 100644 index 000000000..f02892123 --- /dev/null +++ b/cypress/platform/css1.html @@ -0,0 +1,39 @@ + + + + + + Mermaid Quick Test Page + + + + +
+ %%{init: { 'themeCSS': '} * { background: lightblue }' } }%% + flowchart TD + a --> b +
+
+ %%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%% + flowchart LR + subgraph A + a --> b + end + subgraph B + i -->f + end + A --> B +
+ + + + diff --git a/src/defaultConfig.js b/src/defaultConfig.js index 92d8b5771..305ba0867 100644 --- a/src/defaultConfig.js +++ b/src/defaultConfig.js @@ -37,6 +37,7 @@ const config = { themeCSS: undefined, /* **maxTextSize** - The maximum allowed size of the users text diamgram */ maxTextSize: 50000, + darkMode: false, /** * | Parameter | Description | Type | Required | Values | diff --git a/src/mermaidAPI.js b/src/mermaidAPI.js index 0e73b3032..e51f22468 100755 --- a/src/mermaidAPI.js +++ b/src/mermaidAPI.js @@ -60,7 +60,7 @@ import { attachFunctions } from './interactionDb'; import { log, setLogLevel } from './logger'; import getStyles from './styles'; import theme from './themes'; -import utils, { directiveSanitizer, assignWithDepth } from './utils'; +import utils, { directiveSanitizer, assignWithDepth, sanitizeCss } from './utils'; /** * @param text @@ -223,6 +223,7 @@ const render = function (id, _txt, cb, container) { let txt = _txt; const graphInit = utils.detectInit(txt); if (graphInit) { + directiveSanitizer(graphInit); configApi.addDirective(graphInit); } let cnf = configApi.getConfig(); @@ -533,6 +534,9 @@ const handleDirective = function (p, directive, type) { p.setWrap(directive.type === 'wrap'); } break; + case 'themeCss': + log.warn('themeCss encountered'); + break; default: log.warn( `Unhandled directive: source: '%%{${directive.type}: ${JSON.stringify( diff --git a/src/utils.js b/src/utils.js index 90a087f9f..012fb98d3 100644 --- a/src/utils.js +++ b/src/utils.js @@ -974,6 +974,11 @@ export const directiveSanitizer = (args) => { log.debug('sanitize deleting constr option', key); delete args[key]; } + + if (key.indexOf('themeCSS') >= 0) { + log.debug('sanitizing themeCss option'); + args[key] = sanitizeCss(args[key]); + } if (configKeys.indexOf(key) < 0) { log.debug('sanitize deleting option', key); delete args[key]; @@ -987,6 +992,16 @@ export const directiveSanitizer = (args) => { } } }; +export const sanitizeCss = (str) => { + const stringsearch = 'o'; + const startCnt = (str.match(/\{/g) || []).length; + const endCnt = (str.match(/\}/g) || []).length; + if (startCnt !== endCnt) { + return '{ /* ERROR: Unbalanced CSS */ }'; + } + // Todo add more checks here + return str; +}; export default { assignWithDepth, @@ -1013,4 +1028,5 @@ export default { entityDecode, initIdGeneratior, directiveSanitizer, + sanitizeCss, };