mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-11-19 20:24:16 +01:00
Merge branch 'develop' into sidv/vitest
* develop: (23 commits) Revert #3475 chore: updyaate browsers list Support EMPTYSTR in jison parser, add unit tests for git graph parser Use undefined to mean default tagging behavior feat(git): allow cherry-pick to suppress tag altogether Update src/diagrams/git/parser/gitGraph.jison fix(git): fix cherry-pick regex parsing error test(git): add basic parsing test for cherry-pick feat(git): cherry-pick keyword supports tag attribute ci(e2e-applitols): add applitools CI action Test docs:verify Cleanup docs Fixed Linting issues ci(e2e): re-enable e2e tests style: fix .github/workflow/e2e styling chore: upgrade cypress to v10 fix(flowchart-v2): fix arrowMarkerAbsolute=true test(e2e): fix most arrowMarkerAbsolute tests text(e2e): give git tests consistent commit id test(e2e): widen flowchart width to within 10% ...
This commit is contained in:
44
.github/workflows/e2e
vendored
44
.github/workflows/e2e
vendored
@@ -1,44 +0,0 @@
|
|||||||
name: E2E
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node-version: [16.x]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
cache: yarn
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
|
|
||||||
- name: Install Yarn
|
|
||||||
run: npm i yarn --global
|
|
||||||
|
|
||||||
- name: Install Packages
|
|
||||||
run: |
|
|
||||||
yarn install --frozen-lockfile
|
|
||||||
env:
|
|
||||||
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
|
||||||
|
|
||||||
- name: Run Build
|
|
||||||
run: yarn build
|
|
||||||
|
|
||||||
- name: Run E2E Tests
|
|
||||||
run: yarn e2e
|
|
||||||
env:
|
|
||||||
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
|
||||||
|
|
||||||
- name: Upload Coverage to Coveralls
|
|
||||||
uses: coverallsapp/github-action@master
|
|
||||||
with:
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
flag-name: e2e
|
|
||||||
73
.github/workflows/e2e-applitools.yml
vendored
Normal file
73
.github/workflows/e2e-applitools.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
name: E2E (Applitools)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
# Because we want to limit Applitools usage, so we only want to start this
|
||||||
|
# workflow on rare occasions/manually.
|
||||||
|
inputs:
|
||||||
|
parent_branch:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: master
|
||||||
|
description: 'Parent branch to use for PRs'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
env:
|
||||||
|
# on PRs from forks, this secret will always be empty, for security reasons
|
||||||
|
USE_APPLI: ${{ secrets.APPLITOOLS_API_KEY && 'true' || '' }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [16.x]
|
||||||
|
steps:
|
||||||
|
- if: ${{ ! env.USE_APPLI }}
|
||||||
|
name: Warn if not using Applitools
|
||||||
|
run: |
|
||||||
|
echo "::error,title=Not using Applitols::APPLITOOLS_API_KEY is empty, disabling Applitools for this run."
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Setup Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
cache: yarn
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
|
||||||
|
- name: Install Yarn
|
||||||
|
run: npm i yarn --global
|
||||||
|
|
||||||
|
- name: Install Packages
|
||||||
|
run: |
|
||||||
|
yarn install --frozen-lockfile
|
||||||
|
env:
|
||||||
|
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
||||||
|
|
||||||
|
- name: Run Build
|
||||||
|
run: yarn build
|
||||||
|
|
||||||
|
- if: ${{ env.USE_APPLI }}
|
||||||
|
name: Notify applitools of new batch
|
||||||
|
# Copied from docs https://applitools.com/docs/topics/integrations/github-integration-ci-setup.html
|
||||||
|
run: curl -L -d '' -X POST "$APPLITOOLS_SERVER_URL/api/externals/github/push?apiKey=$APPLITOOLS_API_KEY&CommitSha=$GITHUB_SHA&BranchName=${APPLITOOLS_BRANCH}$&ParentBranchName=$APPLITOOLS_PARENT_BRANCH"
|
||||||
|
env:
|
||||||
|
# e.g. mermaid-js/mermaid/my-branch
|
||||||
|
APPLITOOLS_BRANCH: ${{ github.repository }}/${{ github.ref_name }}
|
||||||
|
APPLITOOLS_PARENT_BRANCH: ${{ github.inputs.parent_branch }}
|
||||||
|
APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
|
||||||
|
APPLITOOLS_SERVER_URL: 'https://eyesapi.applitools.com'
|
||||||
|
|
||||||
|
- name: Run E2E Tests
|
||||||
|
run: yarn e2e
|
||||||
|
env:
|
||||||
|
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
||||||
|
# Mermaid applitools.config.js uses this to pick batch name.
|
||||||
|
APPLI_BRANCH: ${{ github.ref_name }}
|
||||||
|
APPLITOOLS_BATCH_ID: ${{ github.sha }}
|
||||||
|
# e.g. mermaid-js/mermaid/my-branch
|
||||||
|
APPLITOOLS_BRANCH: ${{ github.repository }}/${{ github.ref_name }}
|
||||||
|
APPLITOOLS_PARENT_BRANCH: ${{ github.inputs.parent_branch }}
|
||||||
|
APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
|
||||||
|
APPLITOOLS_SERVER_URL: 'https://eyesapi.applitools.com'
|
||||||
38
.github/workflows/e2e.yml
vendored
Normal file
38
.github/workflows/e2e.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
name: E2E
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [16.x]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
cache: yarn
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
|
||||||
|
- name: Install Yarn
|
||||||
|
run: npm i yarn --global
|
||||||
|
|
||||||
|
- name: Install Packages
|
||||||
|
run: |
|
||||||
|
yarn install --frozen-lockfile
|
||||||
|
env:
|
||||||
|
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
||||||
|
|
||||||
|
- name: Run Build
|
||||||
|
run: yarn build
|
||||||
|
|
||||||
|
- name: Run E2E Tests
|
||||||
|
run: yarn e2e
|
||||||
|
env:
|
||||||
|
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
testConcurrency: 1,
|
|
||||||
// browser: [
|
|
||||||
// // Add browsers with different viewports
|
|
||||||
// { width: 800, height: 600, name: 'chrome' },
|
|
||||||
// { width: 700, height: 500, name: 'firefox' },
|
|
||||||
// { width: 1600, height: 1200, name: 'ie11' },
|
|
||||||
// { width: 1024, height: 768, name: 'edgechromium' },
|
|
||||||
// { width: 800, height: 600, name: 'safari' },
|
|
||||||
// // Add mobile emulation devices in Portrait mode
|
|
||||||
// { deviceName: 'iPhone X', screenOrientation: 'portrait' },
|
|
||||||
// { deviceName: 'Pixel 2', screenOrientation: 'portrait' },
|
|
||||||
// ],
|
|
||||||
// // set batch name to the configuration
|
|
||||||
// batchName: 'Ultrafast Batch',
|
|
||||||
};
|
|
||||||
19
applitools.config.js
Normal file
19
applitools.config.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const { defineConfig } = require('cypress');
|
||||||
|
|
||||||
|
module.exports = defineConfig({
|
||||||
|
testConcurrency: 1,
|
||||||
|
browser: [
|
||||||
|
// Add browsers with different viewports
|
||||||
|
// { width: 800, height: 600, name: 'chrome' },
|
||||||
|
// { width: 700, height: 500, name: 'firefox' },
|
||||||
|
// { width: 1600, height: 1200, name: 'ie11' },
|
||||||
|
// { width: 1024, height: 768, name: 'edgechromium' },
|
||||||
|
// { width: 800, height: 600, name: 'safari' },
|
||||||
|
// // Add mobile emulation devices in Portrait mode
|
||||||
|
// { deviceName: 'iPhone X', screenOrientation: 'portrait' },
|
||||||
|
// { deviceName: 'Pixel 2', screenOrientation: 'portrait' },
|
||||||
|
],
|
||||||
|
// set batch name to the configuration
|
||||||
|
batchName: `Mermaid ${process.env.APPLI_BRANCH ?? "'no APPLI_BRANCH set'"}`,
|
||||||
|
});
|
||||||
@@ -2,21 +2,20 @@
|
|||||||
|
|
||||||
const { defineConfig } = require('cypress');
|
const { defineConfig } = require('cypress');
|
||||||
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
|
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
|
||||||
require('@applitools/eyes-cypress')(module);
|
|
||||||
|
|
||||||
module.exports = defineConfig({
|
module.exports = defineConfig({
|
||||||
e2e: {
|
e2e: {
|
||||||
specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
|
specPattern: 'cypress/integration/**/*.{js,jsx,ts,tsx}',
|
||||||
setupNodeEvents(on, config) {
|
setupNodeEvents(on, config) {
|
||||||
addMatchImageSnapshotPlugin(on, config);
|
addMatchImageSnapshotPlugin(on, config);
|
||||||
// copy any needed variables from process.env to config.env
|
// copy any needed variables from process.env to config.env
|
||||||
config.env.useAppli = process.env.USE_APPLI ? true : false;
|
config.env.useAppli = process.env.USE_APPLI ? true : false;
|
||||||
config.env.codeBranch = process.env.APPLI_BRANCH;
|
|
||||||
|
|
||||||
// do not forget to return the changed config object!
|
// do not forget to return the changed config object!
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
supportFile: 'cypress/support/index.js',
|
|
||||||
},
|
},
|
||||||
video: false,
|
video: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
require('@applitools/eyes-cypress')(module);
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
Cr24
|
|
||||||
@@ -44,15 +44,13 @@ export const imgSnapshotTest = (graphStr, _options, api = false, validation) =>
|
|||||||
}
|
}
|
||||||
const useAppli = Cypress.env('useAppli');
|
const useAppli = Cypress.env('useAppli');
|
||||||
//const useAppli = false;
|
//const useAppli = false;
|
||||||
const branch = Cypress.env('codeBranch');
|
|
||||||
cy.log('Hello ' + useAppli ? 'Appli' : 'image-snapshot');
|
cy.log('Hello ' + useAppli ? 'Appli' : 'image-snapshot');
|
||||||
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||||
|
|
||||||
if (useAppli) {
|
if (useAppli) {
|
||||||
cy.eyesOpen({
|
cy.eyesOpen({
|
||||||
appName: 'Mermaid-' + branch,
|
appName: 'Mermaid',
|
||||||
testName: name,
|
testName: name,
|
||||||
batchName: branch,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,15 +94,13 @@ export const urlSnapshotTest = (url, _options, api = false, validation) => {
|
|||||||
options.fontSize = '16px';
|
options.fontSize = '16px';
|
||||||
}
|
}
|
||||||
const useAppli = Cypress.env('useAppli');
|
const useAppli = Cypress.env('useAppli');
|
||||||
const branch = Cypress.env('codeBranch');
|
|
||||||
cy.log('Hello ' + useAppli ? 'Appli' : 'image-snapshot');
|
cy.log('Hello ' + useAppli ? 'Appli' : 'image-snapshot');
|
||||||
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||||
|
|
||||||
if (useAppli) {
|
if (useAppli) {
|
||||||
cy.eyesOpen({
|
cy.eyesOpen({
|
||||||
appName: 'Mermaid-' + branch,
|
appName: 'Mermaid',
|
||||||
testName: name,
|
testName: name,
|
||||||
batchName: branch,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,13 @@ describe('Configuration', () => {
|
|||||||
|
|
||||||
// Check the marker-end property to make sure it is properly set to
|
// Check the marker-end property to make sure it is properly set to
|
||||||
// start with #
|
// start with #
|
||||||
cy.get('.edgePath path')
|
cy.get('.edgePaths').within(() => {
|
||||||
.first()
|
cy.get('path')
|
||||||
.should('have.attr', 'marker-end')
|
.first()
|
||||||
.should('exist')
|
.should('have.attr', 'marker-end')
|
||||||
.and('include', 'url(#');
|
.should('exist')
|
||||||
|
.and('include', 'url(#');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should handle default value false of arrowMarkerAbsolute', () => {
|
it('should handle default value false of arrowMarkerAbsolute', () => {
|
||||||
renderGraph(
|
renderGraph(
|
||||||
@@ -35,11 +37,13 @@ describe('Configuration', () => {
|
|||||||
|
|
||||||
// Check the marker-end property to make sure it is properly set to
|
// Check the marker-end property to make sure it is properly set to
|
||||||
// start with #
|
// start with #
|
||||||
cy.get('.edgePath path')
|
cy.get('.edgePaths').within(() => {
|
||||||
.first()
|
cy.get('path')
|
||||||
.should('have.attr', 'marker-end')
|
.first()
|
||||||
.should('exist')
|
.should('have.attr', 'marker-end')
|
||||||
.and('include', 'url(#');
|
.should('exist')
|
||||||
|
.and('include', 'url(#');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should handle arrowMarkerAbsolute explicitly set to false', () => {
|
it('should handle arrowMarkerAbsolute explicitly set to false', () => {
|
||||||
renderGraph(
|
renderGraph(
|
||||||
@@ -57,11 +61,13 @@ describe('Configuration', () => {
|
|||||||
|
|
||||||
// Check the marker-end property to make sure it is properly set to
|
// Check the marker-end property to make sure it is properly set to
|
||||||
// start with #
|
// start with #
|
||||||
cy.get('.edgePath path')
|
cy.get('.edgePaths').within(() => {
|
||||||
.first()
|
cy.get('path')
|
||||||
.should('have.attr', 'marker-end')
|
.first()
|
||||||
.should('exist')
|
.should('have.attr', 'marker-end')
|
||||||
.and('include', 'url(#');
|
.should('exist')
|
||||||
|
.and('include', 'url(#');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should handle arrowMarkerAbsolute explicitly set to "false" as false', () => {
|
it('should handle arrowMarkerAbsolute explicitly set to "false" as false', () => {
|
||||||
renderGraph(
|
renderGraph(
|
||||||
@@ -79,15 +85,17 @@ describe('Configuration', () => {
|
|||||||
|
|
||||||
// Check the marker-end property to make sure it is properly set to
|
// Check the marker-end property to make sure it is properly set to
|
||||||
// start with #
|
// start with #
|
||||||
cy.get('.edgePath path')
|
cy.get('.edgePaths').within(() => {
|
||||||
.first()
|
cy.get('path')
|
||||||
.should('have.attr', 'marker-end')
|
.first()
|
||||||
.should('exist')
|
.should('have.attr', 'marker-end')
|
||||||
.and('include', 'url(#');
|
.should('exist')
|
||||||
|
.and('include', 'url(#');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should handle arrowMarkerAbsolute set to true', () => {
|
it('should handle arrowMarkerAbsolute set to true', () => {
|
||||||
renderGraph(
|
renderGraph(
|
||||||
`graph TD
|
`flowchart TD
|
||||||
A[Christmas] -->|Get money| B(Go shopping)
|
A[Christmas] -->|Get money| B(Go shopping)
|
||||||
B --> C{Let me think}
|
B --> C{Let me think}
|
||||||
C -->|One| D[Laptop]
|
C -->|One| D[Laptop]
|
||||||
@@ -99,11 +107,13 @@ describe('Configuration', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
cy.get('.edgePath path')
|
cy.get('.edgePaths').within(() => {
|
||||||
.first()
|
cy.get('path')
|
||||||
.should('have.attr', 'marker-end')
|
.first()
|
||||||
.should('exist')
|
.should('have.attr', 'marker-end')
|
||||||
.and('include', 'url(http://localhost');
|
.should('exist')
|
||||||
|
.and('include', 'url(http://localhost');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('should not taint the initial configuration when using multiple directives', () => {
|
it('should not taint the initial configuration when using multiple directives', () => {
|
||||||
const url = 'http://localhost:9000/regression/issue-1874.html';
|
const url = 'http://localhost:9000/regression/issue-1874.html';
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ describe('XSS', () => {
|
|||||||
cy.get('#the-malware').should('not.exist');
|
cy.get('#the-malware').should('not.exist');
|
||||||
});
|
});
|
||||||
it('should not allow manipulating antiscript to run javascript using onerror in state diagrams with dagre d3', () => {
|
it('should not allow manipulating antiscript to run javascript using onerror in state diagrams with dagre d3', () => {
|
||||||
|
cy.on('uncaught:exception', (_err, _runnable) => {
|
||||||
|
return false; // continue rendering even if there if mermaid throws an error
|
||||||
|
});
|
||||||
cy.visit('http://localhost:9000/xss9.html');
|
cy.visit('http://localhost:9000/xss9.html');
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
cy.get('#the-malware').should('not.exist');
|
cy.get('#the-malware').should('not.exist');
|
||||||
|
|||||||
@@ -745,13 +745,13 @@ describe('Graph', () => {
|
|||||||
cy.get('svg').should((svg) => {
|
cy.get('svg').should((svg) => {
|
||||||
expect(svg).to.have.attr('width', '100%');
|
expect(svg).to.have.attr('width', '100%');
|
||||||
// expect(svg).to.have.attr('height');
|
// expect(svg).to.have.attr('height');
|
||||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
// use within because the absolute value can be slightly different depending on the environment ±10%
|
||||||
// const height = parseFloat(svg.attr('height'));
|
// const height = parseFloat(svg.attr('height'));
|
||||||
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
||||||
const style = svg.attr('style');
|
const style = svg.attr('style');
|
||||||
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
expect(style).to.match(/^max-width: [\d.]+px;$/);
|
||||||
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join(''));
|
||||||
expect(maxWidthValue).to.be.within(300 * 0.95, 300 * 1.05);
|
expect(maxWidthValue).to.be.within(300 * 0.9, 300 * 1.1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('39: should render a flowchart when useMaxWidth is false', () => {
|
it('39: should render a flowchart when useMaxWidth is false', () => {
|
||||||
@@ -768,9 +768,9 @@ describe('Graph', () => {
|
|||||||
cy.get('svg').should((svg) => {
|
cy.get('svg').should((svg) => {
|
||||||
// const height = parseFloat(svg.attr('height'));
|
// const height = parseFloat(svg.attr('height'));
|
||||||
const width = parseFloat(svg.attr('width'));
|
const width = parseFloat(svg.attr('width'));
|
||||||
// use within because the absolute value can be slightly different depending on the environment ±5%
|
// use within because the absolute value can be slightly different depending on the environment ±10%
|
||||||
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
// expect(height).to.be.within(446 * 0.95, 446 * 1.05);
|
||||||
expect(width).to.be.within(300 * 0.95, 300 * 1.05);
|
expect(width).to.be.within(300 * 0.9, 300 * 1.1);
|
||||||
expect(svg).to.not.have.attr('style');
|
expect(svg).to.not.have.attr('style');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -180,7 +180,48 @@ describe('Git Graph diagram', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('11: should render a gitgraph with cherry pick commit with custom tag', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gitGraph
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
commit id:"ONE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"B"
|
||||||
|
checkout main
|
||||||
|
commit id:"TWO"
|
||||||
|
cherry-pick id:"A" tag: "snapshot"
|
||||||
|
commit id:"THREE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"C"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('11: should render a gitgraph with cherry pick commit with no tag', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
gitGraph
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
commit id:"ONE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"B"
|
||||||
|
checkout main
|
||||||
|
commit id:"TWO"
|
||||||
|
cherry-pick id:"A" tag: ""
|
||||||
|
commit id:"THREE"
|
||||||
|
checkout develop
|
||||||
|
commit id:"C"
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
it('11: should render a simple gitgraph with two cherry pick commit', () => {
|
it('11: should render a simple gitgraph with two cherry pick commit', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
@@ -207,48 +248,48 @@ describe('Git Graph diagram', () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('12: should render commits for more than 8 branches', () => {
|
it('12: should render commits for more than 8 branches', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
`
|
`
|
||||||
gitGraph
|
gitGraph
|
||||||
checkout main
|
checkout main
|
||||||
commit
|
%% Make sure to manually set the ID of all commits, for consistent visual tests
|
||||||
|
commit id: "1-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
branch branch1
|
branch branch1
|
||||||
commit
|
commit id: "2-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
merge branch1
|
merge branch1
|
||||||
branch branch2
|
branch branch2
|
||||||
commit
|
commit id: "3-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
merge branch2
|
merge branch2
|
||||||
branch branch3
|
branch branch3
|
||||||
commit
|
commit id: "4-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
merge branch3
|
merge branch3
|
||||||
branch branch4
|
branch branch4
|
||||||
commit
|
commit id: "5-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
merge branch4
|
merge branch4
|
||||||
branch branch5
|
branch branch5
|
||||||
commit
|
commit id: "6-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
merge branch5
|
merge branch5
|
||||||
branch branch6
|
branch branch6
|
||||||
commit
|
commit id: "7-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
merge branch6
|
merge branch6
|
||||||
branch branch7
|
branch branch7
|
||||||
commit
|
commit id: "8-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
merge branch7
|
merge branch7
|
||||||
branch branch8
|
branch branch8
|
||||||
commit
|
commit id: "9-abcdefg"
|
||||||
checkout main
|
checkout main
|
||||||
merge branch8
|
merge branch8
|
||||||
branch branch9
|
branch branch9
|
||||||
commit
|
commit id: "10-abcdefg"
|
||||||
`,
|
`,
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -30,7 +30,31 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>info below</h1>
|
<h1>info below</h1>
|
||||||
|
|
||||||
<pre class="mermaid" style="width: 100%; height: 20%">
|
<pre class="mermaid" style="width: 100%; height: 20%">
|
||||||
|
%%{init: { "logLevel": "debug", "theme": "default" , "gitGraph" : {"showBranches":"false","rotateCommitLabel":"true"},"themeVariables": {
|
||||||
|
"gitBranchLabel0": "#ff0000",
|
||||||
|
"gitBranchLabel1": "#00ff00",
|
||||||
|
"gitBranchLabel2": "#0000ff",
|
||||||
|
"git0": "#550055"
|
||||||
|
} } }%%
|
||||||
|
gitGraph
|
||||||
|
commit
|
||||||
|
branch develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
branch release/1.0.0
|
||||||
|
checkout release/1.0.0
|
||||||
|
commit tag:"1.0.0-beta1"
|
||||||
|
checkout develop
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
commit
|
||||||
|
checkout release/1.0.0
|
||||||
|
merge develop tag: "1.0.0-beta2"
|
||||||
|
</pre>
|
||||||
|
<pre class="mermaid2" style="width: 100%; height: 20%">
|
||||||
%%{init: { "logLevel": "debug", "theme": "default" , "gitGraph" : {"showBranches":"false"},"themeVariables": {
|
%%{init: { "logLevel": "debug", "theme": "default" , "gitGraph" : {"showBranches":"false"},"themeVariables": {
|
||||||
"gitBranchLabel0": "#ff0000",
|
"gitBranchLabel0": "#ff0000",
|
||||||
"gitBranchLabel1": "#00ff00",
|
"gitBranchLabel1": "#00ff00",
|
||||||
@@ -131,6 +155,7 @@
|
|||||||
// arrowMarkerAbsolute: true,
|
// arrowMarkerAbsolute: true,
|
||||||
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
|
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
|
||||||
logLevel: 1,
|
logLevel: 1,
|
||||||
|
gitGraph: { rotateCommitLabel: false },
|
||||||
flowchart: { curve: 'linear', htmlLabels: true },
|
flowchart: { curve: 'linear', htmlLabels: true },
|
||||||
// gantt: { axisFormat: '%m/%d/%Y' },
|
// gantt: { axisFormat: '%m/%d/%Y' },
|
||||||
sequence: { actorMargin: 50, showSequenceNumbers: true },
|
sequence: { actorMargin: 50, showSequenceNumbers: true },
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
// ***********************************************************
|
|
||||||
// This example plugins/index.js can be used to load plugins
|
|
||||||
//
|
|
||||||
// You can change the location of this file or turn off loading
|
|
||||||
// the plugins file with the 'pluginsFile' configuration option.
|
|
||||||
//
|
|
||||||
// You can read more here:
|
|
||||||
// https://on.cypress.io/plugins-guide
|
|
||||||
// ***********************************************************
|
|
||||||
|
|
||||||
// This function is called when a project is opened or re-opened (e.g. due to
|
|
||||||
// the project's config changing)
|
|
||||||
|
|
||||||
// module.exports = (on, config) => {
|
|
||||||
// // `on` is used to hook into various events Cypress emits
|
|
||||||
// // `config` is the resolved Cypress config
|
|
||||||
// }
|
|
||||||
|
|
||||||
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
|
|
||||||
require('@applitools/eyes-cypress')(module);
|
|
||||||
|
|
||||||
module.exports = (on, config) => {
|
|
||||||
addMatchImageSnapshotPlugin(on, config);
|
|
||||||
// copy any needed variables from process.env to config.env
|
|
||||||
config.env.useAppli = process.env.USE_APPLI ? true : false;
|
|
||||||
config.env.codeBranch = process.env.APPLI_BRANCH;
|
|
||||||
|
|
||||||
// do not forget to return the changed config object!
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
|
|
||||||
require('@applitools/eyes-cypress')(module);
|
|
||||||
@@ -17,8 +17,6 @@ import '@applitools/eyes-cypress/commands';
|
|||||||
|
|
||||||
// Import commands.js using ES2015 syntax:
|
// Import commands.js using ES2015 syntax:
|
||||||
import './commands';
|
import './commands';
|
||||||
// import '@percy/cypress';
|
|
||||||
import '@applitools/eyes-cypress/commands';
|
|
||||||
|
|
||||||
// Alternatively you can use CommonJS syntax:
|
// Alternatively you can use CommonJS syntax:
|
||||||
// require('./commands')
|
// require('./commands')
|
||||||
@@ -660,14 +660,27 @@ It is also possible to attach a class to a list of nodes in one statement:
|
|||||||
|
|
||||||
A shorter form of adding a class is to attach the classname to the node using the `:::` operator:
|
A shorter form of adding a class is to attach the classname to the node using the `:::` operator:
|
||||||
|
|
||||||
```mmd
|
```mermaid-example
|
||||||
|
classDiagram
|
||||||
|
class Animal:::cssClass
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
classDiagram
|
classDiagram
|
||||||
class Animal:::cssClass
|
class Animal:::cssClass
|
||||||
```
|
```
|
||||||
|
|
||||||
Or:
|
Or:
|
||||||
|
|
||||||
```mmd
|
```mermaid-example
|
||||||
|
classDiagram
|
||||||
|
class Animal:::cssClass {
|
||||||
|
-int sizeInFeet
|
||||||
|
-canEat()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
classDiagram
|
classDiagram
|
||||||
class Animal:::cssClass {
|
class Animal:::cssClass {
|
||||||
-int sizeInFeet
|
-int sizeInFeet
|
||||||
|
|||||||
@@ -101,7 +101,7 @@
|
|||||||
"concurrently": "^7.4.0",
|
"concurrently": "^7.4.0",
|
||||||
"coveralls": "^3.1.1",
|
"coveralls": "^3.1.1",
|
||||||
"css-to-string-loader": "^0.1.3",
|
"css-to-string-loader": "^0.1.3",
|
||||||
"cypress": "9.7.0",
|
"cypress": "^10.0.0",
|
||||||
"cypress-image-snapshot": "^4.0.1",
|
"cypress-image-snapshot": "^4.0.1",
|
||||||
"documentation": "13.2.0",
|
"documentation": "13.2.0",
|
||||||
"esbuild": "^0.15.6",
|
"esbuild": "^0.15.6",
|
||||||
|
|||||||
@@ -472,7 +472,8 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
let url = '';
|
let url = '';
|
||||||
if (getConfig().state.arrowMarkerAbsolute) {
|
// // TODO: Can we load this config only from the rendered graph type?
|
||||||
|
if (getConfig().flowchart.arrowMarkerAbsolute || getConfig().state.arrowMarkerAbsolute) {
|
||||||
url =
|
url =
|
||||||
window.location.protocol +
|
window.location.protocol +
|
||||||
'//' +
|
'//' +
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ import { journeyDetector } from '../diagrams/user-journey/journeyDetector';
|
|||||||
import journeyDb from '../diagrams/user-journey/journeyDb';
|
import journeyDb from '../diagrams/user-journey/journeyDb';
|
||||||
import journeyRenderer from '../diagrams/user-journey/journeyRenderer';
|
import journeyRenderer from '../diagrams/user-journey/journeyRenderer';
|
||||||
import journeyStyles from '../diagrams/user-journey/styles';
|
import journeyStyles from '../diagrams/user-journey/styles';
|
||||||
|
import { getConfig, setConfig } from '../config';
|
||||||
|
|
||||||
import errorRenderer from '../diagrams/error/errorRenderer';
|
import errorRenderer from '../diagrams/error/errorRenderer';
|
||||||
import errorStyles from '../diagrams/error/styles';
|
import errorStyles from '../diagrams/error/styles';
|
||||||
@@ -301,11 +302,12 @@ export const addDiagrams = () => {
|
|||||||
renderer: flowRendererV2,
|
renderer: flowRendererV2,
|
||||||
styles: flowStyles,
|
styles: flowStyles,
|
||||||
init: (cnf) => {
|
init: (cnf) => {
|
||||||
flowRenderer.setConf(cnf.flowchart);
|
|
||||||
if (!cnf.flowchart) {
|
if (!cnf.flowchart) {
|
||||||
cnf.flowchart = {};
|
cnf.flowchart = {};
|
||||||
}
|
}
|
||||||
|
// TODO, broken as of 2022-09-14 (13809b50251845475e6dca65cc395761be38fbd2)
|
||||||
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||||
|
flowRenderer.setConf(cnf.flowchart);
|
||||||
flowDb.clear();
|
flowDb.clear();
|
||||||
flowDb.setGen('gen-1');
|
flowDb.setGen('gen-1');
|
||||||
},
|
},
|
||||||
@@ -320,11 +322,13 @@ export const addDiagrams = () => {
|
|||||||
renderer: flowRendererV2,
|
renderer: flowRendererV2,
|
||||||
styles: flowStyles,
|
styles: flowStyles,
|
||||||
init: (cnf) => {
|
init: (cnf) => {
|
||||||
flowRendererV2.setConf(cnf.flowchart);
|
|
||||||
if (!cnf.flowchart) {
|
if (!cnf.flowchart) {
|
||||||
cnf.flowchart = {};
|
cnf.flowchart = {};
|
||||||
}
|
}
|
||||||
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||||
|
// flowchart-v2 uses dagre-wrapper, which doesn't have access to flowchart cnf
|
||||||
|
setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } });
|
||||||
|
flowRendererV2.setConf(cnf.flowchart);
|
||||||
flowDb.clear();
|
flowDb.clear();
|
||||||
flowDb.setGen('gen-2');
|
flowDb.setGen('gen-2');
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -258,9 +258,11 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag
|
|||||||
log.debug('in mergeBranch');
|
log.debug('in mergeBranch');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cherryPick = function (sourceId, targetId) {
|
export const cherryPick = function (sourceId, targetId, tag) {
|
||||||
|
log.debug('Entering cherryPick:', sourceId, targetId, tag);
|
||||||
sourceId = common.sanitizeText(sourceId, configApi.getConfig());
|
sourceId = common.sanitizeText(sourceId, configApi.getConfig());
|
||||||
targetId = common.sanitizeText(targetId, configApi.getConfig());
|
targetId = common.sanitizeText(targetId, configApi.getConfig());
|
||||||
|
tag = common.sanitizeText(tag, configApi.getConfig());
|
||||||
|
|
||||||
if (!sourceId || typeof commits[sourceId] === 'undefined') {
|
if (!sourceId || typeof commits[sourceId] === 'undefined') {
|
||||||
let error = new Error(
|
let error = new Error(
|
||||||
@@ -328,13 +330,13 @@ export const cherryPick = function (sourceId, targetId) {
|
|||||||
parents: [head == null ? null : head.id, sourceCommit.id],
|
parents: [head == null ? null : head.id, sourceCommit.id],
|
||||||
branch: curBranch,
|
branch: curBranch,
|
||||||
type: commitType.CHERRY_PICK,
|
type: commitType.CHERRY_PICK,
|
||||||
tag: 'cherry-pick:' + sourceCommit.id,
|
tag: tag ?? 'cherry-pick:' + sourceCommit.id,
|
||||||
};
|
};
|
||||||
head = commit;
|
head = commit;
|
||||||
commits[commit.id] = commit;
|
commits[commit.id] = commit;
|
||||||
branches[curBranch] = commit.id;
|
branches[curBranch] = commit.id;
|
||||||
log.debug(branches);
|
log.debug(branches);
|
||||||
log.debug('in cheeryPick');
|
log.debug('in cherryPick');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
export const checkout = function (branch) {
|
export const checkout = function (branch) {
|
||||||
|
|||||||
@@ -611,6 +611,54 @@ describe('when parsing a gitGraph', function () {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support cherry-picking commits', function () {
|
||||||
|
const str = `gitGraph
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
cherry-pick id:"A"
|
||||||
|
`;
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
const commits = parser.yy.getCommits();
|
||||||
|
const cherryPickCommitID = Object.keys(commits)[2];
|
||||||
|
expect(commits[cherryPickCommitID].tag).toBe('cherry-pick:A');
|
||||||
|
expect(commits[cherryPickCommitID].branch).toBe('main');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support cherry-picking commits with custom tag', function () {
|
||||||
|
const str = `gitGraph
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
cherry-pick id:"A" tag:"MyTag"
|
||||||
|
`;
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
const commits = parser.yy.getCommits();
|
||||||
|
const cherryPickCommitID = Object.keys(commits)[2];
|
||||||
|
expect(commits[cherryPickCommitID].tag).toBe('MyTag');
|
||||||
|
expect(commits[cherryPickCommitID].branch).toBe('main');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support cherry-picking commits with no tag', function () {
|
||||||
|
const str = `gitGraph
|
||||||
|
commit id: "ZERO"
|
||||||
|
branch develop
|
||||||
|
commit id:"A"
|
||||||
|
checkout main
|
||||||
|
cherry-pick id:"A" tag:""
|
||||||
|
`;
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
const commits = parser.yy.getCommits();
|
||||||
|
const cherryPickCommitID = Object.keys(commits)[2];
|
||||||
|
expect(commits[cherryPickCommitID].tag).toBe('');
|
||||||
|
expect(commits[cherryPickCommitID].branch).toBe('main');
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw error when try to branch existing branch: main', function () {
|
it('should throw error when try to branch existing branch: main', function () {
|
||||||
const str = `gitGraph
|
const str = `gitGraph
|
||||||
commit
|
commit
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { select } from 'd3';
|
import { select } from 'd3';
|
||||||
import { configureSvgSize } from '../../setupGraphViewbox';
|
import { getConfig, setupGraphViewbox } from '../../diagram-api/diagramAPI';
|
||||||
import { log } from '../../logger';
|
import { log } from '../../logger';
|
||||||
import { getConfig } from '../../config';
|
|
||||||
import addSVGAccessibilityFields from '../../accessibility';
|
import addSVGAccessibilityFields from '../../accessibility';
|
||||||
|
|
||||||
let allCommitsDict = {};
|
let allCommitsDict = {};
|
||||||
@@ -523,18 +522,8 @@ export const draw = function (txt, id, ver, diagObj) {
|
|||||||
drawArrows(diagram, allCommitsDict);
|
drawArrows(diagram, allCommitsDict);
|
||||||
drawCommits(diagram, allCommitsDict, true);
|
drawCommits(diagram, allCommitsDict, true);
|
||||||
|
|
||||||
const padding = gitGraphConfig.diagramPadding;
|
// Setup the view box and size of the svg element
|
||||||
const svgBounds = diagram.node().getBBox();
|
setupGraphViewbox(undefined, diagram, gitGraphConfig.diagramPadding, conf.useMaxWidth);
|
||||||
const width = svgBounds.width + padding * 2;
|
|
||||||
const height = svgBounds.height + padding * 2;
|
|
||||||
|
|
||||||
configureSvgSize(diagram, height, width, conf.useMaxWidth);
|
|
||||||
const vBox = `${
|
|
||||||
svgBounds.x -
|
|
||||||
padding -
|
|
||||||
(gitGraphConfig.showBranches && gitGraphConfig.rotateCommitLabel === true ? 30 : 0)
|
|
||||||
} ${svgBounds.y - padding} ${width} ${height}`;
|
|
||||||
diagram.attr('viewBox', vBox);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ commit(?=\s|$) return 'COMMIT';
|
|||||||
branch(?=\s|$) return 'BRANCH';
|
branch(?=\s|$) return 'BRANCH';
|
||||||
"order:" return 'ORDER';
|
"order:" return 'ORDER';
|
||||||
merge(?=\s|$) return 'MERGE';
|
merge(?=\s|$) return 'MERGE';
|
||||||
cherry-pick(?=\s|$) return 'CHERRY_PICK';
|
cherry\-pick(?=\s|$) return 'CHERRY_PICK';
|
||||||
// "reset" return 'RESET';
|
// "reset" return 'RESET';
|
||||||
checkout(?=\s|$) return 'CHECKOUT';
|
checkout(?=\s|$) return 'CHECKOUT';
|
||||||
"LR" return 'DIR';
|
"LR" return 'DIR';
|
||||||
@@ -57,6 +57,7 @@ checkout(?=\s|$) return 'CHECKOUT';
|
|||||||
"options"\r?\n this.begin("options"); //
|
"options"\r?\n this.begin("options"); //
|
||||||
<options>[ \r\n\t]+"end" this.popState(); // not used anymore in the renderer, fixed for backward compatibility
|
<options>[ \r\n\t]+"end" this.popState(); // not used anymore in the renderer, fixed for backward compatibility
|
||||||
<options>[\s\S]+(?=[ \r\n\t]+"end") return 'OPT'; //
|
<options>[\s\S]+(?=[ \r\n\t]+"end") return 'OPT'; //
|
||||||
|
["]["] return 'EMPTYSTR';
|
||||||
["] this.begin("string");
|
["] this.begin("string");
|
||||||
<string>["] this.popState();
|
<string>["] this.popState();
|
||||||
<string>[^"]* return 'STR';
|
<string>[^"]* return 'STR';
|
||||||
@@ -117,7 +118,11 @@ branchStatement
|
|||||||
;
|
;
|
||||||
|
|
||||||
cherryPickStatement
|
cherryPickStatement
|
||||||
: CHERRY_PICK COMMIT_ID STR {yy.cherryPick($3)}
|
: CHERRY_PICK COMMIT_ID STR {yy.cherryPick($3, '', undefined)}
|
||||||
|
| CHERRY_PICK COMMIT_ID STR COMMIT_TAG STR {yy.cherryPick($3, '', $5)}
|
||||||
|
| CHERRY_PICK COMMIT_ID STR COMMIT_TAG EMPTYSTR {yy.cherryPick($3, '', '')}
|
||||||
|
| CHERRY_PICK COMMIT_TAG STR COMMIT_ID STR {yy.cherryPick($5, '', $3)}
|
||||||
|
| CHERRY_PICK COMMIT_TAG EMPTYSTR COMMIT_ID STR {yy.cherryPick($3, '', '')}
|
||||||
;
|
;
|
||||||
|
|
||||||
mergeStatement
|
mergeStatement
|
||||||
|
|||||||
@@ -493,14 +493,14 @@ It is also possible to attach a class to a list of nodes in one statement:
|
|||||||
|
|
||||||
A shorter form of adding a class is to attach the classname to the node using the `:::` operator:
|
A shorter form of adding a class is to attach the classname to the node using the `:::` operator:
|
||||||
|
|
||||||
```mmd
|
```mermaid-example
|
||||||
classDiagram
|
classDiagram
|
||||||
class Animal:::cssClass
|
class Animal:::cssClass
|
||||||
```
|
```
|
||||||
|
|
||||||
Or:
|
Or:
|
||||||
|
|
||||||
```mmd
|
```mermaid-example
|
||||||
classDiagram
|
classDiagram
|
||||||
class Animal:::cssClass {
|
class Animal:::cssClass {
|
||||||
-int sizeInFeet
|
-int sizeInFeet
|
||||||
|
|||||||
24
yarn.lock
24
yarn.lock
@@ -3485,9 +3485,9 @@ camelcase@^5.0.0, camelcase@^5.3.1:
|
|||||||
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
|
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001359:
|
caniuse-lite@^1.0.30001359:
|
||||||
version "1.0.30001397"
|
version "1.0.30001406"
|
||||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001397.tgz"
|
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001406.tgz"
|
||||||
integrity sha512-SW9N2TbCdLf0eiNDRrrQXx2sOkaakNZbCjgNpPyMJJbiOrU5QzMIrXOVMRM1myBXTD5iTkdrtU/EguCrBocHlA==
|
integrity sha512-bWTlaXUy/rq0BBtYShc/jArYfBPjEV95euvZ8JVtO43oQExEN/WquoqpufFjNu4kSpi5cy5kMbNvzztWDfv1Jg==
|
||||||
|
|
||||||
caseless@~0.12.0:
|
caseless@~0.12.0:
|
||||||
version "0.12.0"
|
version "0.12.0"
|
||||||
@@ -4248,10 +4248,10 @@ cypress-image-snapshot@^4.0.1:
|
|||||||
pkg-dir "^3.0.0"
|
pkg-dir "^3.0.0"
|
||||||
term-img "^4.0.0"
|
term-img "^4.0.0"
|
||||||
|
|
||||||
cypress@9.7.0:
|
cypress@^10.0.0:
|
||||||
version "9.7.0"
|
version "10.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/cypress/-/cypress-9.7.0.tgz#bf55b2afd481f7a113ef5604aa8b693564b5e744"
|
resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.8.0.tgz#12a681f2642b6f13d636bab65d5b71abdb1497a5"
|
||||||
integrity sha512-+1EE1nuuuwIt/N1KXRR2iWHU+OiIt7H28jJDyyI4tiUftId/DrXYEwoDa5+kH2pki1zxnA0r6HrUGHV5eLbF5Q==
|
integrity sha512-QVse0dnLm018hgti2enKMVZR9qbIO488YGX06nH5j3Dg1isL38DwrBtyrax02CANU6y8F4EJUuyW6HJKw1jsFA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cypress/request" "^2.88.10"
|
"@cypress/request" "^2.88.10"
|
||||||
"@cypress/xvfb" "^1.2.4"
|
"@cypress/xvfb" "^1.2.4"
|
||||||
@@ -4272,7 +4272,7 @@ cypress@9.7.0:
|
|||||||
dayjs "^1.10.4"
|
dayjs "^1.10.4"
|
||||||
debug "^4.3.2"
|
debug "^4.3.2"
|
||||||
enquirer "^2.3.6"
|
enquirer "^2.3.6"
|
||||||
eventemitter2 "^6.4.3"
|
eventemitter2 "6.4.7"
|
||||||
execa "4.1.0"
|
execa "4.1.0"
|
||||||
executable "^4.1.1"
|
executable "^4.1.1"
|
||||||
extract-zip "2.0.1"
|
extract-zip "2.0.1"
|
||||||
@@ -5647,10 +5647,10 @@ event-target-shim@^5.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
||||||
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
|
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
|
||||||
|
|
||||||
eventemitter2@^6.4.3:
|
eventemitter2@6.4.7:
|
||||||
version "6.4.5"
|
version "6.4.7"
|
||||||
resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.5.tgz#97380f758ae24ac15df8353e0cc27f8b95644655"
|
resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.7.tgz#a7f6c4d7abf28a14c1ef3442f21cb306a054271d"
|
||||||
integrity sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==
|
integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==
|
||||||
|
|
||||||
eventemitter3@^4.0.0:
|
eventemitter3@^4.0.0:
|
||||||
version "4.0.7"
|
version "4.0.7"
|
||||||
|
|||||||
Reference in New Issue
Block a user