mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
Merge branch 'sidv/eslintv9' into 5237-unified-layout-common-renderer-eslint
* sidv/eslintv9: (24 commits) chore: Cleanup tsconfig chore: Fix lint Apply suggestions from code review chore: Remove extra words from cspell chore: Log granular rebuild times fix: Message wrap fix: Message wrap chore: Use `??` instead of `||` chore: Organise imports chore: Remove unused variables chore: Remove cross-env from eslint chore: Cleanup rules chore: Fix eslint issues chore: Fix eslint issues chore: Add type checked rules, auto fix chore: Remove max_old_space_size as v9 does not have perf issues fix: Eslint jison linting chore: Resolve eslint errors chore: Resolve eslint errors chore: Remove orphaned files ...
This commit is contained in:
commit
d5a03a9054
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
import { packageOptions } from './common.js';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
@ -5,11 +6,17 @@ const buildType = (packageName: string) => {
|
||||
console.log(`Building types for ${packageName}`);
|
||||
try {
|
||||
const out = execSync(`tsc -p ./packages/${packageName}/tsconfig.json --emitDeclarationOnly`);
|
||||
out.length > 0 && console.log(out.toString());
|
||||
if (out.length > 0) {
|
||||
console.log(out.toString());
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
e.stdout.length > 0 && console.error(e.stdout.toString());
|
||||
e.stderr.length > 0 && console.error(e.stderr.toString());
|
||||
if (e.stdout.length > 0) {
|
||||
console.error(e.stdout.toString());
|
||||
}
|
||||
if (e.stderr.length > 0) {
|
||||
console.error(e.stderr.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,7 @@ bqstring
|
||||
BQUOTE
|
||||
bramp
|
||||
BRKT
|
||||
brotli
|
||||
callbackargs
|
||||
callbackname
|
||||
classdef
|
||||
@ -114,6 +115,7 @@ STYLEDEF
|
||||
STYLEOPTS
|
||||
subcomponent
|
||||
subcomponents
|
||||
subconfig
|
||||
SUBROUTINEEND
|
||||
SUBROUTINESTART
|
||||
Subschemas
|
||||
@ -128,6 +130,7 @@ titlevalue
|
||||
topbar
|
||||
TRAPEND
|
||||
TRAPSTART
|
||||
treemap
|
||||
ts-nocheck
|
||||
tsdoc
|
||||
typeof
|
||||
|
@ -4,5 +4,6 @@ cpettitt
|
||||
Dong Cai
|
||||
Nikolay Rozhkov
|
||||
Peng Xiao
|
||||
Per Brolin
|
||||
subhash-halder
|
||||
Vinod Sidharth
|
||||
|
@ -56,12 +56,14 @@ redmine
|
||||
rehype
|
||||
roughjs
|
||||
rscratch
|
||||
shiki
|
||||
sparkline
|
||||
sphinxcontrib
|
||||
ssim
|
||||
stylis
|
||||
Swimm
|
||||
tsbuildinfo
|
||||
tseslint
|
||||
Tuleap
|
||||
Typora
|
||||
unocss
|
||||
|
@ -1,4 +1,6 @@
|
||||
BRANDES
|
||||
KOEPF
|
||||
circo
|
||||
handdrawnSeed
|
||||
handdrawn
|
||||
neato
|
||||
newbranch
|
||||
|
@ -2,7 +2,8 @@ import { build } from 'esbuild';
|
||||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import { packageOptions } from '../.build/common.js';
|
||||
import { generateLangium } from '../.build/generateLangium.js';
|
||||
import { MermaidBuildOptions, defaultOptions, getBuildConfig } from './util.js';
|
||||
import type { MermaidBuildOptions } from './util.js';
|
||||
import { defaultOptions, getBuildConfig } from './util.js';
|
||||
|
||||
const shouldVisualize = process.argv.includes('--visualize');
|
||||
|
||||
@ -35,11 +36,11 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => {
|
||||
|
||||
if (shouldVisualize) {
|
||||
for (const { metafile } of results) {
|
||||
if (!metafile) {
|
||||
if (!metafile?.outputs) {
|
||||
continue;
|
||||
}
|
||||
const fileName = Object.keys(metafile.outputs)
|
||||
.filter((file) => !file.includes('chunks') && file.endsWith('js'))[0]
|
||||
.find((file) => !file.includes('chunks') && file.endsWith('js'))
|
||||
.replace('dist/', '');
|
||||
// Upload metafile into https://esbuild.github.io/analyze/
|
||||
await writeFile(`stats/${fileName}.meta.json`, JSON.stringify(metafile));
|
||||
@ -48,13 +49,14 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => {
|
||||
};
|
||||
|
||||
const handler = (e) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
await generateLangium();
|
||||
await mkdir('stats').catch(() => {});
|
||||
await mkdir('stats', { recursive: true });
|
||||
const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[];
|
||||
// it should build `parser` before `mermaid` because it's a dependency
|
||||
for (const pkg of packageNames) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { transformJison } from '../.build/jisonTransformer.js';
|
||||
import { Plugin } from 'esbuild';
|
||||
import type { Plugin } from 'esbuild';
|
||||
|
||||
export const jisonPlugin: Plugin = {
|
||||
name: 'jison',
|
||||
|
@ -1,11 +1,12 @@
|
||||
import express from 'express';
|
||||
import type { NextFunction, Request, Response } from 'express';
|
||||
import cors from 'cors';
|
||||
import { getBuildConfig, defaultOptions } from './util.js';
|
||||
import { context } from 'esbuild';
|
||||
/* eslint-disable no-console */
|
||||
import chokidar from 'chokidar';
|
||||
import { generateLangium } from '../.build/generateLangium.js';
|
||||
import cors from 'cors';
|
||||
import { context } from 'esbuild';
|
||||
import type { Request, Response } from 'express';
|
||||
import express from 'express';
|
||||
import { packageOptions } from '../.build/common.js';
|
||||
import { generateLangium } from '../.build/generateLangium.js';
|
||||
import { defaultOptions, getBuildConfig } from './util.js';
|
||||
|
||||
const configs = Object.values(packageOptions).map(({ packageName }) =>
|
||||
getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: packageName })
|
||||
@ -19,16 +20,28 @@ const mermaidIIFEConfig = getBuildConfig({
|
||||
});
|
||||
configs.push(mermaidIIFEConfig);
|
||||
|
||||
const contexts = await Promise.all(configs.map((config) => context(config)));
|
||||
const contexts = await Promise.all(
|
||||
configs.map(async (config) => ({ config, context: await context(config) }))
|
||||
);
|
||||
|
||||
let rebuildCounter = 1;
|
||||
const rebuildAll = async () => {
|
||||
console.time('Rebuild time');
|
||||
await Promise.all(contexts.map((ctx) => ctx.rebuild())).catch((e) => console.error(e));
|
||||
console.timeEnd('Rebuild time');
|
||||
const buildNumber = rebuildCounter++;
|
||||
const timeLabel = `Rebuild ${buildNumber} Time (total)`;
|
||||
console.time(timeLabel);
|
||||
await Promise.all(
|
||||
contexts.map(async ({ config, context }) => {
|
||||
const buildVariant = `Rebuild ${buildNumber} Time (${Object.keys(config.entryPoints!)[0]} ${config.format})`;
|
||||
console.time(buildVariant);
|
||||
await context.rebuild();
|
||||
console.timeEnd(buildVariant);
|
||||
})
|
||||
).catch((e) => console.error(e));
|
||||
console.timeEnd(timeLabel);
|
||||
};
|
||||
|
||||
let clients: { id: number; response: Response }[] = [];
|
||||
function eventsHandler(request: Request, response: Response, next: NextFunction) {
|
||||
function eventsHandler(request: Request, response: Response) {
|
||||
const headers = {
|
||||
'Content-Type': 'text/event-stream',
|
||||
Connection: 'keep-alive',
|
||||
@ -45,19 +58,20 @@ function eventsHandler(request: Request, response: Response, next: NextFunction)
|
||||
});
|
||||
}
|
||||
|
||||
let timeoutId: NodeJS.Timeout | undefined = undefined;
|
||||
let timeoutID: NodeJS.Timeout | undefined = undefined;
|
||||
|
||||
/**
|
||||
* Debounce file change events to avoid rebuilding multiple times.
|
||||
*/
|
||||
function handleFileChange() {
|
||||
if (timeoutId !== undefined) {
|
||||
clearTimeout(timeoutId);
|
||||
if (timeoutID !== undefined) {
|
||||
clearTimeout(timeoutID);
|
||||
}
|
||||
timeoutId = setTimeout(async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
timeoutID = setTimeout(async () => {
|
||||
await rebuildAll();
|
||||
sendEventsToAll();
|
||||
timeoutId = undefined;
|
||||
timeoutID = undefined;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
@ -74,15 +88,16 @@ async function createServer() {
|
||||
ignoreInitial: true,
|
||||
ignored: [/node_modules/, /dist/, /docs/, /coverage/],
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
.on('all', async (event, path) => {
|
||||
// Ignore other events.
|
||||
if (!['add', 'change'].includes(event)) {
|
||||
return;
|
||||
}
|
||||
if (/\.langium$/.test(path)) {
|
||||
console.log(`${path} changed. Rebuilding...`);
|
||||
if (path.endsWith('.langium')) {
|
||||
await generateLangium();
|
||||
}
|
||||
console.log(`${path} changed. Rebuilding...`);
|
||||
handleFileChange();
|
||||
});
|
||||
|
||||
@ -99,4 +114,4 @@ async function createServer() {
|
||||
});
|
||||
}
|
||||
|
||||
createServer();
|
||||
void createServer();
|
||||
|
@ -56,7 +56,7 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
|
||||
const external: string[] = ['require', 'fs', 'path'];
|
||||
const { name, file, packageName } = packageOptions[entryName];
|
||||
const outFileName = getFileName(name, options);
|
||||
let output: BuildOptions = buildOptions({
|
||||
const output: BuildOptions = buildOptions({
|
||||
absWorkingDir: resolve(__dirname, `../packages/${packageName}`),
|
||||
entryPoints: {
|
||||
[outFileName]: `src/${file}`,
|
||||
|
@ -1 +0,0 @@
|
||||
.gitignore
|
190
.eslintrc.cjs
190
.eslintrc.cjs
@ -1,190 +0,0 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
'jest/globals': true,
|
||||
node: true,
|
||||
},
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
experimentalObjectRestSpread: true,
|
||||
jsx: true,
|
||||
},
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2022,
|
||||
allowAutomaticSingleRunInference: true,
|
||||
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:json/recommended',
|
||||
'plugin:markdown/recommended-legacy',
|
||||
'plugin:@cspell/recommended',
|
||||
'prettier',
|
||||
],
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
'no-only-tests',
|
||||
'html',
|
||||
'jest',
|
||||
'jsdoc',
|
||||
'json',
|
||||
'@cspell',
|
||||
'lodash',
|
||||
'unicorn',
|
||||
],
|
||||
ignorePatterns: [
|
||||
// this file is automatically generated by `pnpm run --filter mermaid types:build-config`
|
||||
'packages/mermaid/src/config.type.ts',
|
||||
],
|
||||
rules: {
|
||||
curly: 'error',
|
||||
'no-console': 'error',
|
||||
'no-prototype-builtins': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'cypress/no-async-tests': 'off',
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-floating-promises': 'error',
|
||||
'@typescript-eslint/no-misused-promises': 'error',
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
'@typescript-eslint/consistent-type-definitions': 'error',
|
||||
'@typescript-eslint/ban-ts-comment': [
|
||||
'error',
|
||||
{
|
||||
'ts-expect-error': 'allow-with-description',
|
||||
'ts-ignore': 'allow-with-description',
|
||||
'ts-nocheck': 'allow-with-description',
|
||||
'ts-check': 'allow-with-description',
|
||||
minimumDescriptionLength: 10,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'typeLike',
|
||||
format: ['PascalCase'],
|
||||
custom: {
|
||||
regex: '^I[A-Z]',
|
||||
match: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
'json/*': ['error', 'allowComments'],
|
||||
'@cspell/spellchecker': [
|
||||
'error',
|
||||
{
|
||||
checkIdentifiers: true,
|
||||
checkStrings: true,
|
||||
checkStringTemplates: true,
|
||||
},
|
||||
],
|
||||
'no-empty': [
|
||||
'error',
|
||||
{
|
||||
allowEmptyCatch: true,
|
||||
},
|
||||
],
|
||||
'no-only-tests/no-only-tests': 'error',
|
||||
'lodash/import-scope': ['error', 'method'],
|
||||
'unicorn/better-regex': 'error',
|
||||
'unicorn/no-abusive-eslint-disable': 'error',
|
||||
'unicorn/no-array-push-push': 'error',
|
||||
'unicorn/no-for-loop': 'error',
|
||||
'unicorn/no-instanceof-array': 'error',
|
||||
'unicorn/no-typeof-undefined': 'error',
|
||||
'unicorn/no-unnecessary-await': 'error',
|
||||
'unicorn/no-unsafe-regex': 'warn',
|
||||
'unicorn/no-useless-promise-resolve-reject': 'error',
|
||||
'unicorn/prefer-array-find': 'error',
|
||||
'unicorn/prefer-array-flat-map': 'error',
|
||||
'unicorn/prefer-array-index-of': 'error',
|
||||
'unicorn/prefer-array-some': 'error',
|
||||
'unicorn/prefer-default-parameters': 'error',
|
||||
'unicorn/prefer-includes': 'error',
|
||||
'unicorn/prefer-negative-index': 'error',
|
||||
'unicorn/prefer-object-from-entries': 'error',
|
||||
'unicorn/prefer-string-starts-ends-with': 'error',
|
||||
'unicorn/prefer-string-trim-start-end': 'error',
|
||||
'unicorn/string-content': 'error',
|
||||
'unicorn/prefer-spread': 'error',
|
||||
'unicorn/no-lonely-if': 'error',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['cypress/**', 'demos/**'],
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.{js,jsx,mjs,cjs}'],
|
||||
extends: ['plugin:jsdoc/recommended'],
|
||||
rules: {
|
||||
'jsdoc/check-indentation': 'off',
|
||||
'jsdoc/check-alignment': 'off',
|
||||
'jsdoc/check-line-alignment': 'off',
|
||||
'jsdoc/multiline-blocks': 'off',
|
||||
'jsdoc/newline-after-description': 'off',
|
||||
'jsdoc/tag-lines': 'off',
|
||||
'jsdoc/require-param-description': 'off',
|
||||
'jsdoc/require-param-type': 'off',
|
||||
'jsdoc/require-returns': 'off',
|
||||
'jsdoc/require-returns-description': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.{ts,tsx}'],
|
||||
plugins: ['tsdoc'],
|
||||
rules: {
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
selector: 'TSEnumDeclaration',
|
||||
message:
|
||||
'Prefer using TypeScript union types over TypeScript enum, since TypeScript enums have a bunch of issues, see https://dev.to/dvddpl/whats-the-problem-with-typescript-enums-2okj',
|
||||
},
|
||||
],
|
||||
'tsdoc/syntax': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.spec.{ts,js}', 'cypress/**', 'demos/**', '**/docs/**'],
|
||||
rules: {
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.spec.{ts,js}', 'tests/**', 'cypress/**/*.js'],
|
||||
rules: {
|
||||
'@cspell/spellchecker': [
|
||||
'error',
|
||||
{
|
||||
checkIdentifiers: false,
|
||||
checkStrings: false,
|
||||
checkStringTemplates: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.html', '*.md', '**/*.md/*'],
|
||||
rules: {
|
||||
'no-var': 'error',
|
||||
'no-undef': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'off',
|
||||
'@typescript-eslint/no-misused-promises': 'off',
|
||||
},
|
||||
parserOptions: {
|
||||
project: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
@ -1,4 +1,5 @@
|
||||
import { build, InlineConfig, type PluginOption } from 'vite';
|
||||
import type { InlineConfig } from 'vite';
|
||||
import { build, type PluginOption } from 'vite';
|
||||
import { resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import jisonPlugin from './jisonPlugin.js';
|
||||
@ -46,9 +47,10 @@ interface BuildOptions {
|
||||
|
||||
export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions): InlineConfig => {
|
||||
const external: (string | RegExp)[] = ['require', 'fs', 'path'];
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(entryName, packageOptions[entryName]);
|
||||
const { name, file, packageName } = packageOptions[entryName];
|
||||
let output: OutputOptions = [
|
||||
const output: OutputOptions = [
|
||||
{
|
||||
name,
|
||||
format: 'esm',
|
||||
@ -83,7 +85,6 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
|
||||
plugins: [
|
||||
jisonPlugin(),
|
||||
jsonSchemaPlugin(), // handles `.schema.yaml` files
|
||||
// @ts-expect-error According to the type definitions, rollup plugins are incompatible with vite
|
||||
typescript({ compilerOptions: { declaration: false } }),
|
||||
istanbul({
|
||||
exclude: ['node_modules', 'test/', '__mocks__', 'generated'],
|
||||
@ -121,10 +122,10 @@ await generateLangium();
|
||||
|
||||
if (watch) {
|
||||
await build(getBuildConfig({ minify: false, watch, core: false, entryName: 'parser' }));
|
||||
build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' }));
|
||||
void build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' }));
|
||||
if (!mermaidOnly) {
|
||||
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
|
||||
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-zenuml' }));
|
||||
void build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
|
||||
void build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-zenuml' }));
|
||||
}
|
||||
} else if (visualize) {
|
||||
await build(getBuildConfig({ minify: false, watch, core: false, entryName: 'parser' }));
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { PluginOption } from 'vite';
|
||||
import type { PluginOption } from 'vite';
|
||||
import { getDefaults, getSchema, loadSchema } from '../.build/jsonSchema.js';
|
||||
|
||||
/**
|
||||
|
@ -23,8 +23,9 @@ async function createServer() {
|
||||
app.use(express.static('cypress/platform'));
|
||||
|
||||
app.listen(9000, () => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Listening on http://localhost:9000`);
|
||||
});
|
||||
}
|
||||
|
||||
createServer();
|
||||
void createServer();
|
||||
|
@ -35,7 +35,7 @@ export const mermaidUrl = (
|
||||
};
|
||||
const objStr: string = JSON.stringify(codeObject);
|
||||
let url = `http://localhost:9000/e2e.html?graph=${utf8ToB64(objStr)}`;
|
||||
if (api) {
|
||||
if (api && typeof graphStr === 'string') {
|
||||
url = `http://localhost:9000/xss.html?graph=${graphStr}`;
|
||||
}
|
||||
|
||||
@ -54,16 +54,15 @@ export const imgSnapshotTest = (
|
||||
): void => {
|
||||
const options: CypressMermaidConfig = {
|
||||
..._options,
|
||||
fontFamily: _options.fontFamily || 'courier',
|
||||
fontFamily: _options.fontFamily ?? 'courier',
|
||||
// @ts-ignore TODO: Fix type of fontSize
|
||||
fontSize: _options.fontSize || '16px',
|
||||
fontSize: _options.fontSize ?? '16px',
|
||||
sequence: {
|
||||
...(_options.sequence || {}),
|
||||
...(_options.sequence ?? {}),
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily:
|
||||
_options.sequence && _options.sequence.noteFontFamily
|
||||
? _options.sequence.noteFontFamily
|
||||
: 'courier',
|
||||
noteFontFamily: _options.sequence?.noteFontFamily
|
||||
? _options.sequence.noteFontFamily
|
||||
: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
};
|
||||
@ -95,7 +94,7 @@ export const openURLAndVerifyRendering = (
|
||||
options: CypressMermaidConfig,
|
||||
validation?: any
|
||||
): void => {
|
||||
const name: string = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||
const name: string = (options.name ?? cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||
|
||||
cy.visit(url);
|
||||
// cy.window().should('have.property', 'rendered', true);
|
||||
|
@ -1,8 +1,6 @@
|
||||
// <reference types="Cypress" />
|
||||
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||
|
||||
context('Sequence diagram', () => {
|
||||
describe('Sequence diagram', () => {
|
||||
it('should render a sequence diagram with boxes', () => {
|
||||
renderGraph(
|
||||
`
|
||||
@ -244,7 +242,7 @@ context('Sequence diagram', () => {
|
||||
`
|
||||
);
|
||||
});
|
||||
context('font settings', () => {
|
||||
describe('font settings', () => {
|
||||
it('should render different note fonts when configured', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -341,7 +339,7 @@ context('Sequence diagram', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
context('auth width scaling', () => {
|
||||
describe('auth width scaling', () => {
|
||||
it('should render long actor descriptions', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -530,7 +528,7 @@ context('Sequence diagram', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
context('background rects', () => {
|
||||
describe('background rects', () => {
|
||||
it('should render a single and nested rects', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -810,7 +808,7 @@ context('Sequence diagram', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
context('directives', () => {
|
||||
describe('directives', () => {
|
||||
it('should override config with directive settings', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -842,7 +840,7 @@ context('Sequence diagram', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
context('links', () => {
|
||||
describe('links', () => {
|
||||
it('should support actor links', () => {
|
||||
renderGraph(
|
||||
`
|
||||
@ -858,7 +856,7 @@ context('Sequence diagram', () => {
|
||||
);
|
||||
cy.get('#actor0_popup').should((popupMenu) => {
|
||||
const style = popupMenu.attr('style');
|
||||
expect(style).to.undefined;
|
||||
// expect(style).to.undefined;
|
||||
});
|
||||
cy.get('#root-0').click();
|
||||
cy.get('#actor0_popup').should((popupMenu) => {
|
||||
@ -933,7 +931,7 @@ context('Sequence diagram', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
context('svg size', () => {
|
||||
describe('svg size', () => {
|
||||
it('should render a sequence diagram when useMaxWidth is true (default)', () => {
|
||||
renderGraph(
|
||||
`
|
||||
@ -1012,7 +1010,7 @@ context('Sequence diagram', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
context('render after error', () => {
|
||||
describe('render after error', () => {
|
||||
it('should render diagram after fixing destroy participant error', () => {
|
||||
cy.on('uncaught:exception', (err) => {
|
||||
return false;
|
||||
|
@ -27,7 +27,7 @@ const code3 = `flowchart TD
|
||||
A(<img scr='https://iconscout.com/ms-icon-310x310.png' width='20' height='20' />)
|
||||
B(<b>Bold text!</b>)`;
|
||||
|
||||
if (location.href.match('test-html-escaping')) {
|
||||
if (/test-html-escaping/.exec(location.href)) {
|
||||
code = code3;
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ if (typeof document !== 'undefined') {
|
||||
window.addEventListener(
|
||||
'load',
|
||||
function () {
|
||||
if (this.location.href.match('xss.html')) {
|
||||
if (/xss.html/.exec(this.location.href)) {
|
||||
this.console.log('Using api');
|
||||
void contentLoadedApi().finally(markRendered);
|
||||
} else {
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/utils.ts:789](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L789)
|
||||
[packages/mermaid/src/utils.ts:785](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L785)
|
||||
|
||||
---
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/utils.ts:787](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L787)
|
||||
[packages/mermaid/src/utils.ts:783](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L783)
|
||||
|
||||
---
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/utils.ts:790](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L790)
|
||||
[packages/mermaid/src/utils.ts:786](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L786)
|
||||
|
||||
---
|
||||
|
||||
@ -46,4 +46,4 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/utils.ts:785](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L785)
|
||||
[packages/mermaid/src/utils.ts:781](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L781)
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/Diagram.ts:9](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/Diagram.ts#L9)
|
||||
[packages/mermaid/src/Diagram.ts:10](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/Diagram.ts#L10)
|
||||
|
||||
## Variables
|
||||
|
||||
|
221
eslint.config.js
Normal file
221
eslint.config.js
Normal file
@ -0,0 +1,221 @@
|
||||
import cspell from '@cspell/eslint-plugin';
|
||||
import eslint from '@eslint/js';
|
||||
import cypress from 'eslint-plugin-cypress';
|
||||
import jsdoc from 'eslint-plugin-jsdoc';
|
||||
import json from 'eslint-plugin-json';
|
||||
import lodash from 'eslint-plugin-lodash';
|
||||
import markdown from 'eslint-plugin-markdown';
|
||||
import noOnlyTests from 'eslint-plugin-no-only-tests';
|
||||
import tsdoc from 'eslint-plugin-tsdoc';
|
||||
import unicorn from 'eslint-plugin-unicorn';
|
||||
import globals from 'globals';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommendedTypeChecked,
|
||||
...tseslint.configs.stylisticTypeChecked,
|
||||
{
|
||||
ignores: [
|
||||
'**/dist/',
|
||||
'**/node_modules/',
|
||||
'.git/',
|
||||
'**/generated/',
|
||||
'**/coverage/',
|
||||
'packages/mermaid/src/config.type.ts',
|
||||
],
|
||||
},
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: [
|
||||
'./tsconfig.eslint.json',
|
||||
'./packages/*/tsconfig.json',
|
||||
'./packages/*/tsconfig.eslint.json',
|
||||
'./packages/mermaid/src/docs/tsconfig.json',
|
||||
],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
...globals.es2020,
|
||||
...globals.jest,
|
||||
cy: 'readonly',
|
||||
Cypress: 'readonly',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
json,
|
||||
'@cspell': cspell,
|
||||
'no-only-tests': noOnlyTests,
|
||||
lodash,
|
||||
unicorn,
|
||||
cypress,
|
||||
markdown,
|
||||
tsdoc,
|
||||
jsdoc,
|
||||
},
|
||||
rules: {
|
||||
curly: 'error',
|
||||
'no-console': 'error',
|
||||
'no-prototype-builtins': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'cypress/no-async-tests': 'off',
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-floating-promises': 'error',
|
||||
'@typescript-eslint/no-misused-promises': 'error',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
args: 'after-used',
|
||||
argsIgnorePattern: '^_',
|
||||
caughtErrors: 'all',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
destructuredArrayIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
ignoreRestSiblings: true,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/consistent-type-definitions': 'error',
|
||||
'@typescript-eslint/ban-ts-comment': [
|
||||
'error',
|
||||
{
|
||||
'ts-expect-error': 'allow-with-description',
|
||||
'ts-ignore': 'allow-with-description',
|
||||
'ts-nocheck': 'allow-with-description',
|
||||
'ts-check': 'allow-with-description',
|
||||
minimumDescriptionLength: 10,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'typeLike',
|
||||
format: ['PascalCase'],
|
||||
custom: {
|
||||
regex: '^I[A-Z]',
|
||||
match: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
// START: These rules should be turned on once the codebase is cleaned up
|
||||
'@typescript-eslint/no-unsafe-argument': 'off',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||
'@typescript-eslint/no-unsafe-return': 'off',
|
||||
'@typescript-eslint/only-throw-error': 'warn',
|
||||
'@typescript-eslint/prefer-promise-reject-errors': 'warn',
|
||||
// END
|
||||
'json/*': ['error', 'allowComments'],
|
||||
'@cspell/spellchecker': [
|
||||
'error',
|
||||
{
|
||||
checkIdentifiers: true,
|
||||
checkStrings: true,
|
||||
checkStringTemplates: true,
|
||||
},
|
||||
],
|
||||
'no-empty': [
|
||||
'error',
|
||||
{
|
||||
allowEmptyCatch: true,
|
||||
},
|
||||
],
|
||||
'no-only-tests/no-only-tests': 'error',
|
||||
'lodash/import-scope': ['error', 'method'],
|
||||
'unicorn/better-regex': 'error',
|
||||
'unicorn/no-abusive-eslint-disable': 'error',
|
||||
'unicorn/no-array-push-push': 'error',
|
||||
'unicorn/no-for-loop': 'error',
|
||||
'unicorn/no-instanceof-array': 'error',
|
||||
'unicorn/no-typeof-undefined': 'error',
|
||||
'unicorn/no-unnecessary-await': 'error',
|
||||
'unicorn/no-unsafe-regex': 'warn',
|
||||
'unicorn/no-useless-promise-resolve-reject': 'error',
|
||||
'unicorn/prefer-array-find': 'error',
|
||||
'unicorn/prefer-array-flat-map': 'error',
|
||||
'unicorn/prefer-array-index-of': 'error',
|
||||
'unicorn/prefer-array-some': 'error',
|
||||
'unicorn/prefer-default-parameters': 'error',
|
||||
'unicorn/prefer-includes': 'error',
|
||||
'unicorn/prefer-negative-index': 'error',
|
||||
'unicorn/prefer-object-from-entries': 'error',
|
||||
'unicorn/prefer-string-starts-ends-with': 'error',
|
||||
'unicorn/prefer-string-trim-start-end': 'error',
|
||||
'unicorn/string-content': 'error',
|
||||
'unicorn/prefer-spread': 'error',
|
||||
'unicorn/no-lonely-if': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['cypress/**', 'demos/**'],
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.{js,jsx,mjs,cjs}'],
|
||||
rules: {
|
||||
'jsdoc/check-indentation': 'off',
|
||||
'jsdoc/check-alignment': 'off',
|
||||
'jsdoc/check-line-alignment': 'off',
|
||||
'jsdoc/multiline-blocks': 'off',
|
||||
'jsdoc/newline-after-description': 'off',
|
||||
'jsdoc/tag-lines': 'off',
|
||||
'jsdoc/require-param-description': 'off',
|
||||
'jsdoc/require-param-type': 'off',
|
||||
'jsdoc/require-returns': 'off',
|
||||
'jsdoc/require-returns-description': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
rules: {
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
selector: 'TSEnumDeclaration',
|
||||
message:
|
||||
'Prefer using TypeScript union types over TypeScript enum, since TypeScript enums have a bunch of issues, see https://dev.to/dvddpl/whats-the-problem-with-typescript-enums-2okj',
|
||||
},
|
||||
],
|
||||
'tsdoc/syntax': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.spec.{ts,js}', 'cypress/**', 'demos/**', '**/docs/**'],
|
||||
rules: {
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.spec.{ts,js}', 'tests/**', 'cypress/**/*.js'],
|
||||
rules: {
|
||||
'@cspell/spellchecker': [
|
||||
'error',
|
||||
{
|
||||
checkIdentifiers: false,
|
||||
checkStrings: false,
|
||||
checkStringTemplates: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.html', '*.md', '**/*.md/*'],
|
||||
rules: {
|
||||
'no-var': 'error',
|
||||
'no-undef': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'off',
|
||||
'@typescript-eslint/no-misused-promises': 'off',
|
||||
},
|
||||
processor: 'markdown/markdown',
|
||||
}
|
||||
);
|
36
package.json
36
package.json
@ -25,8 +25,8 @@
|
||||
"dev:vite": "tsx .vite/server.ts",
|
||||
"dev:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm dev:vite",
|
||||
"release": "pnpm build",
|
||||
"lint": "cross-env NODE_OPTIONS=--max_old_space_size=48192 eslint --cache --cache-strategy content . && pnpm lint:jison && prettier --cache --check .",
|
||||
"lint:fix": "cross-env NODE_OPTIONS=--max_old_space_size=48192 eslint --cache --cache-strategy content --fix . && prettier --write . && tsx scripts/fixCSpell.ts",
|
||||
"lint": "eslint --quiet --stats --cache --cache-strategy content . && pnpm lint:jison && prettier --cache --check .",
|
||||
"lint:fix": "eslint --cache --cache-strategy content --fix . && prettier --write . && tsx scripts/fixCSpell.ts",
|
||||
"lint:jison": "tsx ./scripts/jison/lint.mts",
|
||||
"contributors": "tsx scripts/updateContributors.ts",
|
||||
"cypress": "cypress run",
|
||||
@ -63,11 +63,11 @@
|
||||
"devDependencies": {
|
||||
"@applitools/eyes-cypress": "^3.44.4",
|
||||
"@argos-ci/cypress": "^2.0.5",
|
||||
"@cspell/eslint-plugin": "^8.6.0",
|
||||
"@cspell/eslint-plugin": "^8.8.4",
|
||||
"@cypress/code-coverage": "^3.12.30",
|
||||
"@eslint/js": "^9.4.0",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/eslint": "^8.56.6",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/jsdom": "^21.1.6",
|
||||
@ -75,8 +75,6 @@
|
||||
"@types/mdast": "^4.0.3",
|
||||
"@types/node": "^20.11.30",
|
||||
"@types/rollup-plugin-visualizer": "^4.2.4",
|
||||
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
||||
"@typescript-eslint/parser": "^7.3.1",
|
||||
"@vitest/coverage-v8": "^1.4.0",
|
||||
"@vitest/spy": "^1.4.0",
|
||||
"@vitest/ui": "^1.4.0",
|
||||
@ -88,20 +86,21 @@
|
||||
"cspell": "^8.6.0",
|
||||
"cypress": "^13.11.0",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
"esbuild": "^0.20.2",
|
||||
"eslint": "^8.57.0",
|
||||
"esbuild": "^0.21.5",
|
||||
"eslint": "^9.4.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-cypress": "^2.15.1",
|
||||
"eslint-plugin-html": "^8.0.0",
|
||||
"eslint-plugin-jest": "^27.9.0",
|
||||
"eslint-plugin-jsdoc": "^48.2.1",
|
||||
"eslint-plugin-json": "^3.1.0",
|
||||
"eslint-plugin-lodash": "^7.4.0",
|
||||
"eslint-plugin-markdown": "^4.0.1",
|
||||
"eslint-plugin-cypress": "^3.3.0",
|
||||
"eslint-plugin-html": "^8.1.1",
|
||||
"eslint-plugin-jest": "^28.6.0",
|
||||
"eslint-plugin-jsdoc": "^48.2.9",
|
||||
"eslint-plugin-json": "^4.0.0",
|
||||
"eslint-plugin-lodash": "^8.0.0",
|
||||
"eslint-plugin-markdown": "^5.0.0",
|
||||
"eslint-plugin-no-only-tests": "^3.1.0",
|
||||
"eslint-plugin-tsdoc": "^0.2.17",
|
||||
"eslint-plugin-unicorn": "^51.0.1",
|
||||
"eslint-plugin-tsdoc": "^0.3.0",
|
||||
"eslint-plugin-unicorn": "^53.0.0",
|
||||
"express": "^4.19.1",
|
||||
"globals": "^15.4.0",
|
||||
"globby": "^14.0.1",
|
||||
"husky": "^9.0.11",
|
||||
"jest": "^29.7.0",
|
||||
@ -120,7 +119,8 @@
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"start-server-and-test": "^2.0.3",
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "~5.4.3",
|
||||
"typescript": "~5.4.5",
|
||||
"typescript-eslint": "^8.0.0-alpha.34",
|
||||
"vite": "^5.2.3",
|
||||
"vite-plugin-istanbul": "^6.0.0",
|
||||
"vitest": "^1.4.0"
|
||||
|
@ -25,7 +25,7 @@ export const log: Record<keyof typeof LEVELS, typeof console.log> = {
|
||||
fatal: warning,
|
||||
};
|
||||
|
||||
export let setLogLevel: (level: keyof typeof LEVELS | number | string) => void;
|
||||
export let setLogLevel: (level: keyof typeof LEVELS | number) => void;
|
||||
export let getConfig: () => object;
|
||||
export let sanitizeText: (str: string) => string;
|
||||
export let commonDb: () => object;
|
||||
|
11
packages/mermaid-example-diagram/tsconfig.eslint.json
Normal file
11
packages/mermaid-example-diagram/tsconfig.eslint.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": ["./tsconfig.json"],
|
||||
"compilerOptions": {
|
||||
"noEmit": true
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.spec.js",
|
||||
"./src/**/*.spec.ts" // test files
|
||||
]
|
||||
}
|
@ -187,19 +187,6 @@ export const addVertices = async function (vert, svgId, root, doc, diagObj, pare
|
||||
nodeEl = await insertNode(nodes, node, vertex.dir);
|
||||
boundingBox = nodeEl.node().getBBox();
|
||||
} else {
|
||||
doc.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
// svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
|
||||
// const rows = vertexText.split(common.lineBreakRegex);
|
||||
// for (const row of rows) {
|
||||
// const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
// tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
|
||||
// tspan.setAttribute('dy', '1em');
|
||||
// tspan.setAttribute('x', '1');
|
||||
// tspan.textContent = row;
|
||||
// svgLabel.appendChild(tspan);
|
||||
// }
|
||||
// vertexNode = svgLabel;
|
||||
// const bbox = vertexNode.getBBox();
|
||||
const { shapeSvg, bbox } = await labelHelper(nodes, node, undefined, true);
|
||||
labelData.width = bbox.width;
|
||||
labelData.wrappingWidth = getConfig().flowchart.wrappingWidth;
|
||||
|
@ -26,7 +26,7 @@ export const log: Record<keyof typeof LEVELS, typeof console.log> = {
|
||||
fatal: warning,
|
||||
};
|
||||
|
||||
export let setLogLevel: (level: keyof typeof LEVELS | number | string) => void;
|
||||
export let setLogLevel: (level: keyof typeof LEVELS | number) => void;
|
||||
export let getConfig: () => MermaidConfig;
|
||||
export let sanitizeText: (str: string) => string;
|
||||
// eslint-disable @typescript-eslint/no-explicit-any
|
||||
|
@ -9,7 +9,7 @@ function createTemporaryZenumlContainer(id: string) {
|
||||
container.id = `container-${id}`;
|
||||
container.style.display = 'flex';
|
||||
container.innerHTML = `<div id="zenUMLApp-${id}"></div>`;
|
||||
const app = container.querySelector(`#zenUMLApp-${id}`) as HTMLElement;
|
||||
const app = container.querySelector(`#zenUMLApp-${id}`)!;
|
||||
return { container, app };
|
||||
}
|
||||
|
||||
|
@ -103,8 +103,6 @@
|
||||
"@types/prettier": "^3.0.0",
|
||||
"@types/stylis": "^4.2.5",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
||||
"@typescript-eslint/parser": "^7.3.1",
|
||||
"ajv": "^8.12.0",
|
||||
"chokidar": "^3.6.0",
|
||||
"concurrently": "^8.2.2",
|
||||
|
@ -97,7 +97,7 @@ async function generateTypescript(mermaidConfigSchema: JSONSchemaType<MermaidCon
|
||||
* @returns The schema with `allOf` replaced with `extends`.
|
||||
*/
|
||||
function replaceAllOfWithExtends(schema: JSONSchemaType<Record<string, any>>) {
|
||||
if (schema['allOf']) {
|
||||
if (schema.allOf) {
|
||||
const { allOf, ...schemaWithoutAllOf } = schema;
|
||||
return {
|
||||
...schemaWithoutAllOf,
|
||||
|
@ -88,9 +88,9 @@ const WARN_DOCSDIR_DOESNT_MATCH = `Changed files were transformed in ${SOURCE_DO
|
||||
const prettierConfig = (await prettier.resolveConfig('.')) ?? {};
|
||||
// From https://github.com/vuejs/vitepress/blob/428eec3750d6b5648a77ac52d88128df0554d4d1/src/node/markdownToVue.ts#L20-L21
|
||||
const includesRE = /<!--\s*@include:\s*(.*?)\s*-->/g;
|
||||
const includedFiles: Set<string> = new Set();
|
||||
const includedFiles = new Set<string>();
|
||||
|
||||
const filesTransformed: Set<string> = new Set();
|
||||
const filesTransformed = new Set<string>();
|
||||
|
||||
const generateHeader = (file: string): string => {
|
||||
// path from file in docs/* to repo root, e.g ../ or ../../ */
|
||||
@ -181,10 +181,10 @@ export const transformToBlockQuote = (
|
||||
) => {
|
||||
if (vitepress) {
|
||||
const vitepressType = type === 'note' ? 'info' : type;
|
||||
return `::: ${vitepressType} ${customTitle || ''}\n${content}\n:::`;
|
||||
return `::: ${vitepressType} ${customTitle ?? ''}\n${content}\n:::`;
|
||||
} else {
|
||||
const icon = blockIcons[type] || '';
|
||||
const title = `${icon}${customTitle || capitalize(type)}`;
|
||||
const icon = blockIcons[type] ?? '';
|
||||
const title = `${icon}${customTitle ?? capitalize(type)}`;
|
||||
return `> **${title}** \n> ${content.replace(/\n/g, '\n> ')}`;
|
||||
}
|
||||
};
|
||||
@ -201,6 +201,7 @@ const transformIncludeStatements = (file: string, text: string): string => {
|
||||
includedFiles.add(changeToFinalDocDir(includePath));
|
||||
return content;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
throw new Error(`Failed to resolve include "${m1}" in "${file}": ${error}`);
|
||||
}
|
||||
});
|
||||
@ -241,7 +242,7 @@ export function transformMarkdownAst({
|
||||
addEditLink,
|
||||
removeYAML,
|
||||
}: TransformMarkdownAstOptions) {
|
||||
return (tree: Root, _file?: any): Root => {
|
||||
return (tree: Root): Root => {
|
||||
const astWithTransformedBlocks = flatmap(tree, (node: Code) => {
|
||||
if (node.type !== 'code' || !node.lang) {
|
||||
return [node]; // no transformation if this is not a code block
|
||||
@ -509,6 +510,7 @@ export const getGlobs = (globs: string[]): string[] => {
|
||||
globs.push(
|
||||
'!**/.vitepress/**',
|
||||
'!**/vite.config.ts',
|
||||
'!**/tsconfig.json',
|
||||
'!src/docs/index.md',
|
||||
'!**/package.json',
|
||||
'!**/user-avatars/**'
|
||||
|
@ -6,6 +6,7 @@ import { encodeEntities } from './utils.js';
|
||||
import type { DetailedError } from './utils.js';
|
||||
import type { DiagramDefinition, DiagramMetadata } from './diagram-api/types.js';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
||||
export type ParseErrorFunction = (err: string | DetailedError | unknown, hash?: any) => void;
|
||||
|
||||
/**
|
||||
@ -19,7 +20,7 @@ export class Diagram {
|
||||
text = encodeEntities(text) + '\n';
|
||||
try {
|
||||
getDiagram(type);
|
||||
} catch (e) {
|
||||
} catch {
|
||||
const loader = getDiagramLoader(type);
|
||||
if (!loader) {
|
||||
throw new UnknownDiagramError(`Diagram ${type} not found.`);
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import * as configApi from './config.js';
|
||||
import type { MermaidConfig } from './config.type.js';
|
||||
|
||||
|
@ -189,7 +189,7 @@ export const addDirective = (directive: MermaidConfig) => {
|
||||
sanitizeDirective(directive);
|
||||
|
||||
// If the directive has a fontFamily, but no themeVariables, add the fontFamily to the themeVariables
|
||||
if (directive.fontFamily && (!directive.themeVariables || !directive.themeVariables.fontFamily)) {
|
||||
if (directive.fontFamily && !directive.themeVariables?.fontFamily) {
|
||||
directive.themeVariables = {
|
||||
...directive.themeVariables,
|
||||
fontFamily: directive.fontFamily,
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/unbound-method */
|
||||
import type { Mocked } from 'vitest';
|
||||
import type { SVG } from '../diagram-api/types.js';
|
||||
import { addEdgeMarkers } from './edgeMarker.js';
|
||||
|
@ -51,7 +51,7 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
|
||||
}
|
||||
}
|
||||
log.info('(Insert) Node XXX' + v + ': ' + JSON.stringify(graph.node(v)));
|
||||
if (node && node.clusterNode) {
|
||||
if (node?.clusterNode) {
|
||||
// const children = graph.children(v);
|
||||
log.info('Cluster identified', v, node.width, graph.node(v));
|
||||
// `node.graph.setGraph` applies the graph configurations such as nodeSpacing to subgraphs as without this the default values would be used
|
||||
@ -131,7 +131,7 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
|
||||
' height: ',
|
||||
node.height
|
||||
);
|
||||
if (node && node.clusterNode) {
|
||||
if (node?.clusterNode) {
|
||||
// clusterDb[node.id].node = node;
|
||||
node.y += subGraphTitleTotalMargin;
|
||||
positionNode(node);
|
||||
|
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
node: require('./intersect-node'),
|
||||
circle: require('./intersect-circle'),
|
||||
ellipse: require('./intersect-ellipse'),
|
||||
polygon: require('./intersect-polygon'),
|
||||
rect: require('./intersect-rect'),
|
||||
};
|
@ -399,7 +399,7 @@ export const extractor = (graph, depth) => {
|
||||
|
||||
const graphSettings = graph.graph();
|
||||
let dir = graphSettings.rankdir === 'TB' ? 'LR' : 'TB';
|
||||
if (clusterDb[node] && clusterDb[node].clusterData && clusterDb[node].clusterData.dir) {
|
||||
if (clusterDb[node]?.clusterData?.dir) {
|
||||
dir = clusterDb[node].clusterData.dir;
|
||||
log.warn('Fixing dir', clusterDb[node].clusterData.dir, dir);
|
||||
}
|
||||
|
@ -902,7 +902,7 @@ const class_box = (parent, node) => {
|
||||
|
||||
const labelContainer = shapeSvg.insert('g').attr('class', 'label');
|
||||
let verticalPos = 0;
|
||||
const hasInterface = node.classData.annotations && node.classData.annotations[0];
|
||||
const hasInterface = node.classData.annotations?.[0];
|
||||
|
||||
// 1. Create the labels
|
||||
const interfaceLabelText = node.classData.annotations[0]
|
||||
|
@ -1,52 +0,0 @@
|
||||
/** Setup arrow head and define the marker. The result is appended to the svg. */
|
||||
|
||||
// import { log } from '../logger.js';
|
||||
|
||||
// Only add the number of markers that the diagram needs
|
||||
const insertPatterns = (elem, patternArray, type, id) => {
|
||||
patternArray.forEach((patternName) => {
|
||||
patterns[patternName](elem, type, id);
|
||||
});
|
||||
};
|
||||
|
||||
{
|
||||
/* <svg height="10" width="10" xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||
{' '}
|
||||
<defs>
|
||||
{' '}
|
||||
<pattern id="circles-1" patternUnits="userSpaceOnUse" width="10" height="10">
|
||||
{' '}
|
||||
<image
|
||||
xlink:href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+CiAgPHJlY3Qgd2lkdGg9JzEwJyBoZWlnaHQ9JzEwJyBmaWxsPSJ3aGl0ZSIgLz4KICA8Y2lyY2xlIGN4PSIxIiBjeT0iMSIgcj0iMSIgZmlsbD0iYmxhY2siLz4KPC9zdmc+"
|
||||
x="0"
|
||||
y="0"
|
||||
width="10"
|
||||
height="10"
|
||||
>
|
||||
{' '}
|
||||
</image>{' '}
|
||||
</pattern>{' '}
|
||||
</defs>{' '}
|
||||
</svg>; */
|
||||
}
|
||||
|
||||
const dots = (elem, type) => {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-barbEnd')
|
||||
.attr('refX', 19)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 20)
|
||||
.attr('markerHeight', 14)
|
||||
.attr('markerUnits', 0)
|
||||
.attr('orient', 'auto')
|
||||
.append('path')
|
||||
.attr('d', 'M 19,7 L9,13 L14,7 L9,1 Z');
|
||||
};
|
||||
|
||||
// TODO rename the class diagram markers to something shape descriptive and semantic free
|
||||
const patterns = {
|
||||
dots,
|
||||
};
|
||||
export default insertPatterns;
|
@ -23,7 +23,7 @@ const config: RequiredDeep<MermaidConfig> = {
|
||||
themeCSS: undefined,
|
||||
|
||||
// add non-JSON default config values
|
||||
themeVariables: theme['default'].getThemeVariables(),
|
||||
themeVariables: theme.default.getThemeVariables(),
|
||||
sequence: {
|
||||
...defaultConfigJson.sequence,
|
||||
messageFont: function () {
|
||||
@ -272,5 +272,5 @@ const keyify = (obj: any, prefix = ''): string[] =>
|
||||
return [...res, prefix + el];
|
||||
}, []);
|
||||
|
||||
export const configKeys: Set<string> = new Set(keyify(config, ''));
|
||||
export const configKeys = new Set<string>(keyify(config, ''));
|
||||
export default config;
|
||||
|
@ -29,7 +29,7 @@ describe('DiagramAPI', () => {
|
||||
`[UnknownDiagramError: No diagram type detected matching given configuration for text: loki diagram]`
|
||||
);
|
||||
const detector: DiagramDetector = (str: string) => {
|
||||
return str.match('loki') !== null;
|
||||
return /loki/.exec(str) !== null;
|
||||
};
|
||||
registerDiagram(
|
||||
'loki',
|
||||
|
@ -30,9 +30,7 @@ export const getCommonDb = () => {
|
||||
};
|
||||
|
||||
const diagrams: Record<string, DiagramDefinition> = {};
|
||||
export interface Detectors {
|
||||
[key: string]: DiagramDetector;
|
||||
}
|
||||
export type Detectors = Record<string, DiagramDetector>;
|
||||
|
||||
/**
|
||||
* Registers the given diagram with Mermaid.
|
||||
|
@ -10,7 +10,7 @@ export const loadRegisteredDiagrams = async () => {
|
||||
if (loader) {
|
||||
try {
|
||||
getDiagram(key);
|
||||
} catch (error) {
|
||||
} catch {
|
||||
try {
|
||||
// Register diagram if it is not already registered
|
||||
const { diagram, id } = await loader();
|
||||
|
@ -30,12 +30,12 @@ const getDummyDiagram = (id: string, title?: string): Awaited<ReturnType<Diagram
|
||||
|
||||
describe('diagram detection', () => {
|
||||
test('should detect inbuilt diagrams', async () => {
|
||||
const graph = (await Diagram.fromText('graph TD; A-->B')) as Diagram;
|
||||
const graph = await Diagram.fromText('graph TD; A-->B');
|
||||
expect(graph).toBeInstanceOf(Diagram);
|
||||
expect(graph.type).toBe('flowchart-v2');
|
||||
const sequence = (await Diagram.fromText(
|
||||
const sequence = await Diagram.fromText(
|
||||
'sequenceDiagram; Alice->>+John: Hello John, how are you?'
|
||||
)) as Diagram;
|
||||
);
|
||||
expect(sequence).toBeInstanceOf(Diagram);
|
||||
expect(sequence.type).toBe('sequence');
|
||||
});
|
||||
|
@ -8,9 +8,9 @@ import { clear as commonClear } from '../common/commonDb.js';
|
||||
import type { Block, ClassDef } from './blockTypes.js';
|
||||
|
||||
// Initialize the node database for simple lookups
|
||||
let blockDatabase: Map<string, Block> = new Map();
|
||||
let blockDatabase = new Map<string, Block>();
|
||||
let edgeList: Block[] = [];
|
||||
let edgeCount: Map<string, number> = new Map();
|
||||
let edgeCount = new Map<string, number>();
|
||||
|
||||
const COLOR_KEYWORD = 'color';
|
||||
const FILL_KEYWORD = 'fill';
|
||||
@ -18,7 +18,7 @@ const BG_FILL = 'bgFill';
|
||||
const STYLECLASS_SEP = ',';
|
||||
const config = getConfig();
|
||||
|
||||
let classes: Map<string, ClassDef> = new Map();
|
||||
let classes = new Map<string, ClassDef>();
|
||||
|
||||
const sanitizeText = (txt: string) => common.sanitizeText(txt, config);
|
||||
|
||||
@ -42,7 +42,7 @@ export const addStyleClass = function (id: string, styleAttributes = '') {
|
||||
const fixedAttrib = attrib.replace(/([^;]*);/, '$1').trim();
|
||||
|
||||
// replace some style keywords
|
||||
if (attrib.match(COLOR_KEYWORD)) {
|
||||
if (RegExp(COLOR_KEYWORD).exec(attrib)) {
|
||||
const newStyle1 = fixedAttrib.replace(FILL_KEYWORD, BG_FILL);
|
||||
const newStyle2 = newStyle1.replace(COLOR_KEYWORD, FILL_KEYWORD);
|
||||
foundClass.textStyles.push(newStyle2);
|
||||
@ -89,7 +89,7 @@ export const setCssClass = function (itemIds: string, cssClassName: string) {
|
||||
});
|
||||
};
|
||||
|
||||
const populateBlockDatabase = (_blockList: Block[] | Block[][], parent: Block): void => {
|
||||
const populateBlockDatabase = (_blockList: Block[], parent: Block): void => {
|
||||
const blockList = _blockList.flat();
|
||||
const children = [];
|
||||
for (const block of blockList) {
|
||||
@ -101,7 +101,7 @@ const populateBlockDatabase = (_blockList: Block[] | Block[][], parent: Block):
|
||||
continue;
|
||||
}
|
||||
if (block.type === 'applyClass') {
|
||||
setCssClass(block.id, block?.styleClass || '');
|
||||
setCssClass(block.id, block?.styleClass ?? '');
|
||||
continue;
|
||||
}
|
||||
if (block.type === 'applyStyles') {
|
||||
@ -111,7 +111,7 @@ const populateBlockDatabase = (_blockList: Block[] | Block[][], parent: Block):
|
||||
continue;
|
||||
}
|
||||
if (block.type === 'column-setting') {
|
||||
parent.columns = block.columns || -1;
|
||||
parent.columns = block.columns ?? -1;
|
||||
} else if (block.type === 'edge') {
|
||||
const count = (edgeCount.get(block.id) ?? 0) + 1;
|
||||
edgeCount.set(block.id, count);
|
||||
@ -145,7 +145,7 @@ const populateBlockDatabase = (_blockList: Block[] | Block[][], parent: Block):
|
||||
}
|
||||
if (block.type === 'space') {
|
||||
// log.debug('abc95 space', block);
|
||||
const w = block.width || 1;
|
||||
const w = block.width ?? 1;
|
||||
for (let j = 0; j < w; j++) {
|
||||
const newBlock = clone(block);
|
||||
newBlock.id = newBlock.id + '-' + j;
|
||||
@ -168,7 +168,7 @@ const clear = (): void => {
|
||||
commonClear();
|
||||
rootBlock = { id: 'root', type: 'composite', children: [], columns: -1 } as Block;
|
||||
blockDatabase = new Map([['root', rootBlock]]);
|
||||
blocks = [] as Block[];
|
||||
blocks = [];
|
||||
classes = new Map();
|
||||
|
||||
edgeList = [];
|
||||
|
@ -1,11 +1,6 @@
|
||||
import {
|
||||
scaleOrdinal as d3scaleOrdinal,
|
||||
schemeTableau10 as d3schemeTableau10,
|
||||
select as d3select,
|
||||
} from 'd3';
|
||||
import { select as d3select } from 'd3';
|
||||
import type { Diagram } from '../../Diagram.js';
|
||||
import * as configApi from '../../config.js';
|
||||
import type { MermaidConfig } from '../../config.type.js';
|
||||
import insertMarkers from '../../dagre-wrapper/markers.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||
@ -75,7 +70,7 @@ export const draw = async function (
|
||||
const magicFactor = Math.max(1, Math.round(0.125 * (bounds2.width / bounds2.height)));
|
||||
const height = bounds2.height + magicFactor + 10;
|
||||
const width = bounds2.width + 10;
|
||||
const { useMaxWidth } = conf as Exclude<MermaidConfig['block'], undefined>;
|
||||
const { useMaxWidth } = conf!;
|
||||
configureSvgSize(svg, height, width, !!useMaxWidth);
|
||||
log.debug('Here Bounds', bounds, bounds2);
|
||||
svg.attr(
|
||||
@ -83,9 +78,6 @@ export const draw = async function (
|
||||
`${bounds2.x - 5} ${bounds2.y - 5} ${bounds2.width + 10} ${bounds2.height + 10}`
|
||||
);
|
||||
}
|
||||
|
||||
// Get color scheme for the graph
|
||||
// const colorScheme = d3scaleOrdinal(d3schemeTableau10);
|
||||
};
|
||||
|
||||
export default {
|
||||
|
@ -2,7 +2,8 @@ import type { BlockDB } from './blockDB.js';
|
||||
import type { Block } from './blockTypes.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
const padding = getConfig()?.block?.padding || 8;
|
||||
// TODO: This means the number we provide in diagram's config will never be used. Should fix.
|
||||
const padding = getConfig()?.block?.padding ?? 8;
|
||||
|
||||
interface BlockPosition {
|
||||
px: number;
|
||||
@ -42,7 +43,7 @@ const getMaxChildSize = (block: Block) => {
|
||||
// find max width of children
|
||||
// log.debug('getMaxChildSize abc95 (start) parent:', block.id);
|
||||
for (const child of block.children) {
|
||||
const { width, height, x, y } = child.size || { width: 0, height: 0, x: 0, y: 0 };
|
||||
const { width, height, x, y } = child.size ?? { width: 0, height: 0, x: 0, y: 0 };
|
||||
log.debug(
|
||||
'getMaxChildSize abc95 child:',
|
||||
child.id,
|
||||
@ -60,7 +61,7 @@ const getMaxChildSize = (block: Block) => {
|
||||
continue;
|
||||
}
|
||||
if (width > maxWidth) {
|
||||
maxWidth = width / (block.widthInColumns || 1);
|
||||
maxWidth = width / (block.widthInColumns ?? 1);
|
||||
}
|
||||
if (height > maxHeight) {
|
||||
maxHeight = height;
|
||||
@ -104,10 +105,10 @@ function setBlockSizes(block: Block, db: BlockDB, siblingWidth = 0, siblingHeigh
|
||||
for (const child of block.children) {
|
||||
if (child.size) {
|
||||
log.debug(
|
||||
`abc95 Setting size of children of ${block.id} id=${child.id} ${maxWidth} ${maxHeight} ${child.size}`
|
||||
`abc95 Setting size of children of ${block.id} id=${child.id} ${maxWidth} ${maxHeight} ${JSON.stringify(child.size)}`
|
||||
);
|
||||
child.size.width =
|
||||
maxWidth * (child.widthInColumns || 1) + padding * ((child.widthInColumns || 1) - 1);
|
||||
maxWidth * (child.widthInColumns ?? 1) + padding * ((child.widthInColumns ?? 1) - 1);
|
||||
child.size.height = maxHeight;
|
||||
child.size.x = 0;
|
||||
child.size.y = 0;
|
||||
@ -121,10 +122,10 @@ function setBlockSizes(block: Block, db: BlockDB, siblingWidth = 0, siblingHeigh
|
||||
setBlockSizes(child, db, maxWidth, maxHeight);
|
||||
}
|
||||
|
||||
const columns = block.columns || -1;
|
||||
const columns = block.columns ?? -1;
|
||||
let numItems = 0;
|
||||
for (const child of block.children) {
|
||||
numItems += child.widthInColumns || 1;
|
||||
numItems += child.widthInColumns ?? 1;
|
||||
}
|
||||
|
||||
// The width and height in number blocks
|
||||
@ -133,8 +134,6 @@ function setBlockSizes(block: Block, db: BlockDB, siblingWidth = 0, siblingHeigh
|
||||
xSize = columns;
|
||||
}
|
||||
|
||||
const w = block.widthInColumns || 1;
|
||||
|
||||
const ySize = Math.ceil(numItems / xSize);
|
||||
|
||||
let width = xSize * (maxWidth + padding) + padding;
|
||||
@ -206,13 +205,13 @@ function layoutBlocks(block: Block, db: BlockDB) {
|
||||
log.debug(
|
||||
`abc85 layout blocks (=>layoutBlocks) ${block.id} x: ${block?.size?.x} y: ${block?.size?.y} width: ${block?.size?.width}`
|
||||
);
|
||||
const columns = block.columns || -1;
|
||||
const columns = block.columns ?? -1;
|
||||
log.debug('layoutBlocks columns abc95', block.id, '=>', columns, block);
|
||||
if (
|
||||
block.children && // find max width of children
|
||||
block.children.length > 0
|
||||
) {
|
||||
const width = block?.children[0]?.size?.width || 0;
|
||||
const width = block?.children[0]?.size?.width ?? 0;
|
||||
const widthOfChildren = block.children.length * width + (block.children.length - 1) * padding;
|
||||
|
||||
log.debug('widthOfChildren 88', widthOfChildren, 'posX');
|
||||
@ -251,7 +250,7 @@ function layoutBlocks(block: Block, db: BlockDB) {
|
||||
} ${halfWidth} padding=${padding} width=${width} halfWidth=${halfWidth} => x:${
|
||||
child.size.x
|
||||
} y:${child.size.y} ${child.widthInColumns} (width * (child?.w || 1)) / 2 ${
|
||||
(width * (child?.widthInColumns || 1)) / 2
|
||||
(width * (child?.widthInColumns ?? 1)) / 2
|
||||
}`
|
||||
);
|
||||
|
||||
@ -265,15 +264,13 @@ function layoutBlocks(block: Block, db: BlockDB) {
|
||||
child.id
|
||||
}startingPosX${startingPosX}${padding}${halfWidth}=>x:${child.size.x}y:${child.size.y}${
|
||||
child.widthInColumns
|
||||
}(width * (child?.w || 1)) / 2${(width * (child?.widthInColumns || 1)) / 2}`
|
||||
}(width * (child?.w || 1)) / 2${(width * (child?.widthInColumns ?? 1)) / 2}`
|
||||
);
|
||||
}
|
||||
|
||||
// posY += height + padding;
|
||||
if (child.children) {
|
||||
layoutBlocks(child, db);
|
||||
}
|
||||
columnPos += child?.widthInColumns || 1;
|
||||
columnPos += child?.widthInColumns ?? 1;
|
||||
log.debug('abc88 columnsPos', child, columnPos);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
// @ts-ignore: jison doesn't export types
|
||||
import block from './block.jison';
|
||||
import db from '../blockDB.js';
|
||||
import { cleanupComments } from '../../../diagram-api/comments.js';
|
||||
import { prepareTextForParsing } from '../blockUtils.js';
|
||||
import { setConfig } from '../../../config.js';
|
||||
|
||||
describe('Block diagram', function () {
|
||||
describe('when parsing an block diagram graph it should handle > ', function () {
|
||||
@ -13,7 +10,7 @@ describe('Block diagram', function () {
|
||||
block.parser.yy.getLogger = () => console;
|
||||
});
|
||||
|
||||
it('a diagram with a node', async () => {
|
||||
it('a diagram with a node', () => {
|
||||
const str = `block-beta
|
||||
id
|
||||
`;
|
||||
@ -24,7 +21,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks[0].id).toBe('id');
|
||||
expect(blocks[0].label).toBe('id');
|
||||
});
|
||||
it('a node with a square shape and a label', async () => {
|
||||
it('a node with a square shape and a label', () => {
|
||||
const str = `block-beta
|
||||
id["A label"]
|
||||
`;
|
||||
@ -36,7 +33,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks[0].label).toBe('A label');
|
||||
expect(blocks[0].type).toBe('square');
|
||||
});
|
||||
it('a diagram with multiple nodes', async () => {
|
||||
it('a diagram with multiple nodes', () => {
|
||||
const str = `block-beta
|
||||
id1
|
||||
id2
|
||||
@ -52,7 +49,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks[1].label).toBe('id2');
|
||||
expect(blocks[1].type).toBe('na');
|
||||
});
|
||||
it('a diagram with multiple nodes', async () => {
|
||||
it('a diagram with multiple nodes', () => {
|
||||
const str = `block-beta
|
||||
id1
|
||||
id2
|
||||
@ -73,7 +70,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks[2].type).toBe('na');
|
||||
});
|
||||
|
||||
it('a node with a square shape and a label', async () => {
|
||||
it('a node with a square shape and a label', () => {
|
||||
const str = `block-beta
|
||||
id["A label"]
|
||||
id2`;
|
||||
@ -88,7 +85,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks[1].label).toBe('id2');
|
||||
expect(blocks[1].type).toBe('na');
|
||||
});
|
||||
it('a diagram with multiple nodes with edges abc123', async () => {
|
||||
it('a diagram with multiple nodes with edges abc123', () => {
|
||||
const str = `block-beta
|
||||
id1["first"] --> id2["second"]
|
||||
`;
|
||||
@ -102,7 +99,7 @@ describe('Block diagram', function () {
|
||||
expect(edges[0].end).toBe('id2');
|
||||
expect(edges[0].arrowTypeEnd).toBe('arrow_point');
|
||||
});
|
||||
it('a diagram with multiple nodes with edges abc123', async () => {
|
||||
it('a diagram with multiple nodes with edges abc123', () => {
|
||||
const str = `block-beta
|
||||
id1["first"] -- "a label" --> id2["second"]
|
||||
`;
|
||||
@ -117,7 +114,7 @@ describe('Block diagram', function () {
|
||||
expect(edges[0].arrowTypeEnd).toBe('arrow_point');
|
||||
expect(edges[0].label).toBe('a label');
|
||||
});
|
||||
it('a diagram with column statements', async () => {
|
||||
it('a diagram with column statements', () => {
|
||||
const str = `block-beta
|
||||
columns 2
|
||||
block1["Block 1"]
|
||||
@ -128,7 +125,7 @@ describe('Block diagram', function () {
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(1);
|
||||
});
|
||||
it('a diagram withput column statements', async () => {
|
||||
it('a diagram withput column statements', () => {
|
||||
const str = `block-beta
|
||||
block1["Block 1"]
|
||||
`;
|
||||
@ -138,7 +135,7 @@ describe('Block diagram', function () {
|
||||
const blocks = db.getBlocks();
|
||||
expect(blocks.length).toBe(1);
|
||||
});
|
||||
it('a diagram with auto column statements', async () => {
|
||||
it('a diagram with auto column statements', () => {
|
||||
const str = `block-beta
|
||||
columns auto
|
||||
block1["Block 1"]
|
||||
@ -150,7 +147,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks.length).toBe(1);
|
||||
});
|
||||
|
||||
it('blocks next to each other', async () => {
|
||||
it('blocks next to each other', () => {
|
||||
const str = `block-beta
|
||||
columns 2
|
||||
block1["Block 1"]
|
||||
@ -164,7 +161,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks.length).toBe(2);
|
||||
});
|
||||
|
||||
it('blocks on top of each other', async () => {
|
||||
it('blocks on top of each other', () => {
|
||||
const str = `block-beta
|
||||
columns 1
|
||||
block1["Block 1"]
|
||||
@ -178,7 +175,7 @@ describe('Block diagram', function () {
|
||||
expect(blocks.length).toBe(2);
|
||||
});
|
||||
|
||||
it('compound blocks 2', async () => {
|
||||
it('compound blocks 2', () => {
|
||||
const str = `block-beta
|
||||
block
|
||||
aBlock["ABlock"]
|
||||
@ -206,7 +203,7 @@ describe('Block diagram', function () {
|
||||
expect(bBlock.label).toBe('BBlock');
|
||||
expect(bBlock.type).toBe('square');
|
||||
});
|
||||
it('compound blocks of compound blocks', async () => {
|
||||
it('compound blocks of compound blocks', () => {
|
||||
const str = `block-beta
|
||||
block
|
||||
aBlock["ABlock"]
|
||||
@ -241,7 +238,7 @@ describe('Block diagram', function () {
|
||||
expect(bBlock.label).toBe('BBlock');
|
||||
expect(bBlock.type).toBe('square');
|
||||
});
|
||||
it('compound blocks with title', async () => {
|
||||
it('compound blocks with title', () => {
|
||||
const str = `block-beta
|
||||
block:compoundBlock["Compound block"]
|
||||
columns 1
|
||||
@ -266,7 +263,7 @@ describe('Block diagram', function () {
|
||||
expect(block2.label).toBe('Block 2');
|
||||
expect(block2.type).toBe('square');
|
||||
});
|
||||
it('blocks mixed with compound blocks', async () => {
|
||||
it('blocks mixed with compound blocks', () => {
|
||||
const str = `block-beta
|
||||
columns 1
|
||||
block1["Block 1"]
|
||||
@ -293,7 +290,7 @@ describe('Block diagram', function () {
|
||||
expect(block2.type).toBe('square');
|
||||
});
|
||||
|
||||
it('Arrow blocks', async () => {
|
||||
it('Arrow blocks', () => {
|
||||
const str = `block-beta
|
||||
columns 3
|
||||
block1["Block 1"]
|
||||
@ -317,7 +314,7 @@ describe('Block diagram', function () {
|
||||
expect(blockArrow.type).toBe('block_arrow');
|
||||
expect(blockArrow.directions).toContain('right');
|
||||
});
|
||||
it('Arrow blocks with multiple points', async () => {
|
||||
it('Arrow blocks with multiple points', () => {
|
||||
const str = `block-beta
|
||||
columns 1
|
||||
A
|
||||
@ -340,7 +337,7 @@ describe('Block diagram', function () {
|
||||
expect(blockArrow.directions).toContain('down');
|
||||
expect(blockArrow.directions).not.toContain('right');
|
||||
});
|
||||
it('blocks with different widths', async () => {
|
||||
it('blocks with different widths', () => {
|
||||
const str = `block-beta
|
||||
columns 3
|
||||
one["One Slot"]
|
||||
@ -355,7 +352,7 @@ describe('Block diagram', function () {
|
||||
const two = blocks[1];
|
||||
expect(two.widthInColumns).toBe(2);
|
||||
});
|
||||
it('empty blocks', async () => {
|
||||
it('empty blocks', () => {
|
||||
const str = `block-beta
|
||||
columns 3
|
||||
space
|
||||
@ -374,7 +371,7 @@ describe('Block diagram', function () {
|
||||
expect(sp2.type).toBe('space');
|
||||
expect(middle.label).toBe('In the middle');
|
||||
});
|
||||
it('classDef statements applied to a block', async () => {
|
||||
it('classDef statements applied to a block', () => {
|
||||
const str = `block-beta
|
||||
classDef black color:#ffffff, fill:#000000;
|
||||
|
||||
@ -392,7 +389,7 @@ describe('Block diagram', function () {
|
||||
expect(black.id).toBe('black');
|
||||
expect(black.styles[0]).toEqual('color:#ffffff');
|
||||
});
|
||||
it('style statements applied to a block', async () => {
|
||||
it('style statements applied to a block', () => {
|
||||
const str = `block-beta
|
||||
columns 1
|
||||
B["A wide one in the middle"]
|
||||
|
@ -11,14 +11,13 @@ function getNodeFromBlock(block: Block, db: BlockDB, positioned = false) {
|
||||
|
||||
let classStr = 'default';
|
||||
if ((vertex?.classes?.length || 0) > 0) {
|
||||
classStr = (vertex?.classes || []).join(' ');
|
||||
classStr = (vertex?.classes ?? []).join(' ');
|
||||
}
|
||||
classStr = classStr + ' flowchart-label';
|
||||
|
||||
// We create a SVG label, either by delegating to addHtmlLabel or manually
|
||||
let radius = 0;
|
||||
let shape = '';
|
||||
let layoutOptions = {};
|
||||
let padding;
|
||||
// Set the shape based parameters
|
||||
switch (vertex.type) {
|
||||
@ -36,9 +35,6 @@ function getNodeFromBlock(block: Block, db: BlockDB, positioned = false) {
|
||||
break;
|
||||
case 'diamond':
|
||||
shape = 'question';
|
||||
layoutOptions = {
|
||||
portConstraints: 'FIXED_SIDE',
|
||||
};
|
||||
break;
|
||||
case 'hexagon':
|
||||
shape = 'hexagon';
|
||||
@ -89,12 +85,12 @@ function getNodeFromBlock(block: Block, db: BlockDB, positioned = false) {
|
||||
shape = 'rect';
|
||||
}
|
||||
|
||||
const styles = getStylesFromArray(vertex?.styles || []);
|
||||
const styles = getStylesFromArray(vertex?.styles ?? []);
|
||||
|
||||
// Use vertex id as text in the box if no text is provided by the graph definition
|
||||
const vertexText = vertex.label;
|
||||
|
||||
const bounds = vertex.size || { width: 0, height: 0, x: 0, y: 0 };
|
||||
const bounds = vertex.size ?? { width: 0, height: 0, x: 0, y: 0 };
|
||||
// Add the node
|
||||
const node = {
|
||||
labelStyle: styles.labelStyle,
|
||||
@ -113,7 +109,7 @@ function getNodeFromBlock(block: Block, db: BlockDB, positioned = false) {
|
||||
positioned,
|
||||
intersect: undefined,
|
||||
type: vertex.type,
|
||||
padding: padding ?? (getConfig()?.block?.padding || 0),
|
||||
padding: padding ?? getConfig()?.block?.padding ?? 0,
|
||||
};
|
||||
return node;
|
||||
}
|
||||
@ -142,7 +138,7 @@ export async function insertBlockPositioned(elem: any, block: Block, db: any) {
|
||||
// Add the element to the DOM to size it
|
||||
const obj = db.getBlock(node.id);
|
||||
if (obj.type !== 'space') {
|
||||
const nodeEl = await insertNode(elem, node);
|
||||
await insertNode(elem, node);
|
||||
block.intersect = node?.intersect;
|
||||
positionNode(node);
|
||||
}
|
||||
@ -218,7 +214,7 @@ export async function insertEdges(
|
||||
{ x: end.x, y: end.y },
|
||||
];
|
||||
// edge.points = points;
|
||||
await insertEdge(
|
||||
insertEdge(
|
||||
elem,
|
||||
{ v: edge.start, w: edge.end, name: edge.id },
|
||||
{
|
||||
@ -243,7 +239,7 @@ export async function insertEdges(
|
||||
points,
|
||||
classes: 'edge-thickness-normal edge-pattern-solid flowchart-link LS-a1 LE-b1',
|
||||
});
|
||||
await positionEdgeLabel(
|
||||
positionEdgeLabel(
|
||||
{ ...edge, x: points[1].x, y: points[1].y },
|
||||
{
|
||||
originalPath: points,
|
||||
|
@ -258,21 +258,21 @@ export const drawC4ShapeArray = function (currentBounds, diagram, c4ShapeArray,
|
||||
c4ShapeLabelConf.fontSize = c4ShapeLabelConf.fontSize + 2;
|
||||
c4ShapeLabelConf.fontWeight = 'bold';
|
||||
calcC4ShapeTextWH('label', c4Shape, c4ShapeTextWrap, c4ShapeLabelConf, textLimitWidth);
|
||||
c4Shape['label'].Y = Y + 8;
|
||||
Y = c4Shape['label'].Y + c4Shape['label'].height;
|
||||
c4Shape.label.Y = Y + 8;
|
||||
Y = c4Shape.label.Y + c4Shape.label.height;
|
||||
|
||||
if (c4Shape.type && c4Shape.type.text !== '') {
|
||||
c4Shape.type.text = '[' + c4Shape.type.text + ']';
|
||||
let c4ShapeTypeConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
|
||||
calcC4ShapeTextWH('type', c4Shape, c4ShapeTextWrap, c4ShapeTypeConf, textLimitWidth);
|
||||
c4Shape['type'].Y = Y + 5;
|
||||
Y = c4Shape['type'].Y + c4Shape['type'].height;
|
||||
c4Shape.type.Y = Y + 5;
|
||||
Y = c4Shape.type.Y + c4Shape.type.height;
|
||||
} else if (c4Shape.techn && c4Shape.techn.text !== '') {
|
||||
c4Shape.techn.text = '[' + c4Shape.techn.text + ']';
|
||||
let c4ShapeTechnConf = c4ShapeFont(conf, c4Shape.techn.text);
|
||||
calcC4ShapeTextWH('techn', c4Shape, c4ShapeTextWrap, c4ShapeTechnConf, textLimitWidth);
|
||||
c4Shape['techn'].Y = Y + 5;
|
||||
Y = c4Shape['techn'].Y + c4Shape['techn'].height;
|
||||
c4Shape.techn.Y = Y + 5;
|
||||
Y = c4Shape.techn.Y + c4Shape.techn.height;
|
||||
}
|
||||
|
||||
let rectHeight = Y;
|
||||
@ -281,11 +281,11 @@ export const drawC4ShapeArray = function (currentBounds, diagram, c4ShapeArray,
|
||||
if (c4Shape.descr && c4Shape.descr.text !== '') {
|
||||
let c4ShapeDescrConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
|
||||
calcC4ShapeTextWH('descr', c4Shape, c4ShapeTextWrap, c4ShapeDescrConf, textLimitWidth);
|
||||
c4Shape['descr'].Y = Y + 20;
|
||||
Y = c4Shape['descr'].Y + c4Shape['descr'].height;
|
||||
c4Shape.descr.Y = Y + 20;
|
||||
Y = c4Shape.descr.Y + c4Shape.descr.height;
|
||||
|
||||
rectWidth = Math.max(c4Shape.label.width, c4Shape.descr.width);
|
||||
rectHeight = Y - c4Shape['descr'].textLines * 5;
|
||||
rectHeight = Y - c4Shape.descr.textLines * 5;
|
||||
}
|
||||
|
||||
rectWidth = rectWidth + conf.c4ShapePadding;
|
||||
@ -482,8 +482,8 @@ function drawInsideBoundary(
|
||||
currentBoundaryLabelConf,
|
||||
currentBounds.data.widthLimit
|
||||
);
|
||||
currentBoundary['label'].Y = Y + 8;
|
||||
Y = currentBoundary['label'].Y + currentBoundary['label'].height;
|
||||
currentBoundary.label.Y = Y + 8;
|
||||
Y = currentBoundary.label.Y + currentBoundary.label.height;
|
||||
|
||||
if (currentBoundary.type && currentBoundary.type.text !== '') {
|
||||
currentBoundary.type.text = '[' + currentBoundary.type.text + ']';
|
||||
@ -495,8 +495,8 @@ function drawInsideBoundary(
|
||||
currentBoundaryTypeConf,
|
||||
currentBounds.data.widthLimit
|
||||
);
|
||||
currentBoundary['type'].Y = Y + 5;
|
||||
Y = currentBoundary['type'].Y + currentBoundary['type'].height;
|
||||
currentBoundary.type.Y = Y + 5;
|
||||
Y = currentBoundary.type.Y + currentBoundary.type.height;
|
||||
}
|
||||
|
||||
if (currentBoundary.descr && currentBoundary.descr.text !== '') {
|
||||
@ -509,8 +509,8 @@ function drawInsideBoundary(
|
||||
currentBoundaryDescrConf,
|
||||
currentBounds.data.widthLimit
|
||||
);
|
||||
currentBoundary['descr'].Y = Y + 20;
|
||||
Y = currentBoundary['descr'].Y + currentBoundary['descr'].height;
|
||||
currentBoundary.descr.Y = Y + 20;
|
||||
Y = currentBoundary.descr.Y + currentBoundary.descr.height;
|
||||
}
|
||||
|
||||
if (i == 0 || i % c4BoundaryInRow === 0) {
|
||||
|
@ -26,10 +26,10 @@ import type {
|
||||
const MERMAID_DOM_ID_PREFIX = 'classId-';
|
||||
|
||||
let relations: ClassRelation[] = [];
|
||||
let classes: Map<string, ClassNode> = new Map();
|
||||
let classes = new Map<string, ClassNode>();
|
||||
let notes: ClassNote[] = [];
|
||||
let classCounter = 0;
|
||||
let namespaces: Map<string, NamespaceNode> = new Map();
|
||||
let namespaces = new Map<string, NamespaceNode>();
|
||||
let namespaceCounter = 0;
|
||||
|
||||
let functions: any[] = [];
|
||||
@ -223,7 +223,7 @@ export const cleanupLabel = function (label: string) {
|
||||
export const setCssClass = function (ids: string, className: string) {
|
||||
ids.split(',').forEach(function (_id) {
|
||||
let id = _id;
|
||||
if (_id[0].match(/\d/)) {
|
||||
if (/\d/.exec(_id[0])) {
|
||||
id = MERMAID_DOM_ID_PREFIX + id;
|
||||
}
|
||||
const classNode = classes.get(id);
|
||||
@ -266,7 +266,7 @@ export const setLink = function (ids: string, linkStr: string, target: string) {
|
||||
const config = getConfig();
|
||||
ids.split(',').forEach(function (_id) {
|
||||
let id = _id;
|
||||
if (_id[0].match(/\d/)) {
|
||||
if (/\d/.exec(_id[0])) {
|
||||
id = MERMAID_DOM_ID_PREFIX + id;
|
||||
}
|
||||
const theClass = classes.get(id);
|
||||
@ -320,7 +320,7 @@ const setClickFunc = function (_domId: string, functionName: string, functionArg
|
||||
let item = argList[i].trim();
|
||||
/* Removes all double quotes at the start and end of an argument */
|
||||
/* This preserves all starting and ending whitespace inside */
|
||||
if (item.charAt(0) === '"' && item.charAt(item.length - 1) === '"') {
|
||||
if (item.startsWith('"') && item.endsWith('"')) {
|
||||
item = item.substr(1, item.length - 2);
|
||||
}
|
||||
argList[i] = item;
|
||||
|
@ -343,7 +343,7 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement!.nodes()[0]!.contentDocument.body)
|
||||
? select(sandboxElement.nodes()[0]!.contentDocument.body)
|
||||
: select('body');
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
|
||||
@ -363,8 +363,7 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
|
||||
// Add label rects for non html labels
|
||||
if (!conf?.htmlLabels) {
|
||||
const doc =
|
||||
securityLevel === 'sandbox' ? sandboxElement!.nodes()[0]!.contentDocument : document;
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0]!.contentDocument : document;
|
||||
const labels = doc.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
||||
for (const label of labels) {
|
||||
// Get dimensions of label
|
||||
|
@ -77,7 +77,7 @@ export class ClassMember {
|
||||
|
||||
if (this.memberType === 'method') {
|
||||
const methodRegEx = /([#+~-])?(.+)\((.*)\)([\s$*])?(.*)([$*])?/;
|
||||
const match = input.match(methodRegEx);
|
||||
const match = methodRegEx.exec(input);
|
||||
if (match) {
|
||||
const detectedVisibility = match[1] ? match[1].trim() : '';
|
||||
|
||||
@ -92,7 +92,7 @@ export class ClassMember {
|
||||
|
||||
if (potentialClassifier === '') {
|
||||
const lastChar = this.returnType.substring(this.returnType.length - 1);
|
||||
if (lastChar.match(/[$*]/)) {
|
||||
if (/[$*]/.exec(lastChar)) {
|
||||
potentialClassifier = lastChar;
|
||||
this.returnType = this.returnType.substring(0, this.returnType.length - 1);
|
||||
}
|
||||
@ -107,7 +107,7 @@ export class ClassMember {
|
||||
this.visibility = firstChar as Visibility;
|
||||
}
|
||||
|
||||
if (lastChar.match(/[$*]/)) {
|
||||
if (/[$*]/.exec(lastChar)) {
|
||||
potentialClassifier = lastChar;
|
||||
}
|
||||
|
||||
|
@ -315,10 +315,10 @@ export const getClassTitleString = function (classDef) {
|
||||
* @param {SVGSVGElement} elem The element to draw it into
|
||||
* @param {{id: string; text: string; class: string;}} note
|
||||
* @param conf
|
||||
* @param diagObj
|
||||
* @param _diagObj
|
||||
* @todo Add more information in the JSDOC here
|
||||
*/
|
||||
export const drawNote = function (elem, note, conf, diagObj) {
|
||||
export const drawNote = function (elem, note, conf, _diagObj) {
|
||||
log.debug('Rendering note ', note, conf);
|
||||
|
||||
const id = note.id;
|
||||
|
@ -34,13 +34,13 @@ function setupDompurifyHooks() {
|
||||
|
||||
DOMPurify.addHook('beforeSanitizeAttributes', (node: Element) => {
|
||||
if (node.tagName === 'A' && node.hasAttribute('target')) {
|
||||
node.setAttribute(TEMPORARY_ATTRIBUTE, node.getAttribute('target') || '');
|
||||
node.setAttribute(TEMPORARY_ATTRIBUTE, node.getAttribute('target') ?? '');
|
||||
}
|
||||
});
|
||||
|
||||
DOMPurify.addHook('afterSanitizeAttributes', (node: Element) => {
|
||||
if (node.tagName === 'A' && node.hasAttribute(TEMPORARY_ATTRIBUTE)) {
|
||||
node.setAttribute('target', node.getAttribute(TEMPORARY_ATTRIBUTE) || '');
|
||||
node.setAttribute('target', node.getAttribute(TEMPORARY_ATTRIBUTE) ?? '');
|
||||
node.removeAttribute(TEMPORARY_ATTRIBUTE);
|
||||
if (node.getAttribute('target') === '_blank') {
|
||||
node.setAttribute('rel', 'noopener');
|
||||
@ -83,6 +83,7 @@ export const sanitizeText = (text: string, config: MermaidConfig): string => {
|
||||
return text;
|
||||
}
|
||||
if (config.dompurifyConfig) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
text = DOMPurify.sanitize(sanitizeMore(text, config), config.dompurifyConfig).toString();
|
||||
} else {
|
||||
text = DOMPurify.sanitize(sanitizeMore(text, config), {
|
||||
|
@ -24,8 +24,12 @@ export const drawRect = (element: SVG | Group, rectData: RectData): D3RectElemen
|
||||
if (rectData.name) {
|
||||
rectElement.attr('name', rectData.name);
|
||||
}
|
||||
rectData.rx !== undefined && rectElement.attr('rx', rectData.rx);
|
||||
rectData.ry !== undefined && rectElement.attr('ry', rectData.ry);
|
||||
if (rectData.rx) {
|
||||
rectElement.attr('rx', rectData.rx);
|
||||
}
|
||||
if (rectData.ry) {
|
||||
rectElement.attr('ry', rectData.ry);
|
||||
}
|
||||
|
||||
if (rectData.attrs !== undefined) {
|
||||
for (const attrKey in rectData.attrs) {
|
||||
@ -33,7 +37,9 @@ export const drawRect = (element: SVG | Group, rectData: RectData): D3RectElemen
|
||||
}
|
||||
}
|
||||
|
||||
rectData.class !== undefined && rectElement.attr('class', rectData.class);
|
||||
if (rectData.class) {
|
||||
rectElement.attr('class', rectData.class);
|
||||
}
|
||||
|
||||
return rectElement;
|
||||
};
|
||||
@ -67,7 +73,9 @@ export const drawText = (element: SVG | Group, textData: TextData): D3TextElemen
|
||||
textElem.attr('class', 'legend');
|
||||
|
||||
textElem.style('text-anchor', textData.anchor);
|
||||
textData.class !== undefined && textElem.attr('class', textData.class);
|
||||
if (textData.class) {
|
||||
textElem.attr('class', textData.class);
|
||||
}
|
||||
|
||||
const tspan: D3TSpanElement = textElem.append('tspan');
|
||||
tspan.attr('x', textData.x + textData.textMargin * 2);
|
||||
|
@ -26,12 +26,16 @@ const Identification = {
|
||||
NON_IDENTIFYING: 'NON_IDENTIFYING',
|
||||
IDENTIFYING: 'IDENTIFYING',
|
||||
};
|
||||
|
||||
/**
|
||||
* Add entity
|
||||
* @param {string} name - The name of the entity
|
||||
* @param {string | undefined} alias - The alias of the entity
|
||||
*/
|
||||
const addEntity = function (name, alias = undefined) {
|
||||
if (!entities.has(name)) {
|
||||
entities.set(name, { attributes: [], alias: alias });
|
||||
entities.set(name, { attributes: [], alias });
|
||||
log.info('Added new entity :', name);
|
||||
} else if (entities.has(name) && !entities.get(name).alias && alias) {
|
||||
} else if (!entities.get(name).alias && alias) {
|
||||
entities.get(name).alias = alias;
|
||||
log.info(`Add alias '${alias}' to entity '${name}'`);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
import { addToRender } from './flowChartShapes.js';
|
||||
|
||||
describe('flowchart shapes', function () {
|
||||
|
@ -18,12 +18,12 @@ import type { FlowVertex, FlowClass, FlowSubGraph, FlowText, FlowEdge, FlowLink
|
||||
const MERMAID_DOM_ID_PREFIX = 'flowchart-';
|
||||
let vertexCounter = 0;
|
||||
let config = getConfig();
|
||||
let vertices: Map<string, FlowVertex> = new Map();
|
||||
let vertices = new Map<string, FlowVertex>();
|
||||
let edges: FlowEdge[] & { defaultInterpolate?: string; defaultStyle?: string[] } = [];
|
||||
let classes: Map<string, FlowClass> = new Map();
|
||||
let classes = new Map<string, FlowClass>();
|
||||
let subGraphs: FlowSubGraph[] = [];
|
||||
let subGraphLookup: Map<string, FlowSubGraph> = new Map();
|
||||
let tooltips: Map<string, string> = new Map();
|
||||
let subGraphLookup = new Map<string, FlowSubGraph>();
|
||||
let tooltips = new Map<string, string>();
|
||||
let subCount = 0;
|
||||
let firstGraphFlag = true;
|
||||
let direction: string;
|
||||
@ -85,7 +85,7 @@ export const addVertex = function (
|
||||
txt = sanitizeText(textObj.text.trim());
|
||||
vertex.labelType = textObj.type;
|
||||
// strip quotes if string starts and ends with a quote
|
||||
if (txt[0] === '"' && txt[txt.length - 1] === '"') {
|
||||
if (txt.startsWith('"') && txt.endsWith('"')) {
|
||||
txt = txt.substring(1, txt.length - 1);
|
||||
}
|
||||
vertex.text = txt;
|
||||
@ -133,7 +133,7 @@ export const addSingleLink = function (_start: string, _end: string, type: any)
|
||||
edge.text = sanitizeText(linkTextObj.text.trim());
|
||||
|
||||
// strip quotes if string starts and ends with a quote
|
||||
if (edge.text[0] === '"' && edge.text[edge.text.length - 1] === '"') {
|
||||
if (edge.text.startsWith('"') && edge.text.endsWith('"')) {
|
||||
edge.text = edge.text.substring(1, edge.text.length - 1);
|
||||
}
|
||||
edge.labelType = linkTextObj.type;
|
||||
@ -219,7 +219,7 @@ export const addClass = function (ids: string, style: string[]) {
|
||||
|
||||
if (style !== undefined && style !== null) {
|
||||
style.forEach(function (s) {
|
||||
if (s.match('color')) {
|
||||
if (/color/.exec(s)) {
|
||||
const newStyle = s.replace('fill', 'bgFill'); // .replace('color', 'fill');
|
||||
classNode.textStyles.push(newStyle);
|
||||
}
|
||||
@ -235,16 +235,16 @@ export const addClass = function (ids: string, style: string[]) {
|
||||
*/
|
||||
export const setDirection = function (dir: string) {
|
||||
direction = dir;
|
||||
if (direction.match(/.*</)) {
|
||||
if (/.*</.exec(direction)) {
|
||||
direction = 'RL';
|
||||
}
|
||||
if (direction.match(/.*\^/)) {
|
||||
if (/.*\^/.exec(direction)) {
|
||||
direction = 'BT';
|
||||
}
|
||||
if (direction.match(/.*>/)) {
|
||||
if (/.*>/.exec(direction)) {
|
||||
direction = 'LR';
|
||||
}
|
||||
if (direction.match(/.*v/)) {
|
||||
if (/.*v/.exec(direction)) {
|
||||
direction = 'TB';
|
||||
}
|
||||
if (direction === 'TD') {
|
||||
@ -298,7 +298,7 @@ const setClickFun = function (id: string, functionName: string, functionArgs: st
|
||||
let item = argList[i].trim();
|
||||
/* Removes all double quotes at the start and end of an argument */
|
||||
/* This preserves all starting and ending whitespace inside */
|
||||
if (item.charAt(0) === '"' && item.charAt(item.length - 1) === '"') {
|
||||
if (item.startsWith('"') && item.endsWith('"')) {
|
||||
item = item.substr(1, item.length - 2);
|
||||
}
|
||||
argList[i] = item;
|
||||
@ -470,7 +470,7 @@ export const addSubGraph = function (
|
||||
) {
|
||||
let id: string | undefined = _id.text.trim();
|
||||
let title = _title.text;
|
||||
if (_id === _title && _title.text.match(/\s/)) {
|
||||
if (_id === _title && /\s/.exec(_title.text)) {
|
||||
id = undefined;
|
||||
}
|
||||
|
||||
@ -504,7 +504,7 @@ export const addSubGraph = function (
|
||||
}
|
||||
}
|
||||
|
||||
id = id || 'subGraph' + subCount;
|
||||
id = id ?? 'subGraph' + subCount;
|
||||
title = title || '';
|
||||
title = sanitizeText(title);
|
||||
subCount = subCount + 1;
|
||||
@ -652,21 +652,21 @@ const destructEndLink = (_str: string) => {
|
||||
switch (str.slice(-1)) {
|
||||
case 'x':
|
||||
type = 'arrow_cross';
|
||||
if (str[0] === 'x') {
|
||||
if (str.startsWith('x')) {
|
||||
type = 'double_' + type;
|
||||
line = line.slice(1);
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
type = 'arrow_point';
|
||||
if (str[0] === '<') {
|
||||
if (str.startsWith('<')) {
|
||||
type = 'double_' + type;
|
||||
line = line.slice(1);
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
type = 'arrow_circle';
|
||||
if (str[0] === 'o') {
|
||||
if (str.startsWith('o')) {
|
||||
type = 'double_' + type;
|
||||
line = line.slice(1);
|
||||
}
|
||||
@ -676,11 +676,11 @@ const destructEndLink = (_str: string) => {
|
||||
let stroke = 'normal';
|
||||
let length = line.length - 1;
|
||||
|
||||
if (line[0] === '=') {
|
||||
if (line.startsWith('=')) {
|
||||
stroke = 'thick';
|
||||
}
|
||||
|
||||
if (line[0] === '~') {
|
||||
if (line.startsWith('~')) {
|
||||
stroke = 'invisible';
|
||||
}
|
||||
|
||||
@ -764,7 +764,7 @@ const getTypeFromVertex = (vertex: FlowVertex) => {
|
||||
return 'roundedRect';
|
||||
}
|
||||
|
||||
return vertex.type || 'squareRect';
|
||||
return vertex.type ?? 'squareRect';
|
||||
};
|
||||
|
||||
const findNode = (nodes: Node[], id: string) => nodes.find((node) => node.id === id);
|
||||
@ -796,7 +796,7 @@ const addNodeFromVertex = (
|
||||
look: string
|
||||
) => {
|
||||
const parentId = parentDB.get(vertex.id);
|
||||
const isGroup = subGraphDB.get(vertex.id) || false;
|
||||
const isGroup = subGraphDB.get(vertex.id) ?? false;
|
||||
|
||||
const node = findNode(nodes, vertex.id);
|
||||
if (!node) {
|
||||
@ -870,7 +870,7 @@ export const getData = () => {
|
||||
label: subGraph.title,
|
||||
labelStyle: '',
|
||||
parentId: parentDB.get(subGraph.id),
|
||||
padding: config.flowchart?.padding || 8,
|
||||
padding: config.flowchart?.padding ?? 8,
|
||||
cssCompiledStyles: getCompiledStyles(subGraph.classes),
|
||||
cssClasses: subGraph.classes.join(' '),
|
||||
shape: 'rect',
|
||||
@ -888,7 +888,7 @@ export const getData = () => {
|
||||
const e = getEdges();
|
||||
e.forEach((rawEdge, index) => {
|
||||
const { arrowTypeStart, arrowTypeEnd } = destructEdgeType(rawEdge.type);
|
||||
const styles = [...(e.defaultStyle || [])];
|
||||
const styles = [...(e.defaultStyle ?? [])];
|
||||
|
||||
if (rawEdge.style) {
|
||||
styles.push(...rawEdge.style);
|
||||
@ -897,7 +897,7 @@ export const getData = () => {
|
||||
id: getEdgeId(rawEdge.start, rawEdge.end, { counter: index, prefix: 'edge' }),
|
||||
start: rawEdge.start,
|
||||
end: rawEdge.end,
|
||||
type: rawEdge.type || 'normal',
|
||||
type: rawEdge.type ?? 'normal',
|
||||
label: rawEdge.text,
|
||||
labelpos: 'c',
|
||||
thickness: rawEdge.stroke,
|
||||
|
@ -367,8 +367,8 @@ export const draw = async function (text, id, _version, diagObj) {
|
||||
}
|
||||
|
||||
const { securityLevel, flowchart: conf } = getConfig();
|
||||
const nodeSpacing = conf.nodeSpacing || 50;
|
||||
const rankSpacing = conf.rankSpacing || 50;
|
||||
const nodeSpacing = conf.nodeSpacing ?? 50;
|
||||
const rankSpacing = conf.rankSpacing ?? 50;
|
||||
|
||||
// Handle root and document for when rendering in sandbox mode
|
||||
let sandboxElement;
|
||||
@ -421,14 +421,13 @@ export const draw = async function (text, id, _version, diagObj) {
|
||||
log.info('Edges', edges);
|
||||
let i = 0;
|
||||
for (i = subGraphs.length - 1; i >= 0; i--) {
|
||||
// for (let i = 0; i < subGraphs.length; i++) {
|
||||
subG = subGraphs[i];
|
||||
|
||||
selectAll('cluster').append('text');
|
||||
|
||||
for (let j = 0; j < subG.nodes.length; j++) {
|
||||
log.info('Setting up subgraphs', subG.nodes[j], subG.id);
|
||||
g.setParent(subG.nodes[j], subG.id);
|
||||
for (const node of subG.nodes) {
|
||||
log.info('Setting up subgraphs', node, subG.id);
|
||||
g.setParent(node, subG.id);
|
||||
}
|
||||
}
|
||||
await addVertices(vert, g, id, root, doc, diagObj);
|
||||
|
@ -301,8 +301,8 @@ export const draw = async function (text, id, _version, diagObj) {
|
||||
if (dir === undefined) {
|
||||
dir = 'TD';
|
||||
}
|
||||
const nodeSpacing = conf.nodeSpacing || 50;
|
||||
const rankSpacing = conf.rankSpacing || 50;
|
||||
const nodeSpacing = conf.nodeSpacing ?? 50;
|
||||
const rankSpacing = conf.rankSpacing ?? 50;
|
||||
|
||||
// Create the input mermaid.graph
|
||||
const g = new graphlib.Graph({
|
||||
@ -339,14 +339,14 @@ export const draw = async function (text, id, _version, diagObj) {
|
||||
|
||||
selectAll('cluster').append('text');
|
||||
|
||||
for (let j = 0; j < subG.nodes.length; j++) {
|
||||
for (const node of subG.nodes) {
|
||||
log.warn(
|
||||
'Setting subgraph',
|
||||
subG.nodes[j],
|
||||
diagObj.db.lookUpDomId(subG.nodes[j]),
|
||||
node,
|
||||
diagObj.db.lookUpDomId(node),
|
||||
diagObj.db.lookUpDomId(subG.id)
|
||||
);
|
||||
g.setParent(diagObj.db.lookUpDomId(subG.nodes[j]), diagObj.db.lookUpDomId(subG.id));
|
||||
g.setParent(diagObj.db.lookUpDomId(node), diagObj.db.lookUpDomId(subG.id));
|
||||
}
|
||||
}
|
||||
await addVertices(vert, g, id, root, doc, diagObj);
|
||||
@ -429,8 +429,8 @@ export const draw = async function (text, id, _version, diagObj) {
|
||||
te.attr('transform', `translate(${xPos + _width / 2}, ${yPos + 14})`);
|
||||
te.attr('id', id + 'Text');
|
||||
|
||||
for (let j = 0; j < subG.classes.length; j++) {
|
||||
clusterEl[0].classList.add(subG.classes[j]);
|
||||
for (const className of subG.classes) {
|
||||
clusterEl[0].classList.add(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
import { addVertices, addEdges } from './flowRenderer.js';
|
||||
import { setConfig } from '../../diagram-api/diagramAPI.js';
|
||||
|
||||
|
@ -676,7 +676,7 @@ const setClickFun = function (id, functionName, functionArgs) {
|
||||
let item = argList[i].trim();
|
||||
/* Removes all double quotes at the start and end of an argument */
|
||||
/* This preserves all starting and ending whitespace inside */
|
||||
if (item.charAt(0) === '"' && item.charAt(item.length - 1) === '"') {
|
||||
if (item.startsWith('"') && item.endsWith('"')) {
|
||||
item = item.substr(1, item.length - 2);
|
||||
}
|
||||
argList[i] = item;
|
||||
|
@ -109,7 +109,7 @@ describe('when using the ganttDb', function () {
|
||||
ganttDb.addTask(taskName2, taskData2);
|
||||
const tasks = ganttDb.getTasks();
|
||||
expect(tasks[1].startTime).toEqual(expStartDate2);
|
||||
if (!expEndDate2 === undefined) {
|
||||
if (expEndDate2) {
|
||||
expect(tasks[1].endTime).toEqual(expEndDate2);
|
||||
}
|
||||
expect(tasks[1].id).toEqual(expId2);
|
||||
|
@ -35,7 +35,7 @@ function getId() {
|
||||
// * @param currentCommit
|
||||
// * @param otherCommit
|
||||
// */
|
||||
// eslint-disable-next-line @cspell/spellchecker
|
||||
|
||||
// function isFastForwardable(currentCommit, otherCommit) {
|
||||
// log.debug('Entering isFastForwardable:', currentCommit.id, otherCommit.id);
|
||||
// let cnt = 0;
|
||||
@ -90,7 +90,7 @@ export const setDirection = function (dir) {
|
||||
let options = {};
|
||||
export const setOptions = function (rawOptString) {
|
||||
log.debug('options str', rawOptString);
|
||||
rawOptString = rawOptString && rawOptString.trim();
|
||||
rawOptString = rawOptString?.trim();
|
||||
rawOptString = rawOptString || '{}';
|
||||
try {
|
||||
options = JSON.parse(rawOptString);
|
||||
|
@ -36,7 +36,7 @@ describe('when parsing a gitGraph', function () {
|
||||
|
||||
parser.parse(str);
|
||||
const commits = parser.yy.getCommits();
|
||||
expect(parser.yy.getOptions()['key']).toBe('value');
|
||||
expect(parser.yy.getOptions().key).toBe('value');
|
||||
expect(commits.size).toBe(1);
|
||||
expect(parser.yy.getCurrentBranch()).toBe('main');
|
||||
expect(parser.yy.getDirection()).toBe('LR');
|
||||
|
@ -1,366 +0,0 @@
|
||||
import { curveBasis, line, select } from 'd3';
|
||||
|
||||
import db from './gitGraphAst.js';
|
||||
import { logger } from '../../logger.js';
|
||||
import { interpolateToCurve } from '../../utils.js';
|
||||
|
||||
let allCommitsDict = {};
|
||||
let branchNum;
|
||||
let config = {
|
||||
nodeSpacing: 150,
|
||||
nodeFillColor: 'yellow',
|
||||
nodeStrokeWidth: 2,
|
||||
nodeStrokeColor: 'grey',
|
||||
lineStrokeWidth: 4,
|
||||
branchOffset: 50,
|
||||
lineColor: 'grey',
|
||||
leftMargin: 50,
|
||||
branchColors: ['#442f74', '#983351', '#609732', '#AA9A39'],
|
||||
nodeRadius: 10,
|
||||
nodeLabel: {
|
||||
width: 75,
|
||||
height: 100,
|
||||
x: -25,
|
||||
y: 0,
|
||||
},
|
||||
};
|
||||
let apiConfig = {};
|
||||
export const setConf = function (c) {
|
||||
apiConfig = c;
|
||||
};
|
||||
|
||||
/** @param svg */
|
||||
function svgCreateDefs(svg) {
|
||||
svg
|
||||
.append('defs')
|
||||
.append('g')
|
||||
.attr('id', 'def-commit')
|
||||
.append('circle')
|
||||
.attr('r', config.nodeRadius)
|
||||
.attr('cx', 0)
|
||||
.attr('cy', 0);
|
||||
svg
|
||||
.select('#def-commit')
|
||||
.append('foreignObject')
|
||||
.attr('width', config.nodeLabel.width)
|
||||
.attr('height', config.nodeLabel.height)
|
||||
.attr('x', config.nodeLabel.x)
|
||||
.attr('y', config.nodeLabel.y)
|
||||
.attr('class', 'node-label')
|
||||
.attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility')
|
||||
.append('p')
|
||||
.html('');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param svg
|
||||
* @param points
|
||||
* @param colorIdx
|
||||
* @param interpolate
|
||||
*/
|
||||
function svgDrawLine(svg, points, colorIdx, interpolate) {
|
||||
const curve = interpolateToCurve(interpolate, curveBasis);
|
||||
const color = config.branchColors[colorIdx % config.branchColors.length];
|
||||
const lineGen = line()
|
||||
.x(function (d) {
|
||||
return Math.round(d.x);
|
||||
})
|
||||
.y(function (d) {
|
||||
return Math.round(d.y);
|
||||
})
|
||||
.curve(curve);
|
||||
|
||||
svg
|
||||
.append('svg:path')
|
||||
.attr('d', lineGen(points))
|
||||
.style('stroke', color)
|
||||
.style('stroke-width', config.lineStrokeWidth)
|
||||
.style('fill', 'none');
|
||||
}
|
||||
|
||||
// Pass in the element and its pre-transform coords
|
||||
/**
|
||||
* @param element
|
||||
* @param coords
|
||||
*/
|
||||
function getElementCoords(element, coords) {
|
||||
coords = coords || element.node().getBBox();
|
||||
const ctm = element.node().getCTM();
|
||||
const xn = ctm.e + coords.x * ctm.a;
|
||||
const yn = ctm.f + coords.y * ctm.d;
|
||||
return {
|
||||
left: xn,
|
||||
top: yn,
|
||||
width: coords.width,
|
||||
height: coords.height,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param svg
|
||||
* @param fromId
|
||||
* @param toId
|
||||
* @param direction
|
||||
* @param color
|
||||
*/
|
||||
function svgDrawLineForCommits(svg, fromId, toId, direction, color) {
|
||||
logger.debug('svgDrawLineForCommits: ', fromId, toId);
|
||||
const fromBbox = getElementCoords(svg.select('#node-' + fromId + ' circle'));
|
||||
const toBbox = getElementCoords(svg.select('#node-' + toId + ' circle'));
|
||||
switch (direction) {
|
||||
case 'LR':
|
||||
// (toBbox)
|
||||
// +--------
|
||||
// + (fromBbox)
|
||||
if (fromBbox.left - toBbox.left > config.nodeSpacing) {
|
||||
const lineStart = {
|
||||
x: fromBbox.left - config.nodeSpacing,
|
||||
y: toBbox.top + toBbox.height / 2,
|
||||
};
|
||||
const lineEnd = { x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height / 2 };
|
||||
svgDrawLine(svg, [lineStart, lineEnd], color, 'linear');
|
||||
svgDrawLine(
|
||||
svg,
|
||||
[
|
||||
{ x: fromBbox.left, y: fromBbox.top + fromBbox.height / 2 },
|
||||
{ x: fromBbox.left - config.nodeSpacing / 2, y: fromBbox.top + fromBbox.height / 2 },
|
||||
{ x: fromBbox.left - config.nodeSpacing / 2, y: lineStart.y },
|
||||
lineStart,
|
||||
],
|
||||
color
|
||||
);
|
||||
} else {
|
||||
svgDrawLine(
|
||||
svg,
|
||||
[
|
||||
{
|
||||
x: fromBbox.left,
|
||||
y: fromBbox.top + fromBbox.height / 2,
|
||||
},
|
||||
{
|
||||
x: fromBbox.left - config.nodeSpacing / 2,
|
||||
y: fromBbox.top + fromBbox.height / 2,
|
||||
},
|
||||
{
|
||||
x: fromBbox.left - config.nodeSpacing / 2,
|
||||
y: toBbox.top + toBbox.height / 2,
|
||||
},
|
||||
{
|
||||
x: toBbox.left + toBbox.width,
|
||||
y: toBbox.top + toBbox.height / 2,
|
||||
},
|
||||
],
|
||||
color
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'BT':
|
||||
// + (fromBbox)
|
||||
// |
|
||||
// |
|
||||
// + (toBbox)
|
||||
if (toBbox.top - fromBbox.top > config.nodeSpacing) {
|
||||
const lineStart = {
|
||||
x: toBbox.left + toBbox.width / 2,
|
||||
y: fromBbox.top + fromBbox.height + config.nodeSpacing,
|
||||
};
|
||||
const lineEnd = { x: toBbox.left + toBbox.width / 2, y: toBbox.top };
|
||||
svgDrawLine(svg, [lineStart, lineEnd], color, 'linear');
|
||||
svgDrawLine(
|
||||
svg,
|
||||
[
|
||||
{ x: fromBbox.left + fromBbox.width / 2, y: fromBbox.top + fromBbox.height },
|
||||
{
|
||||
x: fromBbox.left + fromBbox.width / 2,
|
||||
y: fromBbox.top + fromBbox.height + config.nodeSpacing / 2,
|
||||
},
|
||||
{ x: toBbox.left + toBbox.width / 2, y: lineStart.y - config.nodeSpacing / 2 },
|
||||
lineStart,
|
||||
],
|
||||
color
|
||||
);
|
||||
} else {
|
||||
svgDrawLine(
|
||||
svg,
|
||||
[
|
||||
{
|
||||
x: fromBbox.left + fromBbox.width / 2,
|
||||
y: fromBbox.top + fromBbox.height,
|
||||
},
|
||||
{
|
||||
x: fromBbox.left + fromBbox.width / 2,
|
||||
y: fromBbox.top + config.nodeSpacing / 2,
|
||||
},
|
||||
{
|
||||
x: toBbox.left + toBbox.width / 2,
|
||||
y: toBbox.top - config.nodeSpacing / 2,
|
||||
},
|
||||
{
|
||||
x: toBbox.left + toBbox.width / 2,
|
||||
y: toBbox.top,
|
||||
},
|
||||
],
|
||||
color
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param svg
|
||||
* @param selector
|
||||
*/
|
||||
function cloneNode(svg, selector) {
|
||||
return svg.select(selector).node().cloneNode(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param svg
|
||||
* @param commitId
|
||||
* @param branches
|
||||
* @param direction
|
||||
*/
|
||||
function renderCommitHistory(svg, commitId, branches, direction) {
|
||||
let commit;
|
||||
const numCommits = Object.keys(allCommitsDict).length;
|
||||
if (typeof commitId === 'string') {
|
||||
do {
|
||||
commit = allCommitsDict[commitId];
|
||||
logger.debug('in renderCommitHistory', commit.id, commit.seq);
|
||||
if (svg.select('#node-' + commitId).size() > 0) {
|
||||
return;
|
||||
}
|
||||
svg
|
||||
.append(function () {
|
||||
return cloneNode(svg, '#def-commit');
|
||||
})
|
||||
.attr('class', 'commit')
|
||||
.attr('id', function () {
|
||||
return 'node-' + commit.id;
|
||||
})
|
||||
.attr('transform', function () {
|
||||
switch (direction) {
|
||||
case 'LR':
|
||||
return (
|
||||
'translate(' +
|
||||
(commit.seq * config.nodeSpacing + config.leftMargin) +
|
||||
', ' +
|
||||
branchNum * config.branchOffset +
|
||||
')'
|
||||
);
|
||||
case 'BT':
|
||||
return (
|
||||
'translate(' +
|
||||
(branchNum * config.branchOffset + config.leftMargin) +
|
||||
', ' +
|
||||
(numCommits - commit.seq) * config.nodeSpacing +
|
||||
')'
|
||||
);
|
||||
}
|
||||
})
|
||||
.attr('fill', config.nodeFillColor)
|
||||
.attr('stroke', config.nodeStrokeColor)
|
||||
.attr('stroke-width', config.nodeStrokeWidth);
|
||||
|
||||
let branch;
|
||||
for (let branchName in branches) {
|
||||
if (branches[branchName].commit === commit) {
|
||||
branch = branches[branchName];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (branch) {
|
||||
logger.debug('found branch ', branch.name);
|
||||
svg
|
||||
.select('#node-' + commit.id + ' p')
|
||||
.append('xhtml:span')
|
||||
.attr('class', 'branch-label')
|
||||
.text(branch.name + ', ');
|
||||
}
|
||||
svg
|
||||
.select('#node-' + commit.id + ' p')
|
||||
.append('xhtml:span')
|
||||
.attr('class', 'commit-id')
|
||||
.text(commit.id);
|
||||
if (commit.message !== '' && direction === 'BT') {
|
||||
svg
|
||||
.select('#node-' + commit.id + ' p')
|
||||
.append('xhtml:span')
|
||||
.attr('class', 'commit-msg')
|
||||
.text(', ' + commit.message);
|
||||
}
|
||||
commitId = commit.parent;
|
||||
} while (commitId && allCommitsDict[commitId]);
|
||||
}
|
||||
|
||||
if (Array.isArray(commitId)) {
|
||||
logger.debug('found merge commit', commitId);
|
||||
renderCommitHistory(svg, commitId[0], branches, direction);
|
||||
branchNum++;
|
||||
renderCommitHistory(svg, commitId[1], branches, direction);
|
||||
branchNum--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param svg
|
||||
* @param commit
|
||||
* @param direction
|
||||
* @param branchColor
|
||||
*/
|
||||
function renderLines(svg, commit, direction, branchColor = 0) {
|
||||
while (commit.seq > 0 && !commit.lineDrawn) {
|
||||
if (typeof commit.parent === 'string') {
|
||||
svgDrawLineForCommits(svg, commit.id, commit.parent, direction, branchColor);
|
||||
commit.lineDrawn = true;
|
||||
commit = allCommitsDict[commit.parent];
|
||||
} else if (Array.isArray(commit.parent)) {
|
||||
svgDrawLineForCommits(svg, commit.id, commit.parent[0], direction, branchColor);
|
||||
svgDrawLineForCommits(svg, commit.id, commit.parent[1], direction, branchColor + 1);
|
||||
renderLines(svg, allCommitsDict[commit.parent[1]], direction, branchColor + 1);
|
||||
commit.lineDrawn = true;
|
||||
commit = allCommitsDict[commit.parent[0]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const draw = function (txt, id, ver) {
|
||||
try {
|
||||
logger.debug('in gitgraph renderer', txt + '\n', 'id:', id, ver);
|
||||
|
||||
config = Object.assign(config, apiConfig, db.getOptions());
|
||||
logger.debug('effective options', config);
|
||||
const direction = db.getDirection();
|
||||
allCommitsDict = db.getCommits();
|
||||
const branches = db.getBranchesAsObjArray();
|
||||
if (direction === 'BT') {
|
||||
config.nodeLabel.x = branches.length * config.branchOffset;
|
||||
config.nodeLabel.width = '100%';
|
||||
config.nodeLabel.y = -1 * 2 * config.nodeRadius;
|
||||
}
|
||||
const svg = select(`[id="${id}"]`);
|
||||
svgCreateDefs(svg);
|
||||
branchNum = 1;
|
||||
for (let branch in branches) {
|
||||
const v = branches[branch];
|
||||
renderCommitHistory(svg, v.commit.id, branches, direction);
|
||||
renderLines(svg, v.commit, direction);
|
||||
branchNum++;
|
||||
}
|
||||
svg.attr('height', function () {
|
||||
if (direction === 'BT') {
|
||||
return Object.keys(allCommitsDict).length * config.nodeSpacing;
|
||||
}
|
||||
return (branches.length + 1) * config.branchOffset;
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error('Error while rendering gitgraph');
|
||||
logger.error(e.message);
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
setConf,
|
||||
draw,
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
|
||||
export default (dir, _branches) => {
|
||||
const config = getConfig().gitGraph;
|
||||
const branches = [];
|
||||
const commits = [];
|
||||
|
||||
for (const [i, _branch] of _branches.entries()) {
|
||||
const branch = Object.assign({}, _branch);
|
||||
if (dir === 'TB' || dir === 'BT') {
|
||||
branch.x = config.branchOffset * i;
|
||||
branch.y = -1;
|
||||
} else {
|
||||
branch.y = config.branchOffset * i;
|
||||
branch.x = -1;
|
||||
}
|
||||
branches.push(branch);
|
||||
}
|
||||
|
||||
return { branches, commits };
|
||||
};
|
@ -1,198 +0,0 @@
|
||||
export const getDirection = () => 'LR';
|
||||
export const getCommits = () => {
|
||||
return {
|
||||
'0000001': {
|
||||
id: '0000001',
|
||||
seq: 1,
|
||||
message: '',
|
||||
branch: 'master',
|
||||
parents: null,
|
||||
tag: 'v0.1',
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000002': {
|
||||
id: '0000002',
|
||||
seq: 2,
|
||||
message: '',
|
||||
branch: 'develop',
|
||||
parents: ['0000001'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000003': {
|
||||
id: '0000003',
|
||||
seq: 3,
|
||||
message: '',
|
||||
branch: 'featureB',
|
||||
parents: ['0000002'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000004': {
|
||||
id: '0000004',
|
||||
seq: 4,
|
||||
message: '',
|
||||
branch: 'hotfix',
|
||||
parents: ['0000001'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000005': {
|
||||
id: '0000005',
|
||||
seq: 5,
|
||||
message: '',
|
||||
branch: 'develop',
|
||||
parents: ['0000002'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000006': {
|
||||
id: '0000006',
|
||||
seq: 6,
|
||||
message: '',
|
||||
branch: 'featureB',
|
||||
parents: ['0000003'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000007': {
|
||||
id: '0000007',
|
||||
seq: 7,
|
||||
message: '',
|
||||
branch: 'master',
|
||||
parents: ['0000004'],
|
||||
tag: 'v0.2',
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000008': {
|
||||
id: '0000008',
|
||||
seq: 8,
|
||||
message: '',
|
||||
branch: 'featureB',
|
||||
parents: ['0000006'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000009': {
|
||||
id: '0000009',
|
||||
seq: 9,
|
||||
message: '',
|
||||
branch: 'featureA',
|
||||
parents: ['0000005'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000010': {
|
||||
id: '0000010',
|
||||
seq: 10,
|
||||
message: '',
|
||||
branch: 'develop',
|
||||
parents: ['0000004', '0000005'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000011': {
|
||||
id: '0000011',
|
||||
seq: 11,
|
||||
message: '',
|
||||
branch: 'featureA',
|
||||
parents: ['0000009'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: '',
|
||||
},
|
||||
'0000012': {
|
||||
id: '0000012',
|
||||
seq: 12,
|
||||
message: '',
|
||||
branch: 'featureB',
|
||||
parents: ['0000008'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000013': {
|
||||
id: '0000013',
|
||||
seq: 13,
|
||||
message: '',
|
||||
branch: 'develop',
|
||||
parents: ['0000010', '0000011'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000014': {
|
||||
id: '0000014',
|
||||
seq: 14,
|
||||
message: '',
|
||||
branch: 'release',
|
||||
parents: ['0000013'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000015': {
|
||||
id: '0000015',
|
||||
seq: 15,
|
||||
message: '',
|
||||
branch: 'master',
|
||||
parents: ['0000007'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000016': {
|
||||
id: '0000016',
|
||||
seq: 16,
|
||||
message: '',
|
||||
branch: 'release',
|
||||
parents: ['0000014', '0000015'],
|
||||
tag: 'v1.0',
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
'0000017': {
|
||||
id: '0000017',
|
||||
seq: 17,
|
||||
message: '',
|
||||
branch: 'develop',
|
||||
parents: ['0000013', '0000016'],
|
||||
tag: null,
|
||||
commitType: 'normal',
|
||||
note: null,
|
||||
},
|
||||
};
|
||||
};
|
||||
export const clear = () => {
|
||||
//no-op
|
||||
};
|
||||
export const getBranchesAsObjArray = () => [
|
||||
{
|
||||
name: 'master',
|
||||
},
|
||||
{
|
||||
name: 'hotfix',
|
||||
},
|
||||
{
|
||||
name: 'release',
|
||||
},
|
||||
{
|
||||
name: 'develop',
|
||||
},
|
||||
{
|
||||
name: 'featureA',
|
||||
},
|
||||
{
|
||||
name: 'featureB',
|
||||
},
|
||||
];
|
@ -5,7 +5,6 @@ import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
|
||||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||
import type { PacketDB, PacketWord } from './types.js';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
|
||||
const db = diagram.db as PacketDB;
|
||||
const config = db.getConfig();
|
||||
|
@ -119,6 +119,7 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => {
|
||||
return ((datum.data.value / sum) * 100).toFixed(0) + '%';
|
||||
})
|
||||
.attr('transform', (datum: d3.PieArcDatum<D3Section>): string => {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
||||
return 'translate(' + labelArcGenerator.centroid(datum) + ')';
|
||||
})
|
||||
.style('text-anchor', 'middle')
|
||||
|
@ -127,7 +127,7 @@ export class QuadrantBuilder {
|
||||
private config: QuadrantBuilderConfig;
|
||||
private themeConfig: QuadrantBuilderThemeConfig;
|
||||
private data: QuadrantBuilderData;
|
||||
private classes: Map<string, StylesObject> = new Map();
|
||||
private classes = new Map<string, StylesObject>();
|
||||
|
||||
constructor() {
|
||||
this.config = this.getDefaultConfig();
|
||||
@ -493,8 +493,8 @@ export class QuadrantBuilder {
|
||||
const props: QuadrantPointType = {
|
||||
x: xAxis(point.x),
|
||||
y: yAxis(point.y),
|
||||
fill: point.color || this.themeConfig.quadrantPointFill,
|
||||
radius: point.radius || this.config.pointRadius,
|
||||
fill: point.color ?? this.themeConfig.quadrantPointFill,
|
||||
radius: point.radius ?? this.config.pointRadius,
|
||||
text: {
|
||||
text: point.text,
|
||||
fill: this.themeConfig.quadrantPointTextFill,
|
||||
@ -505,8 +505,8 @@ export class QuadrantBuilder {
|
||||
fontSize: this.config.pointLabelFontSize,
|
||||
rotation: 0,
|
||||
},
|
||||
strokeColor: point.strokeColor || this.themeConfig.quadrantPointFill,
|
||||
strokeWidth: point.strokeWidth || '0px',
|
||||
strokeColor: point.strokeColor ?? this.themeConfig.quadrantPointFill,
|
||||
strokeWidth: point.strokeWidth ?? '0px',
|
||||
};
|
||||
return props;
|
||||
});
|
||||
|
@ -46,10 +46,10 @@ export const draw = (txt: string, id: string, _version: string, diagObj: Diagram
|
||||
|
||||
const group = svg.append('g').attr('class', 'main');
|
||||
|
||||
const width = conf.quadrantChart?.chartWidth || 500;
|
||||
const height = conf.quadrantChart?.chartHeight || 500;
|
||||
const width = conf.quadrantChart?.chartWidth ?? 500;
|
||||
const height = conf.quadrantChart?.chartHeight ?? 500;
|
||||
|
||||
configureSvgSize(svg, height, width, conf.quadrantChart?.useMaxWidth || true);
|
||||
configureSvgSize(svg, height, width, conf.quadrantChart?.useMaxWidth ?? true);
|
||||
|
||||
svg.attr('viewBox', '0 0 ' + width + ' ' + height);
|
||||
|
||||
|
@ -13,7 +13,7 @@ describe('Sankey diagram', function () {
|
||||
sankey.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('parses csv', async () => {
|
||||
it('parses csv', () => {
|
||||
const csv = path.resolve(__dirname, './energy.csv');
|
||||
const data = fs.readFileSync(csv, 'utf8');
|
||||
const graphDefinition = prepareTextForParsing(cleanupComments('sankey-beta\n\n ' + data));
|
||||
|
@ -15,7 +15,7 @@ let links: SankeyLink[] = [];
|
||||
// Array of nodes guarantees their order
|
||||
let nodes: SankeyNode[] = [];
|
||||
// We also have to track nodes uniqueness (by ID)
|
||||
let nodesMap: Map<string, SankeyNode> = new Map();
|
||||
let nodesMap = new Map<string, SankeyNode>();
|
||||
|
||||
const clear = (): void => {
|
||||
links = [];
|
||||
@ -28,7 +28,7 @@ class SankeyLink {
|
||||
constructor(
|
||||
public source: SankeyNode,
|
||||
public target: SankeyNode,
|
||||
public value: number = 0
|
||||
public value = 0
|
||||
) {}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@ import {
|
||||
scaleOrdinal as d3scaleOrdinal,
|
||||
schemeTableau10 as d3schemeTableau10,
|
||||
} from 'd3';
|
||||
|
||||
import type { SankeyNode as d3SankeyNode } from 'd3-sankey';
|
||||
import {
|
||||
sankey as d3Sankey,
|
||||
@ -41,7 +40,7 @@ const alignmentsMap: Record<
|
||||
export const draw = function (text: string, id: string, _version: string, diagObj: Diagram): void {
|
||||
// Get Sankey config
|
||||
const { securityLevel, sankey: conf } = getConfig();
|
||||
const defaultSankeyConfig = defaultConfig!.sankey!;
|
||||
const defaultSankeyConfig = defaultConfig.sankey!;
|
||||
|
||||
// TODO:
|
||||
// This code repeats for every diagram
|
||||
@ -160,7 +159,7 @@ export const draw = function (text: string, id: string, _version: string, diagOb
|
||||
.attr('class', 'link')
|
||||
.style('mix-blend-mode', 'multiply');
|
||||
|
||||
const linkColor = conf?.linkColor || 'gradient';
|
||||
const linkColor = conf?.linkColor ?? 'gradient';
|
||||
|
||||
if (linkColor === 'gradient') {
|
||||
const gradient = link
|
||||
|
@ -46,7 +46,7 @@ const state = new ImperativeState<SequenceState>(() => ({
|
||||
export const addBox = function (data: { text: string; color: string; wrap: boolean }) {
|
||||
state.records.boxes.push({
|
||||
name: data.text,
|
||||
wrap: (data.wrap === undefined && autoWrap()) || !!data.wrap,
|
||||
wrap: data.wrap ?? autoWrap(),
|
||||
fill: data.color,
|
||||
actorKeys: [],
|
||||
});
|
||||
@ -80,18 +80,18 @@ export const addActor = function (
|
||||
}
|
||||
|
||||
// Don't allow null descriptions, either
|
||||
if (description == null || description.text == null) {
|
||||
description = { text: name, wrap: null, type };
|
||||
if (description?.text == null) {
|
||||
description = { text: name, type };
|
||||
}
|
||||
if (type == null || description.text == null) {
|
||||
description = { text: name, wrap: null, type };
|
||||
description = { text: name, type };
|
||||
}
|
||||
|
||||
state.records.actors.set(id, {
|
||||
box: assignedBox,
|
||||
name: name,
|
||||
description: description.text,
|
||||
wrap: (description.wrap === undefined && autoWrap()) || !!description.wrap,
|
||||
wrap: description.wrap ?? autoWrap(),
|
||||
prevActor: state.records.prevActor,
|
||||
links: {},
|
||||
properties: {},
|
||||
@ -145,7 +145,7 @@ export const addMessage = function (
|
||||
from: idFrom,
|
||||
to: idTo,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
|
||||
wrap: message.wrap ?? autoWrap(),
|
||||
answer: answer,
|
||||
});
|
||||
};
|
||||
@ -155,10 +155,10 @@ export const addSignal = function (
|
||||
idTo?: Message['to'],
|
||||
message?: { text: string; wrap: boolean },
|
||||
messageType?: number,
|
||||
activate: boolean = false
|
||||
activate = false
|
||||
) {
|
||||
if (messageType === LINETYPE.ACTIVE_END) {
|
||||
const cnt = activationCount(idFrom || '');
|
||||
const cnt = activationCount(idFrom ?? '');
|
||||
if (cnt < 1) {
|
||||
// Bail out as there is an activation signal from an inactive participant
|
||||
const error = new Error('Trying to inactivate an inactive participant (' + idFrom + ')');
|
||||
@ -178,7 +178,7 @@ export const addSignal = function (
|
||||
from: idFrom,
|
||||
to: idTo,
|
||||
message: message?.text ?? '',
|
||||
wrap: (message?.wrap === undefined && autoWrap()) || !!message?.wrap,
|
||||
wrap: message?.wrap ?? autoWrap(),
|
||||
type: messageType,
|
||||
activate,
|
||||
});
|
||||
@ -228,13 +228,24 @@ export const setWrap = function (wrapSetting?: boolean) {
|
||||
state.records.wrapEnabled = wrapSetting;
|
||||
};
|
||||
|
||||
const extractWrap = (text?: string): { cleanedText?: string; wrap?: boolean } => {
|
||||
if (text === undefined) {
|
||||
return {};
|
||||
}
|
||||
text = text.trim();
|
||||
const wrap =
|
||||
/^:?wrap:/.exec(text) !== null ? true : /^:?nowrap:/.exec(text) !== null ? false : undefined;
|
||||
const cleanedText = (wrap === undefined ? text : text.replace(/^:?(?:no)?wrap:/, '')).trim();
|
||||
return { cleanedText, wrap };
|
||||
};
|
||||
|
||||
export const autoWrap = () => {
|
||||
// if setWrap has been called, use that value, otherwise use the value from the config
|
||||
// TODO: refactor, always use the config value let setWrap update the config value
|
||||
if (state.records.wrapEnabled !== undefined) {
|
||||
return state.records.wrapEnabled;
|
||||
}
|
||||
return getConfig()?.sequence?.wrap;
|
||||
return getConfig().sequence?.wrap ?? false;
|
||||
};
|
||||
|
||||
export const clear = function () {
|
||||
@ -244,16 +255,12 @@ export const clear = function () {
|
||||
|
||||
export const parseMessage = function (str: string) {
|
||||
const trimmedStr = str.trim();
|
||||
const { wrap, cleanedText } = extractWrap(trimmedStr);
|
||||
const message = {
|
||||
text: trimmedStr.replace(/^:?(?:no)?wrap:/, '').trim(),
|
||||
wrap:
|
||||
trimmedStr.match(/^:?wrap:/) !== null
|
||||
? true
|
||||
: trimmedStr.match(/^:?nowrap:/) !== null
|
||||
? false
|
||||
: undefined,
|
||||
text: cleanedText,
|
||||
wrap,
|
||||
};
|
||||
log.debug(`parseMessage: ${message}`);
|
||||
log.debug(`parseMessage: ${JSON.stringify(message)}`);
|
||||
return message;
|
||||
};
|
||||
|
||||
@ -261,12 +268,12 @@ export const parseMessage = function (str: string) {
|
||||
// The color can be rgb,rgba,hsl,hsla, or css code names #hex codes are not supported for now because of the way the char # is handled
|
||||
// We extract first segment as color, the rest of the line is considered as text
|
||||
export const parseBoxData = function (str: string) {
|
||||
const match = str.match(/^((?:rgba?|hsla?)\s*\(.*\)|\w*)(.*)$/);
|
||||
let color = match != null && match[1] ? match[1].trim() : 'transparent';
|
||||
let title = match != null && match[2] ? match[2].trim() : undefined;
|
||||
const match = /^((?:rgba?|hsla?)\s*\(.*\)|\w*)(.*)$/.exec(str);
|
||||
let color = match?.[1] ? match[1].trim() : 'transparent';
|
||||
let title = match?.[2] ? match[2].trim() : undefined;
|
||||
|
||||
// check that the string is a color
|
||||
if (window && window.CSS) {
|
||||
if (window?.CSS) {
|
||||
if (!window.CSS.supports('color', color)) {
|
||||
color = 'transparent';
|
||||
title = str.trim();
|
||||
@ -279,21 +286,11 @@ export const parseBoxData = function (str: string) {
|
||||
title = str.trim();
|
||||
}
|
||||
}
|
||||
|
||||
const { wrap, cleanedText } = extractWrap(title);
|
||||
return {
|
||||
color: color,
|
||||
text:
|
||||
title !== undefined
|
||||
? sanitizeText(title.replace(/^:?(?:no)?wrap:/, ''), getConfig())
|
||||
: undefined,
|
||||
wrap:
|
||||
title !== undefined
|
||||
? title.match(/^:?wrap:/) !== null
|
||||
? true
|
||||
: title.match(/^:?nowrap:/) !== null
|
||||
? false
|
||||
: undefined
|
||||
: undefined,
|
||||
text: cleanedText ? sanitizeText(cleanedText, getConfig()) : undefined,
|
||||
color,
|
||||
wrap,
|
||||
};
|
||||
};
|
||||
|
||||
@ -352,7 +349,7 @@ export const addNote = function (
|
||||
actor: actor,
|
||||
placement: placement,
|
||||
message: message.text,
|
||||
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
|
||||
wrap: message.wrap ?? autoWrap(),
|
||||
};
|
||||
|
||||
//@ts-ignore: Coerce actor into a [to, from, ...] array
|
||||
@ -363,7 +360,7 @@ export const addNote = function (
|
||||
from: actors[0],
|
||||
to: actors[1],
|
||||
message: message.text,
|
||||
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
|
||||
wrap: message.wrap ?? autoWrap(),
|
||||
type: LINETYPE.NOTE,
|
||||
placement: placement,
|
||||
});
|
||||
@ -461,12 +458,12 @@ export const addDetails = function (actorId: string, text: { text: string }) {
|
||||
const text = elem.innerHTML;
|
||||
const details = JSON.parse(text);
|
||||
// add the deserialized text to the actor's property field.
|
||||
if (details['properties']) {
|
||||
insertProperties(actor, details['properties']);
|
||||
if (details.properties) {
|
||||
insertProperties(actor, details.properties);
|
||||
}
|
||||
|
||||
if (details['links']) {
|
||||
insertLinks(actor, details['links']);
|
||||
if (details.links) {
|
||||
insertLinks(actor, details.links);
|
||||
}
|
||||
} catch (e) {
|
||||
log.error('error while parsing actor details text', e);
|
||||
@ -474,13 +471,14 @@ export const addDetails = function (actorId: string, text: { text: string }) {
|
||||
};
|
||||
|
||||
export const getActorProperty = function (actor: Actor, key: string) {
|
||||
if (actor !== undefined && actor.properties !== undefined) {
|
||||
if (actor?.properties !== undefined) {
|
||||
return actor.properties[key];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents
|
||||
export const apply = function (param: any | AddMessageParams | AddMessageParams[]) {
|
||||
if (Array.isArray(param)) {
|
||||
param.forEach(function (item) {
|
||||
@ -544,7 +542,7 @@ export const apply = function (param: any | AddMessageParams | AddMessageParams[
|
||||
if (param.to !== state.records.lastCreated) {
|
||||
throw new Error(
|
||||
'The created participant ' +
|
||||
state.records.lastCreated +
|
||||
state.records.lastCreated.name +
|
||||
' does not have an associated creating message after its declaration. Please check the sequence diagram.'
|
||||
);
|
||||
} else {
|
||||
@ -557,7 +555,7 @@ export const apply = function (param: any | AddMessageParams | AddMessageParams[
|
||||
) {
|
||||
throw new Error(
|
||||
'The destroyed participant ' +
|
||||
state.records.lastDestroyed +
|
||||
state.records.lastDestroyed.name +
|
||||
' does not have an associated destroying message after its declaration. Please check the sequence diagram.'
|
||||
);
|
||||
} else {
|
||||
|
@ -1339,15 +1339,15 @@ link a: Tests @ https://tests.contoso.com/?svc=alice@contoso.com
|
||||
|
||||
await mermaidAPI.parse(str);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('a').links['Repo']).toBe('https://repo.contoso.com/');
|
||||
expect(actors.get('b').links['Repo']).toBe(undefined);
|
||||
expect(actors.get('a').links['Dashboard']).toBe('https://dashboard.contoso.com/');
|
||||
expect(actors.get('b').links['Dashboard']).toBe('https://dashboard.contoso.com/');
|
||||
expect(actors.get('a').links.Repo).toBe('https://repo.contoso.com/');
|
||||
expect(actors.get('b').links.Repo).toBe(undefined);
|
||||
expect(actors.get('a').links.Dashboard).toBe('https://dashboard.contoso.com/');
|
||||
expect(actors.get('b').links.Dashboard).toBe('https://dashboard.contoso.com/');
|
||||
expect(actors.get('a').links['On-Call']).toBe('https://oncall.contoso.com/?svc=alice');
|
||||
expect(actors.get('c').links['Dashboard']).toBe(undefined);
|
||||
expect(actors.get('a').links['Endpoint']).toBe('https://alice.contoso.com');
|
||||
expect(actors.get('a').links['Swagger']).toBe('https://swagger.contoso.com');
|
||||
expect(actors.get('a').links['Tests']).toBe('https://tests.contoso.com/?svc=alice@contoso.com');
|
||||
expect(actors.get('c').links.Dashboard).toBe(undefined);
|
||||
expect(actors.get('a').links.Endpoint).toBe('https://alice.contoso.com');
|
||||
expect(actors.get('a').links.Swagger).toBe('https://swagger.contoso.com');
|
||||
expect(actors.get('a').links.Tests).toBe('https://tests.contoso.com/?svc=alice@contoso.com');
|
||||
});
|
||||
|
||||
it('should handle properties EXPERIMENTAL: USE WITH CAUTION', async () => {
|
||||
@ -1363,11 +1363,11 @@ properties b: {"class": "external-service-actor", "icon": "@computer"}
|
||||
|
||||
await mermaidAPI.parse(str);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('a').properties['class']).toBe('internal-service-actor');
|
||||
expect(actors.get('b').properties['class']).toBe('external-service-actor');
|
||||
expect(actors.get('a').properties['icon']).toBe('@clock');
|
||||
expect(actors.get('b').properties['icon']).toBe('@computer');
|
||||
expect(actors.get('c').properties['class']).toBe(undefined);
|
||||
expect(actors.get('a').properties.class).toBe('internal-service-actor');
|
||||
expect(actors.get('b').properties.class).toBe('external-service-actor');
|
||||
expect(actors.get('a').properties.icon).toBe('@clock');
|
||||
expect(actors.get('b').properties.icon).toBe('@computer');
|
||||
expect(actors.get('c').properties.class).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should handle box', async () => {
|
||||
@ -1519,7 +1519,7 @@ describe('when checking the bounds in a sequenceDiagram', function () {
|
||||
diagram.renderer.bounds.init();
|
||||
conf = diagram.db.getConfig();
|
||||
});
|
||||
it('should handle a simple bound call', async () => {
|
||||
it('should handle a simple bound call', () => {
|
||||
diagram.renderer.bounds.insert(100, 100, 200, 200);
|
||||
|
||||
const { bounds } = diagram.renderer.bounds.getBounds();
|
||||
@ -1528,7 +1528,7 @@ describe('when checking the bounds in a sequenceDiagram', function () {
|
||||
expect(bounds.stopx).toBe(200);
|
||||
expect(bounds.stopy).toBe(200);
|
||||
});
|
||||
it('should handle an expanding bound', async () => {
|
||||
it('should handle an expanding bound', () => {
|
||||
diagram.renderer.bounds.insert(100, 100, 200, 200);
|
||||
diagram.renderer.bounds.insert(25, 50, 300, 400);
|
||||
|
||||
@ -1538,7 +1538,7 @@ describe('when checking the bounds in a sequenceDiagram', function () {
|
||||
expect(bounds.stopx).toBe(300);
|
||||
expect(bounds.stopy).toBe(400);
|
||||
});
|
||||
it('should handle inserts within the bound without changing the outer bounds', async () => {
|
||||
it('should handle inserts within the bound without changing the outer bounds', () => {
|
||||
diagram.renderer.bounds.insert(100, 100, 200, 200);
|
||||
diagram.renderer.bounds.insert(25, 50, 300, 400);
|
||||
diagram.renderer.bounds.insert(125, 150, 150, 200);
|
||||
@ -1549,7 +1549,7 @@ describe('when checking the bounds in a sequenceDiagram', function () {
|
||||
expect(bounds.stopx).toBe(300);
|
||||
expect(bounds.stopy).toBe(400);
|
||||
});
|
||||
it('should handle a loop without expanding the area', async () => {
|
||||
it('should handle a loop without expanding the area', () => {
|
||||
diagram.renderer.bounds.insert(25, 50, 300, 400);
|
||||
diagram.renderer.bounds.verticalPos = 150;
|
||||
diagram.renderer.bounds.newLoop();
|
||||
@ -1570,7 +1570,7 @@ describe('when checking the bounds in a sequenceDiagram', function () {
|
||||
expect(bounds.stopx).toBe(300);
|
||||
expect(bounds.stopy).toBe(400);
|
||||
});
|
||||
it('should handle multiple loops withtout expanding the bounds', async () => {
|
||||
it('should handle multiple loops withtout expanding the bounds', () => {
|
||||
diagram.renderer.bounds.insert(100, 100, 1000, 1000);
|
||||
diagram.renderer.bounds.verticalPos = 200;
|
||||
diagram.renderer.bounds.newLoop();
|
||||
@ -1601,7 +1601,7 @@ describe('when checking the bounds in a sequenceDiagram', function () {
|
||||
expect(bounds.stopx).toBe(1000);
|
||||
expect(bounds.stopy).toBe(1000);
|
||||
});
|
||||
it('should handle a loop that expands the area', async () => {
|
||||
it('should handle a loop that expands the area', () => {
|
||||
diagram.renderer.bounds.insert(100, 100, 200, 200);
|
||||
diagram.renderer.bounds.verticalPos = 200;
|
||||
diagram.renderer.bounds.newLoop();
|
||||
|
@ -383,9 +383,11 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
textObj.textMargin = conf.wrapPadding;
|
||||
textObj.tspan = false;
|
||||
|
||||
hasKatex(textObj.text)
|
||||
? await drawKatex(diagram, textObj, { startx, stopx, starty: lineStartY })
|
||||
: drawText(diagram, textObj);
|
||||
if (hasKatex(textObj.text)) {
|
||||
await drawKatex(diagram, textObj, { startx, stopx, starty: lineStartY });
|
||||
} else {
|
||||
drawText(diagram, textObj);
|
||||
}
|
||||
|
||||
const textWidth = textDims.width;
|
||||
|
||||
@ -493,7 +495,7 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
}
|
||||
};
|
||||
|
||||
const addActorRenderingData = async function (
|
||||
const addActorRenderingData = function (
|
||||
diagram,
|
||||
actors,
|
||||
createdActors: Map<string, any>,
|
||||
@ -820,7 +822,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
actorKeys = actorKeys.filter((actorKey) => newActors.has(actorKey));
|
||||
}
|
||||
|
||||
await addActorRenderingData(diagram, actors, createdActors, actorKeys, 0, messages, false);
|
||||
addActorRenderingData(diagram, actors, createdActors, actorKeys, 0, messages, false);
|
||||
const loopWidths = await calculateLoopBounds(messages, actors, maxMessageWidthPerActor, diagObj);
|
||||
|
||||
// The arrow head definition is attached to the svg once
|
||||
@ -1074,7 +1076,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
box.stopx = box.startx + box.width;
|
||||
box.stopy = box.starty + box.height;
|
||||
box.stroke = 'rgb(0,0,0, 0.5)';
|
||||
await svgDraw.drawBox(diagram, box, conf);
|
||||
svgDraw.drawBox(diagram, box, conf);
|
||||
}
|
||||
|
||||
if (hasBoxes) {
|
||||
@ -1145,7 +1147,7 @@ async function getMaxMessageWidthPerActor(
|
||||
actors: Map<string, any>,
|
||||
messages: any[],
|
||||
diagObj: Diagram
|
||||
): Promise<{ [id: string]: number }> {
|
||||
): Promise<Record<string, number>> {
|
||||
const maxMessageWidthPerActor = {};
|
||||
|
||||
for (const msg of messages) {
|
||||
@ -1579,7 +1581,7 @@ const calculateLoopBounds = async function (messages, actors, _maxWidthPerActor,
|
||||
const lastActorActivationIdx = bounds.activations
|
||||
.map((a) => a.actor)
|
||||
.lastIndexOf(msg.from);
|
||||
delete bounds.activations.splice(lastActorActivationIdx, 1)[0];
|
||||
bounds.activations.splice(lastActorActivationIdx, 1).splice(0, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -115,6 +115,7 @@ export const drawKatex = async function (elem, textData, msgModel = null) {
|
||||
stopx = temp;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
||||
textElem.attr('x', Math.round(startx + Math.abs(startx - stopx) / 2 - dim.width / 2));
|
||||
if (textData.class === 'loopText') {
|
||||
textElem.attr('y', Math.round(starty));
|
||||
@ -325,7 +326,7 @@ export const fixLifeLineHeights = (diagram, actors, actorKeys, conf) => {
|
||||
* @param {any} conf - DrawText implementation discriminator object
|
||||
* @param {boolean} isFooter - If the actor is the footer one
|
||||
*/
|
||||
const drawActorTypeParticipant = async function (elem, actor, conf, isFooter) {
|
||||
const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actorY + 5;
|
||||
@ -359,8 +360,8 @@ const drawActorTypeParticipant = async function (elem, actor, conf, isFooter) {
|
||||
|
||||
const rect = svgDrawCommon.getNoteRect();
|
||||
var cssclass = 'actor';
|
||||
if (actor.properties != null && actor.properties['class']) {
|
||||
cssclass = actor.properties['class'];
|
||||
if (actor.properties?.class) {
|
||||
cssclass = actor.properties.class;
|
||||
} else {
|
||||
rect.fill = '#eaeaea';
|
||||
}
|
||||
@ -380,8 +381,8 @@ const drawActorTypeParticipant = async function (elem, actor, conf, isFooter) {
|
||||
const rectElem = drawRect(g, rect);
|
||||
actor.rectData = rect;
|
||||
|
||||
if (actor.properties != null && actor.properties['icon']) {
|
||||
const iconSrc = actor.properties['icon'].trim();
|
||||
if (actor.properties?.icon) {
|
||||
const iconSrc = actor.properties.icon.trim();
|
||||
if (iconSrc.charAt(0) === '@') {
|
||||
svgDrawCommon.drawEmbeddedImage(g, rect.x + rect.width - 20, rect.y + 10, iconSrc.substr(1));
|
||||
} else {
|
||||
@ -389,7 +390,7 @@ const drawActorTypeParticipant = async function (elem, actor, conf, isFooter) {
|
||||
}
|
||||
}
|
||||
|
||||
await _drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
_drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
actor.description,
|
||||
g,
|
||||
rect.x,
|
||||
@ -410,7 +411,7 @@ const drawActorTypeParticipant = async function (elem, actor, conf, isFooter) {
|
||||
return height;
|
||||
};
|
||||
|
||||
const drawActorTypeActor = async function (elem, actor, conf, isFooter) {
|
||||
const drawActorTypeActor = function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actorY + 80;
|
||||
@ -491,7 +492,7 @@ const drawActorTypeActor = async function (elem, actor, conf, isFooter) {
|
||||
const bounds = actElem.node().getBBox();
|
||||
actor.height = bounds.height;
|
||||
|
||||
await _drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
_drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
actor.description,
|
||||
actElem,
|
||||
rect.x,
|
||||
@ -514,12 +515,12 @@ export const drawActor = async function (elem, actor, conf, isFooter) {
|
||||
}
|
||||
};
|
||||
|
||||
export const drawBox = async function (elem, box, conf) {
|
||||
export const drawBox = function (elem, box, conf) {
|
||||
const boxplusTextGroup = elem.append('g');
|
||||
const g = boxplusTextGroup;
|
||||
drawBackgroundRect(g, box);
|
||||
if (box.name) {
|
||||
await _drawTextCandidateFunc(conf)(
|
||||
_drawTextCandidateFunc(conf)(
|
||||
box.name,
|
||||
g,
|
||||
box.x,
|
||||
|
@ -78,8 +78,7 @@ export interface AddMessageParams {
|
||||
| 'breakEnd'
|
||||
| 'parOverStart'
|
||||
| 'parOverEnd'
|
||||
| 'parOverAnd'
|
||||
| 'parOverEnd';
|
||||
| 'parOverAnd';
|
||||
|
||||
activate: boolean;
|
||||
}
|
||||
|
@ -511,7 +511,7 @@ export const addStyleClass = function (id, styleAttributes = '') {
|
||||
const fixedAttrib = attrib.replace(/([^;]*);/, '$1').trim();
|
||||
|
||||
// replace some style keywords
|
||||
if (attrib.match(COLOR_KEYWORD)) {
|
||||
if (RegExp(COLOR_KEYWORD).exec(attrib)) {
|
||||
const newStyle1 = fixedAttrib.replace(FILL_KEYWORD, BG_FILL);
|
||||
const newStyle2 = newStyle1.replace(COLOR_KEYWORD, FILL_KEYWORD);
|
||||
foundClass.textStyles.push(newStyle2);
|
||||
|
@ -362,8 +362,7 @@ const setupDoc = (g, parentParsedItem, doc, diagramStates, diagramDb, altFlag) =
|
||||
const getDir = (parsedItem, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
|
||||
let dir = defaultDir;
|
||||
if (parsedItem.doc) {
|
||||
for (let i = 0; i < parsedItem.doc.length; i++) {
|
||||
const parsedItemDoc = parsedItem.doc[i];
|
||||
for (const parsedItemDoc of parsedItem.doc) {
|
||||
if (parsedItemDoc.stmt === 'dir') {
|
||||
dir = parsedItemDoc.value;
|
||||
}
|
||||
|
@ -258,23 +258,6 @@ export const drawTask = function (elem, task, conf) {
|
||||
rect.ry = 3;
|
||||
drawRect(g, rect);
|
||||
|
||||
// task.people.forEach((person) => {
|
||||
// const colour = task.actors[person].color;
|
||||
|
||||
// const circle = {
|
||||
// cx: xPos,
|
||||
// cy: task.y,
|
||||
// r: 7,
|
||||
// fill: colour,
|
||||
// stroke: '#000',
|
||||
// title: person,
|
||||
// pos: task.actors[person].position,
|
||||
// };
|
||||
|
||||
// drawCircle(g, circle);
|
||||
// xPos += 10;
|
||||
// });
|
||||
|
||||
_drawTextCandidateFunc(conf)(
|
||||
task.task,
|
||||
g,
|
||||
@ -532,8 +515,7 @@ export const drawNode = function (elem, node, fullSection, conf) {
|
||||
.attr('text-anchor', 'middle')
|
||||
.call(wrap, node.width);
|
||||
const bbox = txt.node().getBBox();
|
||||
const fontSize =
|
||||
conf.fontSize && conf.fontSize.replace ? conf.fontSize.replace('px', '') : conf.fontSize;
|
||||
const fontSize = conf.fontSize?.replace ? conf.fontSize.replace('px', '') : conf.fontSize;
|
||||
node.height = bbox.height + fontSize * 1.1 * 0.5 + node.padding;
|
||||
node.height = Math.max(node.height, node.maxHeight);
|
||||
node.width = node.width + 2 * node.padding;
|
||||
@ -557,8 +539,7 @@ export const getVirtualNodeHeight = function (elem, node, conf) {
|
||||
.attr('text-anchor', 'middle')
|
||||
.call(wrap, node.width);
|
||||
const bbox = txt.node().getBBox();
|
||||
const fontSize =
|
||||
conf.fontSize && conf.fontSize.replace ? conf.fontSize.replace('px', '') : conf.fontSize;
|
||||
const fontSize = conf.fontSize?.replace ? conf.fontSize.replace('px', '') : conf.fontSize;
|
||||
textElem.remove();
|
||||
return bbox.height + fontSize * 1.1 * 0.5 + node.padding;
|
||||
};
|
||||
|
@ -115,8 +115,7 @@ export const draw = function (text: string, id: string, version: string, diagObj
|
||||
maxEventCount = Math.max(maxEventCount, task.events.length);
|
||||
//calculate maxEventLineLength
|
||||
let maxEventLineLengthTemp = 0;
|
||||
for (let j = 0; j < task.events.length; j++) {
|
||||
const event = task.events[j];
|
||||
for (const event of task.events) {
|
||||
const eventNode = {
|
||||
descr: event,
|
||||
section: task.section,
|
||||
|
@ -40,6 +40,6 @@ export class BandAxis extends BaseAxis {
|
||||
}
|
||||
|
||||
getScaleValue(value: string): number {
|
||||
return this.scale(value) || this.getRange()[0];
|
||||
return this.scale(value) ?? this.getRange()[0];
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ export abstract class BaseAxis implements Axis {
|
||||
|
||||
abstract recalculateScale(): void;
|
||||
|
||||
abstract getTickValues(): Array<string | number>;
|
||||
abstract getTickValues(): (string | number)[];
|
||||
|
||||
getTickDistance(): number {
|
||||
const range = this.getRange();
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { defineConfig, MarkdownOptions } from 'vitepress';
|
||||
import type { MarkdownOptions } from 'vitepress';
|
||||
import { defineConfig } from 'vitepress';
|
||||
import { version } from '../../../package.json';
|
||||
import MermaidExample from './mermaid-markdown-all.js';
|
||||
|
||||
@ -8,8 +9,9 @@ const allMarkdownTransformers: MarkdownOptions = {
|
||||
light: 'github-light',
|
||||
dark: 'github-dark',
|
||||
},
|
||||
config: async (md) => {
|
||||
await MermaidExample(md);
|
||||
|
||||
config: (md) => {
|
||||
MermaidExample(md);
|
||||
},
|
||||
};
|
||||
|
||||
@ -228,8 +230,6 @@ function sidebarNews() {
|
||||
|
||||
/**
|
||||
* Return a string that puts together the pagePage, a '#', then the given id
|
||||
* @param pagePath
|
||||
* @param id
|
||||
* @returns the fully formed path
|
||||
*/
|
||||
function pathToId(pagePath: string, id = ''): string {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import contributorUsernamesJson from './contributor-names.json';
|
||||
import { CoreTeam, knut, plainTeamMembers } from './teamMembers.js';
|
||||
import type { CoreTeam } from './teamMembers.js';
|
||||
import { knut, plainTeamMembers } from './teamMembers.js';
|
||||
|
||||
const contributorUsernames: string[] = contributorUsernamesJson;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { MarkdownRenderer } from 'vitepress';
|
||||
|
||||
const MermaidExample = async (md: MarkdownRenderer) => {
|
||||
const MermaidExample = (md: MarkdownRenderer) => {
|
||||
const defaultRenderer = md.renderer.rules.fence;
|
||||
|
||||
if (!defaultRenderer) {
|
||||
|
@ -32,11 +32,11 @@ async function fetchAvatars() {
|
||||
});
|
||||
|
||||
contributors = JSON.parse(await readFile(pathContributors, { encoding: 'utf-8' }));
|
||||
let avatars = contributors.map((name) => {
|
||||
download(`https://github.com/${name}.png?size=100`, getAvatarPath(name));
|
||||
});
|
||||
const avatars = contributors.map((name) =>
|
||||
download(`https://github.com/${name}.png?size=100`, getAvatarPath(name))
|
||||
);
|
||||
|
||||
await Promise.allSettled(avatars);
|
||||
}
|
||||
|
||||
fetchAvatars();
|
||||
void fetchAvatars();
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
// Adapted from https://github.dev/vitest-dev/vitest/blob/991ff33ab717caee85ef6cbe1c16dc514186b4cc/scripts/update-contributors.ts#L6
|
||||
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable @cspell/spellchecker */
|
||||
export interface Contributor {
|
||||
name: string;
|
||||
avatar: string;
|
||||
|
@ -1,14 +1,16 @@
|
||||
/* eslint-disable no-console */
|
||||
import DefaultTheme from 'vitepress/theme';
|
||||
import './custom.css';
|
||||
// @ts-ignore
|
||||
// @ts-ignore Type not available
|
||||
import Mermaid from './Mermaid.vue';
|
||||
// @ts-ignore
|
||||
// @ts-ignore Type not available
|
||||
import Contributors from '../components/Contributors.vue';
|
||||
// @ts-ignore
|
||||
// @ts-ignore Type not available
|
||||
import HomePage from '../components/HomePage.vue';
|
||||
// @ts-ignore
|
||||
// @ts-ignore Type not available
|
||||
import TopBar from '../components/TopBar.vue';
|
||||
import { getRedirect } from './redirect.js';
|
||||
// @ts-ignore Type not available
|
||||
import { h } from 'vue';
|
||||
import Theme from 'vitepress/theme';
|
||||
import '../style/main.css';
|
||||
@ -33,7 +35,7 @@ export default {
|
||||
const url = new URL(window.location.origin + to);
|
||||
const newPath = getRedirect(url);
|
||||
if (newPath) {
|
||||
console.log(`Redirecting to ${newPath} from ${window.location}`);
|
||||
console.log(`Redirecting to ${newPath} from ${window.location.toString()}`);
|
||||
// router.go isn't loading the ID properly.
|
||||
window.location.href = `/${newPath}`;
|
||||
}
|
||||
|
@ -116,3 +116,5 @@ export const getRedirect = (url: URL): string | undefined => {
|
||||
return `${idRedirectMap[path]}.html${id ? `#${id}` : ''}`;
|
||||
}
|
||||
};
|
||||
|
||||
// cspell:ignore mermaidapi, breakingchanges, classdiagram, entityrelationshipdiagram, mermaidapi, mermaidcli, gettingstarted, syntaxreference, newdiagram, requirementdiagram, sequencediagram
|
||||
|
8
packages/mermaid/src/docs/tsconfig.json
Normal file
8
packages/mermaid/src/docs/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": ["../../../../tsconfig.json"],
|
||||
"compilerOptions": {
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["./**/*.ts", "./.vitepress/**/*.ts"]
|
||||
}
|
@ -49,12 +49,12 @@ export default defineConfig({
|
||||
// TODO: will be fixed in the next vitepress release.
|
||||
name: 'fix-virtual',
|
||||
|
||||
async resolveId(id: string) {
|
||||
resolveId(id: string) {
|
||||
if (id === virtualModuleId) {
|
||||
return resolvedVirtualModuleId;
|
||||
}
|
||||
},
|
||||
async load(this, id: string) {
|
||||
load(this, id: string) {
|
||||
if (id === resolvedVirtualModuleId) {
|
||||
return `export default ${JSON.stringify({
|
||||
securityLevel: 'loose',
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/* eslint-disable no-console */
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
@ -32,12 +32,11 @@ export const log: Record<keyof typeof LEVELS, typeof console.log> = {
|
||||
*
|
||||
* @param level - The level to set the logging to. Default is `"fatal"`
|
||||
*/
|
||||
export const setLogLevel = function (level: keyof typeof LEVELS | number | string = 'fatal') {
|
||||
export const setLogLevel = function (level: keyof typeof LEVELS | number = 'fatal') {
|
||||
let numericLevel: number = LEVELS.fatal;
|
||||
if (typeof level === 'string') {
|
||||
level = level.toLowerCase();
|
||||
if (level in LEVELS) {
|
||||
numericLevel = LEVELS[level as keyof typeof LEVELS];
|
||||
if (level.toLowerCase() in LEVELS) {
|
||||
numericLevel = LEVELS[level];
|
||||
}
|
||||
} else if (typeof level === 'number') {
|
||||
numericLevel = level;
|
||||
|
@ -5,7 +5,7 @@ import { addDiagrams } from './diagram-api/diagram-orchestration.js';
|
||||
import { beforeAll, describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import type { DiagramDefinition } from './diagram-api/types.js';
|
||||
|
||||
beforeAll(async () => {
|
||||
beforeAll(() => {
|
||||
addDiagrams();
|
||||
});
|
||||
const spyOn = vi.spyOn;
|
||||
@ -18,7 +18,7 @@ afterEach(() => {
|
||||
|
||||
describe('when using mermaid and ', () => {
|
||||
describe('when detecting chart type ', () => {
|
||||
it('should not start rendering with mermaid.startOnLoad set to false', async () => {
|
||||
it('should not start rendering with mermaid.startOnLoad set to false', () => {
|
||||
mermaid.startOnLoad = false;
|
||||
document.body.innerHTML = '<div class="mermaid">graph TD;\na;</div>';
|
||||
spyOn(mermaid, 'run');
|
||||
@ -26,7 +26,7 @@ describe('when using mermaid and ', () => {
|
||||
expect(mermaid.run).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should start rendering with both startOnLoad set', async () => {
|
||||
it('should start rendering with both startOnLoad set', () => {
|
||||
mermaid.startOnLoad = true;
|
||||
document.body.innerHTML = '<div class="mermaid">graph TD;\na;</div>';
|
||||
spyOn(mermaid, 'run');
|
||||
@ -34,7 +34,7 @@ describe('when using mermaid and ', () => {
|
||||
expect(mermaid.run).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should start rendering with mermaid.startOnLoad', async () => {
|
||||
it('should start rendering with mermaid.startOnLoad', () => {
|
||||
mermaid.startOnLoad = true;
|
||||
document.body.innerHTML = '<div class="mermaid">graph TD;\na;</div>';
|
||||
spyOn(mermaid, 'run');
|
||||
@ -42,7 +42,7 @@ describe('when using mermaid and ', () => {
|
||||
expect(mermaid.run).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should start rendering as a default with no changes performed', async () => {
|
||||
it('should start rendering as a default with no changes performed', () => {
|
||||
document.body.innerHTML = '<div class="mermaid">graph TD;\na;</div>';
|
||||
spyOn(mermaid, 'run');
|
||||
mermaid.contentLoaded();
|
||||
@ -74,7 +74,7 @@ describe('when using mermaid and ', () => {
|
||||
[
|
||||
{
|
||||
id: 'dummyError',
|
||||
detector: (text) => /dummyError/.test(text),
|
||||
detector: (text) => text.includes('dummyError'),
|
||||
loader: () => Promise.reject('dummyError'),
|
||||
},
|
||||
],
|
||||
@ -114,7 +114,7 @@ describe('when using mermaid and ', () => {
|
||||
[
|
||||
{
|
||||
id: 'dummy',
|
||||
detector: (text) => /dummy/.test(text),
|
||||
detector: (text) => text.includes('dummy'),
|
||||
loader: () => {
|
||||
loaded = true;
|
||||
return Promise.resolve({
|
||||
@ -133,7 +133,7 @@ describe('when using mermaid and ', () => {
|
||||
[
|
||||
{
|
||||
id: 'dummy2',
|
||||
detector: (text) => /dummy2/.test(text),
|
||||
detector: (text) => text.includes('dummy2'),
|
||||
loader: () => {
|
||||
loaded = true;
|
||||
return Promise.resolve({
|
||||
|
@ -606,26 +606,26 @@ describe('mermaidAPI', () => {
|
||||
let error: any = { message: '' };
|
||||
try {
|
||||
// @ts-ignore This is a read-only property. Typescript will not allow assignment, but regular javascript might.
|
||||
mermaidAPI['defaultConfig'] = config;
|
||||
mermaidAPI.defaultConfig = config;
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error.message).toBe(
|
||||
"Cannot assign to read only property 'defaultConfig' of object '#<Object>'"
|
||||
);
|
||||
expect(mermaidAPI.defaultConfig['logLevel']).toBe(5);
|
||||
expect(mermaidAPI.defaultConfig.logLevel).toBe(5);
|
||||
});
|
||||
it('prevents changes to global defaults (direct)', () => {
|
||||
let error: any = { message: '' };
|
||||
try {
|
||||
mermaidAPI.defaultConfig['logLevel'] = 0;
|
||||
mermaidAPI.defaultConfig.logLevel = 0;
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error.message).toBe(
|
||||
"Cannot assign to read only property 'logLevel' of object '#<Object>'"
|
||||
);
|
||||
expect(mermaidAPI.defaultConfig['logLevel']).toBe(5);
|
||||
expect(mermaidAPI.defaultConfig.logLevel).toBe(5);
|
||||
});
|
||||
it('prevents sneaky changes to global defaults (assignWithDepth)', () => {
|
||||
const config = {
|
||||
@ -640,7 +640,7 @@ describe('mermaidAPI', () => {
|
||||
expect(error.message).toBe(
|
||||
"Cannot assign to read only property 'logLevel' of object '#<Object>'"
|
||||
);
|
||||
expect(mermaidAPI.defaultConfig['logLevel']).toBe(5);
|
||||
expect(mermaidAPI.defaultConfig.logLevel).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
@ -648,7 +648,7 @@ describe('mermaidAPI', () => {
|
||||
it('allows dompurify config to be set', () => {
|
||||
mermaidAPI.initialize({ dompurifyConfig: { ADD_ATTR: ['onclick'] } });
|
||||
|
||||
expect(mermaidAPI!.getConfig()!.dompurifyConfig!.ADD_ATTR).toEqual(['onclick']);
|
||||
expect(mermaidAPI.getConfig().dompurifyConfig!.ADD_ATTR).toEqual(['onclick']);
|
||||
});
|
||||
});
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user