mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-15 05:19:58 +02:00
Merge branch 'develop' into fix/flowchart-inherit-dir
This commit is contained in:
7
.changeset/honest-trees-dress.md
Normal file
7
.changeset/honest-trees-dress.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
'@mermaid-js/mermaid-zenuml': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
chore: bump minimum ZenUML version to 3.23.28
|
||||||
|
|
||||||
|
commit: 9d06d8f31e7f12af9e9e092214f907f2dc93ad75
|
7
.changeset/yellow-mirrors-change.md
Normal file
7
.changeset/yellow-mirrors-change.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
'@mermaid-js/mermaid-zenuml': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(zenuml): limit `peerDependencies` to Mermaid v10 and v11
|
||||||
|
|
||||||
|
commit: 0ad44c12feead9d20c6a870a49327ada58d6e657
|
@@ -34,6 +34,19 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => {
|
|||||||
{ ...iifeOptions, minify: true, metafile: shouldVisualize }
|
{ ...iifeOptions, minify: true, metafile: shouldVisualize }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (entryName === 'mermaid-zenuml') {
|
||||||
|
const iifeOptions: MermaidBuildOptions = {
|
||||||
|
...commonOptions,
|
||||||
|
format: 'iife',
|
||||||
|
globalName: 'mermaid-zenuml',
|
||||||
|
};
|
||||||
|
buildConfigs.push(
|
||||||
|
// mermaid-zenuml.js
|
||||||
|
{ ...iifeOptions },
|
||||||
|
// mermaid-zenuml.min.js
|
||||||
|
{ ...iifeOptions, minify: true, metafile: shouldVisualize }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const results = await Promise.all(buildConfigs.map((option) => build(getBuildConfig(option))));
|
const results = await Promise.all(buildConfigs.map((option) => build(getBuildConfig(option))));
|
||||||
|
|
||||||
|
@@ -58,6 +58,7 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
|
|||||||
format,
|
format,
|
||||||
minify,
|
minify,
|
||||||
options: { name, file, packageName },
|
options: { name, file, packageName },
|
||||||
|
globalName = 'mermaid',
|
||||||
} = options;
|
} = options;
|
||||||
const external: string[] = ['require', 'fs', 'path'];
|
const external: string[] = ['require', 'fs', 'path'];
|
||||||
const outFileName = getFileName(name, options);
|
const outFileName = getFileName(name, options);
|
||||||
@@ -68,6 +69,7 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
|
|||||||
},
|
},
|
||||||
metafile,
|
metafile,
|
||||||
minify,
|
minify,
|
||||||
|
globalName,
|
||||||
logLevel: 'info',
|
logLevel: 'info',
|
||||||
chunkNames: `chunks/${outFileName}/[name]-[hash]`,
|
chunkNames: `chunks/${outFileName}/[name]-[hash]`,
|
||||||
define: {
|
define: {
|
||||||
@@ -89,11 +91,12 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
|
|||||||
if (format === 'iife') {
|
if (format === 'iife') {
|
||||||
output.format = 'iife';
|
output.format = 'iife';
|
||||||
output.splitting = false;
|
output.splitting = false;
|
||||||
output.globalName = '__esbuild_esm_mermaid';
|
const originalGlobalName = output.globalName ?? 'mermaid';
|
||||||
|
output.globalName = `__esbuild_esm_mermaid_nm[${JSON.stringify(originalGlobalName)}]`;
|
||||||
// Workaround for removing the .default access in esbuild IIFE.
|
// Workaround for removing the .default access in esbuild IIFE.
|
||||||
// https://github.com/mermaid-js/mermaid/pull/4109#discussion_r1292317396
|
// https://github.com/mermaid-js/mermaid/pull/4109#discussion_r1292317396
|
||||||
output.footer = {
|
output.footer = {
|
||||||
js: 'globalThis.mermaid = globalThis.__esbuild_esm_mermaid.default;',
|
js: `globalThis[${JSON.stringify(originalGlobalName)}] = globalThis.${output.globalName}.default;`,
|
||||||
};
|
};
|
||||||
output.outExtension = { '.js': '.js' };
|
output.outExtension = { '.js': '.js' };
|
||||||
} else {
|
} else {
|
||||||
|
5
.github/workflows/e2e-timings.yml
vendored
5
.github/workflows/e2e-timings.yml
vendored
@@ -30,6 +30,7 @@ jobs:
|
|||||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||||
with:
|
with:
|
||||||
runTests: false
|
runTests: false
|
||||||
|
|
||||||
- name: Cypress run
|
- name: Cypress run
|
||||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||||
id: cypress
|
id: cypress
|
||||||
@@ -45,6 +46,10 @@ jobs:
|
|||||||
SPLIT: 1
|
SPLIT: 1
|
||||||
SPLIT_INDEX: 0
|
SPLIT_INDEX: 0
|
||||||
SPLIT_FILE: 'cypress/timings.json'
|
SPLIT_FILE: 'cypress/timings.json'
|
||||||
|
|
||||||
|
- name: Compare timings
|
||||||
|
run: pnpm tsx scripts/compare-timings.ts
|
||||||
|
|
||||||
- name: Commit and create pull request
|
- name: Commit and create pull request
|
||||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
|
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
|
||||||
with:
|
with:
|
||||||
|
115
scripts/compare-timings.ts
Normal file
115
scripts/compare-timings.ts
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/**
|
||||||
|
* Compares new E2E test timings with previous timings and determines whether to keep the new timings.
|
||||||
|
*
|
||||||
|
* The script will:
|
||||||
|
* 1. Read old timings from git HEAD
|
||||||
|
* 2. Read new timings from the current file
|
||||||
|
* 3. Compare the timings and specs
|
||||||
|
* 4. Keep new timings if:
|
||||||
|
* - Specs were added/removed
|
||||||
|
* - Any timing changed by 20% or more
|
||||||
|
* 5. Revert to old timings if:
|
||||||
|
* - No significant timing changes
|
||||||
|
*
|
||||||
|
* This helps prevent unnecessary timing updates when test performance hasn't changed significantly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { execSync } from 'node:child_process';
|
||||||
|
|
||||||
|
interface Timing {
|
||||||
|
spec: string;
|
||||||
|
duration: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TimingsFile {
|
||||||
|
durations: Timing[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CleanupOptions {
|
||||||
|
keepNew: boolean;
|
||||||
|
reason: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TIMINGS_FILE = 'cypress/timings.json';
|
||||||
|
const TIMINGS_PATH = path.join(process.cwd(), TIMINGS_FILE);
|
||||||
|
|
||||||
|
function log(message: string): void {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readOldTimings(): TimingsFile {
|
||||||
|
try {
|
||||||
|
const oldContent = execSync(`git show HEAD:${TIMINGS_FILE}`, { encoding: 'utf8' });
|
||||||
|
return JSON.parse(oldContent);
|
||||||
|
} catch {
|
||||||
|
log('Error getting old timings, using empty file');
|
||||||
|
return { durations: [] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readNewTimings(): TimingsFile {
|
||||||
|
return JSON.parse(fs.readFileSync(TIMINGS_PATH, 'utf8'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanupFiles({ keepNew, reason }: CleanupOptions): void {
|
||||||
|
if (keepNew) {
|
||||||
|
log(`Keeping new timings: ${reason}`);
|
||||||
|
} else {
|
||||||
|
log(`Reverting to old timings: ${reason}`);
|
||||||
|
execSync(`git checkout HEAD -- ${TIMINGS_FILE}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareTimings(): void {
|
||||||
|
const oldTimings = readOldTimings();
|
||||||
|
const newTimings = readNewTimings();
|
||||||
|
|
||||||
|
const oldSpecs = new Set(oldTimings.durations.map((d) => d.spec));
|
||||||
|
const newSpecs = new Set(newTimings.durations.map((d) => d.spec));
|
||||||
|
|
||||||
|
// Check if specs were added or removed
|
||||||
|
const addedSpecs = [...newSpecs].filter((spec) => !oldSpecs.has(spec));
|
||||||
|
const removedSpecs = [...oldSpecs].filter((spec) => !newSpecs.has(spec));
|
||||||
|
|
||||||
|
if (addedSpecs.length > 0 || removedSpecs.length > 0) {
|
||||||
|
log('Specs changed:');
|
||||||
|
if (addedSpecs.length > 0) {
|
||||||
|
log(`Added: ${addedSpecs.join(', ')}`);
|
||||||
|
}
|
||||||
|
if (removedSpecs.length > 0) {
|
||||||
|
log(`Removed: ${removedSpecs.join(', ')}`);
|
||||||
|
}
|
||||||
|
return cleanupFiles({ keepNew: true, reason: 'Specs were added or removed' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check timing variations
|
||||||
|
const timingChanges = newTimings.durations.map((newTiming) => {
|
||||||
|
const oldTiming = oldTimings.durations.find((d) => d.spec === newTiming.spec);
|
||||||
|
if (!oldTiming) {
|
||||||
|
throw new Error(`Could not find old timing for spec: ${newTiming.spec}`);
|
||||||
|
}
|
||||||
|
const change = Math.abs(newTiming.duration - oldTiming.duration);
|
||||||
|
const changePercent = change / oldTiming.duration;
|
||||||
|
return { spec: newTiming.spec, change, changePercent };
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter changes that's more than 5 seconds and 20% different
|
||||||
|
const significantChanges = timingChanges.filter((t) => t.change > 5000 && t.changePercent >= 0.2);
|
||||||
|
|
||||||
|
if (significantChanges.length === 0) {
|
||||||
|
log('No significant timing changes detected (threshold: 5s and 20%)');
|
||||||
|
return cleanupFiles({ keepNew: false, reason: 'No significant timing changes' });
|
||||||
|
}
|
||||||
|
|
||||||
|
log('Significant timing changes:');
|
||||||
|
significantChanges.forEach((t) => {
|
||||||
|
log(`${t.spec}: ${t.change.toFixed(1)}ms (${(t.changePercent * 100).toFixed(1)}%)`);
|
||||||
|
});
|
||||||
|
|
||||||
|
cleanupFiles({ keepNew: true, reason: 'Significant timing changes detected' });
|
||||||
|
}
|
||||||
|
|
||||||
|
compareTimings();
|
Reference in New Issue
Block a user