Merge branch 'develop' into sidv/esbuild

* develop: (50 commits)
  Typo fix
  Fix repo URL
  Revert flowchart change
  Revert flowchart change
  Fix TODO Qs
  chore(deps-dev): bump @commitlint/cli from 17.1.1 to 17.1.2
  chore(deps-dev): bump terser-webpack-plugin from 5.3.5 to 5.3.6
  chore(deps-dev): bump webpack-dev-server from 4.10.0 to 4.10.1
  Fix gitGraph findLane function error
  Update dependabot.yml
  Replacing replaceAll with replace
  Rework 'parseDuration' as a pure duration parsing
  Supports duration in decimal
  Create a more consistent 'parseDuration'
  Remove `@ts-ignore`s.
  Fix svgDraw return types
  ...
This commit is contained in:
Sidharth Vinod 2022-09-01 20:38:21 +05:30
commit 7aeb60f42a
No known key found for this signature in database
GPG Key ID: FB5CCD378D3907CD
56 changed files with 2474 additions and 1555 deletions

View File

@ -4,6 +4,7 @@ updates:
open-pull-requests-limit: 10
directory: /
target-branch: develop
versioning-strategy: increase
schedule:
interval: weekly
day: monday

1
.prettierignore Normal file
View File

@ -0,0 +1 @@
demos/*.html

View File

@ -7,10 +7,10 @@ export default {
amd: false, // https://github.com/lodash/lodash/issues/3052
target: 'web',
entry: {
mermaid: './src/mermaid.js',
mermaid: './src/mermaid',
},
resolve: {
extensions: ['.wasm', '.mjs', '.js', '.json', '.jison'],
extensions: ['.wasm', '.mjs', '.js', '.ts', '.json', '.jison'],
fallback: {
fs: false, // jison generated code requires 'fs'
path: require.resolve('path-browserify'),
@ -28,6 +28,11 @@ export default {
},
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.js$/,
include: [resolveRoot('./src'), resolveRoot('./node_modules/dagre-d3-renderer/lib')],

View File

@ -4,7 +4,7 @@ import { merge } from 'webpack-merge';
export default merge(baseConfig, {
mode: 'development',
entry: {
mermaid: './src/mermaid.js',
mermaid: './src/mermaid',
e2e: './cypress/platform/viewer.js',
'bundle-test': './cypress/platform/bundle-test.js',
},

File diff suppressed because it is too large Load Diff

View File

@ -175,7 +175,7 @@ describe('Gantt diagram', () => {
Another task :after a1, 20ms
section Another
Another another task :b1, 20, 12ms
Another another another task :after b1, 24ms
Another another another task :after b1, 0.024s
`,
{}
);

View File

@ -253,4 +253,32 @@ describe('Git Graph diagram', () => {
{}
);
});
it('13: should render a simple gitgraph with three branches,custom merge commit id,tag,type', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
branch nice_feature
checkout nice_feature
commit id: "3"
checkout main
commit id: "4"
checkout nice_feature
branch very_nice_feature
checkout very_nice_feature
commit id: "5"
checkout main
commit id: "6"
checkout nice_feature
commit id: "7"
checkout main
merge nice_feature id: "customID" tag: "customTag" type: REVERSE
checkout very_nice_feature
commit id: "8"
checkout main
commit id: "9"
`,
{}
);
});
});

View File

@ -58,12 +58,13 @@ Theme , the CSS style sheet
## logLevel
| Parameter | Description | Type | Required | Values |
| --------- | ----------------------------------------------------- | ---------------- | -------- | ------------- |
| logLevel | This option decides the amount of logging to be used. | string \| number | Required | 1, 2, 3, 4, 5 |
| Parameter | Description | Type | Required | Values |
| --------- | ----------------------------------------------------- | ---------------- | -------- | --------------------------------------------- |
| logLevel | This option decides the amount of logging to be used. | string \| number | Required | 'trace','debug','info','warn','error','fatal' |
**Notes:**
- Trace: 0
- Debug: 1
- Info: 2
- Warn: 3
@ -1404,15 +1405,6 @@ This sets the auto-wrap padding for the diagram (sides only)
**Notes:** Default value: 0.
## parse
### Parameters
- `text`
- `dia`
Returns **any**
## setSiteConfig
## setSiteConfig
@ -1428,7 +1420,7 @@ function _Default value: At default, will mirror Global Config_
### Parameters
- `conf` The base currentConfig to use as siteConfig
- `conf` **MermaidConfig** The base currentConfig to use as siteConfig
Returns **[object][5]** The siteConfig
@ -1462,6 +1454,34 @@ corresponding siteConfig value.
Returns **any** The currentConfig merged with the sanitized conf
## render
Function that renders an svg with a graph from a chart definition. Usage example below.
```javascript
mermaidAPI.initialize({
startOnLoad: true,
});
$(function () {
const graphDefinition = 'graph TB\na-->b';
const cb = function (svgGraph) {
console.log(svgGraph);
};
mermaidAPI.render('id1', graphDefinition, cb);
});
```
### Parameters
- `id` **[string][6]** The id of the element to be rendered
- `text` **[string][6]** The graph definition
- `cb` **function (svgCode: [string][6], bindFunctions: function (element: [Element][7]): void): void**
- `container` **[Element][7]** Selector to element in which a div with the graph temporarily will be
inserted. If one is provided a hidden div will be inserted in the body of the page instead. The
element will be removed when rendering is completed.
Returns **void**
## getConfig
## getConfig
@ -1489,34 +1509,6 @@ options in-place
- `options` **any** The potential setConfig parameter
## render
Function that renders an svg with a graph from a chart definition. Usage example below.
```javascript
mermaidAPI.initialize({
startOnLoad: true,
});
$(function () {
const graphDefinition = 'graph TB\na-->b';
const cb = function (svgGraph) {
console.log(svgGraph);
};
mermaidAPI.render('id1', graphDefinition, cb);
});
```
### Parameters
- `id` **any** The id of the element to be rendered
- `_txt` **any** The graph definition
- `cb` **any** Callback which is called after rendering is finished with the svg code as inparam.
- `container` **any** Selector to element in which a div with the graph temporarily will be
inserted. If one is provided a hidden div will be inserted in the body of the page instead. The
element will be removed when rendering is completed.
Returns **any**
## addDirective
Pushes in a directive to the configuration
@ -1541,17 +1533,17 @@ Pushes in a directive to the configuration
**Notes**: (default: current siteConfig ) (optional, default `getSiteConfig()`)
## updateRendererConfigs
### Parameters
- `conf` **any**
- `config` (optional, default `siteConfig`)
Returns **void**
## initialize
### Parameters
- `options` **any**
- `options` **MermaidConfig**
##
@ -1626,3 +1618,7 @@ Pushes in a directive to the configuration
[4]: #mermaidapi-configuration-defaults
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[7]: https://developer.mozilla.org/docs/Web/API/Element

View File

@ -182,7 +182,40 @@ After this we made use of the `checkout` keyword to set the current branch as `m
After this we merge the `develop` branch onto the current branch `main`, resulting in a merge commit.
Since the current branch at this point is still `main`, the last two commits are registered against that.
Additionally, you may add a tag to the merge commit, or override the default id: `merge branch id:"1234" tag:"v1.0.0"`
You can also decorate your merge with similar attributes as you did for the commit using:
- `id`--> To override the default ID with custom ID
- `tag`--> To add a custom tag to your merge commit
- `type`--> To override the default shape of merge commit. Here you can use other commit type mentioned earlier.
And you can choose to use none, some or all of these attributes together.
For example: `merge develop id: "my_custom_id" tag: "my_custom_tag" type: REVERSE`
Let us see how this works with the help of the following diagram:
```mermaid-example
gitGraph
commit id: "1"
commit id: "2"
branch nice_feature
checkout nice_feature
commit id: "3"
checkout main
commit id: "4"
checkout nice_feature
branch very_nice_feature
checkout very_nice_feature
commit id: "5"
checkout main
commit id: "6"
checkout nice_feature
commit id: "7"
checkout main
merge nice_feature id: "customID" tag: "customTag" type: REVERSE
checkout very_nice_feature
commit id: "8"
checkout main
commit id: "9"
```
### Cherry Pick commit from another branch
Similar to how 'git' allows you to cherry-pick a commit from **another branch** onto the **current** branch, Mermaid also supports this functionality. You can also cherry-pick a commit from another branch using the `cherry-pick` keyword.

View File

@ -1,7 +1,9 @@
const path = require('path');
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
testEnvironment: 'jsdom',
preset: 'ts-jest',
transform: {
'^.+\\.jsx?$': ['babel-jest', { rootMode: 'upward' }],
'^.+\\.jison$': [
@ -10,7 +12,7 @@ module.exports = {
],
},
transformIgnorePatterns: ['/node_modules/(?!dagre-d3-renderer/lib|khroma).*\\.js'],
testPathIgnorePatterns: ['/node_modules/', '.cache'],
testPathIgnorePatterns: ['/node_modules/', '.cache', './cypress'],
moduleNameMapper: {
'\\.(css|scss)$': 'identity-obj-proxy',
},

View File

@ -1,13 +1,15 @@
{
"name": "mermaid",
"version": "9.1.5",
"version": "9.1.6",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"main": "dist/mermaid.min.js",
"module": "dist/mermaid.esm.min.mjs",
"types": "dist/mermaid.d.ts",
"exports": {
".": {
"require": "./dist/mermaid.min.js",
"import": "./dist/mermaid.esm.min.mjs"
"import": "./dist/mermaid.esm.min.mjs",
"types": "./dist/mermaid.d.ts"
},
"./*": "./*"
},
@ -22,16 +24,17 @@
],
"scripts": {
"build:fast": "node .esbuild/esbuild.cjs",
"build:development": "webpack --mode development --progress --color",
"build:production": "webpack --mode production --progress --color",
"build": "concurrently \"yarn build:development\" \"yarn build:production\"",
"postbuild": "documentation build src/mermaidAPI.js src/config.js src/defaultConfig.js --shallow -f md --markdown-toc false > docs/Setup.md",
"build:watch": "yarn build:development --watch",
"build:dev": "webpack --mode development --progress --color",
"build:prod": "webpack --mode production --progress --color",
"build": "concurrently \"yarn build:dev\" \"yarn build:prod\"",
"postbuild": "documentation build src/mermaidAPI.ts src/config.ts src/defaultConfig.ts --shallow -f md --markdown-toc false > docs/Setup.md",
"build:watch": "yarn build:dev --watch",
"release": "yarn build",
"lint": "eslint --cache ./ --ext .js,.json,.html,.md",
"lint:fix": "yarn lint --fix",
"e2e:depr": "yarn lint && jest e2e --config e2e/jest.config.js",
"cypress": "cypress run",
"cypress:open": "cypress open",
"e2e": "start-server-and-test dev http://localhost:9000/ cypress",
"e2e-upd": "yarn lint && jest e2e -u --config e2e/jest.config.js",
"dev": "webpack serve --config ./.webpack/webpack.config.e2e.babel.js",
@ -39,12 +42,12 @@
"test": "yarn lint && jest src/.*",
"test:watch": "jest --watch src",
"prepublishOnly": "yarn build && yarn test",
"prepare": "husky install && yarn build",
"prepare": "husky install",
"pre-commit": "lint-staged"
},
"repository": {
"type": "git",
"url": "https://github.com/knsv/mermaid"
"url": "https://github.com/mermaid-js/mermaid"
},
"author": "Knut Sveidqvist",
"license": "MIT",
@ -75,8 +78,12 @@
"@babel/eslint-parser": "^7.14.7",
"@babel/preset-env": "^7.14.7",
"@babel/register": "^7.14.5",
"@commitlint/cli": "^17.0.0",
"@commitlint/cli": "^17.1.2",
"@commitlint/config-conventional": "^17.0.0",
"@types/d3": "^7.4.0",
"@types/dompurify": "^2.3.3",
"@types/jest": "^28.1.7",
"@types/stylis": "^4.0.2",
"babel-jest": "^29.0.1",
"babel-loader": "^8.2.2",
"concurrently": "^7.0.0",
@ -108,10 +115,13 @@
"prettier": "^2.3.2",
"prettier-plugin-jsdoc": "^0.3.30",
"start-server-and-test": "^1.12.6",
"terser-webpack-plugin": "^5.2.4",
"terser-webpack-plugin": "^5.3.6",
"ts-jest": "^28.0.8",
"ts-loader": "^9.3.1",
"typescript": "^4.7.4",
"webpack": "^5.53.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^4.3.0",
"webpack-dev-server": "^4.10.1",
"webpack-merge": "^5.8.0",
"webpack-node-externals": "^3.0.0"
},

View File

@ -1,71 +1,68 @@
import utils from './utils';
import * as configApi from './config';
import { log } from './logger';
import { getDiagrams } from './diagram-api/diagramAPI';
import detectType from './diagram-api/detectType';
class Diagram {
import { getDiagram } from './diagram-api/diagramAPI';
import { detectType } from './diagram-api/detectType';
import { isDetailedError } from './utils';
export class Diagram {
type = 'graph';
parser;
renderer;
db;
constructor(txt) {
const diagrams = getDiagrams();
constructor(public txt: string, parseError?: Function) {
const cnf = configApi.getConfig();
this.txt = txt;
this.type = detectType(txt, cnf);
const diagram = getDiagram(this.type);
log.debug('Type ' + this.type);
// console.log('this.type', this.type, diagrams[this.type]);
// Setup diagram
this.db = diagrams[this.type].db;
this.db = diagram.db;
this.db.clear?.();
this.renderer = diagrams[this.type].renderer;
this.parser = diagrams[this.type].parser;
this.renderer = diagram.renderer;
this.parser = diagram.parser;
this.parser.parser.yy = this.db;
if (typeof diagrams[this.type].init === 'function') {
diagrams[this.type].init(cnf);
if (diagram.init) {
diagram.init(cnf);
log.debug('Initialized diagram ' + this.type, cnf);
}
this.txt = this.txt + '\n';
this.txt += '\n';
this.parser.parser.yy.graphType = this.type;
this.parser.parser.yy.parseError = (str, hash) => {
this.parser.parser.yy.parseError = (str: string, hash: string) => {
const error = { str, hash };
throw error;
};
this.parser.parse(this.txt);
this.parse(this.txt, parseError);
}
parse(text) {
var parseEncounteredException = false;
parse(text: string, parseError?: Function): boolean {
try {
text = text + '\n';
this.db.clear();
this.parser.parse(text);
return true;
} catch (error) {
parseEncounteredException = true;
// Is this the correct way to access mermiad's parseError()
// method ? (or global.mermaid.parseError()) ?
if (global.mermaid.parseError) {
if (error.str != undefined) {
if (parseError) {
if (isDetailedError(error)) {
// handle case where error string and hash were
// wrapped in object like`const error = { str, hash };`
global.mermaid.parseError(error.str, error.hash);
parseError(error.str, error.hash);
} else {
// assume it is just error string and pass it on
global.mermaid.parseError(error);
parseError(error);
}
} else {
// No mermaid.parseError() handler defined, so re-throw it
throw error;
}
}
return !parseEncounteredException;
return false;
}
getParser() {
return this.parser;
}
getType() {
return this.type;
}

View File

@ -3,35 +3,35 @@ import { getConfig } from './config';
let title = '';
let diagramTitle = '';
let description = '';
const sanitizeText = (txt) => _sanitizeText(txt, getConfig());
const sanitizeText = (txt: string): string => _sanitizeText(txt, getConfig());
export const clear = function () {
export const clear = function (): void {
title = '';
description = '';
diagramTitle = '';
};
export const setAccTitle = function (txt) {
export const setAccTitle = function (txt: string): void {
title = sanitizeText(txt).replace(/^\s+/g, '');
};
export const getAccTitle = function () {
export const getAccTitle = function (): string {
return title || diagramTitle;
};
export const setAccDescription = function (txt) {
export const setAccDescription = function (txt: string): void {
description = sanitizeText(txt).replace(/\n\s+/g, '\n');
};
export const getAccDescription = function () {
export const getAccDescription = function (): string {
return description;
};
export const setDiagramTitle = function (txt) {
export const setDiagramTitle = function (txt: string): void {
diagramTitle = sanitizeText(txt);
};
export const getDiagramTitle = function () {
export const getDiagramTitle = function (): string {
return diagramTitle;
};

View File

@ -2,21 +2,22 @@ import assignWithDepth from './assignWithDepth';
import { log } from './logger';
import theme from './themes';
import config from './defaultConfig';
import type { MermaidConfig } from './config.type';
export const defaultConfig = Object.freeze(config);
export const defaultConfig: MermaidConfig = Object.freeze(config);
let siteConfig = assignWithDepth({}, defaultConfig);
let configFromInitialize;
let directives = [];
let currentConfig = assignWithDepth({}, defaultConfig);
let siteConfig: MermaidConfig = assignWithDepth({}, defaultConfig);
let configFromInitialize: MermaidConfig;
let directives: any[] = [];
let currentConfig: MermaidConfig = assignWithDepth({}, defaultConfig);
export const updateCurrentConfig = (siteCfg, _directives) => {
// start with config beeing the siteConfig
let cfg = assignWithDepth({}, siteCfg);
export const updateCurrentConfig = (siteCfg: MermaidConfig, _directives: any[]) => {
// start with config being the siteConfig
let cfg: MermaidConfig = assignWithDepth({}, siteCfg);
// let sCfg = assignWithDepth(defaultConfig, siteConfigDelta);
// Join directives
let sumOfDirectives = {};
let sumOfDirectives: MermaidConfig = {};
for (let i = 0; i < _directives.length; i++) {
const d = _directives[i];
sanitize(d);
@ -27,13 +28,15 @@ export const updateCurrentConfig = (siteCfg, _directives) => {
cfg = assignWithDepth(cfg, sumOfDirectives);
if (sumOfDirectives.theme && theme[sumOfDirectives.theme]) {
if (sumOfDirectives.theme && sumOfDirectives.theme in theme) {
const tmpConfigFromInitialize = assignWithDepth({}, configFromInitialize);
const themeVariables = assignWithDepth(
tmpConfigFromInitialize.themeVariables || {},
sumOfDirectives.themeVariables
);
cfg.themeVariables = theme[cfg.theme].getThemeVariables(themeVariables);
if (cfg.theme && cfg.theme in theme) {
cfg.themeVariables = theme[cfg.theme as keyof typeof theme].getThemeVariables(themeVariables);
}
}
currentConfig = cfg;
@ -55,11 +58,13 @@ export const updateCurrentConfig = (siteCfg, _directives) => {
* @param conf - The base currentConfig to use as siteConfig
* @returns {object} - The siteConfig
*/
export const setSiteConfig = (conf) => {
export const setSiteConfig = (conf: MermaidConfig): MermaidConfig => {
siteConfig = assignWithDepth({}, defaultConfig);
siteConfig = assignWithDepth(siteConfig, conf);
// @ts-ignore
if (conf.theme && theme[conf.theme]) {
// @ts-ignore
siteConfig.themeVariables = theme[conf.theme].getThemeVariables(conf.themeVariables);
}
@ -67,11 +72,11 @@ export const setSiteConfig = (conf) => {
return siteConfig;
};
export const saveConfigFromInitialize = (conf) => {
export const saveConfigFromInitialize = (conf: MermaidConfig): void => {
configFromInitialize = assignWithDepth({}, conf);
};
export const updateSiteConfig = (conf) => {
export const updateSiteConfig = (conf: MermaidConfig): MermaidConfig => {
siteConfig = assignWithDepth(siteConfig, conf);
updateCurrentConfig(siteConfig, directives);
@ -88,7 +93,7 @@ export const updateSiteConfig = (conf) => {
*
* @returns {object} - The siteConfig
*/
export const getSiteConfig = () => {
export const getSiteConfig = (): MermaidConfig => {
return assignWithDepth({}, siteConfig);
};
/**
@ -105,7 +110,7 @@ export const getSiteConfig = () => {
* @param {any} conf - The potential currentConfig
* @returns {any} - The currentConfig merged with the sanitized conf
*/
export const setConfig = (conf) => {
export const setConfig = (conf: MermaidConfig): MermaidConfig => {
// sanitize(conf);
// Object.keys(conf).forEach(key => {
// const manipulator = manipulators[key];
@ -128,7 +133,7 @@ export const setConfig = (conf) => {
*
* @returns {any} - The currentConfig
*/
export const getConfig = () => {
export const getConfig = (): MermaidConfig => {
return assignWithDepth({}, currentConfig);
};
/**
@ -143,17 +148,14 @@ export const getConfig = () => {
*
* @param {any} options - The potential setConfig parameter
*/
export const sanitize = (options) => {
export const sanitize = (options: any) => {
// Checking that options are not in the list of excluded options
Object.keys(siteConfig.secure).forEach((key) => {
if (typeof options[siteConfig.secure[key]] !== 'undefined') {
// DO NOT attempt to print options[siteConfig.secure[key]] within `${}` as a malicious script
['secure', ...(siteConfig.secure ?? [])].forEach((key) => {
if (typeof options[key] !== 'undefined') {
// DO NOT attempt to print options[key] within `${}` as a malicious script
// can exploit the logger's attempt to stringify the value and execute arbitrary code
log.debug(
`Denied attempt to modify a secure key ${siteConfig.secure[key]}`,
options[siteConfig.secure[key]]
);
delete options[siteConfig.secure[key]];
log.debug(`Denied attempt to modify a secure key ${key}`, options[key]);
delete options[key];
}
});
@ -186,7 +188,7 @@ export const sanitize = (options) => {
*
* @param {object} directive The directive to push in
*/
export const addDirective = (directive) => {
export const addDirective = (directive: any) => {
if (directive.fontFamily) {
if (!directive.themeVariables) {
directive.themeVariables = { fontFamily: directive.fontFamily };
@ -215,8 +217,8 @@ export const addDirective = (directive) => {
*
* **Notes**: (default: current siteConfig ) (optional, default `getSiteConfig()`)
*/
export const reset = () => {
export const reset = (config = siteConfig): void => {
// Replace current config with siteConfig
directives = [];
updateCurrentConfig(siteConfig, directives);
updateCurrentConfig(config, directives);
};

351
src/config.type.ts Normal file
View File

@ -0,0 +1,351 @@
// TODO: This was auto generated from defaultConfig. Needs to be verified.
import DOMPurify from 'dompurify';
export interface MermaidConfig {
theme?: string;
themeVariables?: any;
themeCSS?: string;
maxTextSize?: number;
darkMode?: boolean;
htmlLabels?: boolean;
fontFamily?: string;
altFontFamily?: string;
logLevel?: number;
securityLevel?: string;
startOnLoad?: boolean;
arrowMarkerAbsolute?: boolean;
secure?: string[];
deterministicIds?: boolean;
deterministicIDSeed?: string;
flowchart?: FlowchartDiagramConfig;
sequence?: SequenceDiagramConfig;
gantt?: GanttDiagramConfig;
journey?: JourneyDiagramConfig;
class?: ClassDiagramConfig;
state?: StateDiagramConfig;
er?: ErDiagramConfig;
pie?: PieDiagramConfig;
requirement?: RequirementDiagramConfig;
gitGraph?: GitGraphDiagramConfig;
c4?: C4DiagramConfig;
dompurifyConfig?: DOMPurify.Config;
wrap?: boolean;
}
// TODO: More configs needs to be moved in here
export interface BaseDiagramConfig {
useWidth?: number;
useMaxWidth?: boolean;
}
export interface C4DiagramConfig extends BaseDiagramConfig {
diagramMarginX?: number;
diagramMarginY?: number;
c4ShapeMargin?: number;
c4ShapePadding?: number;
width?: number;
height?: number;
boxMargin?: number;
c4ShapeInRow?: number;
nextLinePaddingX?: number;
c4BoundaryInRow?: number;
personFontSize?: string | number;
personFontFamily?: string;
personFontWeight?: string | number;
external_personFontSize?: string | number;
external_personFontFamily?: string;
external_personFontWeight?: string | number;
systemFontSize?: string | number;
systemFontFamily?: string;
systemFontWeight?: string | number;
external_systemFontSize?: string | number;
external_systemFontFamily?: string;
external_systemFontWeight?: string | number;
system_dbFontSize?: string | number;
system_dbFontFamily?: string;
system_dbFontWeight?: string | number;
external_system_dbFontSize?: string | number;
external_system_dbFontFamily?: string;
external_system_dbFontWeight?: string | number;
system_queueFontSize?: string | number;
system_queueFontFamily?: string;
system_queueFontWeight?: string | number;
external_system_queueFontSize?: string | number;
external_system_queueFontFamily?: string;
external_system_queueFontWeight?: string | number;
boundaryFontSize?: string | number;
boundaryFontFamily?: string;
boundaryFontWeight?: string | number;
messageFontSize?: string | number;
messageFontFamily?: string;
messageFontWeight?: string | number;
containerFontSize?: string | number;
containerFontFamily?: string;
containerFontWeight?: string | number;
external_containerFontSize?: string | number;
external_containerFontFamily?: string;
external_containerFontWeight?: string | number;
container_dbFontSize?: string | number;
container_dbFontFamily?: string;
container_dbFontWeight?: string | number;
external_container_dbFontSize?: string | number;
external_container_dbFontFamily?: string;
external_container_dbFontWeight?: string | number;
container_queueFontSize?: string | number;
container_queueFontFamily?: string;
container_queueFontWeight?: string | number;
external_container_queueFontSize?: string | number;
external_container_queueFontFamily?: string;
external_container_queueFontWeight?: string | number;
componentFontSize?: string | number;
componentFontFamily?: string;
componentFontWeight?: string | number;
external_componentFontSize?: string | number;
external_componentFontFamily?: string;
external_componentFontWeight?: string | number;
component_dbFontSize?: string | number;
component_dbFontFamily?: string;
component_dbFontWeight?: string | number;
external_component_dbFontSize?: string | number;
external_component_dbFontFamily?: string;
external_component_dbFontWeight?: string | number;
component_queueFontSize?: string | number;
component_queueFontFamily?: string;
component_queueFontWeight?: string | number;
external_component_queueFontSize?: string | number;
external_component_queueFontFamily?: string;
external_component_queueFontWeight?: string | number;
wrap?: boolean;
wrapPadding?: number;
person_bg_color?: string;
person_border_color?: string;
external_person_bg_color?: string;
external_person_border_color?: string;
system_bg_color?: string;
system_border_color?: string;
system_db_bg_color?: string;
system_db_border_color?: string;
system_queue_bg_color?: string;
system_queue_border_color?: string;
external_system_bg_color?: string;
external_system_border_color?: string;
external_system_db_bg_color?: string;
external_system_db_border_color?: string;
external_system_queue_bg_color?: string;
external_system_queue_border_color?: string;
container_bg_color?: string;
container_border_color?: string;
container_db_bg_color?: string;
container_db_border_color?: string;
container_queue_bg_color?: string;
container_queue_border_color?: string;
external_container_bg_color?: string;
external_container_border_color?: string;
external_container_db_bg_color?: string;
external_container_db_border_color?: string;
external_container_queue_bg_color?: string;
external_container_queue_border_color?: string;
component_bg_color?: string;
component_border_color?: string;
component_db_bg_color?: string;
component_db_border_color?: string;
component_queue_bg_color?: string;
component_queue_border_color?: string;
external_component_bg_color?: string;
external_component_border_color?: string;
external_component_db_bg_color?: string;
external_component_db_border_color?: string;
external_component_queue_bg_color?: string;
external_component_queue_border_color?: string;
personFont?: FontCalculator;
external_personFont?: FontCalculator;
systemFont?: FontCalculator;
external_systemFont?: FontCalculator;
system_dbFont?: FontCalculator;
external_system_dbFont?: FontCalculator;
system_queueFont?: FontCalculator;
external_system_queueFont?: FontCalculator;
containerFont?: FontCalculator;
external_containerFont?: FontCalculator;
container_dbFont?: FontCalculator;
external_container_dbFont?: FontCalculator;
container_queueFont?: FontCalculator;
external_container_queueFont?: FontCalculator;
componentFont?: FontCalculator;
external_componentFont?: FontCalculator;
component_dbFont?: FontCalculator;
external_component_dbFont?: FontCalculator;
component_queueFont?: FontCalculator;
external_component_queueFont?: FontCalculator;
boundaryFont?: FontCalculator;
messageFont?: FontCalculator;
}
export interface GitGraphDiagramConfig extends BaseDiagramConfig {
diagramPadding?: number;
nodeLabel?: NodeLabel;
mainBranchName?: string;
mainBranchOrder?: number;
showCommitLabel?: boolean;
showBranches?: boolean;
rotateCommitLabel?: boolean;
arrowMarkerAbsolute?: boolean;
}
export interface NodeLabel {
width?: number;
height?: number;
x?: number;
y?: number;
}
export interface RequirementDiagramConfig extends BaseDiagramConfig {
rect_fill?: string;
text_color?: string;
rect_border_size?: string;
rect_border_color?: string;
rect_min_width?: number;
rect_min_height?: number;
fontSize?: number;
rect_padding?: number;
line_height?: number;
}
export interface PieDiagramConfig extends BaseDiagramConfig {}
export interface ErDiagramConfig extends BaseDiagramConfig {
diagramPadding?: number;
layoutDirection?: string;
minEntityWidth?: number;
minEntityHeight?: number;
entityPadding?: number;
stroke?: string;
fill?: string;
fontSize?: number;
}
export interface StateDiagramConfig extends BaseDiagramConfig {
arrowMarkerAbsolute?: boolean;
dividerMargin?: number;
sizeUnit?: number;
padding?: number;
textHeight?: number;
titleShift?: number;
noteMargin?: number;
forkWidth?: number;
forkHeight?: number;
miniPadding?: number;
fontSizeFactor?: number;
fontSize?: number;
labelHeight?: number;
edgeLengthFactor?: string;
compositTitleSize?: number;
radius?: number;
defaultRenderer?: string;
}
export interface ClassDiagramConfig extends BaseDiagramConfig {
arrowMarkerAbsolute?: boolean;
dividerMargin?: number;
padding?: number;
textHeight?: number;
defaultRenderer?: string;
}
export interface JourneyDiagramConfig extends BaseDiagramConfig {
diagramMarginX?: number;
diagramMarginY?: number;
leftMargin?: number;
width?: number;
height?: number;
boxMargin?: number;
boxTextMargin?: number;
noteMargin?: number;
messageMargin?: number;
messageAlign?: string;
bottomMarginAdj?: number;
rightAngles?: boolean;
taskFontSize?: string | number;
taskFontFamily?: string;
taskMargin?: number;
activationWidth?: number;
textPlacement?: string;
actorColours?: string[];
sectionFills?: string[];
sectionColours?: string[];
}
export interface GanttDiagramConfig extends BaseDiagramConfig {
titleTopMargin?: number;
barHeight?: number;
barGap?: number;
topPadding?: number;
rightPadding?: number;
leftPadding?: number;
gridLineStartPadding?: number;
fontSize?: number;
sectionFontSize?: string | number;
numberSectionStyles?: number;
axisFormat?: string;
topAxis?: boolean;
}
export interface SequenceDiagramConfig extends BaseDiagramConfig {
arrowMarkerAbsolute?: boolean;
hideUnusedParticipants?: boolean;
activationWidth?: number;
diagramMarginX?: number;
diagramMarginY?: number;
actorMargin?: number;
width?: number;
height?: number;
boxMargin?: number;
boxTextMargin?: number;
noteMargin?: number;
messageMargin?: number;
messageAlign?: string;
mirrorActors?: boolean;
forceMenus?: boolean;
bottomMarginAdj?: number;
rightAngles?: boolean;
showSequenceNumbers?: boolean;
actorFontSize?: string | number;
actorFontFamily?: string;
actorFontWeight?: string | number;
noteFontSize?: string | number;
noteFontFamily?: string;
noteFontWeight?: string | number;
noteAlign?: string;
messageFontSize?: string | number;
messageFontFamily?: string;
messageFontWeight?: string | number;
wrap?: boolean;
wrapPadding?: number;
labelBoxWidth?: number;
labelBoxHeight?: number;
messageFont?: FontCalculator;
noteFont?: FontCalculator;
actorFont?: FontCalculator;
}
export interface FlowchartDiagramConfig extends BaseDiagramConfig {
arrowMarkerAbsolute?: boolean;
diagramPadding?: number;
htmlLabels?: boolean;
nodeSpacing?: number;
rankSpacing?: number;
curve?: string;
padding?: number;
defaultRenderer?: string;
}
export interface FontConfig {
fontSize?: string | number;
fontFamily?: string;
fontWeight?: string | number;
}
export type FontCalculator = () => Partial<FontConfig>;
export {};

View File

@ -1,4 +1,5 @@
import theme from './themes';
import { MermaidConfig } from './config.type';
/**
* **Configuration methods in Mermaid version 8.6.0 have been updated, to learn more[[click
* here](8.6.0_docs.md)].**
@ -21,7 +22,7 @@ import theme from './themes';
*
* @name Configuration
*/
const config = {
const config: Partial<MermaidConfig> = {
/**
* Theme , the CSS style sheet
*
@ -49,12 +50,13 @@ const config = {
fontFamily: '"trebuchet ms", verdana, arial, sans-serif;',
/**
* | Parameter | Description | Type | Required | Values |
* | --------- | ----------------------------------------------------- | ---------------- | -------- | ------------- |
* | logLevel | This option decides the amount of logging to be used. | string \| number | Required | 1, 2, 3, 4, 5 |
* | Parameter | Description | Type | Required | Values |
* | --------- | ----------------------------------------------------- | ---------------- | -------- | --------------------------------------------- |
* | logLevel | This option decides the amount of logging to be used. | string \| number | Required | 'trace','debug','info','warn','error','fatal' |
*
* **Notes:**
*
* - Trace: 0
* - Debug: 1
* - Info: 2
* - Warn: 3
@ -1823,11 +1825,11 @@ const config = {
},
};
config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
config.gitGraph.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
if (config.class) config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
if (config.gitGraph) config.gitGraph.arrowMarkerAbsolute = config.arrowMarkerAbsolute;
const keyify = (obj, prefix = '') =>
Object.keys(obj).reduce((res, el) => {
const keyify = (obj: any, prefix = ''): string[] =>
Object.keys(obj).reduce((res: string[], el): string[] => {
if (Array.isArray(obj[el])) {
return res;
} else if (typeof obj[el] === 'object' && obj[el] !== null) {
@ -1836,5 +1838,5 @@ const keyify = (obj, prefix = '') =>
return [...res, prefix + el];
}, []);
export const configKeys = keyify(config, '');
export const configKeys: string[] = keyify(config, '');
export default config;

View File

@ -1,100 +0,0 @@
const directive =
/[%]{2}[{]\s*(?:(?:(\w+)\s*:|(\w+))\s*(?:(?:(\w+))|((?:(?![}][%]{2}).|\r?\n)*))?\s*)(?:[}][%]{2})?/gi;
const anyComment = /\s*%%.*\n/gm;
const detectors = {};
/**
* @function detectType Detects the type of the graph text. Takes into consideration the possible
* existence of an %%init directive
*
* ```mermaid
* %%{initialize: {"startOnLoad": true, logLevel: "fatal" }}%%
* graph LR
* a-->b
* b-->c
* c-->d
* d-->e
* e-->f
* f-->g
* g-->h
* ```
* @param {string} text The text defining the graph
* @param {{
* class: { defaultRenderer: string } | undefined;
* state: { defaultRenderer: string } | undefined;
* flowchart: { defaultRenderer: string } | undefined;
* }} [cnf]
* @returns {string} A graph definition key
*/
const detectType = function (text, cnf) {
text = text.replace(directive, '').replace(anyComment, '\n');
if (text.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/)) {
return 'c4';
}
if (text.match(/^\s*sequenceDiagram/)) {
return 'sequence';
}
if (text.match(/^\s*gantt/)) {
return 'gantt';
}
if (text.match(/^\s*classDiagram-v2/)) {
return 'classDiagram';
}
if (text.match(/^\s*classDiagram/)) {
if (cnf && cnf.class && cnf.class.defaultRenderer === 'dagre-wrapper') return 'classDiagram';
return 'class';
}
if (text.match(/^\s*stateDiagram-v2/)) {
return 'stateDiagram';
}
if (text.match(/^\s*stateDiagram/)) {
if (cnf && cnf.class && cnf.state.defaultRenderer === 'dagre-wrapper') return 'stateDiagram';
return 'state';
}
// if (text.match(/^\s*gitGraph/)) {
// return 'gitGraph';
// }
if (text.match(/^\s*flowchart/)) {
return 'flowchart-v2';
}
if (text.match(/^\s*info/)) {
return 'info';
}
if (text.match(/^\s*pie/)) {
return 'pie';
}
if (text.match(/^\s*erDiagram/)) {
return 'er';
}
if (text.match(/^\s*journey/)) {
return 'journey';
}
if (text.match(/^\s*requirement/) || text.match(/^\s*requirementDiagram/)) {
return 'requirement';
}
if (cnf && cnf.flowchart && cnf.flowchart.defaultRenderer === 'dagre-wrapper')
return 'flowchart-v2';
const k = Object.keys(detectors);
for (let i = 0; i < k.length; i++) {
const key = k[i];
const dia = detectors[key];
if (dia && dia.detector(text)) {
return key;
}
}
return 'flowchart';
};
export const addDetector = (key, detector) => {
detectors[key] = {
detector,
};
};
export default detectType;

View File

@ -0,0 +1,82 @@
import { MermaidConfig } from '../config.type';
export type DiagramDetector = (text: string) => boolean;
const directive =
/[%]{2}[{]\s*(?:(?:(\w+)\s*:|(\w+))\s*(?:(?:(\w+))|((?:(?![}][%]{2}).|\r?\n)*))?\s*)(?:[}][%]{2})?/gi;
const anyComment = /\s*%%.*\n/gm;
const detectors: Record<string, DiagramDetector> = {};
const diagramMatchers: Record<string, RegExp> = {
c4: /^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/,
sequence: /^\s*sequenceDiagram/,
gantt: /^\s*gantt/,
classDiagram: /^\s*classDiagram-v2/,
stateDiagram: /^\s*stateDiagram-v2/,
'flowchart-v2': /^\s*flowchart/, // Might need to add |graph to fix #3391
info: /^\s*info/,
pie: /^\s*pie/,
er: /^\s*erDiagram/,
journey: /^\s*journey/,
// gitGraph: /^\s*gitGraph/,
requirement: /^\s*requirement(Diagram)?/,
};
/**
* @function detectType Detects the type of the graph text. Takes into consideration the possible
* existence of an %%init directive
*
* ```mermaid
* %%{initialize: {"startOnLoad": true, logLevel: "fatal" }}%%
* graph LR
* a-->b
* b-->c
* c-->d
* d-->e
* e-->f
* f-->g
* g-->h
* ```
* @param {string} text The text defining the graph
* @param {{
* class: { defaultRenderer: string } | undefined;
* state: { defaultRenderer: string } | undefined;
* flowchart: { defaultRenderer: string } | undefined;
* }} [config]
* @returns {string} A graph definition key
*/
export const detectType = function (text: string, config?: MermaidConfig): string {
text = text.replace(directive, '').replace(anyComment, '\n');
for (const [diagram, matcher] of Object.entries(diagramMatchers)) {
if (text.match(matcher)) {
return diagram;
}
}
if (text.match(/^\s*classDiagram/)) {
if (config?.class?.defaultRenderer === 'dagre-wrapper') return 'classDiagram';
return 'class';
}
if (text.match(/^\s*stateDiagram/)) {
if (config?.state?.defaultRenderer === 'dagre-wrapper') return 'stateDiagram';
return 'state';
}
if (config?.flowchart?.defaultRenderer === 'dagre-wrapper') {
return 'flowchart-v2';
}
for (const [key, detector] of Object.entries(detectors)) {
if (detector(text)) {
return key;
}
}
// TODO: #3391
// throw new Error(`No diagram type detected for text: ${text}`);
return 'flowchart';
};
export const addDetector = (key: string, detector: DiagramDetector) => {
detectors[key] = detector;
};

View File

@ -1,13 +1,14 @@
import { registerDiagram } from './diagramAPI.js';
import { registerDiagram } from './diagramAPI';
// import mindmapDb from '../diagrams/mindmap/mindmapDb';
// import mindmapRenderer from '../diagrams/mindmap/mindmapRenderer';
// import mindmapParser from '../diagrams/mindmap/parser/mindmapDiagram';
// import mindmapDetector from '../diagrams/mindmap/mindmapDetector';
// import { mindmapDetector } from '../diagrams/mindmap/mindmapDetector';
import gitGraphDb from '../diagrams/git/gitGraphAst';
import gitGraphRenderer from '../diagrams/git/gitGraphRenderer';
// @ts-ignore
import gitGraphParser from '../diagrams/git/parser/gitGraph';
import gitGraphDetector from '../diagrams/git/gitGraphDetector';
import { gitGraphDetector } from '../diagrams/git/gitGraphDetector';
// Register mindmap and other built-in diagrams
// registerDiagram(
@ -19,14 +20,10 @@ import gitGraphDetector from '../diagrams/git/gitGraphDetector';
// mindmapRenderer,
// mindmapDetector
// );
const addDiagrams = () => {
export const addDiagrams = () => {
registerDiagram(
'gitGraph',
gitGraphParser,
gitGraphDb,
gitGraphRenderer,
undefined,
{ parser: gitGraphParser, db: gitGraphDb, renderer: gitGraphRenderer },
gitGraphDetector
);
};
export default addDiagrams;

View File

@ -0,0 +1,28 @@
import { detectType } from './detectType';
import { getDiagram, registerDiagram } from './diagramAPI';
describe('DiagramAPI', () => {
it('should return default diagrams', () => {
expect(getDiagram('sequence')).not.toBeNull();
});
it('should throw error if diagram is not defined', () => {
expect(() => getDiagram('loki')).toThrow();
});
it('should handle diagram registrations', () => {
expect(() => getDiagram('loki')).toThrow();
expect(() => detectType('loki diagram')).not.toThrow(); // TODO: #3391
registerDiagram(
'loki',
{
db: {},
parser: {},
renderer: {},
},
(text: string) => text.includes('loki')
);
expect(getDiagram('loki')).not.toBeNull();
expect(detectType('loki diagram')).toBe('loki');
});
});

View File

@ -1,42 +1,62 @@
import c4Db from '../diagrams/c4/c4Db';
import c4Renderer from '../diagrams/c4/c4Renderer';
// @ts-ignore
import c4Parser from '../diagrams/c4/parser/c4Diagram';
import classDb from '../diagrams/class/classDb';
import classRenderer from '../diagrams/class/classRenderer';
import classRendererV2 from '../diagrams/class/classRenderer-v2';
// @ts-ignore
import classParser from '../diagrams/class/parser/classDiagram';
import erDb from '../diagrams/er/erDb';
import erRenderer from '../diagrams/er/erRenderer';
// @ts-ignore
import erParser from '../diagrams/er/parser/erDiagram';
import flowDb from '../diagrams/flowchart/flowDb';
import flowRenderer from '../diagrams/flowchart/flowRenderer';
import flowRendererV2 from '../diagrams/flowchart/flowRenderer-v2';
// @ts-ignore
import flowParser from '../diagrams/flowchart/parser/flow';
import ganttDb from '../diagrams/gantt/ganttDb';
import ganttRenderer from '../diagrams/gantt/ganttRenderer';
// @ts-ignore
import ganttParser from '../diagrams/gantt/parser/gantt';
import infoDb from '../diagrams/info/infoDb';
import infoRenderer from '../diagrams/info/infoRenderer';
// @ts-ignore
import infoParser from '../diagrams/info/parser/info';
// @ts-ignore
import pieParser from '../diagrams/pie/parser/pie';
import pieDb from '../diagrams/pie/pieDb';
import pieRenderer from '../diagrams/pie/pieRenderer';
// @ts-ignore
import requirementParser from '../diagrams/requirement/parser/requirementDiagram';
import requirementDb from '../diagrams/requirement/requirementDb';
import requirementRenderer from '../diagrams/requirement/requirementRenderer';
// @ts-ignore
import sequenceParser from '../diagrams/sequence/parser/sequenceDiagram';
import sequenceDb from '../diagrams/sequence/sequenceDb';
import sequenceRenderer from '../diagrams/sequence/sequenceRenderer';
// @ts-ignore
import stateParser from '../diagrams/state/parser/stateDiagram';
import stateDb from '../diagrams/state/stateDb';
import stateRenderer from '../diagrams/state/stateRenderer';
import stateRendererV2 from '../diagrams/state/stateRenderer-v2';
import journeyDb from '../diagrams/user-journey/journeyDb';
import journeyRenderer from '../diagrams/user-journey/journeyRenderer';
// @ts-ignore
import journeyParser from '../diagrams/user-journey/parser/journey';
import { addDetector } from './detectType';
import { addDetector, DiagramDetector } from './detectType';
import { log } from '../logger';
import { MermaidConfig } from '../config.type';
const diagrams = {
export interface DiagramDefinition {
db: any;
renderer: any;
parser: any;
init?: (config: MermaidConfig) => void;
}
const diagrams: Record<string, DiagramDefinition> = {
c4: {
db: c4Db,
renderer: c4Renderer,
@ -50,6 +70,9 @@ const diagrams = {
renderer: classRenderer,
parser: classParser,
init: (cnf) => {
if (!cnf.class) {
cnf.class = {};
}
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
classDb.clear();
},
@ -59,6 +82,9 @@ const diagrams = {
renderer: classRendererV2,
parser: classParser,
init: (cnf) => {
if (!cnf.class) {
cnf.class = {};
}
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
classDb.clear();
},
@ -74,6 +100,9 @@ const diagrams = {
parser: flowParser,
init: (cnf) => {
flowRenderer.setConf(cnf.flowchart);
if (!cnf.flowchart) {
cnf.flowchart = {};
}
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
flowDb.clear();
flowDb.setGen('gen-1');
@ -85,6 +114,9 @@ const diagrams = {
parser: flowParser,
init: (cnf) => {
flowRendererV2.setConf(cnf.flowchart);
if (!cnf.flowchart) {
cnf.flowchart = {};
}
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
flowDb.clear();
flowDb.setGen('gen-2');
@ -94,15 +126,7 @@ const diagrams = {
db: ganttDb,
renderer: ganttRenderer,
parser: ganttParser,
init: (cnf) => {
ganttRenderer.setConf(cnf.gantt);
},
},
// git: {
// db: gitGraphAst,
// renderer: gitGraphRenderer,
// parser: gitGraphParser,
// },
info: {
db: infoDb,
renderer: infoRenderer,
@ -123,11 +147,12 @@ const diagrams = {
renderer: sequenceRenderer,
parser: sequenceParser,
init: (cnf) => {
if (!cnf.sequence) {
cnf.sequence = {};
}
cnf.sequence.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
if (cnf.sequenceDiagram) {
// backwards compatibility
sequenceRenderer.setConf(Object.assign(cnf.sequence, cnf.sequenceDiagram));
console.error(
if ('sequenceDiagram' in cnf) {
throw new Error(
'`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.'
);
}
@ -140,7 +165,10 @@ const diagrams = {
renderer: stateRenderer,
parser: stateParser,
init: (cnf) => {
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
if (!cnf.state) {
cnf.state = {};
}
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
stateDb.clear();
},
},
@ -149,7 +177,10 @@ const diagrams = {
renderer: stateRendererV2,
parser: stateParser,
init: (cnf) => {
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
if (!cnf.state) {
cnf.state = {};
}
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
stateDb.clear();
},
},
@ -163,13 +194,22 @@ const diagrams = {
},
},
};
// console.log(sequenceDb);
export const registerDiagram = (id, parser, db, renderer, init, detector) => {
diagrams[id] = { parser, db, renderer, init };
export const registerDiagram = (
id: string,
diagram: DiagramDefinition,
detector: DiagramDetector
) => {
if (diagrams[id]) {
log.warn(`Diagram ${id} already registered.`);
}
diagrams[id] = diagram;
addDetector(id, detector);
};
export const getDiagrams = () => {
// console.log('diagrams', diagrams);
return diagrams;
export const getDiagram = (name: string): DiagramDefinition => {
if (name in diagrams) {
return diagrams[name];
}
throw new Error(`Diagram ${name} not found.`);
};

View File

@ -347,10 +347,9 @@ const buildMethodDisplay = function (parsedText) {
};
const buildLegacyDisplay = function (text) {
// if for some reason we dont have any match, use old format to parse text
// if for some reason we don't have any match, use old format to parse text
let displayText = '';
let cssStyle = '';
let memberText = '';
let returnType = '';
let methodStart = text.indexOf('(');
let methodEnd = text.indexOf(')');
@ -370,26 +369,27 @@ const buildLegacyDisplay = function (text) {
methodName = text.substring(1, methodStart).trim();
}
let parameters = text.substring(methodStart + 1, methodEnd);
let classifier = text.substring(methodEnd + 1, 1);
const parameters = text.substring(methodStart + 1, methodEnd);
const classifier = text.substring(methodEnd + 1, methodEnd + 2);
cssStyle = parseClassifier(classifier);
displayText = visibility + methodName + '(' + parseGenericTypes(parameters.trim()) + ')';
if (methodEnd < memberText.length) {
if (methodEnd <= text.length) {
returnType = text.substring(methodEnd + 2).trim();
if (returnType !== '') {
returnType = ' : ' + parseGenericTypes(returnType);
displayText += returnType;
}
} else {
// finally - if all else fails, just send the text back as written (other than parsing for generic types)
displayText = parseGenericTypes(text);
}
} else {
// finally - if all else fails, just send the text back as written (other than parsing for generic types)
displayText = parseGenericTypes(text);
}
return {
displayText: displayText,
cssStyle: cssStyle,
displayText,
cssStyle,
};
};

View File

@ -137,6 +137,14 @@ describe('class member Renderer, ', function () {
expect(actual.displayText).toBe('+foo(List<int> ids) : List<Item>');
expect(actual.cssStyle).toBe('font-style:italic;');
});
it('should handle method declaration with nested markup', function () {
const str = '+foo ( List~List~int~~ ids )* List~List~Item~~';
let actual = svgDraw.parseMember(str);
expect(actual.displayText).toBe('+foo(List<List<int>> ids) : List<List<Item>>');
expect(actual.cssStyle).toBe('font-style:italic;');
});
});
describe('when parsing text to build field display string', function () {

View File

@ -1,219 +0,0 @@
import DOMPurify from 'dompurify';
/**
* Gets the number of lines in a string
*
* @param {string | undefined} s The string to check the lines for
* @returns {number} The number of lines in that string
*/
export const getRows = (s) => {
if (!s) return 1;
let str = breakToPlaceholder(s);
str = str.replace(/\\n/g, '#br#');
return str.split('#br#');
};
export const removeEscapes = (text) => {
let newStr = text.replace(/\\u[\dA-F]{4}/gi, function (match) {
return String.fromCharCode(parseInt(match.replace(/\\u/g, ''), 16));
});
newStr = newStr.replace(/\\x([0-9a-f]{2})/gi, (_, c) => String.fromCharCode(parseInt(c, 16)));
newStr = newStr.replace(/\\[\d\d\d]{3}/gi, function (match) {
return String.fromCharCode(parseInt(match.replace(/\\/g, ''), 8));
});
newStr = newStr.replace(/\\[\d\d\d]{2}/gi, function (match) {
return String.fromCharCode(parseInt(match.replace(/\\/g, ''), 8));
});
return newStr;
};
/**
* Removes script tags from a text
*
* @param {string} txt The text to sanitize
* @returns {string} The safer text
*/
export const removeScript = (txt) => {
var rs = '';
var idx = 0;
while (idx >= 0) {
idx = txt.indexOf('<script');
if (idx >= 0) {
rs += txt.substr(0, idx);
txt = txt.substr(idx + 1);
idx = txt.indexOf('</script>');
if (idx >= 0) {
idx += 9;
txt = txt.substr(idx);
}
} else {
rs += txt;
idx = -1;
break;
}
}
let decodedText = removeEscapes(rs);
decodedText = decodedText.replaceAll(/script>/gi, '#');
decodedText = decodedText.replaceAll(/javascript:/gi, '#');
decodedText = decodedText.replaceAll(/javascript&colon/gi, '#');
decodedText = decodedText.replaceAll(/onerror=/gi, 'onerror:');
decodedText = decodedText.replaceAll(/<iframe/gi, '');
return decodedText;
};
const sanitizeMore = (text, config) => {
let txt = text;
let htmlLabels = true;
if (
config.flowchart &&
(config.flowchart.htmlLabels === false || config.flowchart.htmlLabels === 'false')
) {
htmlLabels = false;
}
if (htmlLabels) {
const level = config.securityLevel;
if (level === 'antiscript' || level === 'strict') {
txt = removeScript(txt);
} else if (level !== 'loose') {
// eslint-disable-line
txt = breakToPlaceholder(txt);
txt = txt.replace(/</g, '&lt;').replace(/>/g, '&gt;');
txt = txt.replace(/=/g, '&equals;');
txt = placeholderToBreak(txt);
}
}
return txt;
};
export const sanitizeText = (text, config) => {
if (!text) return text;
let txt = '';
if (config['dompurifyConfig']) {
txt = DOMPurify.sanitize(sanitizeMore(text, config), config['dompurifyConfig']);
} else {
txt = DOMPurify.sanitize(sanitizeMore(text, config));
}
return txt;
};
export const sanitizeTextOrArray = (a, config) => {
if (typeof a === 'string') return sanitizeText(a, config);
const f = (x) => sanitizeText(x, config);
return a.flat().map(f);
};
export const lineBreakRegex = /<br\s*\/?>/gi;
/**
* Whether or not a text has any linebreaks
*
* @param {string} text The text to test
* @returns {boolean} Whether or not the text has breaks
*/
export const hasBreaks = (text) => {
return lineBreakRegex.test(text);
};
/**
* Splits on <br> tags
*
* @param {string} text Text to split
* @returns {string[]} List of lines as strings
*/
export const splitBreaks = (text) => {
return text.split(lineBreakRegex);
};
/**
* Converts placeholders to linebreaks in HTML
*
* @param {string} s HTML with placeholders
* @returns {string} HTML with breaks instead of placeholders
*/
const placeholderToBreak = (s) => {
return s.replace(/#br#/g, '<br/>');
};
/**
* Opposite of `placeholderToBreak`, converts breaks to placeholders
*
* @param {string} s HTML string
* @returns {string} String with placeholders
*/
const breakToPlaceholder = (s) => {
return s.replace(lineBreakRegex, '#br#');
};
/**
* Gets the current URL
*
* @param {boolean} useAbsolute Whether to return the absolute URL or not
* @returns {string} The current URL
*/
const getUrl = (useAbsolute) => {
let url = '';
if (useAbsolute) {
url =
window.location.protocol +
'//' +
window.location.host +
window.location.pathname +
window.location.search;
url = url.replace(/\(/g, '\\(');
url = url.replace(/\)/g, '\\)');
}
return url;
};
/**
* Converts a string/boolean into a boolean
*
* @param {string | boolean} val String or boolean to convert
* @returns {boolean} The result from the input
*/
export const evaluate = (val) => (val === 'false' || val === false ? false : true);
/**
* Makes generics in typescript syntax
*
* @example <caption>Array of array of strings in typescript syntax</caption>
* // returns "Array<Array<string>>"
* parseGenericTypes('Array~Array~string~~');
*
* @param {string} text The text to convert
* @returns {string} The converted string
*/
export const parseGenericTypes = function (text) {
let cleanedText = text;
if (text.indexOf('~') != -1) {
cleanedText = cleanedText.replace('~', '<');
cleanedText = cleanedText.replace('~', '>');
return parseGenericTypes(cleanedText);
} else {
return cleanedText;
}
};
export default {
getRows,
sanitizeText,
sanitizeTextOrArray,
hasBreaks,
splitBreaks,
lineBreakRegex,
removeScript,
getUrl,
evaluate,
removeEscapes,
};

View File

@ -1,4 +1,4 @@
import { sanitizeText, removeScript, removeEscapes, parseGenericTypes } from './common';
import { sanitizeText, removeScript, parseGenericTypes } from './common';
describe('when securityLevel is antiscript, all script must be removed', function () {
/**
@ -6,7 +6,7 @@ describe('when securityLevel is antiscript, all script must be removed', functio
* @param {string} result The expected sanitized text
*/
function compareRemoveScript(original, result) {
expect(removeScript(original)).toEqual(result);
expect(removeScript(original).trim()).toEqual(result);
}
it('should remove all script block, script inline.', function () {
@ -29,70 +29,24 @@ describe('when securityLevel is antiscript, all script must be removed', functio
compareRemoveScript(
`This is a <a href="javascript:runHijackingScript();">clean link</a> + <a href="javascript:runHijackingScript();">clean link</a>
and <a href="javascript&colon;bipassedMining();">me too</a>`,
`This is a <a href="#runHijackingScript();">clean link</a> + <a href="#runHijackingScript();">clean link</a>
and <a href="#;bipassedMining();">me too</a>`
`This is a <a>clean link</a> + <a>clean link</a>
and <a>me too</a>`
);
});
it('should detect malicious images', function () {
compareRemoveScript(`<img onerror="alert('hello');">`, `<img onerror:"alert('hello');">`);
compareRemoveScript(`<img onerror="alert('hello');">`, `<img>`);
});
it('should detect iframes', function () {
compareRemoveScript(
`<iframe src="http://abc.com/script1.js"></iframe>
<iframe src="http://example.com/iframeexample"></iframe>`,
` src="http://abc.com/script1.js"></iframe>
src="http://example.com/iframeexample"></iframe>`
''
);
});
});
describe('remove escape code in text', function () {
it('should remove a unicode colon', function () {
const labelString = '\\u003A';
const result = removeEscapes(labelString);
expect(result).toEqual(':');
});
it('should remove a hex colon', function () {
const labelString = '\\x3A';
const result = removeEscapes(labelString);
expect(result).toEqual(':');
});
it('should remove a oct colon', function () {
const labelString = '\\72';
const result = removeEscapes(labelString);
expect(result).toEqual(':');
});
it('should remove a oct colon 3 numbers', function () {
const labelString = '\\072';
const result = removeEscapes(labelString);
expect(result).toEqual(':');
});
it('should remove multiple colons 3 numbers', function () {
const labelString = '\\072\\072\\72';
const result = removeEscapes(labelString);
expect(result).toEqual(':::');
});
it('should handle greater and smaller then', function () {
const labelString = '\\74\\076';
const result = removeEscapes(labelString);
expect(result).toEqual('<>');
});
it('should handle letters', function () {
const labelString = '\\u0073\\143ri\\x70\\u0074\\x3A';
const result = removeEscapes(labelString);
expect(result).toEqual('script:');
});
});
describe('Sanitize text', function () {
it('should remove script tag', function () {
const maliciousStr = 'javajavascript:script:alert(1)';
@ -106,7 +60,13 @@ describe('Sanitize text', function () {
describe('generic parser', function () {
it('should parse generic types', function () {
const result = parseGenericTypes('test~T~');
expect(result).toEqual('test<T>');
expect(parseGenericTypes('test~T~')).toEqual('test<T>');
expect(parseGenericTypes('test~Array~Array~string~~~')).toEqual('test<Array<Array<string>>>');
expect(parseGenericTypes('test~Array~Array~string[]~~~')).toEqual(
'test<Array<Array<string[]>>>'
);
expect(parseGenericTypes('test ~Array~Array~string[]~~~')).toEqual(
'test <Array<Array<string[]>>>'
);
});
});

View File

@ -0,0 +1,166 @@
import DOMPurify from 'dompurify';
import { MermaidConfig } from '../../config.type';
/**
* Gets the rows of lines in a string
*
* @param {string | undefined} s The string to check the lines for
* @returns {string[]} The rows in that string
*/
export const getRows = (s?: string): string[] => {
if (!s) return [''];
const str = breakToPlaceholder(s).replace(/\\n/g, '#br#');
return str.split('#br#');
};
/**
* Removes script tags from a text
*
* @param {string} txt The text to sanitize
* @returns {string} The safer text
*/
export const removeScript = (txt: string): string => {
return DOMPurify.sanitize(txt);
};
const sanitizeMore = (text: string, config: MermaidConfig) => {
if (config.flowchart?.htmlLabels !== false) {
const level = config.securityLevel;
if (level === 'antiscript' || level === 'strict') {
text = removeScript(text);
} else if (level !== 'loose') {
text = breakToPlaceholder(text);
text = text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
text = text.replace(/=/g, '&equals;');
text = placeholderToBreak(text);
}
}
return text;
};
export const sanitizeText = (text: string, config: MermaidConfig): string => {
if (!text) return text;
if (config.dompurifyConfig) {
text = DOMPurify.sanitize(sanitizeMore(text, config), config.dompurifyConfig).toString();
} else {
text = DOMPurify.sanitize(sanitizeMore(text, config));
}
return text;
};
export const sanitizeTextOrArray = (
a: string | string[] | string[][],
config: MermaidConfig
): string | string[] => {
if (typeof a === 'string') return sanitizeText(a, config);
// TODO: Refactor to avoid flat.
return a.flat().map((x: string) => sanitizeText(x, config));
};
export const lineBreakRegex = /<br\s*\/?>/gi;
/**
* Whether or not a text has any linebreaks
*
* @param {string} text The text to test
* @returns {boolean} Whether or not the text has breaks
*/
export const hasBreaks = (text: string): boolean => {
return lineBreakRegex.test(text);
};
/**
* Splits on <br> tags
*
* @param {string} text Text to split
* @returns {string[]} List of lines as strings
*/
export const splitBreaks = (text: string): string[] => {
return text.split(lineBreakRegex);
};
/**
* Converts placeholders to linebreaks in HTML
*
* @param {string} s HTML with placeholders
* @returns {string} HTML with breaks instead of placeholders
*/
const placeholderToBreak = (s: string): string => {
return s.replace(/#br#/g, '<br/>');
};
/**
* Opposite of `placeholderToBreak`, converts breaks to placeholders
*
* @param {string} s HTML string
* @returns {string} String with placeholders
*/
const breakToPlaceholder = (s: string): string => {
return s.replace(lineBreakRegex, '#br#');
};
/**
* Gets the current URL
*
* @param {boolean} useAbsolute Whether to return the absolute URL or not
* @returns {string} The current URL
*/
const getUrl = (useAbsolute: boolean): string => {
let url = '';
if (useAbsolute) {
url =
window.location.protocol +
'//' +
window.location.host +
window.location.pathname +
window.location.search;
url = url.replaceAll(/\(/g, '\\(');
url = url.replaceAll(/\)/g, '\\)');
}
return url;
};
/**
* Converts a string/boolean into a boolean
*
* @param {string | boolean} val String or boolean to convert
* @returns {boolean} The result from the input
*/
export const evaluate = (val?: string | boolean): boolean =>
val === false || ['false', 'null', '0'].includes(String(val).trim().toLowerCase()) ? false : true;
/**
* Makes generics in typescript syntax
*
* @example <caption>Array of array of strings in typescript syntax</caption>
* // returns "Array<Array<string>>"
* parseGenericTypes('Array~Array~string~~');
*
* @param {string} text The text to convert
* @returns {string} The converted string
*/
export const parseGenericTypes = function (text: string): string {
let cleanedText = text;
if (text.indexOf('~') !== -1) {
cleanedText = cleanedText.replace(/~([^~].*)/, '<$1');
cleanedText = cleanedText.replace(/~([^~]*)$/, '>$1');
return parseGenericTypes(cleanedText);
} else {
return cleanedText;
}
};
export default {
getRows,
sanitizeText,
sanitizeTextOrArray,
hasBreaks,
splitBreaks,
lineBreakRegex,
removeScript,
getUrl,
evaluate,
};

View File

@ -425,7 +425,7 @@ funs.push(setupToolTips);
*
* @param ver
*/
export const clear = function (ver) {
export const clear = function (ver = 'gen-1') {
vertices = {};
classes = {};
edges = [];
@ -436,7 +436,7 @@ export const clear = function (ver) {
subCount = 0;
tooltips = [];
firstGraphFlag = true;
version = ver || 'gen-1';
version = ver;
commonClear();
};
export const setGen = (ver) => {

View File

@ -2,7 +2,6 @@ import graphlib from 'graphlib';
import { select, curveLinear, selectAll } from 'd3';
import flowDb from './flowDb';
import flow from './parser/flow';
import { getConfig } from '../../config';
import { render } from '../../dagre-wrapper/index.js';
@ -363,11 +362,10 @@ export const draw = function (text, id, _version, diagObj) {
dir = 'TD';
}
const conf = getConfig().flowchart;
const { securityLevel, flowchart: conf } = getConfig();
const nodeSpacing = conf.nodeSpacing || 50;
const rankSpacing = conf.rankSpacing || 50;
const securityLevel = getConfig().securityLevel;
// Handle root and document for when rendering in sandbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {

View File

@ -296,7 +296,7 @@ export const getClasses = function (text, diagObj) {
export const draw = function (text, id, _version, diagObj) {
log.info('Drawing flowchart');
diagObj.db.clear();
const securityLevel = getConfig().securityLevel;
const { securityLevel, flowchart: conf } = getConfig();
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
@ -319,8 +319,6 @@ export const draw = function (text, id, _version, diagObj) {
if (typeof dir === 'undefined') {
dir = 'TD';
}
const conf = getConfig().flowchart;
const nodeSpacing = conf.nodeSpacing || 50;
const rankSpacing = conf.rankSpacing || 50;
@ -460,7 +458,7 @@ export const draw = function (text, id, _version, diagObj) {
}
// Add label rects for non html labels
if (!evaluate(conf.htmlLabels) || true) { // eslint-disable-line
if (!conf.htmlLabels) {
const labels = doc.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
for (let k = 0; k < labels.length; k++) {
const label = labels[k];

View File

@ -1,25 +1,21 @@
/**
* Returns the styles given options
*
* @param {{
* fontFamily: string;
* nodeTextColor: string;
* textColor: string;
* titleColor: string;
* mainBkg: string;
* nodeBorder: string;
* arrowheadColor: string;
* lineColor: string;
* edgeLabelBackground: string;
* clusterBkg: string;
* clusterBorder: string;
* tertiaryColor: string;
* border2: string;
* }} options
* The options for the styles
* @returns {string} The resulting styles
*/
const getStyles = (options) =>
/** Returns the styles given options */
export interface FlowChartStyleOptions {
arrowheadColor: string;
border2: string;
clusterBkg: string;
clusterBorder: string;
edgeLabelBackground: string;
fontFamily: string;
lineColor: string;
mainBkg: string;
nodeBorder: string;
nodeTextColor: string;
tertiaryColor: string;
textColor: string;
titleColor: string;
}
const getStyles = (options: FlowChartStyleOptions) =>
`.label {
font-family: ${options.fontFamily};
color: ${options.nodeTextColor || options.textColor};

View File

@ -230,31 +230,31 @@ const getStartDate = function (prevTime, dateFormat, str) {
return new Date();
};
const durationToDate = function (durationStatement, relativeTime) {
if (durationStatement !== null) {
switch (durationStatement[2]) {
case 'ms':
relativeTime.add(durationStatement[1], 'milliseconds');
break;
case 's':
relativeTime.add(durationStatement[1], 'seconds');
break;
case 'm':
relativeTime.add(durationStatement[1], 'minutes');
break;
case 'h':
relativeTime.add(durationStatement[1], 'hours');
break;
case 'd':
relativeTime.add(durationStatement[1], 'days');
break;
case 'w':
relativeTime.add(durationStatement[1], 'weeks');
break;
}
/**
* Parse a string as a moment duration.
*
* The string have to be compound by a value and a shorthand duration unit. For example `5d`
* representes 5 days.
*
* Shorthand unit supported are:
*
* - `y` for years
* - `M` for months
* - `w` for weeks
* - `d` for days
* - `h` for hours
* - `s` for seconds
* - `ms` for milliseconds
*
* @param {string} str - A string representing the duration.
* @returns {moment.Duration} A moment duration, including an invalid moment for invalid input string.
*/
const parseDuration = function (str) {
const statement = /^(\d+(?:\.\d+)?)([yMwdhms]|ms)$/.exec(str.trim());
if (statement !== null) {
return moment.duration(Number.parseFloat(statement[1]), statement[2]);
}
// Default date - now
return relativeTime.toDate();
return moment.duration.invalid();
};
const getEndDate = function (prevTime, dateFormat, str, inclusive) {
@ -270,7 +270,12 @@ const getEndDate = function (prevTime, dateFormat, str, inclusive) {
return mDate.toDate();
}
return durationToDate(/^([\d]+)([wdhms]|ms)$/.exec(str.trim()), moment(prevTime));
const endTime = moment(prevTime);
const duration = parseDuration(str);
if (duration.isValid()) {
endTime.add(duration);
}
return endTime.toDate();
};
let taskCnt = 0;
@ -666,7 +671,7 @@ export default {
setLink,
getLinks,
bindFunctions,
durationToDate,
parseDuration,
isInvalidDate,
};

View File

@ -6,13 +6,16 @@ describe('when using the ganttDb', function () {
ganttDb.clear();
});
describe('when using relative times', function () {
describe('when using duration', function () {
it.each`
diff | date | expected
${' 1d'} | ${moment('2019-01-01')} | ${moment('2019-01-02').toDate()}
${' 1w'} | ${moment('2019-01-01')} | ${moment('2019-01-08').toDate()}
`('should add $diff to $date resulting in $expected', ({ diff, date, expected }) => {
expect(ganttDb.durationToDate(diff, date)).toEqual(expected);
str | expected
${'1d'} | ${moment.duration(1, 'd')}
${'2w'} | ${moment.duration(2, 'w')}
${'1ms'} | ${moment.duration(1, 'ms')}
${'0.1s'} | ${moment.duration(100, 'ms')}
${'1f'} | ${moment.duration.invalid()}
`('should $str resulting in $expected duration', ({ str, expected }) => {
expect(ganttDb.parseDuration(str)).toEqual(expected);
});
});
@ -106,7 +109,7 @@ describe('when using the ganttDb', function () {
ganttDb.addTask('test2', 'id2,after id1,5ms');
ganttDb.addSection('testa2');
ganttDb.addTask('test3', 'id3,20,10ms');
ganttDb.addTask('test4', 'id4,after id3,5ms');
ganttDb.addTask('test4', 'id4,after id3,0.005s');
const tasks = ganttDb.getTasks();

View File

@ -148,16 +148,9 @@ export const branch = function (name, order) {
}
};
/**
* Creates a merge commit.
*
* @param {string} otherBranch - Target branch to merge to.
* @param {string} [tag] - Git tag to use on this merge commit.
* @param {string} [id] - Git commit id.
*/
export const merge = function (otherBranch, tag, id) {
export const merge = function (otherBranch, custom_id, override_type, custom_tag) {
otherBranch = common.sanitizeText(otherBranch, configApi.getConfig());
id = common.sanitizeText(id, configApi.getConfig());
custom_id = common.sanitizeText(custom_id, configApi.getConfig());
const currentCommit = commits[branches[curBranch]];
const otherCommit = commits[branches[otherBranch]];
@ -216,6 +209,23 @@ export const merge = function (otherBranch, tag, id) {
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['branch abc'],
};
throw error;
} else if (custom_id && typeof commits[custom_id] !== 'undefined') {
let error = new Error(
'Incorrect usage of "merge". Commit with id:' +
custom_id +
' already exists, use different custom Id'
);
error.hash = {
text: 'merge ' + otherBranch + custom_id + override_type + custom_tag,
token: 'merge ' + otherBranch + custom_id + override_type + custom_tag,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: [
'merge ' + otherBranch + ' ' + custom_id + '_UNIQUE ' + override_type + ' ' + custom_tag,
],
};
throw error;
}
// if (isReachableFrom(currentCommit, otherCommit)) {
@ -228,13 +238,15 @@ export const merge = function (otherBranch, tag, id) {
// } else {
// create merge commit
const commit = {
id: id || seq + '-' + getId(),
id: custom_id ? custom_id : seq + '-' + getId(),
message: 'merged branch ' + otherBranch + ' into ' + curBranch,
seq: seq++,
parents: [head == null ? null : head.id, branches[otherBranch]],
branch: curBranch,
type: commitType.MERGE,
tag: tag ? tag : '',
customType: override_type,
customId: custom_id ? true : false,
tag: custom_tag ? custom_tag : '',
};
head = commit;
commits[commit.id] = commit;

View File

@ -1,8 +0,0 @@
const detector = (txt) => {
if (txt.match(/^\s*gitGraph/)) {
return 'gitGraph';
}
return null;
};
export default detector;

View File

@ -0,0 +1,5 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const gitGraphDetector: DiagramDetector = (txt) => {
return txt.match(/^\s*gitGraph/) !== null;
};

View File

@ -4,7 +4,6 @@ import gitGraphAst from './gitGraphAst';
import { parser } from './parser/gitGraph';
//import randomString from 'crypto-random-string';
//import cryptoRandomString from 'crypto-random-string';
import { logger } from '../../logger';
//jest.mock('crypto-random-string');
@ -496,7 +495,7 @@ describe('when parsing a gitGraph', function () {
]);
});
it('should handle merge ids', function () {
it('should handle merge with custom ids, tags and typr', function () {
const str = `gitGraph:
commit
branch testBranch
@ -510,7 +509,7 @@ describe('when parsing a gitGraph', function () {
commit
checkout main
%% Merge ID and Tag (reverse order)
merge testBranch2 id: "4-444" tag: "merge-tag2"
merge testBranch2 id: "4-444" tag: "merge-tag2" type:HIGHLIGHT
branch testBranch3
checkout testBranch3
commit
@ -553,6 +552,8 @@ describe('when parsing a gitGraph', function () {
expect(testBranch2Merge.parents).toStrictEqual([testBranchMerge.id, testBranch2Commit.id]);
expect(testBranch2Merge.tag).toBe('merge-tag2');
expect(testBranch2Merge.id).toBe('4-444');
expect(testBranch2Merge.customType).toBe(2);
expect(testBranch2Merge.customId).toBe(true);
expect(testBranch3Merge.branch).toBe('main');
expect(testBranch3Merge.parents).toStrictEqual([testBranch2Merge.id, testBranch3Commit.id]);
@ -687,6 +688,27 @@ describe('when parsing a gitGraph', function () {
expect(e.message).toBe('Incorrect usage of "merge". Cannot merge a branch to itself');
}
});
it('should throw error when using existing id as merge ID', function () {
const str = `gitGraph
commit id: "1-111"
branch testBranch
commit id: "2-222"
commit id: "3-333"
checkout main
merge testBranch id: "1-111"
`;
try {
parser.parse(str);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe(
'Incorrect usage of "merge". Commit with id:1-111 already exists, use different custom Id'
);
}
});
it('should throw error when trying to merge branches having same heads', function () {
const str = `gitGraph
commit

View File

@ -91,7 +91,9 @@ const drawCommits = (svg, commits, modifyGraph) => {
// Don't draw the commits now but calculate the positioning which is used by the branch lines etc.
if (modifyGraph) {
let typeClass;
switch (commit.type) {
let commitSymbolType =
typeof commit.customType !== 'undefined' ? commit.customType : commit.type;
switch (commitSymbolType) {
case commitType.NORMAL:
typeClass = 'commit-normal';
break;
@ -111,7 +113,7 @@ const drawCommits = (svg, commits, modifyGraph) => {
typeClass = 'commit-normal';
}
if (commit.type === commitType.HIGHLIGHT) {
if (commitSymbolType === commitType.HIGHLIGHT) {
const circle = gBullets.append('rect');
circle.attr('x', x - 10);
circle.attr('y', y - 10);
@ -135,7 +137,7 @@ const drawCommits = (svg, commits, modifyGraph) => {
branchPos[commit.branch].index % THEME_COLOR_LIMIT
} ${typeClass}-inner`
);
} else if (commit.type === commitType.CHERRY_PICK) {
} else if (commitSymbolType === commitType.CHERRY_PICK) {
gBullets
.append('circle')
.attr('cx', x)
@ -181,7 +183,7 @@ const drawCommits = (svg, commits, modifyGraph) => {
'class',
`commit ${commit.id} commit${branchPos[commit.branch].index % THEME_COLOR_LIMIT}`
);
if (commit.type === commitType.MERGE) {
if (commitSymbolType === commitType.MERGE) {
const circle2 = gBullets.append('circle');
circle2.attr('cx', x);
circle2.attr('cy', y);
@ -193,7 +195,7 @@ const drawCommits = (svg, commits, modifyGraph) => {
}`
);
}
if (commit.type === commitType.REVERSE) {
if (commitSymbolType === commitType.REVERSE) {
const cross = gBullets.append('path');
cross
.attr('d', `M ${x - 5},${y - 5}L${x + 5},${y + 5}M${x - 5},${y + 5}L${x + 5},${y - 5}`)
@ -215,7 +217,12 @@ const drawCommits = (svg, commits, modifyGraph) => {
const px = 4;
const py = 2;
// Draw the commit label
if (commit.type !== commitType.CHERRY_PICK && gitGraphConfig.showCommitLabel) {
if (
commit.type !== commitType.CHERRY_PICK &&
((commit.customId && commit.type === commitType.MERGE) ||
commit.type !== commitType.MERGE) &&
gitGraphConfig.showCommitLabel
) {
const wrapper = gLabels.append('g');
const labelBkg = wrapper.insert('rect').attr('class', 'commit-label-bkg');
@ -336,7 +343,7 @@ const findLane = (y1, y2, _depth) => {
return candidate;
}
const diff = Math.abs(y1 - y2);
return findLane(y1, y2 - diff / 5, depth);
return findLane(y1, y2 - diff / 5, depth + 1);
};
/**

View File

@ -121,11 +121,22 @@ cherryPickStatement
;
mergeStatement
: MERGE ID {yy.merge($2)}
| MERGE ID COMMIT_TAG STR {yy.merge($2, $4)}
| MERGE ID COMMIT_ID STR {yy.merge($2, '', $4)}
| MERGE ID COMMIT_TAG STR COMMIT_ID STR {yy.merge($2, $4, $6)}
| MERGE ID COMMIT_ID STR COMMIT_TAG STR {yy.merge($2, $6, $4)}
: MERGE ID {yy.merge($2,'','','')}
| MERGE ID COMMIT_ID STR {yy.merge($2, $4,'','')}
| MERGE ID COMMIT_TYPE commitType {yy.merge($2,'', $4,'')}
| MERGE ID COMMIT_TAG STR {yy.merge($2, '','',$4)}
| MERGE ID COMMIT_TAG STR COMMIT_ID STR {yy.merge($2, $6,'', $4)}
| MERGE ID COMMIT_TAG STR COMMIT_TYPE commitType {yy.merge($2, '',$6, $4)}
| MERGE ID COMMIT_TYPE commitType COMMIT_TAG STR {yy.merge($2, '',$4, $6)}
| MERGE ID COMMIT_ID STR COMMIT_TYPE commitType {yy.merge($2, $4, $6, '')}
| MERGE ID COMMIT_ID STR COMMIT_TAG STR {yy.merge($2, $4, '', $6)}
| MERGE ID COMMIT_TYPE commitType COMMIT_ID STR {yy.merge($2, $6,$4, '')}
| MERGE ID COMMIT_ID STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.merge($2, $4, $6, $8)}
| MERGE ID COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_ID STR {yy.merge($2, $8, $4, $6)}
| MERGE ID COMMIT_ID STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.merge($2, $4, $8, $6)}
| MERGE ID COMMIT_TYPE commitType COMMIT_ID STR COMMIT_TAG STR {yy.merge($2, $6, $4, $8)}
| MERGE ID COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.merge($2, $8, $6, $4)}
| MERGE ID COMMIT_TAG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.merge($2, $6, $8, $4)}
;
commitStatement

View File

@ -15,7 +15,7 @@ export const draw = (text, id, version, diagObj) => {
try {
// const parser = infoParser.parser;
// parser.yy = db;
log.debug('Renering info diagram\n' + text);
log.debug('Rendering info diagram\n' + text);
const securityLevel = getConfig().securityLevel;
// Handle root and Document for when rendering in sanbox mode
@ -49,6 +49,7 @@ export const draw = (text, id, version, diagObj) => {
svg.attr('width', 400);
// svg.attr('viewBox', '0 0 300 150');
} catch (e) {
console.error(e);
log.error('Error while rendering info diagram');
log.error(e.message);
}

View File

@ -1,8 +0,0 @@
const detector = (txt) => {
if (txt.match(/^\s*mindmap/)) {
return 'mindmap';
}
return null;
};
export default detector;

View File

@ -0,0 +1,5 @@
import { DiagramDetector } from '../../diagram-api/detectType';
export const mindmapDetector: DiagramDetector = (txt) => {
return txt.match(/^\s*mindmap/) !== null;
};

View File

@ -588,8 +588,8 @@ function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoop
* @param {any} diagObj A stanard diagram containing the db and the text and type etc of the diagram
*/
export const draw = function (_text, id, _version, diagObj) {
conf = configApi.getConfig().sequence;
const securityLevel = configApi.getConfig().securityLevel;
const { securityLevel, sequence } = configApi.getConfig();
conf = sequence;
// Handle root and Document for when rendering in sanbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {

View File

@ -248,12 +248,10 @@ export const draw = function (text, id, _version, diag) {
dir = 'LR';
}
const conf = getConfig().state;
const { securityLevel, state: conf } = getConfig();
const nodeSpacing = conf.nodeSpacing || 50;
const rankSpacing = conf.rankSpacing || 50;
const securityLevel = getConfig().securityLevel;
log.info(diag.db.getRootDocV2());
diag.db.extract(diag.db.getRootDocV2());
log.info(diag.db.getRootDocV2());

View File

@ -44,8 +44,9 @@ function drawActorLegend(diagram) {
yPos += 20;
});
}
// TODO: Cleanup?
const conf = getConfig().journey;
const LEFT_MARGIN = getConfig().journey.leftMargin;
const LEFT_MARGIN = conf.leftMargin;
export const draw = function (text, id, version, diagObj) {
const conf = getConfig().journey;
diagObj.db.clear();

View File

@ -1,29 +1,26 @@
/** Created by knut on 14-12-11. */
import { select } from 'd3';
import { log } from './logger';
import { getErrorMessage } from './utils';
const conf = {};
let conf = {};
/**
* Merges the value of `conf` with the passed `cnf`
*
* @param {object} cnf Config to merge
*/
export const setConf = function (cnf) {
const keys = Object.keys(cnf);
keys.forEach(function (key) {
conf[key] = cnf[key];
});
export const setConf = function (cnf: any) {
conf = { ...conf, ...cnf };
};
/**
* Draws a an info picture in the tag with id: id based on the graph definition in text.
*
* @param {string} id The text for the error
* @param {string} ver The version
* @param {string} mermaidVersion The version
*/
export const draw = (id, ver) => {
export const draw = (id: string, mermaidVersion: string) => {
try {
log.debug('Renering svg for syntax error\n');
@ -86,14 +83,14 @@ export const draw = (id, ver) => {
.attr('y', 400)
.attr('font-size', '100px')
.style('text-anchor', 'middle')
.text('mermaid version ' + ver);
.text('mermaid version ' + mermaidVersion);
svg.attr('height', 100);
svg.attr('width', 400);
svg.attr('viewBox', '768 0 512 512');
} catch (e) {
log.error('Error while rendering info diagram');
log.error(e.message);
log.error(getErrorMessage(e));
}
};

View File

@ -1,5 +1,5 @@
let interactionFunctions = [];
export const addFunction = (func) => {
let interactionFunctions: (() => {})[] = [];
export const addFunction = (func: () => {}) => {
interactionFunctions.push(func);
};
export const attachFunctions = () => {

View File

@ -1,9 +1,9 @@
import moment from 'moment-mini';
/** @typedef {'debug' | 'info' | 'warn' | 'error' | 'fatal'} LogLevel A log level */
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
/** @type {Object<LogLevel, number>} */
export const LEVELS = {
export const LEVELS: Record<LogLevel, number> = {
trace: 0,
debug: 1,
info: 2,
warn: 3,
@ -11,12 +11,13 @@ export const LEVELS = {
fatal: 5,
};
export const log = {
debug: () => {},
info: () => {},
warn: () => {},
error: () => {},
fatal: () => {},
export const log: Record<keyof typeof LEVELS, typeof console.log> = {
trace: (..._args: any[]) => {},
debug: (..._args: any[]) => {},
info: (..._args: any[]) => {},
warn: (..._args: any[]) => {},
error: (..._args: any[]) => {},
fatal: (..._args: any[]) => {},
};
/**
@ -24,11 +25,12 @@ export const log = {
*
* @param {LogLevel} [level="fatal"] The level to set the logging to. Default is `"fatal"`
*/
export const setLogLevel = function (level = 'fatal') {
if (isNaN(level)) {
export const setLogLevel = function (level: keyof typeof LEVELS | number | string = 'fatal') {
let numericLevel: number = LEVELS.fatal;
if (typeof level === 'string') {
level = level.toLowerCase();
if (LEVELS[level] !== undefined) {
level = LEVELS[level];
if (level in LEVELS) {
numericLevel = LEVELS[level as keyof typeof LEVELS];
}
}
log.trace = () => {};
@ -37,31 +39,36 @@ export const setLogLevel = function (level = 'fatal') {
log.warn = () => {};
log.error = () => {};
log.fatal = () => {};
if (level <= LEVELS.fatal) {
if (numericLevel <= LEVELS.fatal) {
log.fatal = console.error
? console.error.bind(console, format('FATAL'), 'color: orange')
: console.log.bind(console, '\x1b[35m', format('FATAL'));
}
if (level <= LEVELS.error) {
if (numericLevel <= LEVELS.error) {
log.error = console.error
? console.error.bind(console, format('ERROR'), 'color: orange')
: console.log.bind(console, '\x1b[31m', format('ERROR'));
}
if (level <= LEVELS.warn) {
if (numericLevel <= LEVELS.warn) {
log.warn = console.warn
? console.warn.bind(console, format('WARN'), 'color: orange')
: console.log.bind(console, `\x1b[33m`, format('WARN'));
}
if (level <= LEVELS.info) {
log.info = console.info // ? console.info.bind(console, '\x1b[34m', format('INFO'), 'color: blue')
if (numericLevel <= LEVELS.info) {
log.info = console.info
? console.info.bind(console, format('INFO'), 'color: lightblue')
: console.log.bind(console, '\x1b[34m', format('INFO'));
}
if (level <= LEVELS.debug) {
if (numericLevel <= LEVELS.debug) {
log.debug = console.debug
? console.debug.bind(console, format('DEBUG'), 'color: lightgreen')
: console.log.bind(console, '\x1b[32m', format('DEBUG'));
}
if (numericLevel <= LEVELS.trace) {
log.trace = console.debug
? console.debug.bind(console, format('TRACE'), 'color: lightgreen')
: console.log.bind(console, '\x1b[32m', format('TRACE'));
}
};
/**
@ -70,7 +77,7 @@ export const setLogLevel = function (level = 'fatal') {
* @param {LogLevel} level The level for the log format
* @returns {string} The format with the timestamp and log level
*/
const format = (level) => {
const format = (level: string): string => {
const time = moment().format('ss.SSS');
return `%c${time} : ${level} : `;
};

View File

@ -227,5 +227,14 @@ describe('when using mermaid and ', function () {
'end';
expect(() => mermaid.parse(text)).toThrow();
});
it('should return false for invalid definition WITH a parseError() callback defined', function () {
let parseErrorWasCalled = false;
mermaid.setParseErrorHandler(() => {
parseErrorWasCalled = true;
});
expect(mermaid.parse('this is not a mermaid diagram definition')).toEqual(false);
expect(parseErrorWasCalled).toEqual(true);
});
});
});

View File

@ -2,9 +2,11 @@
* Web page integration module for the mermaid framework. It uses the mermaidAPI for mermaid
* functionality and to render the diagrams to svg code.
*/
import { MermaidConfig } from './config.type';
import { log } from './logger';
import mermaidAPI from './mermaidAPI';
import utils from './utils';
import { mermaidAPI } from './mermaidAPI';
import { isDetailedError } from './utils';
/**
* ## init
@ -29,81 +31,70 @@ import utils from './utils';
*
* Renders the mermaid diagrams
*/
const init = function () {
const init = function (
config?: MermaidConfig,
nodes?: string | HTMLElement | NodeListOf<HTMLElement>,
callback?: Function
) {
try {
initThrowsErrors(...arguments);
initThrowsErrors(config, nodes, callback);
} catch (e) {
log.warn('Syntax Error rendering');
log.warn(e.str);
if (this.parseError) {
this.parseError(e);
if (isDetailedError(e)) {
log.warn(e.str);
}
if (mermaid.parseError) {
mermaid.parseError(e);
}
}
};
const initThrowsErrors = function () {
const initThrowsErrors = function (
config?: MermaidConfig,
nodes?: string | HTMLElement | NodeListOf<HTMLElement>,
callback?: Function
) {
const conf = mermaidAPI.getConfig();
// console.log('Starting rendering diagrams (init) - mermaid.init', conf);
let nodes;
if (arguments.length >= 2) {
/*! sequence config was passed as #1 */
if (typeof arguments[0] !== 'undefined') {
mermaid.sequenceConfig = arguments[0];
}
nodes = arguments[1];
} else {
nodes = arguments[0];
if (config) {
// This is a legacy way of setting config. It is not documented and should be removed in the future.
// @ts-ignore
mermaid.sequenceConfig = config;
}
// if last argument is a function this is the callback function
let callback;
if (typeof arguments[arguments.length - 1] === 'function') {
callback = arguments[arguments.length - 1];
log.debug('Callback function found');
log.debug(`${!callback ? 'No ' : ''}Callback function found`);
let nodesToProcess: NodeListOf<HTMLElement>;
if (typeof nodes === 'undefined') {
nodesToProcess = document.querySelectorAll('.mermaid');
} else if (typeof nodes === 'string') {
nodesToProcess = document.querySelectorAll(nodes);
} else if (nodes instanceof HTMLElement) {
nodesToProcess = new NodeList() as NodeListOf<HTMLElement>;
nodesToProcess[0] = nodes;
} else if (nodes instanceof NodeList) {
nodesToProcess = nodes;
} else {
if (typeof conf.mermaid !== 'undefined') {
if (typeof conf.mermaid.callback === 'function') {
callback = conf.mermaid.callback;
log.debug('Callback function found');
} else {
log.debug('No Callback function found');
}
}
}
nodes =
nodes === undefined
? document.querySelectorAll('.mermaid')
: typeof nodes === 'string'
? document.querySelectorAll(nodes)
: nodes instanceof window.Node
? [nodes]
: nodes; // Last case - sequence config was passed pick next
log.debug('Start On Load before: ' + mermaid.startOnLoad);
if (typeof mermaid.startOnLoad !== 'undefined') {
log.debug('Start On Load inner: ' + mermaid.startOnLoad);
mermaidAPI.updateSiteConfig({ startOnLoad: mermaid.startOnLoad });
throw new Error('Invalid argument nodes for mermaid.init');
}
if (typeof mermaid.ganttConfig !== 'undefined') {
mermaidAPI.updateSiteConfig({ gantt: mermaid.ganttConfig });
log.debug(`Found ${nodesToProcess.length} diagrams`);
if (typeof config?.startOnLoad !== 'undefined') {
log.debug('Start On Load: ' + config?.startOnLoad);
mermaidAPI.updateSiteConfig({ startOnLoad: config?.startOnLoad });
}
const idGenerator = new utils.initIdGenerator(conf.deterministicIds, conf.deterministicIDSeed);
let txt;
for (let i = 0; i < nodes.length; i++) {
// element is the current div with mermaid class
const element = nodes[i];
// element is the current div with mermaid class
for (const element of Array.from(nodesToProcess)) {
/*! Check if previously processed */
if (!element.getAttribute('data-processed')) {
element.setAttribute('data-processed', true);
} else {
if (element.getAttribute('data-processed')) {
continue;
}
element.setAttribute('data-processed', 'true');
const id = `mermaid-${idGenerator.next()}`;
@ -124,7 +115,7 @@ const initThrowsErrors = function () {
mermaidAPI.render(
id,
txt,
(svgCode, bindFunctions) => {
(svgCode: string, bindFunctions?: (el: Element) => void) => {
element.innerHTML = svgCode;
if (typeof callback !== 'undefined') {
callback(id);
@ -135,24 +126,15 @@ const initThrowsErrors = function () {
);
} catch (error) {
log.warn('Catching Error (bootstrap)');
// @ts-ignore
// TODO: We should be throwing an error object.
throw { error, message: error.str };
}
}
};
const initialize = function (config) {
// mermaidAPI.reset();
if (typeof config.mermaid !== 'undefined') {
if (typeof config.mermaid.startOnLoad !== 'undefined') {
mermaid.startOnLoad = config.mermaid.startOnLoad;
}
if (typeof config.mermaid.htmlLabels !== 'undefined') {
mermaid.htmlLabels =
config.mermaid.htmlLabels === 'false' || config.mermaid.htmlLabels === false ? false : true;
}
}
const initialize = function (config: MermaidConfig) {
mermaidAPI.initialize(config);
// mermaidAPI.reset();
};
/**
@ -160,22 +142,11 @@ const initialize = function (config) {
* configuration for mermaid rendering and calls init for rendering the mermaid diagrams on the page.
*/
const contentLoaded = function () {
let config;
if (mermaid.startOnLoad) {
// No config found, do check API config
config = mermaidAPI.getConfig();
if (config.startOnLoad) {
const { startOnLoad } = mermaidAPI.getConfig();
if (startOnLoad) {
mermaid.init();
}
} else {
if (typeof mermaid.startOnLoad === 'undefined') {
log.debug('In start, no config');
config = mermaidAPI.getConfig();
if (config.startOnLoad) {
mermaid.init();
}
}
}
};
@ -206,24 +177,37 @@ if (typeof document !== 'undefined') {
*
* @param {function (err, hash)} newParseErrorHandler New parseError() callback.
*/
const setParseErrorHandler = function (newParseErrorHandler) {
const setParseErrorHandler = function (newParseErrorHandler: (err: any, hash: any) => void) {
mermaid.parseError = newParseErrorHandler;
};
const mermaid = {
const parse = (txt: string) => {
return mermaidAPI.parse(txt, mermaid.parseError);
};
const mermaid: {
startOnLoad: boolean;
diagrams: any;
parseError?: Function;
mermaidAPI: typeof mermaidAPI;
parse: typeof parse;
render: typeof mermaidAPI.render;
init: typeof init;
initThrowsErrors: typeof initThrowsErrors;
initialize: typeof initialize;
contentLoaded: typeof contentLoaded;
setParseErrorHandler: typeof setParseErrorHandler;
} = {
startOnLoad: true,
htmlLabels: true,
diagrams: {},
mermaidAPI,
parse: mermaidAPI != undefined ? mermaidAPI.parse : null,
render: mermaidAPI != undefined ? mermaidAPI.render : null,
parse,
render: mermaidAPI.render,
init,
initThrowsErrors,
initialize,
parseError: undefined,
contentLoaded,
setParseErrorHandler,
};

View File

@ -47,9 +47,12 @@ describe('when using mermaidAPI and ', function () {
mermaidAPI.setConfig({ securityLevel: 'strict', logLevel: 1 });
expect(mermaidAPI.getConfig().logLevel).toBe(1);
expect(mermaidAPI.getConfig().securityLevel).toBe('strict');
mermaidAPI.globalReset();
mermaidAPI.reset();
expect(mermaidAPI.getConfig().logLevel).toBe(0);
expect(mermaidAPI.getConfig().securityLevel).toBe('loose');
mermaidAPI.globalReset();
expect(mermaidAPI.getConfig().logLevel).toBe(5);
expect(mermaidAPI.getConfig().securityLevel).toBe('strict');
});
it('should prevent changes to site defaults (sneaky)', function () {
@ -129,15 +132,14 @@ describe('when using mermaidAPI and ', function () {
it('should not throw for a valid definition', function () {
expect(() => mermaidAPI.parse('graph TD;A--x|text including URL space|B;')).not.toThrow();
});
it('should return false for invalid definition WITH a parseError() callback defined', function () {
var parseErrorWasCalled = false;
it('it should return false for invalid definition WITH a parseError() callback defined', function () {
let parseErrorWasCalled = false;
// also test setParseErrorHandler() call working to set mermaid.parseError
mermaid.setParseErrorHandler(function (error, hash) {
// got here.
parseErrorWasCalled = true;
});
expect(mermaid.parseError).not.toEqual(undefined);
expect(mermaidAPI.parse('this is not a mermaid diagram definition')).toEqual(false);
expect(
mermaidAPI.parse('this is not a mermaid diagram definition', () => {
parseErrorWasCalled = true;
})
).toEqual(false);
expect(parseErrorWasCalled).toEqual(true);
});
it('should return true for valid definition', function () {

View File

@ -17,19 +17,14 @@
*/
import { select } from 'd3';
import { compile, serialize, stringify } from 'stylis';
// @ts-ignore
import pkg from '../package.json';
import * as configApi from './config';
import addDiagrams from './diagram-api/diagram-orchestration';
import { addDiagrams } from './diagram-api/diagram-orchestration';
import classDb from './diagrams/class/classDb';
import flowDb from './diagrams/flowchart/flowDb';
import flowRenderer from './diagrams/flowchart/flowRenderer';
import flowRendererV2 from './diagrams/flowchart/flowRenderer-v2';
import ganttDb from './diagrams/gantt/ganttDb';
import ganttRenderer from './diagrams/gantt/ganttRenderer';
import sequenceRenderer from './diagrams/sequence/sequenceRenderer';
import stateRenderer from './diagrams/state/stateRenderer';
import stateRendererV2 from './diagrams/state/stateRenderer-v2';
import journeyRenderer from './diagrams/user-journey/journeyRenderer';
import Diagram from './Diagram';
import errorRenderer from './errorRenderer';
import { attachFunctions } from './interactionDb';
@ -37,50 +32,22 @@ import { log, setLogLevel } from './logger';
import getStyles from './styles';
import theme from './themes';
import utils, { directiveSanitizer } from './utils';
import assignWithDepth from './assignWithDepth';
import DOMPurify from 'dompurify';
import mermaid from './mermaid';
import { MermaidConfig } from './config.type';
import { evaluate } from './diagrams/common/common';
let hasLoadedDiagrams = false;
/**
* @param text
* @param dia
* @returns {any}
*/
function parse(text, dia) {
function parse(text: string, parseError?: Function): boolean {
if (!hasLoadedDiagrams) {
addDiagrams();
hasLoadedDiagrams = true;
}
var parseEncounteredException = false;
try {
const diag = dia ? dia : new Diagram(text);
diag.db.clear();
return diag.parse(text);
} catch (error) {
parseEncounteredException = true;
// Is this the correct way to access mermiad's parseError()
// method ? (or global.mermaid.parseError()) ?
if (mermaid.parseError) {
if (error.str != undefined) {
// handle case where error string and hash were
// wrapped in object like`const error = { str, hash };`
mermaid.parseError(error.str, error.hash);
} else {
// assume it is just error string and pass it on
mermaid.parseError(error);
}
} else {
// No mermaid.parseError() handler defined, so re-throw it
throw error;
}
}
return !parseEncounteredException;
const diagram = new Diagram(text, parseError);
return diagram.parse(text, parseError);
}
export const encodeEntities = function (text) {
export const encodeEntities = function (text: string): string {
let txt = text;
txt = txt.replace(/style.*:\S*#.*;/g, function (s) {
@ -106,7 +73,7 @@ export const encodeEntities = function (text) {
return txt;
};
export const decodeEntities = function (text) {
export const decodeEntities = function (text: string): string {
let txt = text;
txt = txt.replace(/fl°°/g, function () {
@ -137,18 +104,24 @@ export const decodeEntities = function (text) {
* });
* ```
*
* @param {any} id The id of the element to be rendered
* @param {any} _txt The graph definition
* @param {any} cb Callback which is called after rendering is finished with the svg code as inparam.
* @param {any} container Selector to element in which a div with the graph temporarily will be
* @param {string} id The id of the element to be rendered
* @param {string} text The graph definition
* @param {(svgCode: string, bindFunctions?: (element: Element) => void) => void} cb Callback which
* is called after rendering is finished with the svg code as inparam.
* @param {Element} container Selector to element in which a div with the graph temporarily will be
* inserted. If one is provided a hidden div will be inserted in the body of the page instead. The
* element will be removed when rendering is completed.
* @returns {any}
* @returns {void}
*/
const render = function (id, _txt, cb, container) {
const render = function (
id: string,
text: string,
cb: (svgCode: string, bindFunctions?: (element: Element) => void) => void,
container?: Element
): void {
configApi.reset();
let txt = _txt.replace(/\r\n?/g, '\n'); // parser problems on CRLF ignore all CR and leave LF;;
const graphInit = utils.detectInit(txt);
text = text.replace(/\r\n?/g, '\n'); // parser problems on CRLF ignore all CR and leave LF;;
const graphInit = utils.detectInit(text);
if (graphInit) {
directiveSanitizer(graphInit);
configApi.addDirective(graphInit);
@ -158,28 +131,18 @@ const render = function (id, _txt, cb, container) {
log.debug(cnf);
// Check the maximum allowed text size
if (_txt.length > cnf.maxTextSize) {
txt = 'graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa';
if (text.length > cnf.maxTextSize!) {
text = 'graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa';
}
let root = select('body');
let root: any = select('body');
// In regular execution the container will be the div with a mermaid class
if (typeof container !== 'undefined') {
if (cnf.securityLevel === 'sandbox') {
// IF we are in sandboxed mode, we do everyting mermaid related
// in a sandboxed div
const iframe = select('body')
.append('iframe')
.attr('id', 'i' + id)
.attr('style', 'width: 100%; height: 100%;')
.attr('sandbox', '');
root = select(iframe.nodes()[0].contentDocument.body);
root.node().style.margin = 0;
}
// A container was provided by the caller
container.innerHTML = '';
if (container) {
container.innerHTML = '';
}
if (cnf.securityLevel === 'sandbox') {
// IF we are in sandboxed mode, we do everyting mermaid related
@ -190,7 +153,7 @@ const render = function (id, _txt, cb, container) {
.attr('style', 'width: 100%; height: 100%;')
.attr('sandbox', '');
// const iframeBody = ;
root = select(iframe.nodes()[0].contentDocument.body);
root = select(iframe.nodes()[0]!.contentDocument!.body);
root.node().style.margin = 0;
} else {
root = select(container);
@ -217,11 +180,12 @@ const render = function (id, _txt, cb, container) {
// Remove previous tpm element if it exists
let element;
if (cnf.securityLevel !== 'sandbox') {
element = document.querySelector('#' + 'd' + id);
if (cnf.securityLevel === 'sandbox') {
element = document.querySelector('#i' + id);
} else {
element = document.querySelector('#' + 'i' + id);
element = document.querySelector('#d' + id);
}
if (element) {
element.remove();
}
@ -238,7 +202,7 @@ const render = function (id, _txt, cb, container) {
.attr('style', 'width: 100%; height: 100%;')
.attr('sandbox', '');
root = select(iframe.nodes()[0].contentDocument.body);
root = select(iframe.nodes()[0]!.contentDocument!.body);
root.node().style.margin = 0;
} else {
root = select('body');
@ -256,10 +220,10 @@ const render = function (id, _txt, cb, container) {
.append('g');
}
txt = encodeEntities(txt);
text = encodeEntities(text);
// Important that we do not create the diagram until after the directives have been included
const diag = new Diagram(txt);
const diag = new Diagram(text);
// Get the tmp element containing the the svg
const element = root.select('#d' + id).node();
const graphType = diag.type;
@ -286,8 +250,8 @@ const render = function (id, _txt, cb, container) {
// classDef
if (graphType === 'flowchart' || graphType === 'flowchart-v2' || graphType === 'graph') {
const classes = flowRenderer.getClasses(txt, diag);
const htmlLabels = cnf.htmlLabels || cnf.flowchart.htmlLabels;
const classes: any = flowRenderer.getClasses(text, diag);
const htmlLabels = cnf.htmlLabels || cnf.flowchart?.htmlLabels;
for (const className in classes) {
if (htmlLabels) {
userStyles += `\n.${className} > * { ${classes[className].styles.join(
@ -321,7 +285,8 @@ const render = function (id, _txt, cb, container) {
}
}
const stylis = (selector, styles) => serialize(compile(`${selector}{${styles}}`), stringify);
const stylis = (selector: string, styles: string) =>
serialize(compile(`${selector}{${styles}}`), stringify);
const rules = stylis(`#${id}`, getStyles(graphType, userStyles, cnf.themeVariables));
const style1 = document.createElement('style');
@ -329,7 +294,7 @@ const render = function (id, _txt, cb, container) {
svg.insertBefore(style1, firstChild);
try {
diag.renderer.draw(txt, id, pkg.version, diag);
diag.renderer.draw(text, id, pkg.version, diag);
} catch (e) {
errorRenderer.draw(id, pkg.version);
throw e;
@ -344,10 +309,7 @@ const render = function (id, _txt, cb, container) {
let svgCode = root.select('#d' + id).node().innerHTML;
log.debug('cnf.arrowMarkerAbsolute', cnf.arrowMarkerAbsolute);
if (
(!cnf.arrowMarkerAbsolute || cnf.arrowMarkerAbsolute === 'false') &&
cnf.arrowMarkerAbsolute !== 'sandbox'
) {
if (!evaluate(cnf.arrowMarkerAbsolute) && cnf.securityLevel !== 'sandbox') {
svgCode = svgCode.replace(/marker-end="url\(.*?#/g, 'marker-end="url(#', 'g');
}
@ -400,16 +362,16 @@ const render = function (id, _txt, cb, container) {
const tmpElementSelector = cnf.securityLevel === 'sandbox' ? '#i' + id : '#d' + id;
const node = select(tmpElementSelector).node();
if (node !== null && typeof node.remove === 'function') {
select(tmpElementSelector).node().remove();
if (node && 'remove' in node) {
node.remove();
}
return svgCode;
};
let currentDirective = {};
let currentDirective: { type?: string; args?: any } | undefined = {};
const parseDirective = function (p, statement, context, type) {
const parseDirective = function (p: any, statement: string, context: string, type: string): void {
try {
if (statement !== undefined) {
statement = statement.trim();
@ -418,14 +380,16 @@ const parseDirective = function (p, statement, context, type) {
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 = null;
currentDirective = undefined;
break;
}
}
@ -433,11 +397,12 @@ const parseDirective = function (p, statement, context, type) {
log.error(
`Error while rendering sequenceDiagram directive: ${statement} jison context: ${context}`
);
// @ts-ignore
log.error(error.message);
}
};
const handleDirective = function (p, directive, type) {
const handleDirective = function (p: any, directive: any, type: string): void {
log.debug(`Directive type=${directive.type} with args:`, directive.args);
switch (directive.type) {
case 'init':
@ -477,27 +442,8 @@ const handleDirective = function (p, directive, type) {
}
};
/** @param {any} conf */
function updateRendererConfigs(conf) {
// Todo remove, all diagrams should get config on demand from the config object, no need for this
flowRenderer.setConf(conf.flowchart);
flowRendererV2.setConf(conf.flowchart);
if (typeof conf['sequenceDiagram'] !== 'undefined') {
sequenceRenderer.setConf(assignWithDepth(conf.sequence, conf['sequenceDiagram']));
}
sequenceRenderer.setConf(conf.sequence);
ganttRenderer.setConf(conf.gantt);
// classRenderer.setConf(conf.class);
stateRenderer.setConf(conf.state);
stateRendererV2.setConf(conf.state);
// infoRenderer.setConf(conf.class);
journeyRenderer.setConf(conf.journey);
errorRenderer.setConf(conf.class);
}
/** @param {any} options */
function initialize(options) {
/** @param {MermaidConfig} options */
function initialize(options: MermaidConfig) {
// Handle legacy location of font-family configuration
if (options?.fontFamily) {
if (!options.themeVariables?.fontFamily) {
@ -508,9 +454,11 @@ function initialize(options) {
// Set default options
configApi.saveConfigFromInitialize(options);
if (options?.theme && theme[options.theme]) {
if (options?.theme && options.theme in theme) {
// Todo merge with user options
options.themeVariables = theme[options.theme].getThemeVariables(options.themeVariables);
options.themeVariables = theme[options.theme as keyof typeof theme].getThemeVariables(
options.themeVariables
);
} else if (options) {
options.themeVariables = theme.default.getThemeVariables(options.themeVariables);
}
@ -518,7 +466,6 @@ function initialize(options) {
const config =
typeof options === 'object' ? configApi.setSiteConfig(options) : configApi.getSiteConfig();
updateRendererConfigs(config);
setLogLevel(config.logLevel);
if (!hasLoadedDiagrams) {
addDiagrams();
@ -526,7 +473,7 @@ function initialize(options) {
}
}
const mermaidAPI = Object.freeze({
export const mermaidAPI = Object.freeze({
render,
parse,
parseDirective,
@ -540,14 +487,12 @@ const mermaidAPI = Object.freeze({
},
globalReset: () => {
configApi.reset(configApi.defaultConfig);
updateRendererConfigs(configApi.getConfig());
},
defaultConfig: configApi.defaultConfig,
});
setLogLevel(configApi.getConfig().logLevel);
configApi.reset(configApi.getConfig());
export default mermaidAPI;
/**
* ## mermaidAPI configuration defaults

View File

@ -10,8 +10,10 @@ import sequence from './diagrams/sequence/styles';
import stateDiagram from './diagrams/state/styles';
import journey from './diagrams/user-journey/styles';
import c4 from './diagrams/c4/styles';
import { FlowChartStyleOptions } from './diagrams/flowchart/styles';
import { log } from './logger';
// TODO @knut: Inject from registerDiagram.
const themes = {
flowchart,
'flowchart-v2': flowchart,
@ -31,12 +33,24 @@ const themes = {
c4,
};
export const calcThemeVariables = (theme, userOverRides) => {
log.info('userOverides', userOverRides);
return theme.calcColors(userOverRides);
};
const getStyles = (type, userStyles, options) => {
const getStyles = (
type: string,
userStyles: string,
options: {
fontFamily: string;
fontSize: string;
textColor: string;
errorBkgColor: string;
errorTextColor: string;
lineColor: string;
} & FlowChartStyleOptions
) => {
let diagramStyles: string = '';
if (type in themes && themes[type as keyof typeof themes]) {
diagramStyles = themes[type as keyof typeof themes](options);
} else {
log.warn(`No theme found for ${type}`);
}
return ` {
font-family: ${options.fontFamily};
font-size: ${options.fontSize};
@ -83,7 +97,7 @@ const getStyles = (type, userStyles, options) => {
font-size: ${options.fontSize};
}
${themes[type](options)}
${diagramStyles}
${userStyles}
`;

View File

@ -1,7 +1,7 @@
import utils from './utils';
import assignWithDepth from './assignWithDepth';
import detectType from './diagram-api/detectType';
import addDiagrams from './diagram-api/diagram-orchestration';
import { detectType } from './diagram-api/detectType';
import { addDiagrams } from './diagram-api/diagram-orchestration';
addDiagrams();

View File

@ -1,3 +1,4 @@
// @ts-nocheck
import { sanitizeUrl } from '@braintree/sanitize-url';
import {
curveBasis,
@ -16,8 +17,9 @@ import {
import common from './diagrams/common/common';
import { configKeys } from './defaultConfig';
import { log } from './logger';
import detectType from './diagram-api/detectType';
import { detectType } from './diagram-api/detectType';
import assignWithDepth from './assignWithDepth';
import { MermaidConfig } from './config.type';
// Effectively an enum of the supported curve types, accessible by name
const d3CurveTypes = {
@ -71,7 +73,7 @@ const anyComment = /\s*%%.*\n/gm;
* @param {any} cnf
* @returns {object} The json object representing the init passed to mermaid.initialize()
*/
export const detectInit = function (text, cnf) {
export const detectInit = function (text: string, config?: MermaidConfig): MermaidConfig {
let inits = detectDirective(text, /(?:init\b)|(?:initialize\b)/);
let results = {};
@ -84,7 +86,7 @@ export const detectInit = function (text, cnf) {
results = inits.args;
}
if (results) {
let type = detectType(text, cnf);
let type = detectType(text, config);
['config'].forEach((prop) => {
if (typeof results[prop] !== 'undefined') {
if (type === 'flowchart-v2') {
@ -821,6 +823,7 @@ export const setupGraphViewbox = function (graph, svgElem, padding, useMaxWidth)
export const initIdGenerator = class iterator {
constructor(deterministic, seed) {
this.deterministic = deterministic;
// TODO: Seed is only used for length?
this.seed = seed;
this.count = seed ? seed.length : 0;
@ -937,6 +940,20 @@ export const sanitizeCss = (str) => {
return str;
};
export interface DetailedError {
str: string;
hash: any;
}
export function isDetailedError(error: unknown): error is DetailedError {
return 'str' in error;
}
export function getErrorMessage(error: unknown): string {
if (error instanceof Error) return error.message;
return String(error);
}
export default {
assignWithDepth,
wrapLabel,

104
tsconfig.json Normal file
View File

@ -0,0 +1,104 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Projects */
"incremental": true /* Enable incremental compilation */,
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"lib": [
"ES2021"
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
/* Modules */
"module": "ES6" /* Specify what module code is generated. */,
"rootDir": "./src" /* Specify the root folder within your source files. */,
"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
// "baseUrl": "./src" /* Specify the base directory to resolve non-relative module names. */,
// "paths": {} /* Specify a set of entries that re-map imports to additional lookup locations. */,
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [] /* Specify multiple folders that act like `./node_modules/@types`. */,
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
"resolveJsonModule": true /* Enable importing .json files */,
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
"allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */,
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
/* Emit */
"declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
// "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": ["./src/**/*.ts", "./package.json"]
}

443
yarn.lock
View File

@ -1532,14 +1532,14 @@
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.0.tgz#fe364f025ba74f6de6c837a84ef44bdb1d61e68f"
integrity sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w==
"@commitlint/cli@^17.0.0":
version "17.1.1"
resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-17.1.1.tgz#994e91a873aea2bcb53dfa3225ffce2c9022fd3e"
integrity sha512-xyQJNJs1j18At5wSBF6bMo1on6ZrpcHUr4duacznPU0RnywCAABDBP1s63BmhkTMdNXLVgVM4J1H2sG0HSS3IA==
"@commitlint/cli@^17.1.2":
version "17.1.2"
resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-17.1.2.tgz#38240f84936df5216f749f06f838dc50cc85a43d"
integrity sha512-h/4Hlka3bvCLbnxf0Er2ri5A44VMlbMSkdTRp8Adv2tRiklSTRIoPGs7OEXDv3EoDs2AAzILiPookgM4Gi7LOw==
dependencies:
"@commitlint/format" "^17.0.0"
"@commitlint/lint" "^17.1.0"
"@commitlint/load" "^17.1.1"
"@commitlint/load" "^17.1.2"
"@commitlint/read" "^17.1.0"
"@commitlint/types" "^17.0.0"
execa "^5.0.0"
@ -1602,10 +1602,10 @@
"@commitlint/rules" "^17.0.0"
"@commitlint/types" "^17.0.0"
"@commitlint/load@^17.1.1":
version "17.1.1"
resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-17.1.1.tgz#16f945d2cc4a5d4d75cccc3d7df8066ff152024b"
integrity sha512-jEgdDabfj58kFKZmB7rMtmQa7Feo7Ozh3KmvIlXWqrJmal5auO1RC0Iczfl52DlPn26Uo0goUDHrhoAFs2ze0Q==
"@commitlint/load@^17.1.2":
version "17.1.2"
resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-17.1.2.tgz#19c88be570d8666bbd32f9b3d81925a08328bc13"
integrity sha512-sk2p/jFYAWLChIfOIp/MGSIn/WzZ0vkc3afw+l4X8hGEYkvDe4gQUUAVxjl/6xMRn0HgnSLMZ04xXh5pkTsmgg==
dependencies:
"@commitlint/config-validator" "^17.1.0"
"@commitlint/execute-rule" "^17.0.0"
@ -1614,9 +1614,10 @@
"@types/node" "^14.0.0"
chalk "^4.1.0"
cosmiconfig "^7.0.0"
cosmiconfig-typescript-loader "^3.0.0"
cosmiconfig-typescript-loader "^4.0.0"
lodash "^4.17.19"
resolve-from "^5.0.0"
ts-node "^10.8.1"
typescript "^4.6.4"
"@commitlint/message@^17.0.0":
@ -1686,6 +1687,13 @@
dependencies:
chalk "^4.1.0"
"@cspotcode/source-map-support@^0.8.0":
version "0.8.1"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
"@cypress/request@^2.88.10":
version "2.88.10"
resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.10.tgz#b66d76b07f860d3a4b8d7a0604d020c662752cce"
@ -2101,6 +2109,14 @@
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
"@jridgewell/trace-mapping@0.3.9":
version "0.3.9"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping@^0.3.0", "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.15", "@jridgewell/trace-mapping@^0.3.9":
version "0.3.15"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774"
@ -2193,6 +2209,26 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
"@tsconfig/node10@^1.0.7":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
"@tsconfig/node12@^1.0.7":
version "1.0.11"
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
"@tsconfig/node14@^1.0.0":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
"@tsconfig/node16@^1.0.2":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
"@types/babel__core@^7.1.14":
version "7.1.17"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.17.tgz#f50ac9d20d64153b510578d84f9643f9a3afbe64"
@ -2266,6 +2302,216 @@
dependencies:
"@types/node" "*"
"@types/d3-array@*":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.0.3.tgz#87d990bf504d14ad6b16766979d04e943c046dac"
integrity sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==
"@types/d3-axis@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-3.0.1.tgz#6afc20744fa5cc0cbc3e2bd367b140a79ed3e7a8"
integrity sha512-zji/iIbdd49g9WN0aIsGcwcTBUkgLsCSwB+uH+LPVDAiKWENMtI3cJEWt+7/YYwelMoZmbBfzA3qCdrZ2XFNnw==
dependencies:
"@types/d3-selection" "*"
"@types/d3-brush@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-3.0.1.tgz#ae5f17ce391935ca88b29000e60ee20452c6357c"
integrity sha512-B532DozsiTuQMHu2YChdZU0qsFJSio3Q6jmBYGYNp3gMDzBmuFFgPt9qKA4VYuLZMp4qc6eX7IUFUEsvHiXZAw==
dependencies:
"@types/d3-selection" "*"
"@types/d3-chord@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-3.0.1.tgz#54c8856c19c8e4ab36a53f73ba737de4768ad248"
integrity sha512-eQfcxIHrg7V++W8Qxn6QkqBNBokyhdWSAS73AbkbMzvLQmVVBviknoz2SRS/ZJdIOmhcmmdCRE/NFOm28Z1AMw==
"@types/d3-color@*":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.0.tgz#6594da178ded6c7c3842f3cc0ac84b156f12f2d4"
integrity sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==
"@types/d3-contour@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-contour/-/d3-contour-3.0.1.tgz#9ff4e2fd2a3910de9c5097270a7da8a6ef240017"
integrity sha512-C3zfBrhHZvrpAAK3YXqLWVAGo87A4SvJ83Q/zVJ8rFWJdKejUnDYaWZPkA8K84kb2vDA/g90LTQAz7etXcgoQQ==
dependencies:
"@types/d3-array" "*"
"@types/geojson" "*"
"@types/d3-delaunay@*":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz#006b7bd838baec1511270cb900bf4fc377bbbf41"
integrity sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==
"@types/d3-dispatch@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-3.0.1.tgz#a1b18ae5fa055a6734cb3bd3cbc6260ef19676e3"
integrity sha512-NhxMn3bAkqhjoxabVJWKryhnZXXYYVQxaBnbANu0O94+O/nX9qSjrA1P1jbAQJxJf+VC72TxDX/YJcKue5bRqw==
"@types/d3-drag@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-3.0.1.tgz#fb1e3d5cceeee4d913caa59dedf55c94cb66e80f"
integrity sha512-o1Va7bLwwk6h03+nSM8dpaGEYnoIG19P0lKqlic8Un36ymh9NSkNFX1yiXMKNMx8rJ0Kfnn2eovuFaL6Jvj0zA==
dependencies:
"@types/d3-selection" "*"
"@types/d3-dsv@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-3.0.0.tgz#f3c61fb117bd493ec0e814856feb804a14cfc311"
integrity sha512-o0/7RlMl9p5n6FQDptuJVMxDf/7EDEv2SYEO/CwdG2tr1hTfUVi0Iavkk2ax+VpaQ/1jVhpnj5rq1nj8vwhn2A==
"@types/d3-ease@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.0.tgz#c29926f8b596f9dadaeca062a32a45365681eae0"
integrity sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==
"@types/d3-fetch@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-fetch/-/d3-fetch-3.0.1.tgz#f9fa88b81aa2eea5814f11aec82ecfddbd0b8fe0"
integrity sha512-toZJNOwrOIqz7Oh6Q7l2zkaNfXkfR7mFSJvGvlD/Ciq/+SQ39d5gynHJZ/0fjt83ec3WL7+u3ssqIijQtBISsw==
dependencies:
"@types/d3-dsv" "*"
"@types/d3-force@*":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-3.0.3.tgz#76cb20d04ae798afede1ea6e41750763ff5a9c82"
integrity sha512-z8GteGVfkWJMKsx6hwC3SiTSLspL98VNpmvLpEFJQpZPq6xpA1I8HNBDNSpukfK0Vb0l64zGFhzunLgEAcBWSA==
"@types/d3-format@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-3.0.1.tgz#194f1317a499edd7e58766f96735bdc0216bb89d"
integrity sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==
"@types/d3-geo@*":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-3.0.2.tgz#e7ec5f484c159b2c404c42d260e6d99d99f45d9a"
integrity sha512-DbqK7MLYA8LpyHQfv6Klz0426bQEf7bRTvhMy44sNGVyZoWn//B0c+Qbeg8Osi2Obdc9BLLXYAKpyWege2/7LQ==
dependencies:
"@types/geojson" "*"
"@types/d3-hierarchy@*":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.0.tgz#4561bb7ace038f247e108295ef77b6a82193ac25"
integrity sha512-g+sey7qrCa3UbsQlMZZBOHROkFqx7KZKvUpRzI/tAp/8erZWpYq7FgNKvYwebi2LaEiVs1klhUfd3WCThxmmWQ==
"@types/d3-interpolate@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz#e7d17fa4a5830ad56fe22ce3b4fac8541a9572dc"
integrity sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==
dependencies:
"@types/d3-color" "*"
"@types/d3-path@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.0.0.tgz#939e3a784ae4f80b1fde8098b91af1776ff1312b"
integrity sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==
"@types/d3-polygon@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/d3-polygon/-/d3-polygon-3.0.0.tgz#5200a3fa793d7736fa104285fa19b0dbc2424b93"
integrity sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==
"@types/d3-quadtree@*":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/d3-quadtree/-/d3-quadtree-3.0.2.tgz#433112a178eb7df123aab2ce11c67f51cafe8ff5"
integrity sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==
"@types/d3-random@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-3.0.1.tgz#5c8d42b36cd4c80b92e5626a252f994ca6bfc953"
integrity sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==
"@types/d3-scale-chromatic@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#103124777e8cdec85b20b51fd3397c682ee1e954"
integrity sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==
"@types/d3-scale@*":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.2.tgz#41be241126af4630524ead9cb1008ab2f0f26e69"
integrity sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==
dependencies:
"@types/d3-time" "*"
"@types/d3-selection@*":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.3.tgz#57be7da68e7d9c9b29efefd8ea5a9ef1171e42ba"
integrity sha512-Mw5cf6nlW1MlefpD9zrshZ+DAWL4IQ5LnWfRheW6xwsdaWOb6IRRu2H7XPAQcyXEx1D7XQWgdoKR83ui1/HlEA==
"@types/d3-shape@*":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.0.tgz#1d87a6ddcf28285ef1e5c278ca4bdbc0658f3505"
integrity sha512-jYIYxFFA9vrJ8Hd4Se83YI6XF+gzDL1aC5DCsldai4XYYiVNdhtpGbA/GM6iyQ8ayhSp3a148LY34hy7A4TxZA==
dependencies:
"@types/d3-path" "*"
"@types/d3-time-format@*":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-4.0.0.tgz#ee7b6e798f8deb2d9640675f8811d0253aaa1946"
integrity sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==
"@types/d3-time@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.0.tgz#e1ac0f3e9e195135361fa1a1d62f795d87e6e819"
integrity sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==
"@types/d3-timer@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.0.tgz#e2505f1c21ec08bda8915238e397fb71d2fc54ce"
integrity sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==
"@types/d3-transition@*":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.2.tgz#393dc3e3d55009a43cc6f252e73fccab6d78a8a4"
integrity sha512-jo5o/Rf+/u6uerJ/963Dc39NI16FQzqwOc54bwvksGAdVfvDrqDpVeq95bEvPtBwLCVZutAEyAtmSyEMxN7vxQ==
dependencies:
"@types/d3-selection" "*"
"@types/d3-zoom@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.1.tgz#4bfc7e29625c4f79df38e2c36de52ec3e9faf826"
integrity sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==
dependencies:
"@types/d3-interpolate" "*"
"@types/d3-selection" "*"
"@types/d3@^7.4.0":
version "7.4.0"
resolved "https://registry.yarnpkg.com/@types/d3/-/d3-7.4.0.tgz#fc5cac5b1756fc592a3cf1f3dc881bf08225f515"
integrity sha512-jIfNVK0ZlxcuRDKtRS/SypEyOQ6UHaFQBKv032X45VvxSJ6Yi5G9behy9h6tNTHTDGh5Vq+KbmBjUWLgY4meCA==
dependencies:
"@types/d3-array" "*"
"@types/d3-axis" "*"
"@types/d3-brush" "*"
"@types/d3-chord" "*"
"@types/d3-color" "*"
"@types/d3-contour" "*"
"@types/d3-delaunay" "*"
"@types/d3-dispatch" "*"
"@types/d3-drag" "*"
"@types/d3-dsv" "*"
"@types/d3-ease" "*"
"@types/d3-fetch" "*"
"@types/d3-force" "*"
"@types/d3-format" "*"
"@types/d3-geo" "*"
"@types/d3-hierarchy" "*"
"@types/d3-interpolate" "*"
"@types/d3-path" "*"
"@types/d3-polygon" "*"
"@types/d3-quadtree" "*"
"@types/d3-random" "*"
"@types/d3-scale" "*"
"@types/d3-scale-chromatic" "*"
"@types/d3-selection" "*"
"@types/d3-shape" "*"
"@types/d3-time" "*"
"@types/d3-time-format" "*"
"@types/d3-timer" "*"
"@types/d3-transition" "*"
"@types/d3-zoom" "*"
"@types/debug@^4.0.0":
version "4.1.7"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82"
@ -2273,6 +2519,13 @@
dependencies:
"@types/ms" "*"
"@types/dompurify@^2.3.3":
version "2.3.3"
resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.3.3.tgz#c24c92f698f77ed9cc9d9fa7888f90cf2bfaa23f"
integrity sha512-nnVQSgRVuZ/843oAfhA25eRSNzUFcBPk/LOiw5gm8mD9/X7CNcbRkQu/OsjCewO8+VIYfPxUnXvPEVGenw14+w==
dependencies:
"@types/trusted-types" "*"
"@types/eslint-scope@^3.7.3":
version "3.7.3"
resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224"
@ -2313,6 +2566,11 @@
"@types/qs" "*"
"@types/serve-static" "*"
"@types/geojson@*":
version "7946.0.10"
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.10.tgz#6dfbf5ea17142f7f9a043809f1cd4c448cb68249"
integrity sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==
"@types/graceful-fs@^4.1.3":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15"
@ -2351,6 +2609,14 @@
dependencies:
"@types/istanbul-lib-report" "*"
"@types/jest@^28.1.7":
version "28.1.8"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.8.tgz#6936409f3c9724ea431efd412ea0238a0f03b09b"
integrity sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==
dependencies:
expect "^28.0.0"
pretty-format "^28.0.0"
"@types/jsdom@^20.0.0":
version "20.0.0"
resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-20.0.0.tgz#4414fb629465167f8b7b3804b9e067bdd99f1791"
@ -2493,11 +2759,21 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
"@types/stylis@^4.0.2":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@types/stylis/-/stylis-4.0.2.tgz#311c62d68a23dfb01462d54b04549484a4c5cb2a"
integrity sha512-wtckGuk1eXUlUz0Qb1eXHG37Z7HWT2GfMdqRf8F/ifddTwadSS9Jwsqi4qtXk7cP7MtoyGVIHPElFCLc6HItbg==
"@types/tough-cookie@*":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397"
integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==
"@types/trusted-types@*":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756"
integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==
"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
@ -2835,7 +3111,7 @@ acorn-walk@^7.0.0, acorn-walk@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
acorn-walk@^8.2.0:
acorn-walk@^8.1.1, acorn-walk@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
@ -2845,16 +3121,16 @@ acorn@^7.0.0, acorn@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.4.1, acorn@^8.8.0:
version "8.8.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
acorn@^8.5.0, acorn@^8.7.0, acorn@^8.7.1:
version "8.7.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
acorn@^8.8.0:
version "8.8.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
add-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa"
@ -3026,6 +3302,11 @@ arch@^2.2.0:
resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@ -3452,6 +3733,13 @@ browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^4.21.0:
node-releases "^2.0.5"
update-browserslist-db "^1.0.4"
bs-logger@0.x:
version "0.2.6"
resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8"
integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==
dependencies:
fast-json-stable-stringify "2.x"
bser@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
@ -4247,10 +4535,10 @@ core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
cosmiconfig-typescript-loader@^3.0.0:
version "3.1.2"
resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.1.2.tgz#e147457854cabe1416152bdca55f53449b1f865d"
integrity sha512-rIwakk27LtK7vjSjGgs3FDbKkq41Byw3VHRGRuAkRQLfGla+O7s+cy1FXRkjLSZ2G9z1og1bcOIsELo1w4G0Kg==
cosmiconfig-typescript-loader@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.0.0.tgz#4a6d856c1281135197346a6f64dfa73a9cd9fefa"
integrity sha512-cVpucSc2Tf+VPwCCR7SZzmQTQkPbkk4O01yXsYqXBIbjE1bhwqSyAgYQkRK1un4i0OPziTleqFhdkmOc4RQ/9g==
cosmiconfig@^7.0.0:
version "7.0.1"
@ -4274,6 +4562,11 @@ coveralls@^3.0.2:
minimist "^1.2.5"
request "^2.88.2"
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
cross-spawn@^6.0.0:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
@ -5162,7 +5455,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
enhanced-resolve@^5.10.0:
enhanced-resolve@^5.0.0, enhanced-resolve@^5.10.0:
version "5.10.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6"
integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==
@ -5850,7 +6143,7 @@ expand-brackets@^2.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
expect@^28.1.3:
expect@^28.0.0, expect@^28.1.3:
version "28.1.3"
resolved "https://registry.yarnpkg.com/expect/-/expect-28.1.3.tgz#90a7c1a124f1824133dd4533cce2d2bdcb6603ec"
integrity sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==
@ -5973,7 +6266,7 @@ fast-glob@^3.2.9:
merge2 "^1.3.0"
micromatch "^4.0.4"
fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0:
fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
@ -7811,7 +8104,7 @@ jest-snapshot@^28.1.3:
pretty-format "^28.1.3"
semver "^7.3.5"
jest-util@^28.1.3:
jest-util@^28.0.0, jest-util@^28.1.3:
version "28.1.3"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.3.tgz#f4f932aa0074f0679943220ff9cbba7e497028b0"
integrity sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==
@ -8369,6 +8662,11 @@ lodash.ismatch@^4.4.0:
resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37"
integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=
lodash.memoize@4.x:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==
lodash.merge@^4.6.1, lodash.merge@^4.6.2:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
@ -8456,6 +8754,11 @@ make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0:
dependencies:
semver "^6.0.0"
make-error@1.x, make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
makeerror@1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a"
@ -8873,7 +9176,7 @@ micromatch@^3.1.5:
snapdragon "^0.8.1"
to-regex "^3.0.2"
micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5:
micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
@ -9764,7 +10067,7 @@ pretty-bytes@^5.6.0:
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
pretty-format@^28.1.3:
pretty-format@^28.0.0, pretty-format@^28.1.3:
version "28.1.3"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5"
integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==
@ -10584,7 +10887,7 @@ semver@7.0.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
semver@7.3.7, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7:
semver@7.3.7, semver@7.x, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7:
version "7.3.7"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
@ -11301,10 +11604,10 @@ terminal-link@^2.0.0:
ansi-escapes "^4.2.1"
supports-hyperlinks "^2.0.0"
terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.2.4:
version "5.3.5"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.5.tgz#f7d82286031f915a4f8fb81af4bd35d2e3c011bc"
integrity sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA==
terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.6:
version "5.3.6"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz#5590aec31aa3c6f771ce1b1acca60639eab3195c"
integrity sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==
dependencies:
"@jridgewell/trace-mapping" "^0.3.14"
jest-worker "^27.4.5"
@ -11524,6 +11827,49 @@ trough@^1.0.0:
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406"
integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==
ts-jest@^28.0.8:
version "28.0.8"
resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.8.tgz#cd204b8e7a2f78da32cf6c95c9a6165c5b99cc73"
integrity sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg==
dependencies:
bs-logger "0.x"
fast-json-stable-stringify "2.x"
jest-util "^28.0.0"
json5 "^2.2.1"
lodash.memoize "4.x"
make-error "1.x"
semver "7.x"
yargs-parser "^21.0.1"
ts-loader@^9.3.1:
version "9.3.1"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.3.1.tgz#fe25cca56e3e71c1087fe48dc67f4df8c59b22d4"
integrity sha512-OkyShkcZTsTwyS3Kt7a4rsT/t2qvEVQuKCTg4LJmpj9fhFR7ukGdZwV6Qq3tRUkqcXtfGpPR7+hFKHCG/0d3Lw==
dependencies:
chalk "^4.1.0"
enhanced-resolve "^5.0.0"
micromatch "^4.0.0"
semver "^7.3.4"
ts-node@^10.8.1:
version "10.9.1"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
dependencies:
"@cspotcode/source-map-support" "^0.8.0"
"@tsconfig/node10" "^1.0.7"
"@tsconfig/node12" "^1.0.7"
"@tsconfig/node14" "^1.0.0"
"@tsconfig/node16" "^1.0.2"
acorn "^8.4.1"
acorn-walk "^8.1.1"
arg "^4.1.0"
create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
@ -11620,6 +11966,11 @@ typescript@^4.6.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.4.tgz#caa78bbc3a59e6a5c510d35703f6a09877ce45e9"
integrity sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==
typescript@^4.7.4:
version "4.7.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
uglify-js@^3.1.4:
version "3.14.4"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.4.tgz#68756f17d1b90b9d289341736cb9a567d6882f90"
@ -11851,6 +12202,11 @@ uvu@^0.5.0:
kleur "^4.0.3"
sade "^1.7.3"
v8-compile-cache-lib@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
v8-to-istanbul@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4"
@ -12145,10 +12501,10 @@ webpack-dev-middleware@^5.3.1:
range-parser "^1.2.1"
schema-utils "^4.0.0"
webpack-dev-server@^4.3.0:
version "4.10.0"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.10.0.tgz#de270d0009eba050546912be90116e7fd740a9ca"
integrity sha512-7dezwAs+k6yXVFZ+MaL8VnE+APobiO3zvpp3rBHe/HmWQ+avwh0Q3d0xxacOiBybZZ3syTZw9HXzpa3YNbAZDQ==
webpack-dev-server@^4.10.1:
version "4.10.1"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.10.1.tgz#124ac9ac261e75303d74d95ab6712b4aec3e12ed"
integrity sha512-FIzMq3jbBarz3ld9l7rbM7m6Rj1lOsgq/DyLGMX/fPEB1UBUPtf5iL/4eNfhx8YYJTRlzfv107UfWSWcBK5Odw==
dependencies:
"@types/bonjour" "^3.5.9"
"@types/connect-history-api-fallback" "^1.3.5"
@ -12366,12 +12722,7 @@ ws@8.5.0:
resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
ws@^8.2.3, ws@^8.4.2:
version "8.6.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.6.0.tgz#e5e9f1d9e7ff88083d0c0dd8281ea662a42c9c23"
integrity sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==
ws@^8.8.0:
ws@^8.2.3, ws@^8.4.2, ws@^8.8.0:
version "8.8.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.1.tgz#5dbad0feb7ade8ecc99b830c1d77c913d4955ff0"
integrity sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==
@ -12454,6 +12805,11 @@ yargs-parser@^21.0.0:
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55"
integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==
yargs-parser@^21.0.1:
version "21.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
yargs@17.4.1, yargs@^17.0.0, yargs@^17.3.1:
version "17.4.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.4.1.tgz#ebe23284207bb75cee7c408c33e722bfb27b5284"
@ -12505,6 +12861,11 @@ yauzl@^2.10.0:
buffer-crc32 "~0.2.3"
fd-slicer "~1.1.0"
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"