diff --git a/.changeset/eleven-wolves-deny.md b/.changeset/eleven-wolves-deny.md new file mode 100644 index 000000000..76bb69ec5 --- /dev/null +++ b/.changeset/eleven-wolves-deny.md @@ -0,0 +1,5 @@ +--- +'mermaid': patch +--- + +chore: Convert StateDB into TypeScript diff --git a/.changeset/gold-shoes-camp.md b/.changeset/gold-shoes-camp.md new file mode 100644 index 000000000..3018e7381 --- /dev/null +++ b/.changeset/gold-shoes-camp.md @@ -0,0 +1,5 @@ +--- +'mermaid': patch +--- + +fix: Remove incorrect `style="undefined;"` attributes in some Mermaid diagrams diff --git a/.changeset/honest-trees-dress.md b/.changeset/honest-trees-dress.md new file mode 100644 index 000000000..054f1bedb --- /dev/null +++ b/.changeset/honest-trees-dress.md @@ -0,0 +1,7 @@ +--- +'@mermaid-js/mermaid-zenuml': patch +--- + +chore: bump minimum ZenUML version to 3.23.28 + +commit: 9d06d8f31e7f12af9e9e092214f907f2dc93ad75 diff --git a/.changeset/neat-moose-compare.md b/.changeset/neat-moose-compare.md new file mode 100644 index 000000000..98a064789 --- /dev/null +++ b/.changeset/neat-moose-compare.md @@ -0,0 +1,5 @@ +--- +'mermaid': minor +--- + +feat: Add support for styling Journey Diagram title (color, font-family, and font-size) diff --git a/.changeset/sad-mails-accept.md b/.changeset/sad-mails-accept.md new file mode 100644 index 000000000..11dd69d8d --- /dev/null +++ b/.changeset/sad-mails-accept.md @@ -0,0 +1,6 @@ +--- +'mermaid': patch +'@mermaid-js/parser': patch +--- + +Refactor grammar so that title don't break Architecture Diagrams diff --git a/.changeset/soft-readers-tan.md b/.changeset/soft-readers-tan.md new file mode 100644 index 000000000..ec3fa97af --- /dev/null +++ b/.changeset/soft-readers-tan.md @@ -0,0 +1,5 @@ +--- +'mermaid': minor +--- + +feat: Dynamically Render Data Labels Within Bar Charts diff --git a/.changeset/yellow-mirrors-change.md b/.changeset/yellow-mirrors-change.md new file mode 100644 index 000000000..09a766104 --- /dev/null +++ b/.changeset/yellow-mirrors-change.md @@ -0,0 +1,7 @@ +--- +'@mermaid-js/mermaid-zenuml': patch +--- + +fix(zenuml): limit `peerDependencies` to Mermaid v10 and v11 + +commit: 0ad44c12feead9d20c6a870a49327ada58d6e657 diff --git a/.esbuild/build.ts b/.esbuild/build.ts index 423e8f047..05002cb16 100644 --- a/.esbuild/build.ts +++ b/.esbuild/build.ts @@ -34,6 +34,19 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => { { ...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)))); diff --git a/.esbuild/util.ts b/.esbuild/util.ts index 6d6d1d59b..dde0352af 100644 --- a/.esbuild/util.ts +++ b/.esbuild/util.ts @@ -58,6 +58,7 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => { format, minify, options: { name, file, packageName }, + globalName = 'mermaid', } = options; const external: string[] = ['require', 'fs', 'path']; const outFileName = getFileName(name, options); @@ -68,6 +69,7 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => { }, metafile, minify, + globalName, logLevel: 'info', chunkNames: `chunks/${outFileName}/[name]-[hash]`, define: { @@ -89,11 +91,12 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => { if (format === 'iife') { output.format = 'iife'; 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. // https://github.com/mermaid-js/mermaid/pull/4109#discussion_r1292317396 output.footer = { - js: 'globalThis.mermaid = globalThis.__esbuild_esm_mermaid.default;', + js: `globalThis[${JSON.stringify(originalGlobalName)}] = globalThis.${output.globalName}.default;`, }; output.outExtension = { '.js': '.js' }; } else { diff --git a/.github/lychee.toml b/.github/lychee.toml index 5070c3d50..8032bbf98 100644 --- a/.github/lychee.toml +++ b/.github/lychee.toml @@ -50,7 +50,9 @@ exclude = [ "https://docs.swimm.io", # Timeout -"https://huehive.co" +"https://huehive.co", +"https://foswiki.org", +"https://www.gnu.org", ] # Exclude all private IPs from checking. diff --git a/.github/workflows/e2e-timings.yml b/.github/workflows/e2e-timings.yml index 4c36bc238..b048cc1c5 100644 --- a/.github/workflows/e2e-timings.yml +++ b/.github/workflows/e2e-timings.yml @@ -30,6 +30,7 @@ jobs: uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12 with: runTests: false + - name: Cypress run uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12 id: cypress @@ -45,13 +46,25 @@ jobs: SPLIT: 1 SPLIT_INDEX: 0 SPLIT_FILE: 'cypress/timings.json' + + - name: Compare timings + id: compare + run: | + OUTPUT=$(pnpm tsx scripts/compare-timings.ts) + echo "$OUTPUT" >> $GITHUB_STEP_SUMMARY + + echo "output<> $GITHUB_OUTPUT + echo "$OUTPUT" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + - name: Commit and create pull request - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e + uses: peter-evans/create-pull-request@a7b20e1da215b3ef3ccddb48ff65120256ed6226 with: add-paths: | cypress/timings.json commit-message: 'chore: update E2E timings' branch: update-timings title: Update E2E Timings + body: ${{ steps.compare.outputs.output }} delete-branch: true sign-commits: true diff --git a/cypress/integration/rendering/architecture.spec.ts b/cypress/integration/rendering/architecture.spec.ts index 25326ff80..ec74a5dd5 100644 --- a/cypress/integration/rendering/architecture.spec.ts +++ b/cypress/integration/rendering/architecture.spec.ts @@ -19,6 +19,25 @@ describe.skip('architecture diagram', () => { ` ); }); + it('should render a simple architecture diagram with titleAndAccessabilities', () => { + imgSnapshotTest( + `architecture-beta + title Simple Architecture Diagram + accTitle: Accessibility Title + accDescr: Accessibility Description + group api(cloud)[API] + + service db(database)[Database] in api + service disk1(disk)[Storage] in api + service disk2(disk)[Storage] in api + service server(server)[Server] in api + + db:L -- R:server + disk1:T -- B:server + disk2:T -- B:db + ` + ); + }); it('should render an architecture diagram with groups within groups', () => { imgSnapshotTest( `architecture-beta @@ -172,7 +191,7 @@ describe.skip('architecture diagram', () => { ); }); - it('should render an architecture diagram with a resonable height', () => { + it('should render an architecture diagram with a reasonable height', () => { imgSnapshotTest( `architecture-beta group federated(cloud)[Federated Environment] diff --git a/cypress/integration/rendering/journey.spec.js b/cypress/integration/rendering/journey.spec.js index d8bef6d1b..70d5574b8 100644 --- a/cypress/integration/rendering/journey.spec.js +++ b/cypress/integration/rendering/journey.spec.js @@ -63,4 +63,199 @@ section Checkout from website { journey: { useMaxWidth: false } } ); }); + + it('should initialize with a left margin of 150px for user journeys', () => { + renderGraph( + ` + --- + config: + journey: + maxLabelWidth: 320 + --- + journey + title User Journey Example + section Onboarding + Sign Up: 5: + Browse Features: 3: + Use Core Functionality: 4: + section Engagement + Browse Features: 3 + Use Core Functionality: 4 + `, + { journey: { useMaxWidth: true } } + ); + + let diagramStartX; + + cy.contains('foreignobject', 'Sign Up').then(($diagram) => { + diagramStartX = parseFloat($diagram.attr('x')); + expect(diagramStartX).to.be.closeTo(150, 2); + }); + }); + + it('should maintain sufficient space between legend and diagram when legend labels are longer', () => { + renderGraph( + `journey + title Web hook life cycle + section Darkoob + Make preBuilt:5: Darkoob user + register slug : 5: Darkoob userf deliberately increasing the size of this label to check if distance between legend and diagram is maintained + Map slug to a Prebuilt Job:5: Darkoob user + section External Service + set Darkoob slug as hook for an Event : 5 : admin Exjjjnjjjj qwerty + listen to the events : 5 : External Service + call darkoob endpoint : 5 : External Service + section Darkoob + check for inputs : 5 : DarkoobAPI + run the prebuilt job : 5 : DarkoobAPI + `, + { journey: { useMaxWidth: true } } + ); + + let LabelEndX, diagramStartX; + + // Get right edge of the legend + cy.contains('tspan', 'Darkoob userf').then((textBox) => { + const bbox = textBox[0].getBBox(); + LabelEndX = bbox.x + bbox.width; + }); + + // Get left edge of the diagram + cy.contains('foreignobject', 'Make preBuilt').then((rect) => { + diagramStartX = parseFloat(rect.attr('x')); + }); + + // Assert right edge of the diagram is greater than or equal to the right edge of the label + cy.then(() => { + expect(diagramStartX).to.be.gte(LabelEndX); + }); + }); + + it('should wrap a single long word with hyphenation', () => { + renderGraph( + ` + --- + config: + journey: + maxLabelWidth: 100 + --- + journey + title Long Word Test + section Test + VeryLongWord: 5: Supercalifragilisticexpialidocious + `, + { journey: { useMaxWidth: true } } + ); + + // Verify that the line ends with a hyphen, indicating proper hyphenation for words exceeding maxLabelWidth. + cy.get('tspan').then((tspans) => { + const hasHyphen = [...tspans].some((t) => t.textContent.trim().endsWith('-')); + return expect(hasHyphen).to.be.true; + }); + }); + + it('should wrap text on whitespace without adding hyphens', () => { + renderGraph( + ` + --- + config: + journey: + maxLabelWidth: 200 + --- + journey + title Whitespace Test + section Test + TextWithSpaces: 5: Gustavo Fring is played by Giancarlo Esposito and is a character in Breaking Bad. + `, + { journey: { useMaxWidth: true } } + ); + + // Verify that none of the text spans end with a hyphen. + cy.get('tspan').each(($el) => { + const text = $el.text(); + expect(text.trim()).not.to.match(/-$/); + }); + }); + + it('should wrap long labels into multiple lines, keep them under max width, and maintain margins', () => { + renderGraph( + ` + --- + config: + journey: + maxLabelWidth: 320 + --- + journey + title User Journey Example + section Onboarding + Sign Up: 5: This is a long label that will be split into multiple lines to test the wrapping functionality + Browse Features: 3: This is another long label that will be split into multiple lines to test the wrapping functionality + Use Core Functionality: 4: This is yet another long label that will be split into multiple lines to test the wrapping functionality + section Engagement + Browse Features: 3 + Use Core Functionality: 4 + `, + { journey: { useMaxWidth: true } } + ); + + let diagramStartX, maxLineWidth; + + // Get the diagram's left edge x-coordinate + cy.contains('foreignobject', 'Sign Up') + .then(($diagram) => { + diagramStartX = parseFloat($diagram.attr('x')); + }) + .then(() => { + cy.get('text.legend').then(($lines) => { + // Check that there are multiple lines + expect($lines.length).to.be.equal(9); + + // Check that all lines are under the maxLabelWidth + $lines.each((index, el) => { + const bbox = el.getBBox(); + expect(bbox.width).to.be.lte(320); + maxLineWidth = Math.max(maxLineWidth || 0, bbox.width); + }); + + /** The expected margin between the diagram and the legend is 150px, as defined by + * conf.leftMargin in user-journey-config.js + */ + expect(diagramStartX - maxLineWidth).to.be.closeTo(150, 2); + }); + }); + }); + + it('should correctly render the user journey diagram title with the specified styling', () => { + renderGraph( + `--- +config: + journey: + titleColor: "#2900A5" + titleFontFamily: "Times New Roman" + titleFontSize: "5rem" +--- + +journey + title User Journey Example + section Onboarding + Sign Up: 5: John, Shahir + Complete Profile: 4: John + section Engagement + Browse Features: 3: John + Use Core Functionality: 4: John + section Retention + Revisit Application: 5: John + Invite Friends: 3: John + + size: 2rem + ` + ); + + cy.get('text').contains('User Journey Example').as('title'); + cy.get('@title').then(($title) => { + expect($title).to.have.attr('fill', '#2900A5'); + expect($title).to.have.attr('font-family', 'Times New Roman'); + expect($title).to.have.attr('font-size', '5rem'); + }); + }); }); diff --git a/cypress/integration/rendering/xyChart.spec.js b/cypress/integration/rendering/xyChart.spec.js index 1245760e8..a582355e8 100644 --- a/cypress/integration/rendering/xyChart.spec.js +++ b/cypress/integration/rendering/xyChart.spec.js @@ -179,6 +179,7 @@ describe('XY Chart', () => { axisLineWidth: 5 chartOrientation: horizontal plotReservedSpacePercent: 60 + showDataLabel: true --- xychart-beta title "Sales Revenue" @@ -315,4 +316,516 @@ describe('XY Chart', () => { ); cy.get('svg'); }); + + it('should render vertical bar chart with labels', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + --- + xychart-beta + title "Sales Revenue" + x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec] + y-axis "Revenue (in $)" 4000 --> 11000 + bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] + `, + {} + ); + }); + + it('should render horizontal bar chart with labels', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + chartOrientation: horizontal + --- + xychart-beta + title "Sales Revenue" + x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec] + y-axis "Revenue (in $)" 4000 --> 11000 + bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] + `, + {} + ); + }); + + it('should render vertical bar chart without labels by default', () => { + imgSnapshotTest( + ` + xychart-beta + title "Sales Revenue" + x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec] + y-axis "Revenue (in $)" 4000 --> 11000 + bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] + `, + {} + ); + }); + + it('should render horizontal bar chart without labels by default', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + chartOrientation: horizontal + --- + xychart-beta + title "Sales Revenue" + x-axis Months [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec] + y-axis "Revenue (in $)" 4000 --> 11000 + bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000] + `, + {} + ); + }); + + it('should render multiple bar plots vertically with labels correctly', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + --- + xychart-beta + title "Multiple Bar Plots" + x-axis Categories [A, B, C] + y-axis "Values" 0 --> 100 + bar [10, 50, 90] + `, + {} + ); + }); + + it('should render multiple bar plots horizontally with labels correctly', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + chartOrientation: horizontal + --- + xychart-beta + title "Multiple Bar Plots" + x-axis Categories [A, B, C] + y-axis "Values" 0 --> 100 + bar [10, 50, 90] + `, + {} + ); + }); + + it('should render a single bar with label for a vertical xy-chart', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + --- + xychart-beta + title "Single Bar Chart" + x-axis Categories [A] + y-axis "Value" 0 --> 100 + bar [75] + `, + {} + ); + }); + + it('should render a single bar with label for a horizontal xy-chart', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + chartOrientation: horizontal + --- + xychart-beta + title "Single Bar Chart" + x-axis Categories [A] + y-axis "Value" 0 --> 100 + bar [75] + `, + {} + ); + }); + + it('should render negative and decimal values with correct labels for vertical xy-chart', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + --- + xychart-beta + title "Decimal and Negative Values" + x-axis Categories [A, B, C] + y-axis -10 --> 10 + bar [ -2.5, 0.75, 5.1 ] + `, + {} + ); + }); + + it('should render negative and decimal values with correct labels for horizontal xy-chart', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + chartOrientation: horizontal + --- + xychart-beta + title "Decimal and Negative Values" + x-axis Categories [A, B, C] + y-axis -10 --> 10 + bar [ -2.5, 0.75, 5.1 ] + `, + {} + ); + }); + + it('should render data labels within each bar in the vertical xy-chart', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + --- + xychart-beta + title "Sales Revenue" + x-axis Months [jan,b,c] + y-axis "Revenue (in $)" 4000 --> 12000 + bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000, 3000, 2000, 500, 2000, 3000, 11000, 5000, 6000] + `, + {} + ); + + cy.get('g.bar-plot-0').within(() => { + cy.get('rect').each(($rect, index) => { + // Extract bar properties + const barProps = { + x: parseFloat($rect.attr('x')), + y: parseFloat($rect.attr('y')), + width: parseFloat($rect.attr('width')), + height: parseFloat($rect.attr('height')), + }; + + // Get the text element corresponding to this bar by index. + cy.get('text') + .eq(index) + .then(($text) => { + const bbox = $text[0].getBBox(); + const textProps = { + x: bbox.x, + y: bbox.y, + width: bbox.width, + height: bbox.height, + }; + + // Verify that the text label is positioned within the boundaries of the bar. + expect(textProps.x).to.be.greaterThan(barProps.x); + expect(textProps.x + textProps.width).to.be.lessThan(barProps.x + barProps.width); + + // Check horizontal alignment (within tolerance) + expect(textProps.x + textProps.width / 2).to.be.closeTo( + barProps.x + barProps.width / 2, + 5 + ); + + expect(textProps.y).to.be.greaterThan(barProps.y); + expect(textProps.y + textProps.height).to.be.lessThan(barProps.y + barProps.height); + }); + }); + }); + }); + + it('should render data labels within each bar in the horizontal xy-chart', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + chartOrientation: horizontal + --- + xychart-beta + title "Sales Revenue" + x-axis Months [jan,b,c] + y-axis "Revenue (in $)" 4000 --> 12000 + bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000, 3000, 2000, 500, 2000, 3000, 11000, 5000, 6000] + `, + {} + ); + + cy.get('g.bar-plot-0').within(() => { + cy.get('rect').each(($rect, index) => { + // Extract bar properties + const barProps = { + x: parseFloat($rect.attr('x')), + y: parseFloat($rect.attr('y')), + width: parseFloat($rect.attr('width')), + height: parseFloat($rect.attr('height')), + }; + + // Get the text element corresponding to this bar by index. + cy.get('text') + .eq(index) + .then(($text) => { + const bbox = $text[0].getBBox(); + const textProps = { + x: bbox.x, + y: bbox.y, + width: bbox.width, + height: bbox.height, + }; + + // Verify that the text label is positioned within the boundaries of the bar. + expect(textProps.x).to.be.greaterThan(barProps.x); + expect(textProps.x + textProps.width).to.be.lessThan(barProps.x + barProps.width); + + expect(textProps.y).to.be.greaterThan(barProps.y); + expect(textProps.y + textProps.height).to.be.lessThan(barProps.y + barProps.height); + expect(textProps.y + textProps.height / 2).to.be.closeTo( + barProps.y + barProps.height / 2, + 5 + ); + }); + }); + }); + }); + + it('should render data labels within each bar in the vertical xy-chart with a lot of bars of different sizes', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + --- + xychart-beta + title "Sales Revenue" + x-axis Months [jan,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s] + y-axis "Revenue (in $)" 4000 --> 12000 + bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000, 8000, 10000, 5000, 7600, 4999,11000 ,5000,6000] + `, + {} + ); + + cy.get('g.bar-plot-0').within(() => { + cy.get('rect').each(($rect, index) => { + // Extract bar properties + const barProps = { + x: parseFloat($rect.attr('x')), + y: parseFloat($rect.attr('y')), + width: parseFloat($rect.attr('width')), + height: parseFloat($rect.attr('height')), + }; + + // Get the text element corresponding to this bar by index. + cy.get('text') + .eq(index) + .then(($text) => { + const bbox = $text[0].getBBox(); + const textProps = { + x: bbox.x, + y: bbox.y, + width: bbox.width, + height: bbox.height, + }; + + // Verify that the text label is positioned within the boundaries of the bar. + expect(textProps.x).to.be.greaterThan(barProps.x); + expect(textProps.x + textProps.width).to.be.lessThan(barProps.x + barProps.width); + + // Check horizontal alignment (within tolerance) + expect(textProps.x + textProps.width / 2).to.be.closeTo( + barProps.x + barProps.width / 2, + 5 + ); + + expect(textProps.y).to.be.greaterThan(barProps.y); + expect(textProps.y + textProps.height).to.be.lessThan(barProps.y + barProps.height); + }); + }); + }); + }); + + it('should render data labels within each bar in the horizontal xy-chart with a lot of bars of different sizes', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + chartOrientation: horizontal + --- + xychart-beta + title "Sales Revenue" + x-axis Months [jan,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s] + y-axis "Revenue (in $)" 4000 --> 12000 + bar [5000, 6000, 7500, 8200, 9500, 10500, 11000, 10200, 9200, 8500, 7000, 6000, 8000, 10000, 5000, 7600, 4999,11000 ,5000,6000] + `, + {} + ); + + cy.get('g.bar-plot-0').within(() => { + cy.get('rect').each(($rect, index) => { + // Extract bar properties + const barProps = { + x: parseFloat($rect.attr('x')), + y: parseFloat($rect.attr('y')), + width: parseFloat($rect.attr('width')), + height: parseFloat($rect.attr('height')), + }; + + // Get the text element corresponding to this bar by index. + cy.get('text') + .eq(index) + .then(($text) => { + const bbox = $text[0].getBBox(); + const textProps = { + x: bbox.x, + y: bbox.y, + width: bbox.width, + height: bbox.height, + }; + + // Verify that the text label is positioned within the boundaries of the bar. + expect(textProps.x).to.be.greaterThan(barProps.x); + expect(textProps.x + textProps.width).to.be.lessThan(barProps.x + barProps.width); + + expect(textProps.y).to.be.greaterThan(barProps.y); + expect(textProps.y + textProps.height).to.be.lessThan(barProps.y + barProps.height); + expect(textProps.y + textProps.height / 2).to.be.closeTo( + barProps.y + barProps.height / 2, + 5 + ); + }); + }); + }); + }); + + it('should render data labels correctly for a bar in the vertical xy-chart', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + --- + xychart-beta + title "Sales Revenue" + x-axis Months [jan] + y-axis "Revenue (in $)" 3000 --> 12000 + bar [4000] + `, + {} + ); + + cy.get('g.bar-plot-0').within(() => { + cy.get('rect').each(($rect, index) => { + // Extract bar properties + const barProps = { + x: parseFloat($rect.attr('x')), + y: parseFloat($rect.attr('y')), + width: parseFloat($rect.attr('width')), + height: parseFloat($rect.attr('height')), + }; + + // Get the text element corresponding to this bar by index. + cy.get('text') + .eq(index) + .then(($text) => { + const bbox = $text[0].getBBox(); + const textProps = { + x: bbox.x, + y: bbox.y, + width: bbox.width, + height: bbox.height, + }; + + // Verify that the text label is positioned within the boundaries of the bar. + expect(textProps.x).to.be.greaterThan(barProps.x); + expect(textProps.x + textProps.width).to.be.lessThan(barProps.x + barProps.width); + + // Check horizontal alignment (within tolerance) + expect(textProps.x + textProps.width / 2).to.be.closeTo( + barProps.x + barProps.width / 2, + 5 + ); + + expect(textProps.y).to.be.greaterThan(barProps.y); + expect(textProps.y + textProps.height).to.be.lessThan(barProps.y + barProps.height); + }); + }); + }); + }); + + it('should render data labels correctly for a bar in the horizontal xy-chart', () => { + imgSnapshotTest( + ` + --- + config: + xyChart: + showDataLabel: true + chartOrientation: horizontal + --- + xychart-beta + title "Sales Revenue" + x-axis Months [jan] + y-axis "Revenue (in $)" 3000 --> 12000 + bar [4000] + `, + {} + ); + + cy.get('g.bar-plot-0').within(() => { + cy.get('rect').each(($rect, index) => { + // Extract bar properties + const barProps = { + x: parseFloat($rect.attr('x')), + y: parseFloat($rect.attr('y')), + width: parseFloat($rect.attr('width')), + height: parseFloat($rect.attr('height')), + }; + + // Get the text element corresponding to this bar by index. + cy.get('text') + .eq(index) + .then(($text) => { + const bbox = $text[0].getBBox(); + const textProps = { + x: bbox.x, + y: bbox.y, + width: bbox.width, + height: bbox.height, + }; + + // Verify that the text label is positioned within the boundaries of the bar. + expect(textProps.x).to.be.greaterThan(barProps.x); + expect(textProps.x + textProps.width).to.be.lessThan(barProps.x + barProps.width); + + expect(textProps.y).to.be.greaterThan(barProps.y); + expect(textProps.y + textProps.height).to.be.lessThan(barProps.y + barProps.height); + expect(textProps.y + textProps.height / 2).to.be.closeTo( + barProps.y + barProps.height / 2, + 5 + ); + }); + }); + }); + }); }); diff --git a/cypress/timings.json b/cypress/timings.json index 6164a81fb..66ea9918d 100644 --- a/cypress/timings.json +++ b/cypress/timings.json @@ -2,211 +2,211 @@ "durations": [ { "spec": "cypress/integration/other/configuration.spec.js", - "duration": 5475 + "duration": 5450 }, { "spec": "cypress/integration/other/external-diagrams.spec.js", - "duration": 2037 + "duration": 2004 }, { "spec": "cypress/integration/other/ghsa.spec.js", - "duration": 3207 + "duration": 3183 }, { "spec": "cypress/integration/other/iife.spec.js", - "duration": 1915 + "duration": 1913 }, { "spec": "cypress/integration/other/interaction.spec.js", - "duration": 10952 + "duration": 10944 }, { "spec": "cypress/integration/other/rerender.spec.js", - "duration": 1872 + "duration": 1938 }, { "spec": "cypress/integration/other/xss.spec.js", - "duration": 26686 + "duration": 26753 }, { "spec": "cypress/integration/rendering/appli.spec.js", - "duration": 2629 + "duration": 2571 }, { "spec": "cypress/integration/rendering/architecture.spec.ts", - "duration": 104 + "duration": 110 }, { "spec": "cypress/integration/rendering/block.spec.js", - "duration": 14765 + "duration": 14697 }, { "spec": "cypress/integration/rendering/c4.spec.js", - "duration": 4913 + "duration": 4705 }, { "spec": "cypress/integration/rendering/classDiagram-elk-v3.spec.js", - "duration": 36667 + "duration": 35841 }, { "spec": "cypress/integration/rendering/classDiagram-handDrawn-v3.spec.js", - "duration": 33813 + "duration": 34279 }, { "spec": "cypress/integration/rendering/classDiagram-v2.spec.js", - "duration": 20441 + "duration": 20641 }, { "spec": "cypress/integration/rendering/classDiagram-v3.spec.js", - "duration": 32504 + "duration": 33020 }, { "spec": "cypress/integration/rendering/classDiagram.spec.js", - "duration": 13772 + "duration": 13546 }, { "spec": "cypress/integration/rendering/conf-and-directives.spec.js", - "duration": 7978 + "duration": 8072 }, { "spec": "cypress/integration/rendering/current.spec.js", - "duration": 2101 + "duration": 2083 }, { "spec": "cypress/integration/rendering/erDiagram-unified.spec.js", - "duration": 76556 + "duration": 78269 }, { "spec": "cypress/integration/rendering/erDiagram.spec.js", - "duration": 12756 + "duration": 12578 }, { "spec": "cypress/integration/rendering/errorDiagram.spec.js", - "duration": 2766 + "duration": 2784 }, { "spec": "cypress/integration/rendering/flowchart-elk.spec.js", - "duration": 35641 + "duration": 36205 }, { "spec": "cypress/integration/rendering/flowchart-handDrawn.spec.js", - "duration": 26915 + "duration": 26627 }, { "spec": "cypress/integration/rendering/flowchart-shape-alias.spec.ts", - "duration": 21171 + "duration": 21332 }, { "spec": "cypress/integration/rendering/flowchart-v2.spec.js", - "duration": 37844 + "duration": 37328 }, { "spec": "cypress/integration/rendering/flowchart.spec.js", - "duration": 26254 + "duration": 25914 }, { "spec": "cypress/integration/rendering/gantt.spec.js", - "duration": 15149 + "duration": 15383 }, { "spec": "cypress/integration/rendering/gitGraph.spec.js", - "duration": 45049 + "duration": 45226 }, { "spec": "cypress/integration/rendering/iconShape.spec.ts", - "duration": 250225 + "duration": 251094 }, { "spec": "cypress/integration/rendering/imageShape.spec.ts", - "duration": 51531 + "duration": 50916 }, { "spec": "cypress/integration/rendering/info.spec.ts", - "duration": 2455 + "duration": 2489 }, { "spec": "cypress/integration/rendering/journey.spec.js", - "duration": 3181 + "duration": 5988 }, { "spec": "cypress/integration/rendering/kanban.spec.ts", - "duration": 6298 + "duration": 6225 }, { "spec": "cypress/integration/rendering/katex.spec.js", - "duration": 3065 + "duration": 3009 }, { "spec": "cypress/integration/rendering/marker_unique_id.spec.js", - "duration": 2521 + "duration": 2426 }, { "spec": "cypress/integration/rendering/mindmap.spec.ts", - "duration": 9341 + "duration": 9306 }, { "spec": "cypress/integration/rendering/newShapes.spec.ts", - "duration": 132809 + "duration": 134419 }, { "spec": "cypress/integration/rendering/oldShapes.spec.ts", - "duration": 101299 + "duration": 102434 }, { "spec": "cypress/integration/rendering/packet.spec.ts", - "duration": 3481 + "duration": 3373 }, { "spec": "cypress/integration/rendering/pie.spec.ts", - "duration": 4878 + "duration": 4898 }, { "spec": "cypress/integration/rendering/quadrantChart.spec.js", - "duration": 7416 + "duration": 7578 }, { "spec": "cypress/integration/rendering/radar.spec.js", - "duration": 4554 + "duration": 4526 }, { "spec": "cypress/integration/rendering/requirement.spec.js", - "duration": 2068 + "duration": 2172 }, { "spec": "cypress/integration/rendering/requirementDiagram-unified.spec.js", - "duration": 47583 + "duration": 47175 }, { "spec": "cypress/integration/rendering/sankey.spec.ts", - "duration": 5792 + "duration": 5717 }, { "spec": "cypress/integration/rendering/sequencediagram.spec.js", - "duration": 33035 + "duration": 32556 }, { "spec": "cypress/integration/rendering/stateDiagram-v2.spec.js", - "duration": 22716 + "duration": 22572 }, { "spec": "cypress/integration/rendering/stateDiagram.spec.js", - "duration": 13868 + "duration": 14064 }, { "spec": "cypress/integration/rendering/theme.spec.js", - "duration": 26376 + "duration": 26565 }, { "spec": "cypress/integration/rendering/timeline.spec.ts", - "duration": 5872 + "duration": 6233 }, { "spec": "cypress/integration/rendering/xyChart.spec.js", - "duration": 9469 + "duration": 17750 }, { "spec": "cypress/integration/rendering/zenuml.spec.js", - "duration": 2742 + "duration": 2696 } ] } diff --git a/docs/config/theming.md b/docs/config/theming.md index 088d9e755..f510a114a 100644 --- a/docs/config/theming.md +++ b/docs/config/theming.md @@ -53,18 +53,6 @@ Example of `init` directive setting the `theme` to `forest`: a --> b ``` -```mermaid-example -%%{init: {'theme':'forest'}}%% - graph TD - a --> b -``` - -```mermaid -%%{init: {'theme':'forest'}}%% - graph TD - a --> b -``` - > **Reminder**: the only theme that can be customized is the `base` theme. The following section covers how to use `themeVariables` for customizations. ## Customizing Themes with `themeVariables` @@ -139,66 +127,6 @@ Example of modifying `themeVariables` using the `init` directive: end ``` -```mermaid-example -%%{ - init: { - 'theme': 'base', - 'themeVariables': { - 'primaryColor': '#BB2528', - 'primaryTextColor': '#fff', - 'primaryBorderColor': '#7C0000', - 'lineColor': '#F8B229', - 'secondaryColor': '#006100', - 'tertiaryColor': '#fff' - } - } -}%% - graph TD - A[Christmas] -->|Get money| B(Go shopping) - B --> C{Let me think} - B --> G[/Another/] - C ==>|One| D[Laptop] - C -->|Two| E[iPhone] - C -->|Three| F[fa:fa-car Car] - subgraph section - C - D - E - F - G - end -``` - -```mermaid -%%{ - init: { - 'theme': 'base', - 'themeVariables': { - 'primaryColor': '#BB2528', - 'primaryTextColor': '#fff', - 'primaryBorderColor': '#7C0000', - 'lineColor': '#F8B229', - 'secondaryColor': '#006100', - 'tertiaryColor': '#fff' - } - } -}%% - graph TD - A[Christmas] -->|Get money| B(Go shopping) - B --> C{Let me think} - B --> G[/Another/] - C ==>|One| D[Laptop] - C -->|Two| E[iPhone] - C -->|Three| F[fa:fa-car Car] - subgraph section - C - D - E - F - G - end -``` - ## Color and Color Calculation To ensure diagram readability, the default value of certain variables is calculated or derived from other variables. For example, `primaryBorderColor` is derived from the `primaryColor` variable. So if the `primaryColor` variable is customized, Mermaid will adjust `primaryBorderColor` automatically. Adjustments can mean a color inversion, a hue change, a darkening/lightening by 10%, etc. diff --git a/docs/ecosystem/integrations-community.md b/docs/ecosystem/integrations-community.md index 1dbfab8b3..dd497f760 100644 --- a/docs/ecosystem/integrations-community.md +++ b/docs/ecosystem/integrations-community.md @@ -40,6 +40,7 @@ To add an integration to this list, see the [Integrations - create page](./integ - [Mermaid Charts & Diagrams for Jira](https://marketplace.atlassian.com/apps/1224537/) - [Mermaid for Jira Cloud - Draw UML diagrams easily](https://marketplace.atlassian.com/apps/1223053/mermaid-for-jira-cloud-draw-uml-diagrams-easily?hosting=cloud&tab=overview) - [CloudScript.io Mermaid Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview) + - [Mermaid plus for Confluence](https://marketplace.atlassian.com/apps/1236814/mermaid-plus-for-confluence?hosting=cloud&tab=overview) - [Azure Devops](https://learn.microsoft.com/en-us/azure/devops/project/wiki/markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) ✅ - [Deepdwn](https://billiam.itch.io/deepdwn) ✅ - [Doctave](https://www.doctave.com/) ✅ @@ -267,7 +268,5 @@ Communication tools and platforms - [reveal.js-mermaid-plugin](https://github.com/ludwick/reveal.js-mermaid-plugin) - [Reveal CK](https://github.com/jedcn/reveal-ck) - [reveal-ck-mermaid-plugin](https://github.com/tmtm/reveal-ck-mermaid-plugin) -- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic) -- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server) diff --git a/docs/syntax/flowchart.md b/docs/syntax/flowchart.md index 40ee2ef63..20808c765 100644 --- a/docs/syntax/flowchart.md +++ b/docs/syntax/flowchart.md @@ -1193,12 +1193,12 @@ To give an edge an ID, prepend the edge syntax with the ID followed by an `@` ch ```mermaid-example flowchart LR - A e1@–> B + A e1@--> B ``` ```mermaid flowchart LR - A e1@–> B + A e1@--> B ``` In this example, `e1` is the ID of the edge connecting `A` to `B`. You can then use this ID in later definitions or style statements, just like with nodes. @@ -1229,13 +1229,13 @@ In the initial version, two animation speeds are supported: `fast` and `slow`. S ```mermaid-example flowchart LR - A e1@–> B + A e1@--> B e1@{ animation: fast } ``` ```mermaid flowchart LR - A e1@–> B + A e1@--> B e1@{ animation: fast } ``` @@ -1247,14 +1247,14 @@ You can also animate edges by assigning a class to them and then defining animat ```mermaid-example flowchart LR - A e1@–> B + A e1@--> B classDef animate stroke-dasharray: 9,5,stroke-dashoffset: 900,animation: dash 25s linear infinite; class e1 animate ``` ```mermaid flowchart LR - A e1@–> B + A e1@--> B classDef animate stroke-dasharray: 9,5,stroke-dashoffset: 900,animation: dash 25s linear infinite; class e1 animate ``` diff --git a/docs/syntax/gitgraph.md b/docs/syntax/gitgraph.md index 340a31695..05f465358 100644 --- a/docs/syntax/gitgraph.md +++ b/docs/syntax/gitgraph.md @@ -432,7 +432,13 @@ Sometimes you may want to hide the branch names and lines from the diagram. You Usage example: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': false}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: false +--- gitGraph commit branch hotfix @@ -478,7 +484,13 @@ Usage example: ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': false}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: false +--- gitGraph commit branch hotfix @@ -534,7 +546,13 @@ You can change the layout of the commit labels by using the `rotateCommitLabel` Usage example: Rotated commit labels ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'rotateCommitLabel': true}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + rotateCommitLabel: true +--- gitGraph commit id: "feat(api): ..." commit id: "a" @@ -553,7 +571,13 @@ gitGraph ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'rotateCommitLabel': true}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + rotateCommitLabel: true +--- gitGraph commit id: "feat(api): ..." commit id: "a" @@ -574,7 +598,13 @@ gitGraph Usage example: Horizontal commit labels ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'rotateCommitLabel': false}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + rotateCommitLabel: false +--- gitGraph commit id: "feat(api): ..." commit id: "a" @@ -593,7 +623,13 @@ gitGraph ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'rotateCommitLabel': false}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + rotateCommitLabel: false +--- gitGraph commit id: "feat(api): ..." commit id: "a" @@ -618,7 +654,14 @@ Sometimes you may want to hide the commit labels from the diagram. You can do th Usage example: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': false,'showCommitLabel': false}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: false + showCommitLabel: false +--- gitGraph commit branch hotfix @@ -664,7 +707,14 @@ Usage example: ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': false,'showCommitLabel': false}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: false + showCommitLabel: false +--- gitGraph commit branch hotfix @@ -716,7 +766,15 @@ Sometimes you may want to customize the name of the main/default branch. You can Usage example: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'MetroLine1'}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: true + showCommitLabel: true + mainBranchName: 'MetroLine1' +--- gitGraph commit id:"NewYork" commit id:"Dallas" @@ -740,7 +798,15 @@ Usage example: ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'MetroLine1'}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: true + showCommitLabel: true + mainBranchName: 'MetroLine1' +--- gitGraph commit id:"NewYork" commit id:"Dallas" @@ -782,7 +848,14 @@ To fully control the order of all the branches, you must define `order` for all Usage example: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true, 'showCommitLabel':true}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: true + showCommitLabel: true +--- gitGraph commit branch test1 order: 3 @@ -792,7 +865,14 @@ Usage example: ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true, 'showCommitLabel':true}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: true + showCommitLabel: true +--- gitGraph commit branch test1 order: 3 @@ -806,7 +886,15 @@ Look at the diagram, all the branches are following the order defined. Usage example: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchOrder': 2}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: true + showCommitLabel: true + mainBranchOrder: 2 +--- gitGraph commit branch test1 order: 3 @@ -817,7 +905,15 @@ Usage example: ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchOrder': 2}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: true + showCommitLabel: true + mainBranchOrder: 2 +--- gitGraph commit branch test1 order: 3 @@ -1046,7 +1142,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ### Base Theme ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base' } }%% +--- +config: + logLevel: 'debug' + theme: 'base' +--- gitGraph commit branch hotfix @@ -1092,7 +1192,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'base' } }%% +--- +config: + logLevel: 'debug' + theme: 'base' +--- gitGraph commit branch hotfix @@ -1140,7 +1244,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ### Forest Theme ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%% +--- +config: + logLevel: 'debug' + theme: 'forest' +--- gitGraph commit branch hotfix @@ -1186,7 +1294,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%% +--- +config: + logLevel: 'debug' + theme: 'forest' +--- gitGraph commit branch hotfix @@ -1234,7 +1346,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ### Default Theme ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%% +--- +config: + logLevel: 'debug' + theme: 'default' +--- gitGraph commit type:HIGHLIGHT branch hotfix @@ -1280,7 +1396,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%% +--- +config: + logLevel: 'debug' + theme: 'default' +--- gitGraph commit type:HIGHLIGHT branch hotfix @@ -1328,7 +1448,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ### Dark Theme ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%% +--- +config: + logLevel: 'debug' + theme: 'dark' +--- gitGraph commit branch hotfix @@ -1374,7 +1498,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%% +--- +config: + logLevel: 'debug' + theme: 'dark' +--- gitGraph commit branch hotfix @@ -1422,7 +1550,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ### Neutral Theme ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +--- +config: + logLevel: 'debug' + theme: 'neutral' +--- gitGraph commit branch hotfix @@ -1468,7 +1600,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +--- +config: + logLevel: 'debug' + theme: 'neutral' +--- gitGraph commit branch hotfix @@ -1522,7 +1658,11 @@ For understanding let us take a sample diagram with theme `default`, the default See how the default theme is used to set the colors for the branches: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%% +--- +config: + logLevel: 'debug' + theme: 'default' +--- gitGraph commit branch develop @@ -1538,7 +1678,11 @@ See how the default theme is used to set the colors for the branches: ``` ```mermaid -%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%% +--- +config: + logLevel: 'debug' + theme: 'default' +--- gitGraph commit branch develop @@ -1569,16 +1713,20 @@ Example: Now let's override the default values for the `git0` to `git3` variables: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'git0': '#ff0000', - 'git1': '#00ff00', - 'git2': '#0000ff', - 'git3': '#ff00ff', - 'git4': '#00ffff', - 'git5': '#ffff00', - 'git6': '#ff00ff', - 'git7': '#00ffff' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + 'git0': '#ff0000' + 'git1': '#00ff00' + 'git2': '#0000ff' + 'git3': '#ff00ff' + 'git4': '#00ffff' + 'git5': '#ffff00' + 'git6': '#ff00ff' + 'git7': '#00ffff' +--- gitGraph commit branch develop @@ -1595,16 +1743,20 @@ Now let's override the default values for the `git0` to `git3` variables: ``` ```mermaid - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'git0': '#ff0000', - 'git1': '#00ff00', - 'git2': '#0000ff', - 'git3': '#ff00ff', - 'git4': '#00ffff', - 'git5': '#ffff00', - 'git6': '#ff00ff', - 'git7': '#00ffff' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + 'git0': '#ff0000' + 'git1': '#00ff00' + 'git2': '#0000ff' + 'git3': '#ff00ff' + 'git4': '#00ffff' + 'git5': '#ffff00' + 'git6': '#ff00ff' + 'git7': '#00ffff' +--- gitGraph commit branch develop @@ -1631,18 +1783,22 @@ Lets see how the default theme is used to set the colors for the branch labels: Now let's override the default values for the `gitBranchLabel0` to `gitBranchLabel2` variables: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'gitBranchLabel0': '#ffffff', - 'gitBranchLabel1': '#ffffff', - 'gitBranchLabel2': '#ffffff', - 'gitBranchLabel3': '#ffffff', - 'gitBranchLabel4': '#ffffff', - 'gitBranchLabel5': '#ffffff', - 'gitBranchLabel6': '#ffffff', - 'gitBranchLabel7': '#ffffff', - 'gitBranchLabel8': '#ffffff', - 'gitBranchLabel9': '#ffffff' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + 'gitBranchLabel0': '#ffffff' + 'gitBranchLabel1': '#ffffff' + 'gitBranchLabel2': '#ffffff' + 'gitBranchLabel3': '#ffffff' + 'gitBranchLabel4': '#ffffff' + 'gitBranchLabel5': '#ffffff' + 'gitBranchLabel6': '#ffffff' + 'gitBranchLabel7': '#ffffff' + 'gitBranchLabel8': '#ffffff' + 'gitBranchLabel9': '#ffffff' +--- gitGraph checkout main branch branch1 @@ -1659,18 +1815,22 @@ Now let's override the default values for the `gitBranchLabel0` to `gitBranchLab ``` ```mermaid - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'gitBranchLabel0': '#ffffff', - 'gitBranchLabel1': '#ffffff', - 'gitBranchLabel2': '#ffffff', - 'gitBranchLabel3': '#ffffff', - 'gitBranchLabel4': '#ffffff', - 'gitBranchLabel5': '#ffffff', - 'gitBranchLabel6': '#ffffff', - 'gitBranchLabel7': '#ffffff', - 'gitBranchLabel8': '#ffffff', - 'gitBranchLabel9': '#ffffff' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + 'gitBranchLabel0': '#ffffff' + 'gitBranchLabel1': '#ffffff' + 'gitBranchLabel2': '#ffffff' + 'gitBranchLabel3': '#ffffff' + 'gitBranchLabel4': '#ffffff' + 'gitBranchLabel5': '#ffffff' + 'gitBranchLabel6': '#ffffff' + 'gitBranchLabel7': '#ffffff' + 'gitBranchLabel8': '#ffffff' + 'gitBranchLabel9': '#ffffff' +--- gitGraph checkout main branch branch1 @@ -1696,10 +1856,14 @@ Example: Now let's override the default values for the `commitLabelColor` to `commitLabelBackground` variables: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'commitLabelColor': '#ff0000', - 'commitLabelBackground': '#00ff00' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + commitLabelColor: '#ff0000' + commitLabelBackground: '#00ff00' +--- gitGraph commit branch develop @@ -1716,10 +1880,14 @@ Now let's override the default values for the `commitLabelColor` to `commitLabel ``` ```mermaid - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'commitLabelColor': '#ff0000', - 'commitLabelBackground': '#00ff00' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + commitLabelColor: '#ff0000' + commitLabelBackground: '#00ff00' +--- gitGraph commit branch develop @@ -1745,11 +1913,15 @@ Example: Now let's override the default values for the `commitLabelFontSize` variable: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'commitLabelColor': '#ff0000', - 'commitLabelBackground': '#00ff00', - 'commitLabelFontSize': '16px' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + commitLabelColor: '#ff0000' + commitLabelBackground: '#00ff00' + commitLabelFontSize: '16px' +--- gitGraph commit branch develop @@ -1766,11 +1938,15 @@ Now let's override the default values for the `commitLabelFontSize` variable: ``` ```mermaid - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'commitLabelColor': '#ff0000', - 'commitLabelBackground': '#00ff00', - 'commitLabelFontSize': '16px' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + commitLabelColor: '#ff0000' + commitLabelBackground: '#00ff00' + commitLabelFontSize: '16px' +--- gitGraph commit branch develop @@ -1796,11 +1972,15 @@ Example: Now let's override the default values for the `tagLabelFontSize` variable: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'commitLabelColor': '#ff0000', - 'commitLabelBackground': '#00ff00', - 'tagLabelFontSize': '16px' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + commitLabelColor: '#ff0000' + commitLabelBackground: '#00ff00' + tagLabelFontSize: '16px' +--- gitGraph commit branch develop @@ -1817,11 +1997,15 @@ Now let's override the default values for the `tagLabelFontSize` variable: ``` ```mermaid - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'commitLabelColor': '#ff0000', - 'commitLabelBackground': '#00ff00', - 'tagLabelFontSize': '16px' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + commitLabelColor: '#ff0000' + commitLabelBackground: '#00ff00' + tagLabelFontSize: '16px' +--- gitGraph commit branch develop @@ -1846,11 +2030,15 @@ Example: Now let's override the default values for the `tagLabelColor`, `tagLabelBackground` and to `tagLabelBorder` variables: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'tagLabelColor': '#ff0000', - 'tagLabelBackground': '#00ff00', - 'tagLabelBorder': '#0000ff' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + tagLabelColor: '#ff0000' + tagLabelBackground: '#00ff00' + tagLabelBorder: '#0000ff' +--- gitGraph commit branch develop @@ -1867,11 +2055,15 @@ Now let's override the default values for the `tagLabelColor`, `tagLabelBackgrou ``` ```mermaid - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'tagLabelColor': '#ff0000', - 'tagLabelBackground': '#00ff00', - 'tagLabelBorder': '#0000ff' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + tagLabelColor: '#ff0000' + tagLabelBackground: '#00ff00' + tagLabelBorder: '#0000ff' +--- gitGraph commit branch develop @@ -1898,9 +2090,13 @@ Example: Now let's override the default values for the `git0` to `git3` variables: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'gitInv0': '#ff0000' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + 'gitInv0': '#ff0000' +--- gitGraph commit branch develop @@ -1917,9 +2113,13 @@ Now let's override the default values for the `git0` to `git3` variables: ``` ```mermaid - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'gitInv0': '#ff0000' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + 'gitInv0': '#ff0000' +--- gitGraph commit branch develop diff --git a/docs/syntax/xyChart.md b/docs/syntax/xyChart.md index 7197b984d..235b4e337 100644 --- a/docs/syntax/xyChart.md +++ b/docs/syntax/xyChart.md @@ -107,17 +107,18 @@ xychart-beta ## Chart Configurations -| Parameter | Description | Default value | -| ------------------------ | ---------------------------------------------- | :-----------: | -| width | Width of the chart | 700 | -| height | Height of the chart | 500 | -| titlePadding | Top and Bottom padding of the title | 10 | -| titleFontSize | Title font size | 20 | -| showTitle | Title to be shown or not | true | -| xAxis | xAxis configuration | AxisConfig | -| yAxis | yAxis configuration | AxisConfig | -| chartOrientation | 'vertical' or 'horizontal' | 'vertical' | -| plotReservedSpacePercent | Minimum space plots will take inside the chart | 50 | +| Parameter | Description | Default value | +| ------------------------ | ------------------------------------------------------------- | :-----------: | +| width | Width of the chart | 700 | +| height | Height of the chart | 500 | +| titlePadding | Top and Bottom padding of the title | 10 | +| titleFontSize | Title font size | 20 | +| showTitle | Title to be shown or not | true | +| xAxis | xAxis configuration | AxisConfig | +| yAxis | yAxis configuration | AxisConfig | +| chartOrientation | 'vertical' or 'horizontal' | 'vertical' | +| plotReservedSpacePercent | Minimum space plots will take inside the chart | 50 | +| showDataLabel | Should show the value corresponding to the bar within the bar | false | ### AxisConfig @@ -163,6 +164,7 @@ config: xyChart: width: 900 height: 600 + showDataLabel: true themeVariables: xyChart: titleColor: "#ff0000" @@ -181,6 +183,7 @@ config: xyChart: width: 900 height: 600 + showDataLabel: true themeVariables: xyChart: titleColor: "#ff0000" diff --git a/package.json b/package.json index c2901ca06..0356d23f5 100644 --- a/package.json +++ b/package.json @@ -64,12 +64,12 @@ }, "devDependencies": { "@applitools/eyes-cypress": "^3.44.9", - "@argos-ci/cypress": "^3.2.0", + "@argos-ci/cypress": "^4.0.3", "@changesets/changelog-github": "^0.5.1", "@changesets/cli": "^2.27.12", - "@cspell/eslint-plugin": "^8.8.4", + "@cspell/eslint-plugin": "^8.18.1", "@cypress/code-coverage": "^3.12.49", - "@eslint/js": "^9.4.0", + "@eslint/js": "^9.24.0", "@rollup/plugin-typescript": "^12.1.2", "@types/cors": "^2.8.17", "@types/express": "^5.0.0", @@ -83,7 +83,7 @@ "@vitest/spy": "^3.0.6", "@vitest/ui": "^3.0.6", "ajv": "^8.17.1", - "chokidar": "^3.6.0", + "chokidar": "^4.0.3", "concurrently": "^9.1.2", "cors": "^2.8.5", "cpy-cli": "^5.0.0", @@ -93,19 +93,19 @@ "cypress-image-snapshot": "^4.0.1", "cypress-split": "^1.24.14", "esbuild": "^0.25.0", - "eslint": "^9.20.1", - "eslint-config-prettier": "^10.0.0", - "eslint-plugin-cypress": "^4.1.0", + "eslint": "^9.24.0", + "eslint-config-prettier": "^10.1.1", + "eslint-plugin-cypress": "^4.2.1", "eslint-plugin-html": "^8.1.2", - "eslint-plugin-jest": "^28.6.0", - "eslint-plugin-jsdoc": "^50.0.1", + "eslint-plugin-jest": "^28.11.0", + "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-json": "^4.0.1", "eslint-plugin-lodash": "^8.0.0", "eslint-plugin-markdown": "^5.1.0", "eslint-plugin-no-only-tests": "^3.3.0", "eslint-plugin-tsdoc": "^0.4.0", "eslint-plugin-unicorn": "^58.0.0", - "express": "^4.19.2", + "express": "^5.1.0", "globals": "^16.0.0", "globby": "^14.0.2", "husky": "^9.1.7", @@ -126,7 +126,7 @@ "tslib": "^2.8.1", "tsx": "^4.7.3", "typescript": "~5.7.3", - "typescript-eslint": "^8.24.1", + "typescript-eslint": "^8.29.1", "vite": "^6.1.1", "vite-plugin-istanbul": "^7.0.0", "vitest": "^3.0.6" diff --git a/packages/mermaid/package.json b/packages/mermaid/package.json index 4725fde4f..7f8230229 100644 --- a/packages/mermaid/package.json +++ b/packages/mermaid/package.json @@ -78,7 +78,7 @@ "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.11", "dayjs": "^1.11.13", - "dompurify": "^3.2.4", + "dompurify": "^3.2.5", "katex": "^0.16.9", "khroma": "^2.1.0", "lodash-es": "^4.17.21", diff --git a/packages/mermaid/src/config.type.ts b/packages/mermaid/src/config.type.ts index 638847547..7d435512b 100644 --- a/packages/mermaid/src/config.type.ts +++ b/packages/mermaid/src/config.type.ts @@ -559,6 +559,10 @@ export interface JourneyDiagramConfig extends BaseDiagramConfig { * Margin between actors */ leftMargin?: number; + /** + * Maximum width of actor labels + */ + maxLabelWidth?: number; /** * Width of actor boxes */ @@ -617,6 +621,18 @@ export interface JourneyDiagramConfig extends BaseDiagramConfig { actorColours?: string[]; sectionFills?: string[]; sectionColours?: string[]; + /** + * Color of the title text in Journey Diagrams + */ + titleColor?: string; + /** + * Font family to be used for the title text in Journey Diagrams + */ + titleFontFamily?: string; + /** + * Font size to be used for the title text in Journey Diagrams + */ + titleFontSize?: string; } /** * This interface was referenced by `MermaidConfig`'s JSON-Schema @@ -935,6 +951,10 @@ export interface XYChartConfig extends BaseDiagramConfig { * Top and bottom space from the chart title */ titlePadding?: number; + /** + * Should show the value corresponding to the bar within the bar + */ + showDataLabel?: boolean; /** * Should show the chart title */ diff --git a/packages/mermaid/src/diagrams/architecture/architecture.spec.ts b/packages/mermaid/src/diagrams/architecture/architecture.spec.ts new file mode 100644 index 000000000..45c19e23e --- /dev/null +++ b/packages/mermaid/src/diagrams/architecture/architecture.spec.ts @@ -0,0 +1,70 @@ +import { it, describe, expect } from 'vitest'; +import { db } from './architectureDb.js'; +import { parser } from './architectureParser.js'; + +const { + clear, + getDiagramTitle, + getAccTitle, + getAccDescription, + getServices, + getGroups, + getEdges, + getJunctions, +} = db; + +describe('architecture diagrams', () => { + beforeEach(() => { + clear(); + }); + + describe('architecture diagram definitions', () => { + it('should handle the architecture keyword', async () => { + const str = `architecture-beta`; + await expect(parser.parse(str)).resolves.not.toThrow(); + }); + + it('should handle an simple radar definition', async () => { + const str = `architecture-beta + service db + `; + await expect(parser.parse(str)).resolves.not.toThrow(); + }); + }); + + describe('should handle TitleAndAccessibilities', () => { + it('should handle title on the first line', async () => { + const str = `architecture-beta title Simple Architecture Diagram`; + await expect(parser.parse(str)).resolves.not.toThrow(); + expect(getDiagramTitle()).toBe('Simple Architecture Diagram'); + }); + + it('should handle title on another line', async () => { + const str = `architecture-beta + title Simple Architecture Diagram + `; + await expect(parser.parse(str)).resolves.not.toThrow(); + expect(getDiagramTitle()).toBe('Simple Architecture Diagram'); + }); + + it('should handle accessibility title and description', async () => { + const str = `architecture-beta + accTitle: Accessibility Title + accDescr: Accessibility Description + `; + await expect(parser.parse(str)).resolves.not.toThrow(); + expect(getAccTitle()).toBe('Accessibility Title'); + expect(getAccDescription()).toBe('Accessibility Description'); + }); + + it('should handle multiline accessibility description', async () => { + const str = `architecture-beta + accDescr { + Accessibility Description + } + `; + await expect(parser.parse(str)).resolves.not.toThrow(); + expect(getAccDescription()).toBe('Accessibility Description'); + }); + }); +}); diff --git a/packages/mermaid/src/diagrams/architecture/architectureDb.ts b/packages/mermaid/src/diagrams/architecture/architectureDb.ts index 2174ebe19..c7bd64e21 100644 --- a/packages/mermaid/src/diagrams/architecture/architectureDb.ts +++ b/packages/mermaid/src/diagrams/architecture/architectureDb.ts @@ -1,6 +1,6 @@ import type { ArchitectureDiagramConfig } from '../../config.type.js'; import DEFAULT_CONFIG from '../../defaultConfig.js'; -import { getConfig } from '../../diagram-api/diagramAPI.js'; +import { getConfig as commonGetConfig } from '../../config.js'; import type { D3Element } from '../../types.js'; import { ImperativeState } from '../../utils/imperativeState.js'; import { @@ -33,6 +33,7 @@ import { isArchitectureService, shiftPositionByArchitectureDirectionPair, } from './architectureTypes.js'; +import { cleanAndMerge } from '../../utils.js'; const DEFAULT_ARCHITECTURE_CONFIG: Required = DEFAULT_CONFIG.architecture; @@ -316,6 +317,14 @@ const setElementForId = (id: string, element: D3Element) => { }; const getElementById = (id: string) => state.records.elements[id]; +const getConfig = (): Required => { + const config = cleanAndMerge({ + ...DEFAULT_ARCHITECTURE_CONFIG, + ...commonGetConfig().architecture, + }); + return config; +}; + export const db: ArchitectureDB = { clear, setDiagramTitle, @@ -324,6 +333,7 @@ export const db: ArchitectureDB = { getAccTitle, setAccDescription, getAccDescription, + getConfig, addService, getServices, @@ -348,9 +358,5 @@ export const db: ArchitectureDB = { export function getConfigField( field: T ): Required[T] { - const arch = getConfig().architecture; - if (arch?.[field]) { - return arch[field] as Required[T]; - } - return DEFAULT_ARCHITECTURE_CONFIG[field]; + return getConfig()[field]; } diff --git a/packages/mermaid/src/diagrams/architecture/architectureRenderer.ts b/packages/mermaid/src/diagrams/architecture/architectureRenderer.ts index 768c174b0..9479e5108 100644 --- a/packages/mermaid/src/diagrams/architecture/architectureRenderer.ts +++ b/packages/mermaid/src/diagrams/architecture/architectureRenderer.ts @@ -500,6 +500,8 @@ function layoutArchitecture( } export const draw: DrawDefinition = async (text, id, _version, diagObj: Diagram) => { + // TODO: Add title support for architecture diagrams + const db = diagObj.db as ArchitectureDB; const services = db.getServices(); diff --git a/packages/mermaid/src/diagrams/architecture/architectureTypes.ts b/packages/mermaid/src/diagrams/architecture/architectureTypes.ts index a7af33ca7..c61df11ff 100644 --- a/packages/mermaid/src/diagrams/architecture/architectureTypes.ts +++ b/packages/mermaid/src/diagrams/architecture/architectureTypes.ts @@ -1,4 +1,4 @@ -import type { DiagramDB } from '../../diagram-api/types.js'; +import type { DiagramDBBase } from '../../diagram-api/types.js'; import type { ArchitectureDiagramConfig } from '../../config.type.js'; import type { D3Element } from '../../types.js'; import type cytoscape from 'cytoscape'; @@ -242,7 +242,7 @@ export interface ArchitectureEdge
{ title?: string; } -export interface ArchitectureDB extends DiagramDB { +export interface ArchitectureDB extends DiagramDBBase { clear: () => void; addService: (service: Omit) => void; getServices: () => ArchitectureService[]; diff --git a/packages/mermaid/src/diagrams/radar/radar.spec.ts b/packages/mermaid/src/diagrams/radar/radar.spec.ts index 5e5f444c6..3a506c69e 100644 --- a/packages/mermaid/src/diagrams/radar/radar.spec.ts +++ b/packages/mermaid/src/diagrams/radar/radar.spec.ts @@ -1,11 +1,9 @@ import { it, describe, expect } from 'vitest'; import { db } from './db.js'; import { parser } from './parser.js'; -import { renderer, relativeRadius, closedRoundCurve } from './renderer.js'; +import { relativeRadius, closedRoundCurve } from './renderer.js'; import { Diagram } from '../../Diagram.js'; import mermaidAPI from '../../mermaidAPI.js'; -import { a } from 'vitest/dist/chunks/suite.qtkXWc6R.js'; -import { buildRadarStyleOptions } from './styles.js'; const { clear, diff --git a/packages/mermaid/src/diagrams/state/dataFetcher.js b/packages/mermaid/src/diagrams/state/dataFetcher.ts similarity index 84% rename from packages/mermaid/src/diagrams/state/dataFetcher.js rename to packages/mermaid/src/diagrams/state/dataFetcher.ts index 921544ff2..f38084899 100644 --- a/packages/mermaid/src/diagrams/state/dataFetcher.js +++ b/packages/mermaid/src/diagrams/state/dataFetcher.ts @@ -1,3 +1,4 @@ +import type { MermaidConfig } from '../../config.type.js'; import { getConfig } from '../../diagram-api/diagramAPI.js'; import { log } from '../../logger.js'; import common from '../common/common.js'; @@ -33,9 +34,10 @@ import { STMT_RELATION, STMT_STATE, } from './stateCommon.js'; +import type { Edge, NodeData, StateStmt, Stmt, StyleClass } from './stateDb.js'; // List of nodes created from the parsed diagram statement items -let nodeDb = new Map(); +const nodeDb = new Map(); let graphItemCount = 0; // used to construct ids, etc. @@ -43,18 +45,27 @@ let graphItemCount = 0; // used to construct ids, etc. * Create a standard string for the dom ID of an item. * If a type is given, insert that before the counter, preceded by the type spacer * - * @param itemId - * @param counter - * @param {string | null} type - * @param typeSpacer - * @returns {string} */ -export function stateDomId(itemId = '', counter = 0, type = '', typeSpacer = DOMID_TYPE_SPACER) { +export function stateDomId( + itemId = '', + counter = 0, + type: string | null = '', + typeSpacer = DOMID_TYPE_SPACER +) { const typeStr = type !== null && type.length > 0 ? `${typeSpacer}${type}` : ''; return `${DOMID_STATE}-${itemId}${typeStr}-${counter}`; } -const setupDoc = (parentParsedItem, doc, diagramStates, nodes, edges, altFlag, look, classes) => { +const setupDoc = ( + parentParsedItem: StateStmt | undefined, + doc: Stmt[], + diagramStates: Map, + nodes: NodeData[], + edges: Edge[], + altFlag: boolean, + look: MermaidConfig['look'], + classes: Map +) => { // graphItemCount = 0; log.trace('items', doc); doc.forEach((item) => { @@ -95,7 +106,7 @@ const setupDoc = (parentParsedItem, doc, diagramStates, nodes, edges, altFlag, l arrowTypeEnd: 'arrow_barb', style: G_EDGE_STYLE, labelStyle: '', - label: common.sanitizeText(item.description, getConfig()), + label: common.sanitizeText(item.description ?? '', getConfig()), arrowheadStyle: G_EDGE_ARROWHEADSTYLE, labelpos: G_EDGE_LABELPOS, labelType: G_EDGE_LABELTYPE, @@ -115,11 +126,10 @@ const setupDoc = (parentParsedItem, doc, diagramStates, nodes, edges, altFlag, l * Get the direction from the statement items. * Look through all of the documents (docs) in the parsedItems * Because is a _document_ direction, the default direction is not necessarily the same as the overall default _diagram_ direction. - * @param {object[]} parsedItem - the parsed statement item to look through - * @param [defaultDir] - the direction to use if none is found - * @returns {string} + * @param parsedItem - the parsed statement item to look through + * @param defaultDir - the direction to use if none is found */ -const getDir = (parsedItem, defaultDir = DEFAULT_NESTED_DOC_DIR) => { +const getDir = (parsedItem: { doc?: Stmt[] }, defaultDir = DEFAULT_NESTED_DOC_DIR) => { let dir = defaultDir; if (parsedItem.doc) { for (const parsedItemDoc of parsedItem.doc) { @@ -131,7 +141,11 @@ const getDir = (parsedItem, defaultDir = DEFAULT_NESTED_DOC_DIR) => { return dir; }; -function insertOrUpdateNode(nodes, nodeData, classes) { +function insertOrUpdateNode( + nodes: NodeData[], + nodeData: NodeData, + classes: Map +) { if (!nodeData.id || nodeData.id === '' || nodeData.id === '') { return; } @@ -143,9 +157,9 @@ function insertOrUpdateNode(nodes, nodeData, classes) { } nodeData.cssClasses.split(' ').forEach((cssClass) => { - if (classes.get(cssClass)) { - const classDef = classes.get(cssClass); - nodeData.cssCompiledStyles = [...nodeData.cssCompiledStyles, ...classDef.styles]; + const classDef = classes.get(cssClass); + if (classDef) { + nodeData.cssCompiledStyles = [...(nodeData.cssCompiledStyles ?? []), ...classDef.styles]; } }); } @@ -162,31 +176,30 @@ function insertOrUpdateNode(nodes, nodeData, classes) { * If there aren't any or if dbInfoItem isn't defined, return an empty string. * Else create 1 string from the list of classes found * - * @param {undefined | null | object} dbInfoItem - * @returns {string} */ -function getClassesFromDbInfo(dbInfoItem) { +function getClassesFromDbInfo(dbInfoItem?: StateStmt): string { return dbInfoItem?.classes?.join(' ') ?? ''; } -function getStylesFromDbInfo(dbInfoItem) { +function getStylesFromDbInfo(dbInfoItem?: StateStmt): string[] { return dbInfoItem?.styles ?? []; } export const dataFetcher = ( - parent, - parsedItem, - diagramStates, - nodes, - edges, - altFlag, - look, - classes + parent: StateStmt | undefined, + parsedItem: StateStmt, + diagramStates: Map, + nodes: NodeData[], + edges: Edge[], + altFlag: boolean, + look: MermaidConfig['look'], + classes: Map ) => { const itemId = parsedItem.id; const dbState = diagramStates.get(itemId); const classStr = getClassesFromDbInfo(dbState); const style = getStylesFromDbInfo(dbState); + const config = getConfig(); log.info('dataFetcher parsedItem', parsedItem, dbState, style); @@ -207,13 +220,13 @@ export const dataFetcher = ( nodeDb.set(itemId, { id: itemId, shape, - description: common.sanitizeText(itemId, getConfig()), + description: common.sanitizeText(itemId, config), cssClasses: `${classStr} ${CSS_DIAGRAM_STATE}`, cssStyles: style, }); } - const newNode = nodeDb.get(itemId); + const newNode = nodeDb.get(itemId)!; // Save data for description and group so that for instance a statement without description overwrites // one with description @todo TODO What does this mean? If important, add a test for it @@ -225,7 +238,7 @@ export const dataFetcher = ( newNode.shape = SHAPE_STATE_WITH_DESC; newNode.description.push(parsedItem.description); } else { - if (newNode.description?.length > 0) { + if (newNode.description?.length && newNode.description.length > 0) { // if there is a description already transform it to an array newNode.shape = SHAPE_STATE_WITH_DESC; if (newNode.description === itemId) { @@ -239,7 +252,7 @@ export const dataFetcher = ( newNode.description = parsedItem.description; } } - newNode.description = common.sanitizeTextOrArray(newNode.description, getConfig()); + newNode.description = common.sanitizeTextOrArray(newNode.description, config); } // If there's only 1 description entry, just use a regular state shape @@ -262,7 +275,7 @@ export const dataFetcher = ( } // This is what will be added to the graph - const nodeData = { + const nodeData: NodeData = { labelStyle: '', shape: newNode.shape, label: newNode.description, @@ -294,19 +307,19 @@ export const dataFetcher = ( if (parsedItem.note) { // Todo: set random id - const noteData = { + const noteData: NodeData = { labelStyle: '', shape: SHAPE_NOTE, label: parsedItem.note.text, cssClasses: CSS_DIAGRAM_NOTE, // useHtmlLabels: false, cssStyles: [], - cssCompilesStyles: [], + cssCompiledStyles: [], id: itemId + NOTE_ID + '-' + graphItemCount, domId: stateDomId(itemId, graphItemCount, NOTE), type: newNode.type, isGroup: newNode.type === 'group', - padding: getConfig().flowchart.padding, + padding: config.flowchart?.padding, look, position: parsedItem.note.position, }; diff --git a/packages/mermaid/src/diagrams/state/id-cache.js b/packages/mermaid/src/diagrams/state/id-cache.js deleted file mode 100644 index 875dc62b0..000000000 --- a/packages/mermaid/src/diagrams/state/id-cache.js +++ /dev/null @@ -1,16 +0,0 @@ -const idCache = {}; - -export const set = (key, val) => { - idCache[key] = val; -}; - -export const get = (k) => idCache[k]; -export const keys = () => Object.keys(idCache); -export const size = () => keys().length; - -export default { - get, - set, - keys, - size, -}; diff --git a/packages/mermaid/src/diagrams/state/shapes.js b/packages/mermaid/src/diagrams/state/shapes.js index b18b4ca0e..5fa964a4a 100644 --- a/packages/mermaid/src/diagrams/state/shapes.js +++ b/packages/mermaid/src/diagrams/state/shapes.js @@ -1,5 +1,4 @@ import { line, curveBasis } from 'd3'; -import idCache from './id-cache.js'; import { StateDB } from './stateDb.js'; import utils from '../../utils.js'; import common from '../common/common.js'; @@ -405,8 +404,6 @@ export const drawState = function (elem, stateDef) { stateInfo.width = stateBox.width + 2 * getConfig().state.padding; stateInfo.height = stateBox.height + 2 * getConfig().state.padding; - idCache.set(id, stateInfo); - // stateCnt++; return stateInfo; }; diff --git a/packages/mermaid/src/diagrams/state/stateCommon.ts b/packages/mermaid/src/diagrams/state/stateCommon.ts index 2902ce6b0..b1de78405 100644 --- a/packages/mermaid/src/diagrams/state/stateCommon.ts +++ b/packages/mermaid/src/diagrams/state/stateCommon.ts @@ -13,6 +13,10 @@ export const STMT_DIRECTION = 'dir'; // parsed statement type for a state export const STMT_STATE = 'state'; + +// parsed statement type for a root +export const STMT_ROOT = 'root'; + // parsed statement type for a relation export const STMT_RELATION = 'relation'; // parsed statement type for a classDef diff --git a/packages/mermaid/src/diagrams/state/stateDb.js b/packages/mermaid/src/diagrams/state/stateDb.js deleted file mode 100644 index 029db9c6f..000000000 --- a/packages/mermaid/src/diagrams/state/stateDb.js +++ /dev/null @@ -1,706 +0,0 @@ -import { getConfig } from '../../diagram-api/diagramAPI.js'; -import { log } from '../../logger.js'; -import { generateId } from '../../utils.js'; -import common from '../common/common.js'; -import { - clear as commonClear, - getAccDescription, - getAccTitle, - getDiagramTitle, - setAccDescription, - setAccTitle, - setDiagramTitle, -} from '../common/commonDb.js'; -import { dataFetcher, reset as resetDataFetching } from './dataFetcher.js'; -import { getDir } from './stateRenderer-v3-unified.js'; - -import { - DEFAULT_DIAGRAM_DIRECTION, - DEFAULT_STATE_TYPE, - DIVIDER_TYPE, - STMT_APPLYCLASS, - STMT_CLASSDEF, - STMT_DIRECTION, - STMT_RELATION, - STMT_STATE, - STMT_STYLEDEF, -} from './stateCommon.js'; - -const START_NODE = '[*]'; -const START_TYPE = 'start'; -const END_NODE = START_NODE; -const END_TYPE = 'end'; - -const COLOR_KEYWORD = 'color'; -const FILL_KEYWORD = 'fill'; -const BG_FILL = 'bgFill'; -const STYLECLASS_SEP = ','; - -/** - * Returns a new list of classes. - * In the future, this can be replaced with a class common to all diagrams. - * ClassDef information = { id: id, styles: [], textStyles: [] } - * - * @returns {Map} - */ -function newClassesList() { - return new Map(); -} - -const newDoc = () => { - return { - /** @type {{ id1: string, id2: string, relationTitle: string }[]} */ - relations: [], - states: new Map(), - documents: {}, - }; -}; - -const clone = (o) => JSON.parse(JSON.stringify(o)); - -export class StateDB { - /** - * @param {1 | 2} version - v1 renderer or v2 renderer. - */ - constructor(version) { - this.clear(); - - this.version = version; - - // Needed for JISON since it only supports direct properties - this.setRootDoc = this.setRootDoc.bind(this); - this.getDividerId = this.getDividerId.bind(this); - this.setDirection = this.setDirection.bind(this); - this.trimColon = this.trimColon.bind(this); - } - - /** - * @private - * @type {1 | 2} - */ - version; - - /** - * @private - * @type {Array} - */ - nodes = []; - /** - * @private - * @type {Array} - */ - edges = []; - - /** - * @private - * @type {Array} - */ - rootDoc = []; - /** - * @private - * @type {Map} - */ - classes = newClassesList(); // style classes defined by a classDef - - /** - * @private - * @type {Object} - */ - documents = { - root: newDoc(), - }; - - /** - * @private - * @type {Object} - */ - currentDocument = this.documents.root; - /** - * @private - * @type {number} - */ - startEndCount = 0; - /** - * @private - * @type {number} - */ - dividerCnt = 0; - - static relationType = { - AGGREGATION: 0, - EXTENSION: 1, - COMPOSITION: 2, - DEPENDENCY: 3, - }; - - setRootDoc(o) { - log.info('Setting root doc', o); - // rootDoc = { id: 'root', doc: o }; - this.rootDoc = o; - if (this.version === 1) { - this.extract(o); - } else { - this.extract(this.getRootDocV2()); - } - } - - getRootDoc() { - return this.rootDoc; - } - - /** - * @private - * @param {Object} parent - * @param {Object} node - * @param {boolean} first - */ - docTranslator(parent, node, first) { - if (node.stmt === STMT_RELATION) { - this.docTranslator(parent, node.state1, true); - this.docTranslator(parent, node.state2, false); - } else { - if (node.stmt === STMT_STATE) { - if (node.id === '[*]') { - node.id = first ? parent.id + '_start' : parent.id + '_end'; - node.start = first; - } else { - // This is just a plain state, not a start or end - node.id = node.id.trim(); - } - } - - if (node.doc) { - const doc = []; - // Check for concurrency - let currentDoc = []; - let i; - for (i = 0; i < node.doc.length; i++) { - if (node.doc[i].type === DIVIDER_TYPE) { - const newNode = clone(node.doc[i]); - newNode.doc = clone(currentDoc); - doc.push(newNode); - currentDoc = []; - } else { - currentDoc.push(node.doc[i]); - } - } - - // If any divider was encountered - if (doc.length > 0 && currentDoc.length > 0) { - const newNode = { - stmt: STMT_STATE, - id: generateId(), - type: 'divider', - doc: clone(currentDoc), - }; - doc.push(clone(newNode)); - node.doc = doc; - } - - node.doc.forEach((docNode) => this.docTranslator(node, docNode, true)); - } - } - } - - /** - * @private - */ - getRootDocV2() { - this.docTranslator({ id: 'root' }, { id: 'root', doc: this.rootDoc }, true); - return { id: 'root', doc: this.rootDoc }; - // Here - } - - /** - * Convert all of the statements (stmts) that were parsed into states and relationships. - * This is done because a state diagram may have nested sections, - * where each section is a 'document' and has its own set of statements. - * Ex: the section within a fork has its own statements, and incoming and outgoing statements - * refer to the fork as a whole (document). - * See the parser grammar: the definition of a document is a document then a 'line', where a line can be a statement. - * This will push the statement into the list of statements for the current document. - * @private - * @param _doc - */ - extract(_doc) { - // const res = { states: [], relations: [] }; - let doc; - if (_doc.doc) { - doc = _doc.doc; - } else { - doc = _doc; - } - // let doc = root.doc; - // if (!doc) { - // doc = root; - // } - log.info(doc); - this.clear(true); - - log.info('Extract initial document:', doc); - - doc.forEach((item) => { - log.warn('Statement', item.stmt); - switch (item.stmt) { - case STMT_STATE: - this.addState( - item.id.trim(), - item.type, - item.doc, - item.description, - item.note, - item.classes, - item.styles, - item.textStyles - ); - break; - case STMT_RELATION: - this.addRelation(item.state1, item.state2, item.description); - break; - case STMT_CLASSDEF: - this.addStyleClass(item.id.trim(), item.classes); - break; - case STMT_STYLEDEF: - { - const ids = item.id.trim().split(','); - const styles = item.styleClass.split(','); - ids.forEach((id) => { - let foundState = this.getState(id); - if (foundState === undefined) { - const trimmedId = id.trim(); - this.addState(trimmedId); - foundState = this.getState(trimmedId); - } - foundState.styles = styles.map((s) => s.replace(/;/g, '')?.trim()); - }); - } - break; - case STMT_APPLYCLASS: - this.setCssClass(item.id.trim(), item.styleClass); - break; - } - }); - - const diagramStates = this.getStates(); - const config = getConfig(); - const look = config.look; - - resetDataFetching(); - dataFetcher( - undefined, - this.getRootDocV2(), - diagramStates, - this.nodes, - this.edges, - true, - look, - this.classes - ); - this.nodes.forEach((node) => { - if (Array.isArray(node.label)) { - // add the rest as description - node.description = node.label.slice(1); - if (node.isGroup && node.description.length > 0) { - throw new Error( - 'Group nodes can only have label. Remove the additional description for node [' + - node.id + - ']' - ); - } - // add first description as label - node.label = node.label[0]; - } - }); - } - - /** - * Function called by parser when a node definition has been found. - * - * @param {null | string} id - * @param {null | string} type - * @param {null | string} doc - * @param {null | string | string[]} descr - description for the state. Can be a string or a list or strings - * @param {null | string} note - * @param {null | string | string[]} classes - class styles to apply to this state. Can be a string (1 style) or an array of styles. If it's just 1 class, convert it to an array of that 1 class. - * @param {null | string | string[]} styles - styles to apply to this state. Can be a string (1 style) or an array of styles. If it's just 1 style, convert it to an array of that 1 style. - * @param {null | string | string[]} textStyles - text styles to apply to this state. Can be a string (1 text test) or an array of text styles. If it's just 1 text style, convert it to an array of that 1 text style. - */ - addState( - id, - type = DEFAULT_STATE_TYPE, - doc = null, - descr = null, - note = null, - classes = null, - styles = null, - textStyles = null - ) { - const trimmedId = id?.trim(); - // add the state if needed - if (!this.currentDocument.states.has(trimmedId)) { - log.info('Adding state ', trimmedId, descr); - this.currentDocument.states.set(trimmedId, { - id: trimmedId, - descriptions: [], - type, - doc, - note, - classes: [], - styles: [], - textStyles: [], - }); - } else { - if (!this.currentDocument.states.get(trimmedId).doc) { - this.currentDocument.states.get(trimmedId).doc = doc; - } - if (!this.currentDocument.states.get(trimmedId).type) { - this.currentDocument.states.get(trimmedId).type = type; - } - } - - if (descr) { - log.info('Setting state description', trimmedId, descr); - if (typeof descr === 'string') { - this.addDescription(trimmedId, descr.trim()); - } - - if (typeof descr === 'object') { - descr.forEach((des) => this.addDescription(trimmedId, des.trim())); - } - } - - if (note) { - const doc2 = this.currentDocument.states.get(trimmedId); - doc2.note = note; - doc2.note.text = common.sanitizeText(doc2.note.text, getConfig()); - } - - if (classes) { - log.info('Setting state classes', trimmedId, classes); - const classesList = typeof classes === 'string' ? [classes] : classes; - classesList.forEach((cssClass) => this.setCssClass(trimmedId, cssClass.trim())); - } - - if (styles) { - log.info('Setting state styles', trimmedId, styles); - const stylesList = typeof styles === 'string' ? [styles] : styles; - stylesList.forEach((style) => this.setStyle(trimmedId, style.trim())); - } - - if (textStyles) { - log.info('Setting state styles', trimmedId, styles); - const textStylesList = typeof textStyles === 'string' ? [textStyles] : textStyles; - textStylesList.forEach((textStyle) => this.setTextStyle(trimmedId, textStyle.trim())); - } - } - - clear(saveCommon) { - this.nodes = []; - this.edges = []; - this.documents = { - root: newDoc(), - }; - this.currentDocument = this.documents.root; - - // number of start and end nodes; used to construct ids - this.startEndCount = 0; - this.classes = newClassesList(); - if (!saveCommon) { - commonClear(); - } - } - - getState(id) { - return this.currentDocument.states.get(id); - } - getStates() { - return this.currentDocument.states; - } - logDocuments() { - log.info('Documents = ', this.documents); - } - getRelations() { - return this.currentDocument.relations; - } - - /** - * If the id is a start node ( [*] ), then return a new id constructed from - * the start node name and the current start node count. - * else return the given id - * - * @param {string} id - * @returns {string} - the id (original or constructed) - * @private - */ - startIdIfNeeded(id = '') { - let fixedId = id; - if (id === START_NODE) { - this.startEndCount++; - fixedId = `${START_TYPE}${this.startEndCount}`; - } - return fixedId; - } - - /** - * If the id is a start node ( [*] ), then return the start type ('start') - * else return the given type - * - * @param {string} id - * @param {string} type - * @returns {string} - the type that should be used - * @private - */ - startTypeIfNeeded(id = '', type = DEFAULT_STATE_TYPE) { - return id === START_NODE ? START_TYPE : type; - } - - /** - * If the id is an end node ( [*] ), then return a new id constructed from - * the end node name and the current start_end node count. - * else return the given id - * - * @param {string} id - * @returns {string} - the id (original or constructed) - * @private - */ - endIdIfNeeded(id = '') { - let fixedId = id; - if (id === END_NODE) { - this.startEndCount++; - fixedId = `${END_TYPE}${this.startEndCount}`; - } - return fixedId; - } - - /** - * If the id is an end node ( [*] ), then return the end type - * else return the given type - * - * @param {string} id - * @param {string} type - * @returns {string} - the type that should be used - * @private - */ - endTypeIfNeeded(id = '', type = DEFAULT_STATE_TYPE) { - return id === END_NODE ? END_TYPE : type; - } - - /** - * - * @param item1 - * @param item2 - * @param relationTitle - */ - addRelationObjs(item1, item2, relationTitle) { - let id1 = this.startIdIfNeeded(item1.id.trim()); - let type1 = this.startTypeIfNeeded(item1.id.trim(), item1.type); - let id2 = this.startIdIfNeeded(item2.id.trim()); - let type2 = this.startTypeIfNeeded(item2.id.trim(), item2.type); - - this.addState( - id1, - type1, - item1.doc, - item1.description, - item1.note, - item1.classes, - item1.styles, - item1.textStyles - ); - this.addState( - id2, - type2, - item2.doc, - item2.description, - item2.note, - item2.classes, - item2.styles, - item2.textStyles - ); - - this.currentDocument.relations.push({ - id1, - id2, - relationTitle: common.sanitizeText(relationTitle, getConfig()), - }); - } - - /** - * Add a relation between two items. The items may be full objects or just the string id of a state. - * - * @param {string | object} item1 - * @param {string | object} item2 - * @param {string} title - */ - addRelation(item1, item2, title) { - if (typeof item1 === 'object') { - this.addRelationObjs(item1, item2, title); - } else { - const id1 = this.startIdIfNeeded(item1.trim()); - const type1 = this.startTypeIfNeeded(item1); - const id2 = this.endIdIfNeeded(item2.trim()); - const type2 = this.endTypeIfNeeded(item2); - - this.addState(id1, type1); - this.addState(id2, type2); - this.currentDocument.relations.push({ - id1, - id2, - title: common.sanitizeText(title, getConfig()), - }); - } - } - - addDescription(id, descr) { - const theState = this.currentDocument.states.get(id); - const _descr = descr.startsWith(':') ? descr.replace(':', '').trim() : descr; - theState.descriptions.push(common.sanitizeText(_descr, getConfig())); - } - - cleanupLabel(label) { - if (label.substring(0, 1) === ':') { - return label.substr(2).trim(); - } else { - return label.trim(); - } - } - - getDividerId() { - this.dividerCnt++; - return 'divider-id-' + this.dividerCnt; - } - - /** - * Called when the parser comes across a (style) class definition - * @example classDef my-style fill:#f96; - * - * @param {string} id - the id of this (style) class - * @param {string | null} styleAttributes - the string with 1 or more style attributes (each separated by a comma) - */ - addStyleClass(id, styleAttributes = '') { - // create a new style class object with this id - if (!this.classes.has(id)) { - this.classes.set(id, { id: id, styles: [], textStyles: [] }); // This is a classDef - } - const foundClass = this.classes.get(id); - if (styleAttributes !== undefined && styleAttributes !== null) { - styleAttributes.split(STYLECLASS_SEP).forEach((attrib) => { - // remove any trailing ; - const fixedAttrib = attrib.replace(/([^;]*);/, '$1').trim(); - - // replace some style keywords - 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); - } - foundClass.styles.push(fixedAttrib); - }); - } - } - - /** - * Return all of the style classes - * @returns {{} | any | classes} - */ - getClasses() { - return this.classes; - } - - /** - * Add a (style) class or css class to a state with the given id. - * If the state isn't already in the list of known states, add it. - * Might be called by parser when a style class or CSS class should be applied to a state - * - * @param {string | string[]} itemIds The id or a list of ids of the item(s) to apply the css class to - * @param {string} cssClassName CSS class name - */ - setCssClass(itemIds, cssClassName) { - itemIds.split(',').forEach((id) => { - let foundState = this.getState(id); - if (foundState === undefined) { - const trimmedId = id.trim(); - this.addState(trimmedId); - foundState = this.getState(trimmedId); - } - foundState.classes.push(cssClassName); - }); - } - - /** - * Add a style to a state with the given id. - * @example style stateId fill:#f9f,stroke:#333,stroke-width:4px - * where 'style' is the keyword - * stateId is the id of a state - * the rest of the string is the styleText (all of the attributes to be applied to the state) - * - * @param itemId The id of item to apply the style to - * @param styleText - the text of the attributes for the style - */ - setStyle(itemId, styleText) { - const item = this.getState(itemId); - if (item !== undefined) { - item.styles.push(styleText); - } - } - - /** - * Add a text style to a state with the given id - * - * @param itemId The id of item to apply the css class to - * @param cssClassName CSS class name - */ - setTextStyle(itemId, cssClassName) { - const item = this.getState(itemId); - if (item !== undefined) { - item.textStyles.push(cssClassName); - } - } - - /** - * Finds the direction statement in the root document. - * @private - * @returns {{ value: string } | undefined} - the direction statement if present - */ - getDirectionStatement() { - return this.rootDoc.find((doc) => doc.stmt === STMT_DIRECTION); - } - - getDirection() { - return this.getDirectionStatement()?.value ?? DEFAULT_DIAGRAM_DIRECTION; - } - - setDirection(dir) { - const doc = this.getDirectionStatement(); - if (doc) { - doc.value = dir; - } else { - this.rootDoc.unshift({ stmt: STMT_DIRECTION, value: dir }); - } - } - - trimColon(str) { - return str && str[0] === ':' ? str.substr(1).trim() : str.trim(); - } - - getData() { - const config = getConfig(); - return { - nodes: this.nodes, - edges: this.edges, - other: {}, - config, - direction: getDir(this.getRootDocV2()), - }; - } - - getConfig() { - return getConfig().state; - } - getAccTitle = getAccTitle; - setAccTitle = setAccTitle; - getAccDescription = getAccDescription; - setAccDescription = setAccDescription; - setDiagramTitle = setDiagramTitle; - getDiagramTitle = getDiagramTitle; -} diff --git a/packages/mermaid/src/diagrams/state/stateDb.ts b/packages/mermaid/src/diagrams/state/stateDb.ts new file mode 100644 index 000000000..853a0e22f --- /dev/null +++ b/packages/mermaid/src/diagrams/state/stateDb.ts @@ -0,0 +1,693 @@ +import { getConfig } from '../../diagram-api/diagramAPI.js'; +import { log } from '../../logger.js'; +import { generateId } from '../../utils.js'; +import common from '../common/common.js'; +import { + clear as commonClear, + getAccDescription, + getAccTitle, + getDiagramTitle, + setAccDescription, + setAccTitle, + setDiagramTitle, +} from '../common/commonDb.js'; +import { dataFetcher, reset as resetDataFetcher } from './dataFetcher.js'; +import { getDir } from './stateRenderer-v3-unified.js'; +import { + DEFAULT_DIAGRAM_DIRECTION, + DEFAULT_STATE_TYPE, + DIVIDER_TYPE, + STMT_APPLYCLASS, + STMT_CLASSDEF, + STMT_RELATION, + STMT_ROOT, + STMT_DIRECTION, + STMT_STATE, + STMT_STYLEDEF, +} from './stateCommon.js'; +import type { MermaidConfig } from '../../config.type.js'; + +const CONSTANTS = { + START_NODE: '[*]', + START_TYPE: 'start', + END_NODE: '[*]', + END_TYPE: 'end', + COLOR_KEYWORD: 'color', + FILL_KEYWORD: 'fill', + BG_FILL: 'bgFill', + STYLECLASS_SEP: ',', +} as const; + +interface BaseStmt { + stmt: 'applyClass' | 'classDef' | 'dir' | 'relation' | 'state' | 'style' | 'root' | 'default'; +} + +interface ApplyClassStmt extends BaseStmt { + stmt: 'applyClass'; + id: string; + styleClass: string; +} + +interface ClassDefStmt extends BaseStmt { + stmt: 'classDef'; + id: string; + classes: string; +} + +interface DirectionStmt extends BaseStmt { + stmt: 'dir'; + value: 'TB' | 'BT' | 'RL' | 'LR'; +} + +interface RelationStmt extends BaseStmt { + stmt: 'relation'; + state1: StateStmt; + state2: StateStmt; + description?: string; +} + +export interface StateStmt extends BaseStmt { + stmt: 'state' | 'default'; + id: string; + type: 'default' | 'fork' | 'join' | 'choice' | 'divider' | 'start' | 'end'; + description?: string; + descriptions?: string[]; + doc?: Stmt[]; + note?: Note; + start?: boolean; + classes?: string[]; + styles?: string[]; + textStyles?: string[]; +} + +interface StyleStmt extends BaseStmt { + stmt: 'style'; + id: string; + styleClass: string; +} + +export interface RootStmt { + id: 'root'; + stmt: 'root'; + doc?: Stmt[]; +} + +interface Note { + position?: 'left of' | 'right of'; + text: string; +} + +export type Stmt = + | ApplyClassStmt + | ClassDefStmt + | DirectionStmt + | RelationStmt + | StateStmt + | StyleStmt + | RootStmt; + +interface DiagramEdge { + id1: string; + id2: string; + relationTitle?: string; +} + +interface Document { + relations: DiagramEdge[]; + states: Map; + documents: Record; +} + +export interface StyleClass { + id: string; + styles: string[]; + textStyles: string[]; +} + +export interface NodeData { + labelStyle?: string; + shape: string; + label?: string | string[]; + cssClasses: string; + cssCompiledStyles?: string[]; + cssStyles: string[]; + id: string; + dir?: string; + domId?: string; + type?: string; + isGroup?: boolean; + padding?: number; + rx?: number; + ry?: number; + look?: MermaidConfig['look']; + parentId?: string; + centerLabel?: boolean; + position?: string; + description?: string | string[]; +} + +export interface Edge { + id: string; + start: string; + end: string; + arrowhead: string; + arrowTypeEnd: string; + style: string; + labelStyle: string; + label?: string; + arrowheadStyle: string; + labelpos: string; + labelType: string; + thickness: string; + classes: string; + look: MermaidConfig['look']; +} + +/** + * Returns a new list of classes. + * In the future, this can be replaced with a class common to all diagrams. + * ClassDef information = \{ id: id, styles: [], textStyles: [] \} + */ +const newClassesList = (): Map => new Map(); +const newDoc = (): Document => ({ + relations: [], + states: new Map(), + documents: {}, +}); +const clone = (o: T): T => JSON.parse(JSON.stringify(o)); + +export class StateDB { + private nodes: NodeData[] = []; + private edges: Edge[] = []; + private rootDoc: Stmt[] = []; + private classes = newClassesList(); + private documents = { root: newDoc() }; + private currentDocument = this.documents.root; + private startEndCount = 0; + private dividerCnt = 0; + + static readonly relationType = { + AGGREGATION: 0, + EXTENSION: 1, + COMPOSITION: 2, + DEPENDENCY: 3, + } as const; + + constructor(private version: 1 | 2) { + this.clear(); + // Bind methods used by JISON + this.setRootDoc = this.setRootDoc.bind(this); + this.getDividerId = this.getDividerId.bind(this); + this.setDirection = this.setDirection.bind(this); + this.trimColon = this.trimColon.bind(this); + } + + /** + * Convert all of the statements (stmts) that were parsed into states and relationships. + * This is done because a state diagram may have nested sections, + * where each section is a 'document' and has its own set of statements. + * Ex: the section within a fork has its own statements, and incoming and outgoing statements + * refer to the fork as a whole (document). + * See the parser grammar: the definition of a document is a document then a 'line', where a line can be a statement. + * This will push the statement into the list of statements for the current document. + */ + extract(statements: Stmt[] | { doc: Stmt[] }) { + this.clear(true); + for (const item of Array.isArray(statements) ? statements : statements.doc) { + switch (item.stmt) { + case STMT_STATE: + this.addState(item.id.trim(), item.type, item.doc, item.description, item.note); + break; + case STMT_RELATION: + this.addRelation(item.state1, item.state2, item.description); + break; + case STMT_CLASSDEF: + this.addStyleClass(item.id.trim(), item.classes); + break; + case STMT_STYLEDEF: + this.handleStyleDef(item); + break; + case STMT_APPLYCLASS: + this.setCssClass(item.id.trim(), item.styleClass); + break; + } + } + const diagramStates = this.getStates(); + const config = getConfig(); + + resetDataFetcher(); + dataFetcher( + undefined, + this.getRootDocV2() as StateStmt, + diagramStates, + this.nodes, + this.edges, + true, + config.look, + this.classes + ); + + // Process node labels + for (const node of this.nodes) { + if (!Array.isArray(node.label)) { + continue; + } + + node.description = node.label.slice(1); + if (node.isGroup && node.description.length > 0) { + throw new Error( + `Group nodes can only have label. Remove the additional description for node [${node.id}]` + ); + } + node.label = node.label[0]; + } + } + + private handleStyleDef(item: StyleStmt) { + const ids = item.id.trim().split(','); + const styles = item.styleClass.split(','); + + for (const id of ids) { + let state = this.getState(id); + if (!state) { + const trimmedId = id.trim(); + this.addState(trimmedId); + state = this.getState(trimmedId); + } + if (state) { + state.styles = styles.map((s) => s.replace(/;/g, '')?.trim()); + } + } + } + + setRootDoc(o: Stmt[]) { + log.info('Setting root doc', o); + this.rootDoc = o; + if (this.version === 1) { + this.extract(o); + } else { + this.extract(this.getRootDocV2()); + } + } + + docTranslator(parent: RootStmt | StateStmt, node: Stmt, first: boolean) { + if (node.stmt === STMT_RELATION) { + this.docTranslator(parent, node.state1, true); + this.docTranslator(parent, node.state2, false); + return; + } + + if (node.stmt === STMT_STATE) { + if (node.id === CONSTANTS.START_NODE) { + node.id = parent.id + (first ? '_start' : '_end'); + node.start = first; + } else { + // This is just a plain state, not a start or end + node.id = node.id.trim(); + } + } + + if ((node.stmt !== STMT_ROOT && node.stmt !== STMT_STATE) || !node.doc) { + return; + } + + const doc = []; + // Check for concurrency + let currentDoc = []; + for (const stmt of node.doc) { + if ((stmt as StateStmt).type === DIVIDER_TYPE) { + const newNode = clone(stmt as StateStmt); + newNode.doc = clone(currentDoc); + doc.push(newNode); + currentDoc = []; + } else { + currentDoc.push(stmt); + } + } + + // If any divider was encountered + if (doc.length > 0 && currentDoc.length > 0) { + const newNode = { + stmt: STMT_STATE, + id: generateId(), + type: 'divider', + doc: clone(currentDoc), + } satisfies StateStmt; + doc.push(clone(newNode)); + node.doc = doc; + } + + node.doc.forEach((docNode) => this.docTranslator(node, docNode, true)); + } + + private getRootDocV2() { + this.docTranslator( + { id: STMT_ROOT, stmt: STMT_ROOT }, + { id: STMT_ROOT, stmt: STMT_ROOT, doc: this.rootDoc }, + true + ); + return { id: STMT_ROOT, doc: this.rootDoc }; + } + + /** + * Function called by parser when a node definition has been found. + * + * @param descr - description for the state. Can be a string or a list or strings + * @param classes - class styles to apply to this state. Can be a string (1 style) or an array of styles. If it's just 1 class, convert it to an array of that 1 class. + * @param styles - styles to apply to this state. Can be a string (1 style) or an array of styles. If it's just 1 style, convert it to an array of that 1 style. + * @param textStyles - text styles to apply to this state. Can be a string (1 text test) or an array of text styles. If it's just 1 text style, convert it to an array of that 1 text style. + */ + addState( + id: string, + type: StateStmt['type'] = DEFAULT_STATE_TYPE, + doc: Stmt[] | undefined = undefined, + descr: string | string[] | undefined = undefined, + note: Note | undefined = undefined, + classes: string | string[] | undefined = undefined, + styles: string | string[] | undefined = undefined, + textStyles: string | string[] | undefined = undefined + ) { + const trimmedId = id?.trim(); + if (!this.currentDocument.states.has(trimmedId)) { + log.info('Adding state ', trimmedId, descr); + this.currentDocument.states.set(trimmedId, { + stmt: STMT_STATE, + id: trimmedId, + descriptions: [], + type, + doc, + note, + classes: [], + styles: [], + textStyles: [], + }); + } else { + const state = this.currentDocument.states.get(trimmedId); + if (!state) { + throw new Error(`State not found: ${trimmedId}`); + } + if (!state.doc) { + state.doc = doc; + } + if (!state.type) { + state.type = type; + } + } + + if (descr) { + log.info('Setting state description', trimmedId, descr); + const descriptions = Array.isArray(descr) ? descr : [descr]; + descriptions.forEach((des) => this.addDescription(trimmedId, des.trim())); + } + + if (note) { + const doc2 = this.currentDocument.states.get(trimmedId); + if (!doc2) { + throw new Error(`State not found: ${trimmedId}`); + } + doc2.note = note; + doc2.note.text = common.sanitizeText(doc2.note.text, getConfig()); + } + + if (classes) { + log.info('Setting state classes', trimmedId, classes); + const classesList = Array.isArray(classes) ? classes : [classes]; + classesList.forEach((cssClass) => this.setCssClass(trimmedId, cssClass.trim())); + } + + if (styles) { + log.info('Setting state styles', trimmedId, styles); + const stylesList = Array.isArray(styles) ? styles : [styles]; + stylesList.forEach((style) => this.setStyle(trimmedId, style.trim())); + } + + if (textStyles) { + log.info('Setting state styles', trimmedId, styles); + const textStylesList = Array.isArray(textStyles) ? textStyles : [textStyles]; + textStylesList.forEach((textStyle) => this.setTextStyle(trimmedId, textStyle.trim())); + } + } + + clear(saveCommon?: boolean) { + this.nodes = []; + this.edges = []; + this.documents = { root: newDoc() }; + this.currentDocument = this.documents.root; + + // number of start and end nodes; used to construct ids + this.startEndCount = 0; + this.classes = newClassesList(); + if (!saveCommon) { + commonClear(); + } + } + + getState(id: string) { + return this.currentDocument.states.get(id); + } + + getStates() { + return this.currentDocument.states; + } + + logDocuments() { + log.info('Documents = ', this.documents); + } + + getRelations() { + return this.currentDocument.relations; + } + + /** + * If the id is a start node ( [*] ), then return a new id constructed from + * the start node name and the current start node count. + * else return the given id + */ + startIdIfNeeded(id = '') { + if (id === CONSTANTS.START_NODE) { + this.startEndCount++; + return `${CONSTANTS.START_TYPE}${this.startEndCount}`; + } + return id; + } + + /** + * If the id is a start node ( [*] ), then return the start type ('start') + * else return the given type + */ + startTypeIfNeeded(id = '', type: StateStmt['type'] = DEFAULT_STATE_TYPE) { + return id === CONSTANTS.START_NODE ? CONSTANTS.START_TYPE : type; + } + + /** + * If the id is an end node ( [*] ), then return a new id constructed from + * the end node name and the current start_end node count. + * else return the given id + */ + endIdIfNeeded(id = '') { + if (id === CONSTANTS.END_NODE) { + this.startEndCount++; + return `${CONSTANTS.END_TYPE}${this.startEndCount}`; + } + return id; + } + + /** + * If the id is an end node ( [*] ), then return the end type + * else return the given type + * + */ + endTypeIfNeeded(id = '', type: StateStmt['type'] = DEFAULT_STATE_TYPE) { + return id === CONSTANTS.END_NODE ? CONSTANTS.END_TYPE : type; + } + + addRelationObjs(item1: StateStmt, item2: StateStmt, relationTitle = '') { + const id1 = this.startIdIfNeeded(item1.id.trim()); + const type1 = this.startTypeIfNeeded(item1.id.trim(), item1.type); + const id2 = this.startIdIfNeeded(item2.id.trim()); + const type2 = this.startTypeIfNeeded(item2.id.trim(), item2.type); + this.addState( + id1, + type1, + item1.doc, + item1.description, + item1.note, + item1.classes, + item1.styles, + item1.textStyles + ); + this.addState( + id2, + type2, + item2.doc, + item2.description, + item2.note, + item2.classes, + item2.styles, + item2.textStyles + ); + this.currentDocument.relations.push({ + id1, + id2, + relationTitle: common.sanitizeText(relationTitle, getConfig()), + }); + } + + /** + * Add a relation between two items. The items may be full objects or just the string id of a state. + */ + addRelation(item1: string | StateStmt, item2: string | StateStmt, title?: string) { + if (typeof item1 === 'object' && typeof item2 === 'object') { + this.addRelationObjs(item1, item2, title); + } else if (typeof item1 === 'string' && typeof item2 === 'string') { + const id1 = this.startIdIfNeeded(item1.trim()); + const type1 = this.startTypeIfNeeded(item1); + const id2 = this.endIdIfNeeded(item2.trim()); + const type2 = this.endTypeIfNeeded(item2); + + this.addState(id1, type1); + this.addState(id2, type2); + this.currentDocument.relations.push({ + id1, + id2, + relationTitle: title ? common.sanitizeText(title, getConfig()) : undefined, + }); + } + } + + addDescription(id: string, descr: string) { + const theState = this.currentDocument.states.get(id); + const _descr = descr.startsWith(':') ? descr.replace(':', '').trim() : descr; + theState?.descriptions?.push(common.sanitizeText(_descr, getConfig())); + } + + cleanupLabel(label: string) { + return label.startsWith(':') ? label.slice(2).trim() : label.trim(); + } + + getDividerId() { + this.dividerCnt++; + return `divider-id-${this.dividerCnt}`; + } + + /** + * Called when the parser comes across a (style) class definition + * @example classDef my-style fill:#f96; + * + * @param id - the id of this (style) class + * @param styleAttributes - the string with 1 or more style attributes (each separated by a comma) + */ + addStyleClass(id: string, styleAttributes = '') { + // create a new style class object with this id + if (!this.classes.has(id)) { + this.classes.set(id, { id, styles: [], textStyles: [] }); + } + const foundClass = this.classes.get(id); + if (styleAttributes && foundClass) { + styleAttributes.split(CONSTANTS.STYLECLASS_SEP).forEach((attrib) => { + const fixedAttrib = attrib.replace(/([^;]*);/, '$1').trim(); + if (RegExp(CONSTANTS.COLOR_KEYWORD).exec(attrib)) { + const newStyle1 = fixedAttrib.replace(CONSTANTS.FILL_KEYWORD, CONSTANTS.BG_FILL); + const newStyle2 = newStyle1.replace(CONSTANTS.COLOR_KEYWORD, CONSTANTS.FILL_KEYWORD); + foundClass.textStyles.push(newStyle2); + } + foundClass.styles.push(fixedAttrib); + }); + } + } + + getClasses() { + return this.classes; + } + + /** + * Add a (style) class or css class to a state with the given id. + * If the state isn't already in the list of known states, add it. + * Might be called by parser when a style class or CSS class should be applied to a state + * + * @param itemIds - The id or a list of ids of the item(s) to apply the css class to + * @param cssClassName - CSS class name + */ + setCssClass(itemIds: string, cssClassName: string) { + itemIds.split(',').forEach((id) => { + let foundState = this.getState(id); + if (!foundState) { + const trimmedId = id.trim(); + this.addState(trimmedId); + foundState = this.getState(trimmedId); + } + foundState?.classes?.push(cssClassName); + }); + } + + /** + * Add a style to a state with the given id. + * @example style stateId fill:#f9f,stroke:#333,stroke-width:4px + * where 'style' is the keyword + * stateId is the id of a state + * the rest of the string is the styleText (all of the attributes to be applied to the state) + * + * @param itemId - The id of item to apply the style to + * @param styleText - the text of the attributes for the style + */ + setStyle(itemId: string, styleText: string) { + this.getState(itemId)?.styles?.push(styleText); + } + + /** + * Add a text style to a state with the given id + * + * @param itemId - The id of item to apply the css class to + * @param cssClassName - CSS class name + */ + setTextStyle(itemId: string, cssClassName: string) { + this.getState(itemId)?.textStyles?.push(cssClassName); + } + + /** + * Finds the direction statement in the root document. + * @returns the direction statement if present + */ + private getDirectionStatement() { + return this.rootDoc.find((doc): doc is DirectionStmt => doc.stmt === STMT_DIRECTION); + } + + getDirection() { + return this.getDirectionStatement()?.value ?? DEFAULT_DIAGRAM_DIRECTION; + } + + setDirection(dir: DirectionStmt['value']) { + const doc = this.getDirectionStatement(); + if (doc) { + doc.value = dir; + } else { + this.rootDoc.unshift({ stmt: STMT_DIRECTION, value: dir }); + } + } + + trimColon(str: string) { + return str.startsWith(':') ? str.slice(1).trim() : str.trim(); + } + + getData() { + const config = getConfig(); + return { + nodes: this.nodes, + edges: this.edges, + other: {}, + config, + direction: getDir(this.getRootDocV2()), + }; + } + + getConfig() { + return getConfig().state; + } + + getAccTitle = getAccTitle; + setAccTitle = setAccTitle; + getAccDescription = getAccDescription; + setAccDescription = setAccDescription; + setDiagramTitle = setDiagramTitle; + getDiagramTitle = getDiagramTitle; +} diff --git a/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js b/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js index a79e44d5d..35fdd4579 100644 --- a/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js +++ b/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js @@ -5,6 +5,7 @@ import { StateDB } from './stateDb.js'; describe('state diagram V2, ', function () { // TODO - these examples should be put into ./parser/stateDiagram.spec.js describe('when parsing an info graph it', function () { + /** @type {StateDB} */ let stateDb; beforeEach(function () { stateDb = new StateDB(2); @@ -347,6 +348,20 @@ describe('state diagram V2, ', function () { `; parser.parse(str); + expect(stateDb.getState('Active').note).toMatchInlineSnapshot(` + { + "position": "left of", + "text": "this is a short
note", + } + `); + expect(stateDb.getState('Inactive').note).toMatchInlineSnapshot(` + { + "position": "right of", + "text": "A note can also + be defined on + several lines", + } + `); }); it('should handle multiline notes with different line breaks', function () { const str = `stateDiagram-v2 @@ -357,6 +372,12 @@ describe('state diagram V2, ', function () { `; parser.parse(str); + expect(stateDb.getStates().get('State1').note).toMatchInlineSnapshot(` + { + "position": "right of", + "text": "Line1
Line2
Line3
Line4
Line5", + } + `); }); it('should handle floating notes', function () { const str = `stateDiagram-v2 @@ -367,15 +388,14 @@ describe('state diagram V2, ', function () { parser.parse(str); }); it('should handle floating notes', function () { - const str = `stateDiagram-v2\n + const str = `stateDiagram-v2 state foo note "This is a floating note" as N1 `; - parser.parse(str); }); it('should handle notes for composite (nested) states', function () { - const str = `stateDiagram-v2\n + const str = `stateDiagram-v2 [*] --> NotShooting state "Not Shooting State" as NotShooting { @@ -390,6 +410,12 @@ describe('state diagram V2, ', function () { `; parser.parse(str); + expect(stateDb.getState('NotShooting').note).toMatchInlineSnapshot(` + { + "position": "right of", + "text": "This is a note on a composite state", + } + `); }); it('A composite state should be able to link to itself', () => { diff --git a/packages/mermaid/src/diagrams/user-journey/journeyRenderer.ts b/packages/mermaid/src/diagrams/user-journey/journeyRenderer.ts index 13eb31a02..e0b22d026 100644 --- a/packages/mermaid/src/diagrams/user-journey/journeyRenderer.ts +++ b/packages/mermaid/src/diagrams/user-journey/journeyRenderer.ts @@ -13,15 +13,17 @@ export const setConf = function (cnf) { }; const actors = {}; +let maxWidth = 0; /** @param diagram - The diagram to draw to. */ function drawActorLegend(diagram) { const conf = getConfig().journey; - // Draw the actors + const maxLabelWidth = conf.maxLabelWidth; + maxWidth = 0; let yPos = 60; + Object.keys(actors).forEach((person) => { const colour = actors[person].color; - const circleData = { cx: 20, cy: yPos, @@ -32,25 +34,97 @@ function drawActorLegend(diagram) { }; svgDraw.drawCircle(diagram, circleData); - const labelData = { - x: 40, - y: yPos + 7, - fill: '#666', - text: person, - textMargin: conf.boxTextMargin | 5, - }; - svgDraw.drawText(diagram, labelData); + // First, measure the full text width without wrapping. + let measureText = diagram.append('text').attr('visibility', 'hidden').text(person); + const fullTextWidth = measureText.node().getBoundingClientRect().width; + measureText.remove(); - yPos += 20; + let lines = []; + + // If the text is naturally within the max width, use it as a single line. + if (fullTextWidth <= maxLabelWidth) { + lines = [person]; + } else { + // Otherwise, wrap the text using the knuth-plass algorithm. + const words = person.split(' '); // Split the text into words. + let currentLine = ''; + measureText = diagram.append('text').attr('visibility', 'hidden'); + + words.forEach((word) => { + // check the width of the line with the new word. + const testLine = currentLine ? `${currentLine} ${word}` : word; + measureText.text(testLine); + const textWidth = measureText.node().getBoundingClientRect().width; + + if (textWidth > maxLabelWidth) { + // If adding the new word exceeds max width, push the current line. + if (currentLine) { + lines.push(currentLine); + } + currentLine = word; // Start a new line with the current word. + + // If the word itself is too long, break it with a hyphen. + measureText.text(word); + if (measureText.node().getBoundingClientRect().width > maxLabelWidth) { + let brokenWord = ''; + for (const char of word) { + brokenWord += char; + measureText.text(brokenWord + '-'); + if (measureText.node().getBoundingClientRect().width > maxLabelWidth) { + // Push the broken part with a hyphen. + lines.push(brokenWord.slice(0, -1) + '-'); + brokenWord = char; + } + } + currentLine = brokenWord; + } + } else { + // If the line with the new word fits, add the new word to the current line. + currentLine = testLine; + } + }); + + // Push the last line. + if (currentLine) { + lines.push(currentLine); + } + measureText.remove(); // Remove the text element used for measuring. + } + + lines.forEach((line, index) => { + const labelData = { + x: 40, + y: yPos + 7 + index * 20, + fill: '#666', + text: line, + textMargin: conf.boxTextMargin ?? 5, + }; + + // Draw the text and measure the width. + const textElement = svgDraw.drawText(diagram, labelData); + const lineWidth = textElement.node().getBoundingClientRect().width; + + // Use conf.leftMargin as the initial spacing baseline, + // but expand maxWidth if the line is wider. + if (lineWidth > maxWidth && lineWidth > conf.leftMargin - lineWidth) { + maxWidth = lineWidth; + } + }); + + yPos += Math.max(20, lines.length * 20); }); } + // TODO: Cleanup? const conf = getConfig().journey; -const LEFT_MARGIN = conf.leftMargin; +let leftMargin = 0; export const draw = function (text, id, version, diagObj) { - const conf = getConfig().journey; + const configObject = getConfig(); + const titleColor = configObject.journey.titleColor; + const titleFontSize = configObject.journey.titleFontSize; + const titleFontFamily = configObject.journey.titleFontFamily; - const securityLevel = getConfig().securityLevel; + const securityLevel = configObject.securityLevel; // Handle root and Document for when rendering in sandbox mode let sandboxElement; if (securityLevel === 'sandbox') { @@ -84,7 +158,8 @@ export const draw = function (text, id, version, diagObj) { }); drawActorLegend(diagram); - bounds.insert(0, 0, LEFT_MARGIN, Object.keys(actors).length * 50); + leftMargin = conf.leftMargin + maxWidth; + bounds.insert(0, 0, leftMargin, Object.keys(actors).length * 50); drawTasks(diagram, tasks, 0); const box = bounds.getBounds(); @@ -92,23 +167,25 @@ export const draw = function (text, id, version, diagObj) { diagram .append('text') .text(title) - .attr('x', LEFT_MARGIN) - .attr('font-size', '4ex') + .attr('x', leftMargin) + .attr('font-size', titleFontSize) .attr('font-weight', 'bold') - .attr('y', 25); + .attr('y', 25) + .attr('fill', titleColor) + .attr('font-family', titleFontFamily); } const height = box.stopy - box.starty + 2 * conf.diagramMarginY; - const width = LEFT_MARGIN + box.stopx + 2 * conf.diagramMarginX; + const width = leftMargin + box.stopx + 2 * conf.diagramMarginX; configureSvgSize(diagram, height, width, conf.useMaxWidth); // Draw activity line diagram .append('line') - .attr('x1', LEFT_MARGIN) + .attr('x1', leftMargin) .attr('y1', conf.height * 4) // One section head + one task + margins - .attr('x2', width - LEFT_MARGIN - 4) // Subtract stroke width so arrow point is retained + .attr('x2', width - leftMargin - 4) // Subtract stroke width so arrow point is retained .attr('y2', conf.height * 4) .attr('stroke-width', 4) .attr('stroke', 'black') @@ -234,7 +311,7 @@ export const drawTasks = function (diagram, tasks, verticalPos) { } const section = { - x: i * conf.taskMargin + i * conf.width + LEFT_MARGIN, + x: i * conf.taskMargin + i * conf.width + leftMargin, y: 50, text: task.section, fill, @@ -258,7 +335,7 @@ export const drawTasks = function (diagram, tasks, verticalPos) { }, {}); // Add some rendering data to the object - task.x = i * conf.taskMargin + i * conf.width + LEFT_MARGIN; + task.x = i * conf.taskMargin + i * conf.width + leftMargin; task.y = taskPos; task.width = conf.diagramMarginX; task.height = conf.diagramMarginY; diff --git a/packages/mermaid/src/diagrams/xychart/chartBuilder/interfaces.ts b/packages/mermaid/src/diagrams/xychart/chartBuilder/interfaces.ts index 3d188895f..5f6f862ee 100644 --- a/packages/mermaid/src/diagrams/xychart/chartBuilder/interfaces.ts +++ b/packages/mermaid/src/diagrams/xychart/chartBuilder/interfaces.ts @@ -93,6 +93,7 @@ export interface XYChartConfig { titleFontSize: number; titlePadding: number; showTitle: boolean; + showDataLabel: boolean; xAxis: XYChartAxisConfig; yAxis: XYChartAxisConfig; chartOrientation: 'vertical' | 'horizontal'; diff --git a/packages/mermaid/src/diagrams/xychart/xychartDb.ts b/packages/mermaid/src/diagrams/xychart/xychartDb.ts index fb2435df2..9ad7cd420 100644 --- a/packages/mermaid/src/diagrams/xychart/xychartDb.ts +++ b/packages/mermaid/src/diagrams/xychart/xychartDb.ts @@ -195,6 +195,10 @@ function getChartConfig() { return xyChartConfig; } +function getXYChartData() { + return xyChartData; +} + const clear = function () { commonClear(); plotIndex = 0; @@ -226,4 +230,5 @@ export default { setTmpSVGG, getChartThemeConfig, getChartConfig, + getXYChartData, }; diff --git a/packages/mermaid/src/diagrams/xychart/xychartRenderer.ts b/packages/mermaid/src/diagrams/xychart/xychartRenderer.ts index 1f4d36e8a..b86c8556e 100644 --- a/packages/mermaid/src/diagrams/xychart/xychartRenderer.ts +++ b/packages/mermaid/src/diagrams/xychart/xychartRenderer.ts @@ -14,6 +14,7 @@ export const draw = (txt: string, id: string, _version: string, diagObj: Diagram const db = diagObj.db as typeof XYChartDB; const themeConfig = db.getChartThemeConfig(); const chartConfig = db.getChartConfig(); + const labelData = db.getXYChartData().plots[0].data.map((data) => data[1]); function getDominantBaseLine(horizontalPos: TextVerticalPos) { return horizontalPos === 'top' ? 'text-before-edge' : 'middle'; } @@ -49,6 +50,16 @@ export const draw = (txt: string, id: string, _version: string, diagObj: Diagram const groups: Record = {}; + interface BarItem { + data: { + x: number; + y: number; + width: number; + height: number; + }; + label: string; + } + function getGroup(gList: string[]) { let elem = group; let prefix = ''; @@ -87,6 +98,113 @@ export const draw = (txt: string, id: string, _version: string, diagObj: Diagram .attr('fill', (data) => data.fill) .attr('stroke', (data) => data.strokeFill) .attr('stroke-width', (data) => data.strokeWidth); + + if (chartConfig.showDataLabel) { + if (chartConfig.chartOrientation === 'horizontal') { + // Factor to approximate each character's width. + const charWidthFactor = 0.7; + + // Filter out bars that have zero width or height. + const validItems = shape.data + .map((d, i) => ({ data: d, label: labelData[i].toString() })) + .filter((item) => item.data.width > 0 && item.data.height > 0); + + // Helper function to check if the text fits horizontally with a 10px right margin. + function fitsHorizontally(item: BarItem, fontSize: number): boolean { + const { data, label } = item; + // Approximate the text width. + const textWidth: number = fontSize * label.length * charWidthFactor; + // The available width is the bar's width minus a 10px right margin. + return textWidth <= data.width - 10; + } + + // For each valid bar, start with an initial candidate font size (70% of the bar's height), + // then reduce it until the text fits horizontally. + const candidateFontSizes = validItems.map((item) => { + const { data } = item; + let fontSize = data.height * 0.7; + // Decrease fontSize until the text fits horizontally. + while (!fitsHorizontally(item, fontSize) && fontSize > 0) { + fontSize -= 1; + } + return fontSize; + }); + + // Choose the smallest candidate font size across all valid bars for uniformity. + const uniformFontSize = Math.floor(Math.min(...candidateFontSizes)); + + shapeGroup + .selectAll('text') + .data(validItems) + .enter() + .append('text') + .attr('x', (item) => item.data.x + item.data.width - 10) + .attr('y', (item) => item.data.y + item.data.height / 2) + .attr('text-anchor', 'end') + .attr('dominant-baseline', 'middle') + .attr('fill', 'black') + .attr('font-size', `${uniformFontSize}px`) + .text((item) => item.label); + } else { + const yOffset = 10; + + // filter out bars that have zero width or height. + const validItems = shape.data + .map((d, i) => ({ data: d, label: labelData[i].toString() })) + .filter((item) => item.data.width > 0 && item.data.height > 0); + + // Helper function that checks if the text with a given fontSize fits within the bar boundaries. + function fitsInBar(item: BarItem, fontSize: number, yOffset: number): boolean { + const { data, label } = item; + const charWidthFactor = 0.7; + const textWidth = fontSize * label.length * charWidthFactor; + + // Compute horizontal boundaries using the center. + const centerX = data.x + data.width / 2; + const leftEdge = centerX - textWidth / 2; + const rightEdge = centerX + textWidth / 2; + + // Check that text doesn't overflow horizontally. + const horizontalFits = leftEdge >= data.x && rightEdge <= data.x + data.width; + + // For vertical placement, we use 'dominant-baseline: hanging' so that y marks the top of the text. + // Thus, the bottom edge is y + yOffset + fontSize. + const verticalFits = data.y + yOffset + fontSize <= data.y + data.height; + + return horizontalFits && verticalFits; + } + + // For each valid item, start with a candidate font size based on the width, + // then reduce it until the text fits within both the horizontal and vertical boundaries. + const candidateFontSizes = validItems.map((item) => { + const { data, label } = item; + let fontSize = data.width / (label.length * 0.7); + + // Decrease the font size until the text fits or fontSize reaches 0. + while (!fitsInBar(item, fontSize, yOffset) && fontSize > 0) { + fontSize -= 1; + } + return fontSize; + }); + + // Choose the smallest candidate across all valid bars for uniformity. + const uniformFontSize = Math.floor(Math.min(...candidateFontSizes)); + + // Render text only for valid items. + shapeGroup + .selectAll('text') + .data(validItems) + .enter() + .append('text') + .attr('x', (item) => item.data.x + item.data.width / 2) + .attr('y', (item) => item.data.y + yOffset) + .attr('text-anchor', 'middle') + .attr('dominant-baseline', 'hanging') + .attr('fill', 'black') + .attr('font-size', `${uniformFontSize}px`) + .text((item) => item.label); + } + } break; case 'text': shapeGroup diff --git a/packages/mermaid/src/docs/config/8.6.0_docs.md b/packages/mermaid/src/docs/config/8.6.0_docs.md index efd29bfdc..342e05763 100644 --- a/packages/mermaid/src/docs/config/8.6.0_docs.md +++ b/packages/mermaid/src/docs/config/8.6.0_docs.md @@ -75,7 +75,7 @@ When deployed within code, init is called before the graph/diagram description. **for example**: -```mermaid +```mermaid-example %%{init: {"theme": "default", "logLevel": 1 }}%% graph LR a-->b diff --git a/packages/mermaid/src/docs/config/directives.md b/packages/mermaid/src/docs/config/directives.md index 0e211161c..017fc486b 100644 --- a/packages/mermaid/src/docs/config/directives.md +++ b/packages/mermaid/src/docs/config/directives.md @@ -88,7 +88,7 @@ Here the directive declaration will set the `logLevel` to `debug` and the `theme Note: You can use 'init' or 'initialize' as both are acceptable as init directives. Also note that `%%init%%` and `%%initialize%%` directives will be grouped together after they are parsed. -```mermaid +```mermaid-example %%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%% %%{initialize: { 'logLevel': 'fatal', "theme":'dark', 'startOnLoad': true } }%% ... diff --git a/packages/mermaid/src/docs/config/math.md b/packages/mermaid/src/docs/config/math.md index a53dceaf2..bb6556b6c 100644 --- a/packages/mermaid/src/docs/config/math.md +++ b/packages/mermaid/src/docs/config/math.md @@ -10,7 +10,7 @@ Note that at the moment, the only supported diagrams are below: ### Flowcharts -```mermaid +```mermaid-example graph LR A["$$x^2$$"] -->|"$$\sqrt{x+3}$$"| B("$$\frac{1}{2}$$") A -->|"$$\overbrace{a+b+c}^{\text{note}}$$"| C("$$\pi r^2$$") @@ -20,7 +20,7 @@ Note that at the moment, the only supported diagrams are below: ### Sequence -```mermaid +```mermaid-example sequenceDiagram autonumber participant 1 as $$\alpha$$ diff --git a/packages/mermaid/src/docs/config/theming.md b/packages/mermaid/src/docs/config/theming.md index 5643dc7fb..f9afb15b8 100644 --- a/packages/mermaid/src/docs/config/theming.md +++ b/packages/mermaid/src/docs/config/theming.md @@ -41,12 +41,6 @@ Example of `init` directive setting the `theme` to `forest`: a --> b ``` -```mermaid -%%{init: {'theme':'forest'}}%% - graph TD - a --> b -``` - > **Reminder**: the only theme that can be customized is the `base` theme. The following section covers how to use `themeVariables` for customizations. ## Customizing Themes with `themeVariables` @@ -91,36 +85,6 @@ Example of modifying `themeVariables` using the `init` directive: end ``` -```mermaid -%%{ - init: { - 'theme': 'base', - 'themeVariables': { - 'primaryColor': '#BB2528', - 'primaryTextColor': '#fff', - 'primaryBorderColor': '#7C0000', - 'lineColor': '#F8B229', - 'secondaryColor': '#006100', - 'tertiaryColor': '#fff' - } - } -}%% - graph TD - A[Christmas] -->|Get money| B(Go shopping) - B --> C{Let me think} - B --> G[/Another/] - C ==>|One| D[Laptop] - C -->|Two| E[iPhone] - C -->|Three| F[fa:fa-car Car] - subgraph section - C - D - E - F - G - end -``` - ## Color and Color Calculation To ensure diagram readability, the default value of certain variables is calculated or derived from other variables. For example, `primaryBorderColor` is derived from the `primaryColor` variable. So if the `primaryColor` variable is customized, Mermaid will adjust `primaryBorderColor` automatically. Adjustments can mean a color inversion, a hue change, a darkening/lightening by 10%, etc. diff --git a/packages/mermaid/src/docs/ecosystem/integrations-community.md b/packages/mermaid/src/docs/ecosystem/integrations-community.md index 84040a3cd..c756f3eeb 100644 --- a/packages/mermaid/src/docs/ecosystem/integrations-community.md +++ b/packages/mermaid/src/docs/ecosystem/integrations-community.md @@ -35,6 +35,7 @@ To add an integration to this list, see the [Integrations - create page](./integ - [Mermaid Charts & Diagrams for Jira](https://marketplace.atlassian.com/apps/1224537/) - [Mermaid for Jira Cloud - Draw UML diagrams easily](https://marketplace.atlassian.com/apps/1223053/mermaid-for-jira-cloud-draw-uml-diagrams-easily?hosting=cloud&tab=overview) - [CloudScript.io Mermaid Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview) + - [Mermaid plus for Confluence](https://marketplace.atlassian.com/apps/1236814/mermaid-plus-for-confluence?hosting=cloud&tab=overview) - [Azure Devops](https://learn.microsoft.com/en-us/azure/devops/project/wiki/markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) ✅ - [Deepdwn](https://billiam.itch.io/deepdwn) ✅ - [Doctave](https://www.doctave.com/) ✅ @@ -262,7 +263,5 @@ Communication tools and platforms - [reveal.js-mermaid-plugin](https://github.com/ludwick/reveal.js-mermaid-plugin) - [Reveal CK](https://github.com/jedcn/reveal-ck) - [reveal-ck-mermaid-plugin](https://github.com/tmtm/reveal-ck-mermaid-plugin) -- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic) -- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server) diff --git a/packages/mermaid/src/docs/intro/getting-started.md b/packages/mermaid/src/docs/intro/getting-started.md index 574881c4f..8e6482ae2 100644 --- a/packages/mermaid/src/docs/intro/getting-started.md +++ b/packages/mermaid/src/docs/intro/getting-started.md @@ -41,7 +41,7 @@ In the `Code` panel, write or edit Mermaid code, and instantly `Preview` the ren Here is an example of Mermaid code and its rendered result: -```mermaid +```mermaid-example graph TD A[Enter Chart Definition] --> B(Preview) B --> C{decide} diff --git a/packages/mermaid/src/docs/intro/syntax-reference.md b/packages/mermaid/src/docs/intro/syntax-reference.md index 14c56370a..b439c26bc 100644 --- a/packages/mermaid/src/docs/intro/syntax-reference.md +++ b/packages/mermaid/src/docs/intro/syntax-reference.md @@ -83,7 +83,7 @@ Mermaid offers a variety of styles or “looks” for your diagrams, allowing yo You can select a look by adding the look parameter in the metadata section of your Mermaid diagram code. Here’s an example: -```mermaid +```mermaid-example --- config: look: handDrawn @@ -108,7 +108,7 @@ In addition to customizing the look of your diagrams, Mermaid Chart now allows y You can specify the layout algorithm directly in the metadata section of your Mermaid diagram code. Here’s an example: -```mermaid +```mermaid-example --- config: layout: elk diff --git a/packages/mermaid/src/docs/package.json b/packages/mermaid/src/docs/package.json index 473cb204a..fb591f9d3 100644 --- a/packages/mermaid/src/docs/package.json +++ b/packages/mermaid/src/docs/package.json @@ -17,7 +17,7 @@ }, "dependencies": { "@mdi/font": "^7.4.47", - "@vueuse/core": "^12.7.0", + "@vueuse/core": "^13.1.0", "font-awesome": "^4.7.0", "jiti": "^2.4.2", "mermaid": "workspace:^", @@ -26,7 +26,7 @@ "devDependencies": { "@iconify-json/carbon": "^1.1.37", "@unocss/reset": "^66.0.0", - "@vite-pwa/vitepress": "^0.5.3", + "@vite-pwa/vitepress": "^1.0.0", "@vitejs/plugin-vue": "^5.0.5", "fast-glob": "^3.3.3", "https-localhost": "^4.7.1", @@ -34,7 +34,7 @@ "unocss": "^66.0.0", "unplugin-vue-components": "^28.4.0", "vite": "^6.1.1", - "vite-plugin-pwa": "^0.21.1", + "vite-plugin-pwa": "^1.0.0", "vitepress": "1.6.3", "workbox-window": "^7.3.0" } diff --git a/packages/mermaid/src/docs/syntax/block.md b/packages/mermaid/src/docs/syntax/block.md index 5b8aa1c99..396f39148 100644 --- a/packages/mermaid/src/docs/syntax/block.md +++ b/packages/mermaid/src/docs/syntax/block.md @@ -7,7 +7,7 @@ outline: 'deep' # shows all h3 headings in outline in Vitepress ## Introduction to Block Diagrams -```mermaid +```mermaid-example block-beta columns 1 db(("DB")) diff --git a/packages/mermaid/src/docs/syntax/classDiagram.md b/packages/mermaid/src/docs/syntax/classDiagram.md index 552670d3f..f2cec2ec5 100644 --- a/packages/mermaid/src/docs/syntax/classDiagram.md +++ b/packages/mermaid/src/docs/syntax/classDiagram.md @@ -248,7 +248,7 @@ classE o-- classF : aggregation Relations can logically represent an N:M association: -```mermaid +```mermaid-example classDiagram Animal <|--|> Zebra ``` diff --git a/packages/mermaid/src/docs/syntax/examples.md b/packages/mermaid/src/docs/syntax/examples.md index 64e85815f..48af4dc77 100644 --- a/packages/mermaid/src/docs/syntax/examples.md +++ b/packages/mermaid/src/docs/syntax/examples.md @@ -141,7 +141,7 @@ sequenceDiagram ## A commit flow diagram. -```mermaid +```mermaid-example gitGraph: commit "Ashish" branch newbranch diff --git a/packages/mermaid/src/docs/syntax/flowchart.md b/packages/mermaid/src/docs/syntax/flowchart.md index 2ddad4795..f13dafba4 100644 --- a/packages/mermaid/src/docs/syntax/flowchart.md +++ b/packages/mermaid/src/docs/syntax/flowchart.md @@ -721,7 +721,7 @@ To give an edge an ID, prepend the edge syntax with the ID followed by an `@` ch ```mermaid flowchart LR - A e1@–> B + A e1@--> B ``` In this example, `e1` is the ID of the edge connecting `A` to `B`. You can then use this ID in later definitions or style statements, just like with nodes. @@ -746,7 +746,7 @@ In the initial version, two animation speeds are supported: `fast` and `slow`. S ```mermaid flowchart LR - A e1@–> B + A e1@--> B e1@{ animation: fast } ``` @@ -758,7 +758,7 @@ You can also animate edges by assigning a class to them and then defining animat ```mermaid flowchart LR - A e1@–> B + A e1@--> B classDef animate stroke-dasharray: 9,5,stroke-dashoffset: 900,animation: dash 25s linear infinite; class e1 animate ``` diff --git a/packages/mermaid/src/docs/syntax/gantt.md b/packages/mermaid/src/docs/syntax/gantt.md index eab35d09f..de54363bc 100644 --- a/packages/mermaid/src/docs/syntax/gantt.md +++ b/packages/mermaid/src/docs/syntax/gantt.md @@ -259,7 +259,7 @@ gantt The compact mode allows you to display multiple tasks in the same row. Compact mode can be enabled for a gantt chart by setting the display mode of the graph via preceding YAML settings. -```mermaid +```mermaid-example --- displayMode: compact --- diff --git a/packages/mermaid/src/docs/syntax/gitgraph.md b/packages/mermaid/src/docs/syntax/gitgraph.md index 2b3f1a88b..53840b8f7 100644 --- a/packages/mermaid/src/docs/syntax/gitgraph.md +++ b/packages/mermaid/src/docs/syntax/gitgraph.md @@ -290,7 +290,13 @@ Sometimes you may want to hide the branch names and lines from the diagram. You Usage example: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': false}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: false +--- gitGraph commit branch hotfix @@ -346,7 +352,13 @@ You can change the layout of the commit labels by using the `rotateCommitLabel` Usage example: Rotated commit labels ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'rotateCommitLabel': true}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + rotateCommitLabel: true +--- gitGraph commit id: "feat(api): ..." commit id: "a" @@ -367,7 +379,13 @@ gitGraph Usage example: Horizontal commit labels ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'rotateCommitLabel': false}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + rotateCommitLabel: false +--- gitGraph commit id: "feat(api): ..." commit id: "a" @@ -392,7 +410,14 @@ Sometimes you may want to hide the commit labels from the diagram. You can do th Usage example: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': false,'showCommitLabel': false}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: false + showCommitLabel: false +--- gitGraph commit branch hotfix @@ -444,7 +469,15 @@ Sometimes you may want to customize the name of the main/default branch. You can Usage example: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchName': 'MetroLine1'}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: true + showCommitLabel: true + mainBranchName: 'MetroLine1' +--- gitGraph commit id:"NewYork" commit id:"Dallas" @@ -486,7 +519,14 @@ To fully control the order of all the branches, you must define `order` for all Usage example: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true, 'showCommitLabel':true}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: true + showCommitLabel: true +--- gitGraph commit branch test1 order: 3 @@ -500,7 +540,15 @@ Look at the diagram, all the branches are following the order defined. Usage example: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true, 'showCommitLabel':true,'mainBranchOrder': 2}} }%% +--- +config: + logLevel: 'debug' + theme: 'base' + gitGraph: + showBranches: true + showCommitLabel: true + mainBranchOrder: 2 +--- gitGraph commit branch test1 order: 3 @@ -652,7 +700,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ### Base Theme ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'base' } }%% +--- +config: + logLevel: 'debug' + theme: 'base' +--- gitGraph commit branch hotfix @@ -700,7 +752,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ### Forest Theme ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%% +--- +config: + logLevel: 'debug' + theme: 'forest' +--- gitGraph commit branch hotfix @@ -748,7 +804,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ### Default Theme ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%% +--- +config: + logLevel: 'debug' + theme: 'default' +--- gitGraph commit type:HIGHLIGHT branch hotfix @@ -796,7 +856,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ### Dark Theme ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%% +--- +config: + logLevel: 'debug' + theme: 'dark' +--- gitGraph commit branch hotfix @@ -844,7 +908,11 @@ Let's put them to use, and see how our sample diagram looks in different themes: ### Neutral Theme ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +--- +config: + logLevel: 'debug' + theme: 'neutral' +--- gitGraph commit branch hotfix @@ -898,7 +966,11 @@ For understanding let us take a sample diagram with theme `default`, the default See how the default theme is used to set the colors for the branches: ```mermaid-example -%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%% +--- +config: + logLevel: 'debug' + theme: 'default' +--- gitGraph commit branch develop @@ -929,16 +1001,20 @@ Example: Now let's override the default values for the `git0` to `git3` variables: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'git0': '#ff0000', - 'git1': '#00ff00', - 'git2': '#0000ff', - 'git3': '#ff00ff', - 'git4': '#00ffff', - 'git5': '#ffff00', - 'git6': '#ff00ff', - 'git7': '#00ffff' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + 'git0': '#ff0000' + 'git1': '#00ff00' + 'git2': '#0000ff' + 'git3': '#ff00ff' + 'git4': '#00ffff' + 'git5': '#ffff00' + 'git6': '#ff00ff' + 'git7': '#00ffff' +--- gitGraph commit branch develop @@ -965,18 +1041,22 @@ Lets see how the default theme is used to set the colors for the branch labels: Now let's override the default values for the `gitBranchLabel0` to `gitBranchLabel2` variables: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'gitBranchLabel0': '#ffffff', - 'gitBranchLabel1': '#ffffff', - 'gitBranchLabel2': '#ffffff', - 'gitBranchLabel3': '#ffffff', - 'gitBranchLabel4': '#ffffff', - 'gitBranchLabel5': '#ffffff', - 'gitBranchLabel6': '#ffffff', - 'gitBranchLabel7': '#ffffff', - 'gitBranchLabel8': '#ffffff', - 'gitBranchLabel9': '#ffffff' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + 'gitBranchLabel0': '#ffffff' + 'gitBranchLabel1': '#ffffff' + 'gitBranchLabel2': '#ffffff' + 'gitBranchLabel3': '#ffffff' + 'gitBranchLabel4': '#ffffff' + 'gitBranchLabel5': '#ffffff' + 'gitBranchLabel6': '#ffffff' + 'gitBranchLabel7': '#ffffff' + 'gitBranchLabel8': '#ffffff' + 'gitBranchLabel9': '#ffffff' +--- gitGraph checkout main branch branch1 @@ -1002,10 +1082,14 @@ Example: Now let's override the default values for the `commitLabelColor` to `commitLabelBackground` variables: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'commitLabelColor': '#ff0000', - 'commitLabelBackground': '#00ff00' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + commitLabelColor: '#ff0000' + commitLabelBackground: '#00ff00' +--- gitGraph commit branch develop @@ -1031,11 +1115,15 @@ Example: Now let's override the default values for the `commitLabelFontSize` variable: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'commitLabelColor': '#ff0000', - 'commitLabelBackground': '#00ff00', - 'commitLabelFontSize': '16px' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + commitLabelColor: '#ff0000' + commitLabelBackground: '#00ff00' + commitLabelFontSize: '16px' +--- gitGraph commit branch develop @@ -1061,11 +1149,15 @@ Example: Now let's override the default values for the `tagLabelFontSize` variable: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'commitLabelColor': '#ff0000', - 'commitLabelBackground': '#00ff00', - 'tagLabelFontSize': '16px' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + commitLabelColor: '#ff0000' + commitLabelBackground: '#00ff00' + tagLabelFontSize: '16px' +--- gitGraph commit branch develop @@ -1090,11 +1182,15 @@ Example: Now let's override the default values for the `tagLabelColor`, `tagLabelBackground` and to `tagLabelBorder` variables: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'tagLabelColor': '#ff0000', - 'tagLabelBackground': '#00ff00', - 'tagLabelBorder': '#0000ff' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + tagLabelColor: '#ff0000' + tagLabelBackground: '#00ff00' + tagLabelBorder: '#0000ff' +--- gitGraph commit branch develop @@ -1121,9 +1217,13 @@ Example: Now let's override the default values for the `git0` to `git3` variables: ```mermaid-example - %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': { - 'gitInv0': '#ff0000' - } } }%% +--- +config: + logLevel: 'debug' + theme: 'default' + themeVariables: + 'gitInv0': '#ff0000' +--- gitGraph commit branch develop diff --git a/packages/mermaid/src/docs/syntax/sequenceDiagram.md b/packages/mermaid/src/docs/syntax/sequenceDiagram.md index 2357b9bf4..3087eb743 100644 --- a/packages/mermaid/src/docs/syntax/sequenceDiagram.md +++ b/packages/mermaid/src/docs/syntax/sequenceDiagram.md @@ -442,7 +442,7 @@ sequenceDiagram Comments can be entered within a sequence diagram, which will be ignored by the parser. Comments need to be on their own line, and must be prefaced with `%%` (double percent signs). Any text after the start of the comment to the next newline will be treated as a comment, including any diagram syntax -```mermaid +```mermaid-example sequenceDiagram Alice->>John: Hello John, how are you? %% this is a comment diff --git a/packages/mermaid/src/docs/syntax/xyChart.md b/packages/mermaid/src/docs/syntax/xyChart.md index e6e969462..96a56e2a7 100644 --- a/packages/mermaid/src/docs/syntax/xyChart.md +++ b/packages/mermaid/src/docs/syntax/xyChart.md @@ -95,17 +95,18 @@ xychart-beta ## Chart Configurations -| Parameter | Description | Default value | -| ------------------------ | ---------------------------------------------- | :-----------: | -| width | Width of the chart | 700 | -| height | Height of the chart | 500 | -| titlePadding | Top and Bottom padding of the title | 10 | -| titleFontSize | Title font size | 20 | -| showTitle | Title to be shown or not | true | -| xAxis | xAxis configuration | AxisConfig | -| yAxis | yAxis configuration | AxisConfig | -| chartOrientation | 'vertical' or 'horizontal' | 'vertical' | -| plotReservedSpacePercent | Minimum space plots will take inside the chart | 50 | +| Parameter | Description | Default value | +| ------------------------ | ------------------------------------------------------------- | :-----------: | +| width | Width of the chart | 700 | +| height | Height of the chart | 500 | +| titlePadding | Top and Bottom padding of the title | 10 | +| titleFontSize | Title font size | 20 | +| showTitle | Title to be shown or not | true | +| xAxis | xAxis configuration | AxisConfig | +| yAxis | yAxis configuration | AxisConfig | +| chartOrientation | 'vertical' or 'horizontal' | 'vertical' | +| plotReservedSpacePercent | Minimum space plots will take inside the chart | 50 | +| showDataLabel | Should show the value corresponding to the bar within the bar | false | ### AxisConfig @@ -152,6 +153,7 @@ config: xyChart: width: 900 height: 600 + showDataLabel: true themeVariables: xyChart: titleColor: "#ff0000" diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts index 64f4b8d60..6b112b90e 100644 --- a/packages/mermaid/src/mermaidAPI.spec.ts +++ b/packages/mermaid/src/mermaidAPI.spec.ts @@ -31,6 +31,7 @@ vi.mock('./diagrams/xychart/xychartRenderer.js'); vi.mock('./diagrams/requirement/requirementRenderer.js'); vi.mock('./diagrams/sequence/sequenceRenderer.js'); vi.mock('./diagrams/radar/renderer.js'); +vi.mock('./diagrams/architecture/architectureRenderer.js'); // ------------------------------------- @@ -799,6 +800,7 @@ graph TD;A--x|text including URL space|B;`) { textDiagramType: 'sequenceDiagram', expectedType: 'sequence' }, { textDiagramType: 'stateDiagram-v2', expectedType: 'stateDiagram' }, { textDiagramType: 'radar-beta', expectedType: 'radar' }, + { textDiagramType: 'architecture-beta', expectedType: 'architecture' }, ]; describe('accessibility', () => { diff --git a/packages/mermaid/src/rendering-util/rendering-elements/edges.js b/packages/mermaid/src/rendering-util/rendering-elements/edges.js index 434c53856..ce4244ff2 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/edges.js +++ b/packages/mermaid/src/rendering-util/rendering-elements/edges.js @@ -562,7 +562,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod } let svgPath; let linePath = lineFunction(lineData); - const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style]; + const edgeStyles = Array.isArray(edge.style) ? edge.style : edge.style ? [edge.style] : []; let strokeColor = edgeStyles.find((style) => style?.startsWith('stroke:')); if (edge.look === 'handDrawn') { diff --git a/packages/mermaid/src/schemas/config.schema.yaml b/packages/mermaid/src/schemas/config.schema.yaml index e36b00bf9..9c8e0bd33 100644 --- a/packages/mermaid/src/schemas/config.schema.yaml +++ b/packages/mermaid/src/schemas/config.schema.yaml @@ -1228,6 +1228,10 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file) type: number default: 10 minimum: 0 + showDataLabel: + description: Should show the value corresponding to the bar within the bar + type: boolean + default: false showTitle: description: Should show the chart title type: boolean @@ -1484,6 +1488,9 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file) - bottomMarginAdj - useMaxWidth - rightAngles + - titleColor + - titleFontFamily + - titleFontSize properties: diagramMarginX: $ref: '#/$defs/C4DiagramConfig/properties/diagramMarginX' @@ -1496,6 +1503,10 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file) type: integer default: 150 minimum: 0 + maxLabelWidth: + description: Maximum width of actor labels + type: integer + default: 360 width: description: Width of actor boxes type: integer @@ -1584,6 +1595,18 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file) items: type: string default: ['#fff'] + titleColor: + description: Color of the title text in Journey Diagrams + type: string + default: '' + titleFontFamily: + description: Font family to be used for the title text in Journey Diagrams + type: string + default: '"trebuchet ms", verdana, arial, sans-serif' + titleFontSize: + description: Font size to be used for the title text in Journey Diagrams + type: string + default: '4ex' TimelineDiagramConfig: # added by https://github.com/mermaid-js/mermaid/commit/0d5246fbc730bf15463d7183fe4400a1e2fc492c diff --git a/packages/parser/src/language/architecture/arch.langium b/packages/parser/src/language/architecture/arch.langium new file mode 100644 index 000000000..7b3a2fe22 --- /dev/null +++ b/packages/parser/src/language/architecture/arch.langium @@ -0,0 +1,2 @@ +terminal ARCH_ICON: /\([\w-:]+\)/; +terminal ARCH_TITLE: /\[[\w ]+\]/; \ No newline at end of file diff --git a/packages/parser/src/language/architecture/architecture.langium b/packages/parser/src/language/architecture/architecture.langium index 11af26243..2e97372bd 100644 --- a/packages/parser/src/language/architecture/architecture.langium +++ b/packages/parser/src/language/architecture/architecture.langium @@ -1,14 +1,15 @@ grammar Architecture import "../common/common"; +import "arch"; entry Architecture: NEWLINE* "architecture-beta" ( - NEWLINE* TitleAndAccessibilities - | NEWLINE* Statement* - | NEWLINE* - ) + NEWLINE + | TitleAndAccessibilities + | Statement + )* ; fragment Statement: @@ -31,25 +32,21 @@ fragment Arrow: ; Group: - 'group' id=ARCH_ID icon=ARCH_ICON? title=ARCH_TITLE? ('in' in=ARCH_ID)? EOL + 'group' id=ID icon=ARCH_ICON? title=ARCH_TITLE? ('in' in=ID)? EOL ; Service: - 'service' id=ARCH_ID (iconText=ARCH_TEXT_ICON | icon=ARCH_ICON)? title=ARCH_TITLE? ('in' in=ARCH_ID)? EOL + 'service' id=ID (iconText=STRING | icon=ARCH_ICON)? title=ARCH_TITLE? ('in' in=ID)? EOL ; Junction: - 'junction' id=ARCH_ID ('in' in=ARCH_ID)? EOL + 'junction' id=ID ('in' in=ID)? EOL ; Edge: - lhsId=ARCH_ID lhsGroup?=ARROW_GROUP? Arrow rhsId=ARCH_ID rhsGroup?=ARROW_GROUP? EOL + lhsId=ID lhsGroup?=ARROW_GROUP? Arrow rhsId=ID rhsGroup?=ARROW_GROUP? EOL ; terminal ARROW_DIRECTION: 'L' | 'R' | 'T' | 'B'; -terminal ARCH_ID: /[\w]+/; -terminal ARCH_TEXT_ICON: /\("[^"]+"\)/; -terminal ARCH_ICON: /\([\w-:]+\)/; -terminal ARCH_TITLE: /\[[\w ]+\]/; terminal ARROW_GROUP: /\{group\}/; terminal ARROW_INTO: /<|>/; diff --git a/packages/parser/src/language/common/common.langium b/packages/parser/src/language/common/common.langium index 7989de193..b74ffc34d 100644 --- a/packages/parser/src/language/common/common.langium +++ b/packages/parser/src/language/common/common.langium @@ -1,22 +1,35 @@ -interface Common { - accDescr?: string; - accTitle?: string; - title?: string; -} - -fragment TitleAndAccessibilities: - ((accDescr=ACC_DESCR | accTitle=ACC_TITLE | title=TITLE) EOL)+ -; +// Base terminals and fragments for common language constructs +// Terminal Precedence: Lazy to Greedy +// When imported, the terminals are considered after the terminals in the importing grammar +// Note: Hence, to add a terminal greedier than the common terminals, import it separately after the common import fragment EOL returns string: NEWLINE+ | EOF ; -terminal NEWLINE: /\r?\n/; +fragment TitleAndAccessibilities: + ((accDescr=ACC_DESCR | accTitle=ACC_TITLE | title=TITLE) EOL)+ +; + +terminal BOOLEAN returns boolean: 'true' | 'false'; + terminal ACC_DESCR: /[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/; terminal ACC_TITLE: /[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/; terminal TITLE: /[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/; +terminal FLOAT returns number: /[0-9]+\.[0-9]+(?!\.)/; +terminal INT returns number: /0|[1-9][0-9]*(?!\.)/; +terminal NUMBER returns number: FLOAT | INT; + +terminal STRING returns string: /"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/; + +// Alphanumerics with underscores and dashes +// Must start with an alphanumeric or an underscore +// Cant end with a dash +terminal ID returns string: /[\w]([-\w]*\w)?/; + +terminal NEWLINE: /\r?\n/; + hidden terminal WHITESPACE: /[\t ]+/; hidden terminal YAML: /---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/; hidden terminal DIRECTIVE: /[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/; diff --git a/packages/parser/src/language/gitGraph/gitGraph.langium b/packages/parser/src/language/gitGraph/gitGraph.langium index 1571ebba8..5a4b0596c 100644 --- a/packages/parser/src/language/gitGraph/gitGraph.langium +++ b/packages/parser/src/language/gitGraph/gitGraph.langium @@ -1,39 +1,15 @@ grammar GitGraph - -interface Common { - accDescr?: string; - accTitle?: string; - title?: string; -} - -fragment TitleAndAccessibilities: - ((accDescr=ACC_DESCR | accTitle=ACC_TITLE | title=TITLE) EOL)+ -; - -fragment EOL returns string: - NEWLINE+ | EOF -; - -terminal NEWLINE: /\r?\n/; -terminal ACC_DESCR: /[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/; -terminal ACC_TITLE: /[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/; -terminal TITLE: /[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/; - -hidden terminal WHITESPACE: /[\t ]+/; -hidden terminal YAML: /---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/; -hidden terminal DIRECTIVE: /[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/; -hidden terminal SINGLE_LINE_COMMENT: /[\t ]*%%[^\n\r]*/; +import "../common/common"; +import "reference"; entry GitGraph: NEWLINE* ('gitGraph' | 'gitGraph' ':' | 'gitGraph:' | ('gitGraph' Direction ':')) - NEWLINE* ( - NEWLINE* - (TitleAndAccessibilities | - statements+=Statement | - NEWLINE)* - ) + NEWLINE + | TitleAndAccessibilities + | statements+=Statement + )* ; Statement @@ -56,12 +32,12 @@ Commit: |'type:' type=('NORMAL' | 'REVERSE' | 'HIGHLIGHT') )* EOL; Branch: - 'branch' name=(ID|STRING) + 'branch' name=(REFERENCE|STRING) ('order:' order=INT)? EOL; Merge: - 'merge' branch=(ID|STRING) + 'merge' branch=(REFERENCE|STRING) ( 'id:' id=STRING |'tag:' tags+=STRING @@ -69,7 +45,7 @@ Merge: )* EOL; Checkout: - ('checkout'|'switch') branch=(ID|STRING) EOL; + ('checkout'|'switch') branch=(REFERENCE|STRING) EOL; CherryPicking: 'cherry-pick' @@ -78,10 +54,3 @@ CherryPicking: |'tag:' tags+=STRING |'parent:' parent=STRING )* EOL; - - - -terminal INT returns number: /[0-9]+(?=\s)/; -terminal ID returns string: /\w([-\./\w]*[-\w])?/; -terminal STRING: /"[^"]*"|'[^']*'/; - diff --git a/packages/parser/src/language/gitGraph/reference.langium b/packages/parser/src/language/gitGraph/reference.langium new file mode 100644 index 000000000..6e1af5863 --- /dev/null +++ b/packages/parser/src/language/gitGraph/reference.langium @@ -0,0 +1,4 @@ +// Alphanumerics with underscores, dashes, slashes, and dots +// Must start with an alphanumeric or an underscore +// Cant end with a dash, slash, or dot +terminal REFERENCE returns string: /\w([-\./\w]*[-\w])?/; \ No newline at end of file diff --git a/packages/parser/src/language/index.ts b/packages/parser/src/language/index.ts index e3aa5c68c..aa0c0f703 100644 --- a/packages/parser/src/language/index.ts +++ b/packages/parser/src/language/index.ts @@ -12,7 +12,6 @@ export { Commit, Merge, Statement, - isCommon, isInfo, isPacket, isPacketBlock, diff --git a/packages/parser/src/language/packet/packet.langium b/packages/parser/src/language/packet/packet.langium index ad30f8df2..91d6501ed 100644 --- a/packages/parser/src/language/packet/packet.langium +++ b/packages/parser/src/language/packet/packet.langium @@ -5,15 +5,12 @@ entry Packet: NEWLINE* "packet-beta" ( - NEWLINE* TitleAndAccessibilities blocks+=PacketBlock* - | NEWLINE+ blocks+=PacketBlock+ - | NEWLINE* - ) + TitleAndAccessibilities + | blocks+=PacketBlock + | NEWLINE + )* ; PacketBlock: start=INT('-' end=INT)? ':' label=STRING EOL -; - -terminal INT returns number: /0|[1-9][0-9]*/; -terminal STRING: /"[^"]*"|'[^']*'/; +; \ No newline at end of file diff --git a/packages/parser/src/language/pie/pie.langium b/packages/parser/src/language/pie/pie.langium index 2bbf967e1..a80caa81f 100644 --- a/packages/parser/src/language/pie/pie.langium +++ b/packages/parser/src/language/pie/pie.langium @@ -5,15 +5,12 @@ entry Pie: NEWLINE* "pie" showData?="showData"? ( - NEWLINE* TitleAndAccessibilities sections+=PieSection* - | NEWLINE+ sections+=PieSection+ - | NEWLINE* - ) + TitleAndAccessibilities + | sections+=PieSection + | NEWLINE + )* ; PieSection: - label=PIE_SECTION_LABEL ":" value=PIE_SECTION_VALUE EOL + label=STRING ":" value=NUMBER EOL ; - -terminal PIE_SECTION_LABEL: /"[^"]+"/; -terminal PIE_SECTION_VALUE returns number: /(0|[1-9][0-9]*)(\.[0-9]+)?/; diff --git a/packages/parser/src/language/radar/radar.langium b/packages/parser/src/language/radar/radar.langium index f0ecd13cd..8aa9cb0ff 100644 --- a/packages/parser/src/language/radar/radar.langium +++ b/packages/parser/src/language/radar/radar.langium @@ -1,31 +1,5 @@ grammar Radar -// import "../common/common"; -// Note: The import statement breaks TitleAndAccessibilities probably because of terminal order definition -// TODO: May need to change the common.langium to fix this - -interface Common { - accDescr?: string; - accTitle?: string; - title?: string; -} - -fragment TitleAndAccessibilities: - ((accDescr=ACC_DESCR | accTitle=ACC_TITLE | title=TITLE) EOL)+ -; - -fragment EOL returns string: - NEWLINE+ | EOF -; - -terminal NEWLINE: /\r?\n/; -terminal ACC_DESCR: /[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/; -terminal ACC_TITLE: /[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/; -terminal TITLE: /[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/; - -hidden terminal WHITESPACE: /[\t ]+/; -hidden terminal YAML: /---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/; -hidden terminal DIRECTIVE: /[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/; -hidden terminal SINGLE_LINE_COMMENT: /[\t ]*%%[^\n\r]*/; +import "../common/common"; entry Radar: NEWLINE* @@ -76,14 +50,6 @@ Option: | name='min' value=NUMBER | name='graticule' value=GRATICULE ) -; +; - -terminal NUMBER returns number: /(0|[1-9][0-9]*)(\.[0-9]+)?/; - -terminal BOOLEAN returns boolean: 'true' | 'false'; - -terminal GRATICULE returns string: 'circle' | 'polygon'; - -terminal ID returns string: /[a-zA-Z_][a-zA-Z0-9\-_]*/; -terminal STRING: /"[^"]*"|'[^']*'/; \ No newline at end of file +terminal GRATICULE returns string: 'circle' | 'polygon'; \ No newline at end of file diff --git a/packages/parser/tests/architecture.test.ts b/packages/parser/tests/architecture.test.ts new file mode 100644 index 000000000..4dcce17d3 --- /dev/null +++ b/packages/parser/tests/architecture.test.ts @@ -0,0 +1,88 @@ +import { describe, expect, it } from 'vitest'; + +import { Architecture } from '../src/language/index.js'; +import { expectNoErrorsOrAlternatives, architectureParse as parse } from './test-util.js'; + +describe('architecture', () => { + describe('should handle architecture definition', () => { + it.each([ + `architecture-beta`, + ` architecture-beta `, + `\tarchitecture-beta\t`, + ` + \tarchitecture-beta + `, + ])('should handle regular architecture', (context: string) => { + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Architecture); + }); + }); + + describe('should handle TitleAndAccessibilities', () => { + it.each([ + `architecture-beta title sample title`, + ` architecture-beta title sample title `, + `\tarchitecture-beta\ttitle sample title\t`, + `architecture-beta + \ttitle sample title + `, + ])('should handle regular architecture + title in same line', (context: string) => { + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Architecture); + + const { title } = result.value; + expect(title).toBe('sample title'); + }); + + it.each([ + `architecture-beta + title sample title`, + `architecture-beta + title sample title + `, + ])('should handle regular architecture + title in next line', (context: string) => { + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Architecture); + + const { title } = result.value; + expect(title).toBe('sample title'); + }); + + it('should handle regular architecture + title + accTitle + accDescr', () => { + const context = `architecture-beta + title sample title + accTitle: sample accTitle + accDescr: sample accDescr + `; + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Architecture); + + const { title, accTitle, accDescr } = result.value; + expect(title).toBe('sample title'); + expect(accTitle).toBe('sample accTitle'); + expect(accDescr).toBe('sample accDescr'); + }); + + it('should handle regular architecture + title + accTitle + multi-line accDescr', () => { + const context = `architecture-beta + title sample title + accTitle: sample accTitle + accDescr { + sample accDescr + } + `; + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Architecture); + + const { title, accTitle, accDescr } = result.value; + expect(title).toBe('sample title'); + expect(accTitle).toBe('sample accTitle'); + expect(accDescr).toBe('sample accDescr'); + }); + }); +}); diff --git a/packages/parser/tests/gitGraph.test.ts b/packages/parser/tests/gitGraph.test.ts index 2d7c21bbe..f7f302236 100644 --- a/packages/parser/tests/gitGraph.test.ts +++ b/packages/parser/tests/gitGraph.test.ts @@ -63,6 +63,12 @@ describe('Parsing Branch Statements', () => { expect(branch.name).toBe('master'); }); + it('should parse a branch name starting with numbers', () => { + const result = parse(`gitGraph\n commit\n branch 1.0.1\n`); + const branch = result.value.statements[1] as Branch; + expect(branch.name).toBe('1.0.1'); + }); + it('should parse a branch with an order property', () => { const result = parse(`gitGraph\n commit\n branch feature order:1\n`); const branch = result.value.statements[1] as Branch; diff --git a/packages/parser/tests/pie.test.ts b/packages/parser/tests/pie.test.ts index 43e9a374f..caa7cc528 100644 --- a/packages/parser/tests/pie.test.ts +++ b/packages/parser/tests/pie.test.ts @@ -4,226 +4,247 @@ import { Pie } from '../src/language/index.js'; import { expectNoErrorsOrAlternatives, pieParse as parse } from './test-util.js'; describe('pie', () => { - it.each([ - `pie`, - ` pie `, - `\tpie\t`, - ` + describe('should handle pie definition with or without showData', () => { + it.each([ + `pie`, + ` pie `, + `\tpie\t`, + ` \tpie `, - ])('should handle regular pie', (context: string) => { - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); - }); + ])('should handle regular pie', (context: string) => { + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); + }); - it.each([ - `pie showData`, - ` pie showData `, - `\tpie\tshowData\t`, - ` + it.each([ + `pie showData`, + ` pie showData `, + `\tpie\tshowData\t`, + ` pie\tshowData `, - ])('should handle regular showData', (context: string) => { - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); + ])('should handle regular showData', (context: string) => { + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); - const { showData } = result.value; - expect(showData).toBeTruthy(); + const { showData } = result.value; + expect(showData).toBeTruthy(); + }); }); + describe('should handle TitleAndAccessibilities', () => { + describe('should handle TitleAndAccessibilities without showData', () => { + it.each([ + `pie title sample title`, + ` pie title sample title `, + `\tpie\ttitle sample title\t`, + `pie + \ttitle sample title + `, + ])('should handle regular pie + title in same line', (context: string) => { + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); - it.each([ - `pie title sample title`, - ` pie title sample title `, - `\tpie\ttitle sample title\t`, - `pie - \ttitle sample title - `, - ])('should handle regular pie + title in same line', (context: string) => { - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); + const { title } = result.value; + expect(title).toBe('sample title'); + }); - const { title } = result.value; - expect(title).toBe('sample title'); - }); - - it.each([ - `pie - title sample title`, - `pie - title sample title - `, - `pie - title sample title`, - `pie - title sample title - `, - ])('should handle regular pie + title in different line', (context: string) => { - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); - - const { title } = result.value; - expect(title).toBe('sample title'); - }); - - it.each([ - `pie showData title sample title`, - `pie showData title sample title - `, - ])('should handle regular pie + showData + title', (context: string) => { - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); - - const { showData, title } = result.value; - expect(showData).toBeTruthy(); - expect(title).toBe('sample title'); - }); - - it.each([ - `pie showData - title sample title`, - `pie showData - title sample title - `, - `pie showData - title sample title`, - `pie showData - title sample title - `, - ])('should handle regular showData + title in different line', (context: string) => { - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); - - const { showData, title } = result.value; - expect(showData).toBeTruthy(); - expect(title).toBe('sample title'); - }); - - describe('sections', () => { - describe('normal', () => { it.each([ `pie + title sample title`, + `pie + title sample title + `, + `pie + title sample title`, + `pie + title sample title + `, + ])('should handle regular pie + title in different line', (context: string) => { + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); + + const { title } = result.value; + expect(title).toBe('sample title'); + }); + }); + + describe('should handle TitleAndAccessibilities with showData', () => { + it.each([ + `pie showData title sample title`, + `pie showData title sample title + `, + ])('should handle regular pie + showData + title', (context: string) => { + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); + + const { showData, title } = result.value; + expect(showData).toBeTruthy(); + expect(title).toBe('sample title'); + }); + + it.each([ + `pie showData + title sample title`, + `pie showData + title sample title + `, + `pie showData + title sample title`, + `pie showData + title sample title + `, + ])('should handle regular showData + title in different line', (context: string) => { + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); + + const { showData, title } = result.value; + expect(showData).toBeTruthy(); + expect(title).toBe('sample title'); + }); + }); + }); + + describe('should handle sections', () => { + it.each([ + `pie "GitHub":100 "GitLab":50`, - `pie + `pie "GitHub" : 100 "GitLab" : 50`, - `pie + `pie "GitHub"\t:\t100 "GitLab"\t:\t50`, - `pie + `pie \t"GitHub" \t : \t 100 \t"GitLab" \t : \t 50 `, - ])('should handle regular sections', (context: string) => { - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); + ])('should handle regular sections', (context: string) => { + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); - const { sections } = result.value; - expect(sections[0].label).toBe('GitHub'); - expect(sections[0].value).toBe(100); + const { sections } = result.value; + expect(sections[0].label).toBe('GitHub'); + expect(sections[0].value).toBe(100); - expect(sections[1].label).toBe('GitLab'); - expect(sections[1].value).toBe(50); - }); + expect(sections[1].label).toBe('GitLab'); + expect(sections[1].value).toBe(50); + }); - it('should handle sections with showData', () => { - const context = `pie showData + it('should handle sections with showData', () => { + const context = `pie showData "GitHub": 100 "GitLab": 50`; - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); - const { showData, sections } = result.value; - expect(showData).toBeTruthy(); + const { showData, sections } = result.value; + expect(showData).toBeTruthy(); - expect(sections[0].label).toBe('GitHub'); - expect(sections[0].value).toBe(100); + expect(sections[0].label).toBe('GitHub'); + expect(sections[0].value).toBe(100); - expect(sections[1].label).toBe('GitLab'); - expect(sections[1].value).toBe(50); - }); + expect(sections[1].label).toBe('GitLab'); + expect(sections[1].value).toBe(50); + }); - it('should handle sections with title', () => { - const context = `pie title sample wow + it('should handle sections with title', () => { + const context = `pie title sample wow "GitHub": 100 "GitLab": 50`; - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); - const { title, sections } = result.value; - expect(title).toBe('sample wow'); + const { title, sections } = result.value; + expect(title).toBe('sample wow'); - expect(sections[0].label).toBe('GitHub'); - expect(sections[0].value).toBe(100); + expect(sections[0].label).toBe('GitHub'); + expect(sections[0].value).toBe(100); - expect(sections[1].label).toBe('GitLab'); - expect(sections[1].value).toBe(50); - }); + expect(sections[1].label).toBe('GitLab'); + expect(sections[1].value).toBe(50); + }); - it('should handle sections with accTitle', () => { - const context = `pie accTitle: sample wow + it('should handle value with positive decimal', () => { + const context = `pie + "ash": 60.67 + "bat": 40`; + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); + + const { sections } = result.value; + expect(sections[0].label).toBe('ash'); + expect(sections[0].value).toBe(60.67); + + expect(sections[1].label).toBe('bat'); + expect(sections[1].value).toBe(40); + }); + + it('should handle sections with accTitle', () => { + const context = `pie accTitle: sample wow "GitHub": 100 "GitLab": 50`; - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); - const { accTitle, sections } = result.value; - expect(accTitle).toBe('sample wow'); + const { accTitle, sections } = result.value; + expect(accTitle).toBe('sample wow'); - expect(sections[0].label).toBe('GitHub'); - expect(sections[0].value).toBe(100); + expect(sections[0].label).toBe('GitHub'); + expect(sections[0].value).toBe(100); - expect(sections[1].label).toBe('GitLab'); - expect(sections[1].value).toBe(50); - }); + expect(sections[1].label).toBe('GitLab'); + expect(sections[1].value).toBe(50); + }); - it('should handle sections with single line accDescr', () => { - const context = `pie accDescr: sample wow + it('should handle sections with single line accDescr', () => { + const context = `pie accDescr: sample wow "GitHub": 100 "GitLab": 50`; - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); - const { accDescr, sections } = result.value; - expect(accDescr).toBe('sample wow'); + const { accDescr, sections } = result.value; + expect(accDescr).toBe('sample wow'); - expect(sections[0].label).toBe('GitHub'); - expect(sections[0].value).toBe(100); + expect(sections[0].label).toBe('GitHub'); + expect(sections[0].value).toBe(100); - expect(sections[1].label).toBe('GitLab'); - expect(sections[1].value).toBe(50); - }); + expect(sections[1].label).toBe('GitLab'); + expect(sections[1].value).toBe(50); + }); - it('should handle sections with multi line accDescr', () => { - const context = `pie accDescr { + it('should handle sections with multi line accDescr', () => { + const context = `pie accDescr { sample wow } "GitHub": 100 "GitLab": 50`; - const result = parse(context); - expectNoErrorsOrAlternatives(result); - expect(result.value.$type).toBe(Pie); + const result = parse(context); + expectNoErrorsOrAlternatives(result); + expect(result.value.$type).toBe(Pie); - const { accDescr, sections } = result.value; - expect(accDescr).toBe('sample wow'); + const { accDescr, sections } = result.value; + expect(accDescr).toBe('sample wow'); - expect(sections[0].label).toBe('GitHub'); - expect(sections[0].value).toBe(100); + expect(sections[0].label).toBe('GitHub'); + expect(sections[0].value).toBe(100); - expect(sections[1].label).toBe('GitLab'); - expect(sections[1].value).toBe(50); - }); + expect(sections[1].label).toBe('GitLab'); + expect(sections[1].value).toBe(50); }); }); }); diff --git a/packages/parser/tests/test-util.ts b/packages/parser/tests/test-util.ts index bc2224e65..7a6050016 100644 --- a/packages/parser/tests/test-util.ts +++ b/packages/parser/tests/test-util.ts @@ -1,6 +1,8 @@ import type { LangiumParser, ParseResult } from 'langium'; import { expect, vi } from 'vitest'; import type { + Architecture, + ArchitectureServices, Info, InfoServices, Pie, @@ -13,6 +15,7 @@ import type { GitGraphServices, } from '../src/language/index.js'; import { + createArchitectureServices, createInfoServices, createPieServices, createRadarServices, @@ -47,6 +50,17 @@ export function createInfoTestServices() { } export const infoParse = createInfoTestServices().parse; +const architectureServices: ArchitectureServices = createArchitectureServices().Architecture; +const architectureParser: LangiumParser = architectureServices.parser.LangiumParser; +export function createArchitectureTestServices() { + const parse = (input: string) => { + return architectureParser.parse(input); + }; + + return { services: architectureServices, parse }; +} +export const architectureParse = createArchitectureTestServices().parse; + const pieServices: PieServices = createPieServices().Pie; const pieParser: LangiumParser = pieServices.parser.LangiumParser; export function createPieTestServices() { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6a9591bb0..7d65b26bd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,8 +17,8 @@ importers: specifier: ^3.44.9 version: 3.50.2(encoding@0.1.13)(typescript@5.7.3) '@argos-ci/cypress': - specifier: ^3.2.0 - version: 3.2.0(cypress@14.0.3) + specifier: ^4.0.3 + version: 4.0.3(cypress@14.0.3) '@changesets/changelog-github': specifier: ^0.5.1 version: 0.5.1(encoding@0.1.13) @@ -26,14 +26,14 @@ importers: specifier: ^2.27.12 version: 2.28.1 '@cspell/eslint-plugin': - specifier: ^8.8.4 - version: 8.14.4(eslint@9.20.1(jiti@2.4.2)) + specifier: ^8.18.1 + version: 8.18.1(eslint@9.24.0(jiti@2.4.2)) '@cypress/code-coverage': specifier: ^3.12.49 version: 3.13.4(@babel/core@7.26.9)(@babel/preset-env@7.26.9(@babel/core@7.26.9))(babel-loader@9.2.1(@babel/core@7.26.9)(webpack@5.95.0(esbuild@0.25.0)))(cypress@14.0.3)(webpack@5.95.0(esbuild@0.25.0)) '@eslint/js': - specifier: ^9.4.0 - version: 9.12.0 + specifier: ^9.24.0 + version: 9.24.0 '@rollup/plugin-typescript': specifier: ^12.1.2 version: 12.1.2(rollup@4.34.8)(tslib@2.8.1)(typescript@5.7.3) @@ -74,8 +74,8 @@ importers: specifier: ^8.17.1 version: 8.17.1 chokidar: - specifier: ^3.6.0 - version: 3.6.0 + specifier: ^4.0.3 + version: 4.0.3 concurrently: specifier: ^9.1.2 version: 9.1.2 @@ -104,32 +104,32 @@ importers: specifier: ^0.25.0 version: 0.25.0 eslint: - specifier: ^9.20.1 - version: 9.20.1(jiti@2.4.2) + specifier: ^9.24.0 + version: 9.24.0(jiti@2.4.2) eslint-config-prettier: - specifier: ^10.0.0 - version: 10.0.1(eslint@9.20.1(jiti@2.4.2)) + specifier: ^10.1.1 + version: 10.1.1(eslint@9.24.0(jiti@2.4.2)) eslint-plugin-cypress: - specifier: ^4.1.0 - version: 4.1.0(eslint@9.20.1(jiti@2.4.2)) + specifier: ^4.2.1 + version: 4.2.1(eslint@9.24.0(jiti@2.4.2)) eslint-plugin-html: specifier: ^8.1.2 version: 8.1.2 eslint-plugin-jest: - specifier: ^28.6.0 - version: 28.8.3(@typescript-eslint/eslint-plugin@8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3))(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3))(eslint@9.20.1(jiti@2.4.2))(jest@29.7.0(@types/node@22.13.5))(typescript@5.7.3) + specifier: ^28.11.0 + version: 28.11.0(@typescript-eslint/eslint-plugin@8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.24.0(jiti@2.4.2))(jest@29.7.0(@types/node@22.13.5))(typescript@5.7.3) eslint-plugin-jsdoc: - specifier: ^50.0.1 - version: 50.3.2(eslint@9.20.1(jiti@2.4.2)) + specifier: ^50.6.9 + version: 50.6.9(eslint@9.24.0(jiti@2.4.2)) eslint-plugin-json: specifier: ^4.0.1 version: 4.0.1 eslint-plugin-lodash: specifier: ^8.0.0 - version: 8.0.0(eslint@9.20.1(jiti@2.4.2)) + version: 8.0.0(eslint@9.24.0(jiti@2.4.2)) eslint-plugin-markdown: specifier: ^5.1.0 - version: 5.1.0(eslint@9.20.1(jiti@2.4.2)) + version: 5.1.0(eslint@9.24.0(jiti@2.4.2)) eslint-plugin-no-only-tests: specifier: ^3.3.0 version: 3.3.0 @@ -138,10 +138,10 @@ importers: version: 0.4.0 eslint-plugin-unicorn: specifier: ^58.0.0 - version: 58.0.0(eslint@9.20.1(jiti@2.4.2)) + version: 58.0.0(eslint@9.24.0(jiti@2.4.2)) express: - specifier: ^4.19.2 - version: 4.21.0 + specifier: ^5.1.0 + version: 5.1.0 globals: specifier: ^16.0.0 version: 16.0.0 @@ -203,8 +203,8 @@ importers: specifier: ~5.7.3 version: 5.7.3 typescript-eslint: - specifier: ^8.24.1 - version: 8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3) + specifier: ^8.29.1 + version: 8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3) vite: specifier: ^6.1.1 version: 6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0) @@ -257,8 +257,8 @@ importers: specifier: ^1.11.13 version: 1.11.13 dompurify: - specifier: ^3.2.4 - version: 3.2.4 + specifier: ^3.2.5 + version: 3.2.5 katex: specifier: ^0.16.9 version: 0.16.11 @@ -400,10 +400,10 @@ importers: version: 5.0.0 vitepress: specifier: ^1.0.2 - version: 1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.7.9)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3) + version: 1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.8.4)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3) vitepress-plugin-search: specifier: 1.0.4-alpha.22 - version: 1.0.4-alpha.22(flexsearch@0.7.43)(vitepress@1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.7.9)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)) + version: 1.0.4-alpha.22(flexsearch@0.7.43)(vitepress@1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.8.4)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)) packages/mermaid-example-diagram: dependencies: @@ -459,8 +459,8 @@ importers: specifier: ^7.4.47 version: 7.4.47 '@vueuse/core': - specifier: ^12.7.0 - version: 12.7.0(typescript@5.7.3) + specifier: ^13.1.0 + version: 13.1.0(vue@3.5.13(typescript@5.7.3)) font-awesome: specifier: ^4.7.0 version: 4.7.0 @@ -481,8 +481,8 @@ importers: specifier: ^66.0.0 version: 66.0.0 '@vite-pwa/vitepress': - specifier: ^0.5.3 - version: 0.5.3(vite-plugin-pwa@0.21.1(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0)) + specifier: ^1.0.0 + version: 1.0.0(vite-plugin-pwa@1.0.0(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0)) '@vitejs/plugin-vue': specifier: ^5.0.5 version: 5.2.1(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.7.3)) @@ -505,11 +505,11 @@ importers: specifier: ^6.1.1 version: 6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0) vite-plugin-pwa: - specifier: ^0.21.1 - version: 0.21.1(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0) + specifier: ^1.0.0 + version: 1.0.0(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0) vitepress: specifier: 1.6.3 - version: 1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.7.9)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3) + version: 1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.8.4)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3) workbox-window: specifier: ^7.3.0 version: 7.3.0 @@ -774,26 +774,26 @@ packages: resolution: {integrity: sha512-4YQc/FGYmA4Jx8vRNRI6YOE8oa7tOWhCik3b1OV3RQ6OkAY5EpVRF8ruiFpX+9BIjZ2V5AdVpsJacYOIiCHNMg==} engines: {node: '>=12.13.0'} - '@argos-ci/api-client@0.8.0': - resolution: {integrity: sha512-UHa1vAf8gwHVpkqM/RaSryrFe1juqWH6dHpPeMtT4e/ZMB9hNYwYFinaGq/KRWe88JEi2WeAu776YdoeUSZQkQ==} + '@argos-ci/api-client@0.8.1': + resolution: {integrity: sha512-3IHv7ANSPNO6OwWgwULlHbP9/tFV9kQDu6+nL9jysfPkGj0GgtrOsyBb+iU931c7wSMo1OD+XNujCnRzDD968w==} engines: {node: '>=18.0.0'} - '@argos-ci/browser@3.0.1': - resolution: {integrity: sha512-dqRXWCllulbKlqzwNE2bjbCtNqxVnUUrYpI1iIJQCMvyStmPdGHOYD7BoQQQ2uNPT2pCHeDyysrxc5T3mDyScg==} + '@argos-ci/browser@4.1.1': + resolution: {integrity: sha512-UyKdnprGftUjWQkb0jqJ0zGHJmcWBzdko8zRy4y+4efukVX4jjC/Px2HvWW8aqwjoR4aplouMZuzhmOkq2SCsA==} engines: {node: '>=18.0.0'} - '@argos-ci/core@3.1.0': - resolution: {integrity: sha512-bo/pNKk6P0pz4NRdymgU1letwQrRbMPTeFyMsUEW8fhKNdesSFnFIWZBFGsGkkh05uw75PBjl2ZN4PvQ2TxSog==} + '@argos-ci/core@3.1.1': + resolution: {integrity: sha512-7iE3o1XGxlfHC5AF05pzT0OxuO387sryrZt3gKGj/e+6R20DXz7J49yI8++nQ2cuT+wLhcJp8+X0ox+SGMYHmw==} engines: {node: '>=18.0.0'} - '@argos-ci/cypress@3.2.0': - resolution: {integrity: sha512-eBmBiNk3Pxsy9huttYuH5JyZdFooARz12Zxgv6pAnaPLeIG1Rw+E8LwPa71TabNx9b0BjMCzP7L/n/rVd6xbIQ==} + '@argos-ci/cypress@4.0.3': + resolution: {integrity: sha512-JGP48zPwbUGU5ziLP4Okv6mTuLPiEPvQ954BoH78ySlNpDGxyw68yeY4jxz8QpYe+P7vvKmuZiUFPAXTFu8XiQ==} engines: {node: '>=18.0.0'} peerDependencies: cypress: ^12.0.0 || ^13.0.0 || ^14.0.0 - '@argos-ci/util@2.3.0': - resolution: {integrity: sha512-tkxnCpaj7yN9nCFzo9MX0FJ5YjUepEOGYfdvF8COQqp+EdY1qubOPpc4Z0l1B60BlC8YtjQv/oRxHSh1XzxWFg==} + '@argos-ci/util@2.3.1': + resolution: {integrity: sha512-kE61HU2480fbAnimmA4x9HK45ZJvkoqLdW5GxT5uvwhkclQykVd2S6WfGFUr3JokTXfZ5LZEEfoWgtGA316KSQ==} engines: {node: '>=18.0.0'} '@asamuzakjp/css-color@2.8.3': @@ -1469,52 +1469,49 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} - '@cspell/cspell-bundled-dicts@8.14.4': - resolution: {integrity: sha512-JHZOpCJzN6fPBapBOvoeMxZbr0ZA11ZAkwcqM4w0lKoacbi6TwK8GIYf66hHvwLmMeav75TNXWE6aPTvBLMMqA==} - engines: {node: '>=18'} - '@cspell/cspell-bundled-dicts@8.17.4': resolution: {integrity: sha512-oPNQU3Uwc0OnvAmC8Vs7DSCRBhGRbZvO8J57JEnJ6YMNyCJZpKq050OzbAWmNdjjZ7yRLJ+LOcxhzdFg2Qn4Yw==} engines: {node: '>=18'} + '@cspell/cspell-bundled-dicts@8.18.1': + resolution: {integrity: sha512-gxciVVfQqCVXYH0p2Q5D7x7/SgaW3Wv5UjRwO+TCme0P2lVLl/IcfjkujZX+6UQkT7X4QRglXo1QN141UcCRCQ==} + engines: {node: '>=18'} + '@cspell/cspell-json-reporter@8.17.4': resolution: {integrity: sha512-O7V2hMt6zPt2Eu5LSxFyD/dcZRUOASeY+8oE1O2xanfJUMOG1EldCt8LERSmU829RQ4VF4H2Z9TbeQzx+4G21w==} engines: {node: '>=18'} - '@cspell/cspell-pipe@8.14.4': - resolution: {integrity: sha512-CLLdouqfrQ4rqdQdPu0Oo+HHCU/oLYoEsK1nNPb28cZTFxnn0cuSPKB6AMPBJmMwdfJ6fMD0BCKNbEe1UNLHcw==} - engines: {node: '>=18'} - '@cspell/cspell-pipe@8.17.4': resolution: {integrity: sha512-0KzqYetKMT9c3Pt77yRla2/zLDitpztEQ/VPYAbW5DCW+btRe5pAb6VQ7U6HKA2HoM2rhlLTWOBh4jauRFtgxA==} engines: {node: '>=18'} - '@cspell/cspell-resolver@8.14.4': - resolution: {integrity: sha512-s3uZyymJ04yn8+zlTp7Pt1WRSlAel6XVo+iZRxls3LSvIP819KK64DoyjCD2Uon0Vg9P/K7aAPt8GcxDcnJtgA==} + '@cspell/cspell-pipe@8.18.1': + resolution: {integrity: sha512-QHndTQPkR1c02pvvQ7UKFtLjCXgY0OcX8zjTLrCkynmcQxJFjAZAh9cJ7NMOAxab+ciSnkaVf4KWaRSEG17z8Q==} engines: {node: '>=18'} '@cspell/cspell-resolver@8.17.4': resolution: {integrity: sha512-1Z3yZRuhnyGCheD2nt/ZswV+ulXBOfnKCoyfkUKNAR5ALkrqv6bjXXwZrpEi2cIK1km4/59ybT72+r2Ry9dGUw==} engines: {node: '>=18'} - '@cspell/cspell-service-bus@8.14.4': - resolution: {integrity: sha512-i3UG+ep63akNsDXZrtGgICNF3MLBHtvKe/VOIH6+L+NYaAaVHqqQvOY9MdUwt1HXh8ElzfwfoRp36wc5aAvt6g==} + '@cspell/cspell-resolver@8.18.1': + resolution: {integrity: sha512-T2sUBv0p9Hnfyg1xT1u3ESKuIWaaIDo0I8idh5DSlTpHgLjdIeAwasmFjEJ28qZv8OKSGawcSQKgJbStfbZASQ==} engines: {node: '>=18'} '@cspell/cspell-service-bus@8.17.4': resolution: {integrity: sha512-S8fENifriBW8KdDIvOnsP9gdEyCp1zrs4GT15vmDvm6uoevj2mfmdCj4/EbM1KbmmNAh1tlidAgn2OWdtyW7Lg==} engines: {node: '>=18'} - '@cspell/cspell-types@8.14.4': - resolution: {integrity: sha512-VXwikqdHgjOVperVVCn2DOe8W3rPIswwZtMHfRYnagpzZo/TOntIjkXPJSfTtl/cFyx5DnCBsDH8ytKGlMeHkw==} + '@cspell/cspell-service-bus@8.18.1': + resolution: {integrity: sha512-PwWl7EyhGIu4wHEhvBJb6xVlqMtFwQk0qLDArBvugL6nA+MX9NfG/w7PTgS7tCkFjVF1ku2sDzDLTDWwEk+MLw==} engines: {node: '>=18'} '@cspell/cspell-types@8.17.4': resolution: {integrity: sha512-1K6tXEMXSaoUXhH3TiaCyh3Nh8ZE0wPej0+wa5HAMtdcY1B3FGvHZ9DltkgZxbzs3bGNXIySFE5ITqULbhweBA==} engines: {node: '>=18'} - '@cspell/dict-ada@4.0.2': - resolution: {integrity: sha512-0kENOWQeHjUlfyId/aCM/mKXtkEgV0Zu2RhUXCBr4hHo9F9vph+Uu8Ww2b0i5a4ZixoIkudGA+eJvyxrG1jUpA==} + '@cspell/cspell-types@8.18.1': + resolution: {integrity: sha512-d/nMG+qnMbI/1JPm+lD0KcKpgtEHMRsHxkdtGyNCDgvHL/JOGaSHc5ERS3IUgBW0Dfya/3z9wPdaMcHEzt7YCQ==} + engines: {node: '>=18'} '@cspell/dict-ada@4.1.0': resolution: {integrity: sha512-7SvmhmX170gyPd+uHXrfmqJBY5qLcCX8kTGURPVeGxmt8XNXT75uu9rnZO+jwrfuU2EimNoArdVy5GZRGljGNg==} @@ -1522,62 +1519,38 @@ packages: '@cspell/dict-al@1.1.0': resolution: {integrity: sha512-PtNI1KLmYkELYltbzuoztBxfi11jcE9HXBHCpID2lou/J4VMYKJPNqe4ZjVzSI9NYbMnMnyG3gkbhIdx66VSXg==} - '@cspell/dict-aws@4.0.4': - resolution: {integrity: sha512-6AWI/Kkf+RcX/J81VX8+GKLeTgHWEr/OMhGk3dHQzWK66RaqDJCGDqi7494ghZKcBB7dGa3U5jcKw2FZHL/u3w==} - '@cspell/dict-aws@4.0.9': resolution: {integrity: sha512-bDYdnnJGwSkIZ4gzrauu7qzOs/ZAY/FnU4k11LgdMI8BhwMfsbsy2EI1iS+sD/BI5ZnNT9kU5YR3WADeNOmhRg==} - '@cspell/dict-bash@4.1.5': - resolution: {integrity: sha512-YGim/h7E2U5HCCb2ckNufT6/yyWygt9nSZ5C7qw6oOD3bygbObqD1+rlPor1JW+YyO+3GwTIHE70uKEEU6VZYw==} - '@cspell/dict-bash@4.2.0': resolution: {integrity: sha512-HOyOS+4AbCArZHs/wMxX/apRkjxg6NDWdt0jF9i9XkvJQUltMwEhyA2TWYjQ0kssBsnof+9amax2lhiZnh3kCg==} '@cspell/dict-companies@3.1.14': resolution: {integrity: sha512-iqo1Ce4L7h0l0GFSicm2wCLtfuymwkvgFGhmu9UHyuIcTbdFkDErH+m6lH3Ed+QuskJlpQ9dM7puMIGqUlVERw==} - '@cspell/dict-companies@3.1.4': - resolution: {integrity: sha512-y9e0amzEK36EiiKx3VAA+SHQJPpf2Qv5cCt5eTUSggpTkiFkCh6gRKQ97rVlrKh5GJrqinDwYIJtTsxuh2vy2Q==} - - '@cspell/dict-cpp@5.1.19': - resolution: {integrity: sha512-i/odUPNFLdqWisOktu6c4qjUR4k+P9Al2RCri3Wso9EFblp53xt/5jIUdGMdDDVQGqX7s/KLtdqNxNKqP3/d+w==} - '@cspell/dict-cpp@6.0.3': resolution: {integrity: sha512-OFrVXdxCeGKnon36Pe3yFjBuY4kzzEwWFf3vDz+cJTodZDkjFkBifQeTtt5YfimgF8cfAJZXkBCsxjipAgmAiw==} - '@cspell/dict-cryptocurrencies@5.0.0': - resolution: {integrity: sha512-Z4ARIw5+bvmShL+4ZrhDzGhnc9znaAGHOEMaB/GURdS/jdoreEDY34wdN0NtdLHDO5KO7GduZnZyqGdRoiSmYA==} + '@cspell/dict-cpp@6.0.7': + resolution: {integrity: sha512-mk0AUx6au1BJQBTT2Uq9L+y43E0Cy0Vcm6TrK3Toi2iuBLWOnDR/xRE4nZADBsi6WnWoiyl3/QqA1gW2zPkGvQ==} '@cspell/dict-cryptocurrencies@5.0.4': resolution: {integrity: sha512-6iFu7Abu+4Mgqq08YhTKHfH59mpMpGTwdzDB2Y8bbgiwnGFCeoiSkVkgLn1Kel2++hYcZ8vsAW/MJS9oXxuMag==} - '@cspell/dict-csharp@4.0.2': - resolution: {integrity: sha512-1JMofhLK+4p4KairF75D3A924m5ERMgd1GvzhwK2geuYgd2ZKuGW72gvXpIV7aGf52E3Uu1kDXxxGAiZ5uVG7g==} - '@cspell/dict-csharp@4.0.6': resolution: {integrity: sha512-w/+YsqOknjQXmIlWDRmkW+BHBPJZ/XDrfJhZRQnp0wzpPOGml7W0q1iae65P2AFRtTdPKYmvSz7AL5ZRkCnSIw==} - '@cspell/dict-css@4.0.13': - resolution: {integrity: sha512-WfOQkqlAJTo8eIQeztaH0N0P+iF5hsJVKFuhy4jmARPISy8Efcv8QXk2/IVbmjJH0/ZV7dKRdnY5JFVXuVz37g==} - '@cspell/dict-css@4.0.17': resolution: {integrity: sha512-2EisRLHk6X/PdicybwlajLGKF5aJf4xnX2uuG5lexuYKt05xV/J/OiBADmi8q9obhxf1nesrMQbqAt+6CsHo/w==} - '@cspell/dict-dart@2.2.1': - resolution: {integrity: sha512-yriKm7QkoPx3JPSSOcw6iX9gOb2N50bOo/wqWviqPYbhpMRh9Xiv6dkUy3+ot+21GuShZazO8X6U5+Vw67XEwg==} - '@cspell/dict-dart@2.3.0': resolution: {integrity: sha512-1aY90lAicek8vYczGPDKr70pQSTQHwMFLbmWKTAI6iavmb1fisJBS1oTmMOKE4ximDf86MvVN6Ucwx3u/8HqLg==} - '@cspell/dict-data-science@2.0.2': - resolution: {integrity: sha512-VwAck6OZQVqrscKyOrvllixIugIPF+Q6YoFNvXZCPhHGtNyOAVraD3S7kOgPYBdUjgno4QbdMWm92BUPqL1QjQ==} - '@cspell/dict-data-science@2.0.7': resolution: {integrity: sha512-XhAkK+nSW6zmrnWzusmZ1BpYLc62AWYHZc2p17u4nE2Z9XG5DleG55PCZxXQTKz90pmwlhFM9AfpkJsYaBWATA==} - '@cspell/dict-django@4.1.0': - resolution: {integrity: sha512-bKJ4gPyrf+1c78Z0Oc4trEB9MuhcB+Yg+uTTWsvhY6O2ncFYbB/LbEZfqhfmmuK/XJJixXfI1laF2zicyf+l0w==} + '@cspell/dict-data-science@2.0.8': + resolution: {integrity: sha512-uyAtT+32PfM29wRBeAkUSbkytqI8bNszNfAz2sGPtZBRmsZTYugKMEO9eDjAIE/pnT9CmbjNuoiXhk+Ss4fCOg==} '@cspell/dict-django@4.1.4': resolution: {integrity: sha512-fX38eUoPvytZ/2GA+g4bbdUtCMGNFSLbdJJPKX2vbewIQGfgSFJKY56vvcHJKAvw7FopjvgyS/98Ta9WN1gckg==} @@ -1585,23 +1558,14 @@ packages: '@cspell/dict-docker@1.1.12': resolution: {integrity: sha512-6d25ZPBnYZaT9D9An/x6g/4mk542R8bR3ipnby3QFCxnfdd6xaWiTcwDPsCgwN2aQZIQ1jX/fil9KmBEqIK/qA==} - '@cspell/dict-docker@1.1.7': - resolution: {integrity: sha512-XlXHAr822euV36GGsl2J1CkBIVg3fZ6879ZOg5dxTIssuhUOCiV2BuzKZmt6aIFmcdPmR14+9i9Xq+3zuxeX0A==} - - '@cspell/dict-dotnet@5.0.5': - resolution: {integrity: sha512-gjg0L97ee146wX47dnA698cHm85e7EOpf9mVrJD8DmEaqoo/k1oPy2g7c7LgKxK9XnqwoXxhLNnngPrwXOoEtQ==} - '@cspell/dict-dotnet@5.0.9': resolution: {integrity: sha512-JGD6RJW5sHtO5lfiJl11a5DpPN6eKSz5M1YBa1I76j4dDOIqgZB6rQexlDlK1DH9B06X4GdDQwdBfnpAB0r2uQ==} - '@cspell/dict-elixir@4.0.3': - resolution: {integrity: sha512-g+uKLWvOp9IEZvrIvBPTr/oaO6619uH/wyqypqvwpmnmpjcfi8+/hqZH8YNKt15oviK8k4CkINIqNhyndG9d9Q==} - '@cspell/dict-elixir@4.0.7': resolution: {integrity: sha512-MAUqlMw73mgtSdxvbAvyRlvc3bYnrDqXQrx5K9SwW8F7fRYf9V4vWYFULh+UWwwkqkhX9w03ZqFYRTdkFku6uA==} - '@cspell/dict-en-common-misspellings@2.0.4': - resolution: {integrity: sha512-lvOiRjV/FG4pAGZL3PN2GCVHSTCE92cwhfLGGkOsQtxSmef6WCHfHwp9auafkBlX0yFQSKDfq6/TlpQbjbJBtQ==} + '@cspell/dict-en-common-misspellings@2.0.10': + resolution: {integrity: sha512-80mXJLtr0tVEtzowrI7ycVae/ULAYImZUlr0kUTpa8i57AUk7Zy3pYBs44EYIKW7ZC9AHu4Qjjfq4vriAtyTDQ==} '@cspell/dict-en-common-misspellings@2.0.9': resolution: {integrity: sha512-O/jAr1VNtuyCFckbTmpeEf43ZFWVD9cJFvWaA6rO2IVmLirJViHWJUyBZOuQcesSplzEIw80MAYmnK06/MDWXQ==} @@ -1609,126 +1573,75 @@ packages: '@cspell/dict-en-gb@1.1.33': resolution: {integrity: sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==} - '@cspell/dict-en_us@4.3.23': - resolution: {integrity: sha512-l0SoEQBsi3zDSl3OuL4/apBkxjuj4hLIg/oy6+gZ7LWh03rKdF6VNtSZNXWAmMY+pmb1cGA3ouleTiJIglbsIg==} - '@cspell/dict-en_us@4.3.31': resolution: {integrity: sha512-MDc+1B0aFwQONS0JZ6w7ks2KFGkUcaNTFJ8kI6GHvFRmEl3zP5NJDwFEXFsoEdLDb86j2myauSWMJXR3JFuwbA==} + '@cspell/dict-en_us@4.4.0': + resolution: {integrity: sha512-TEfVT2NwvI9k1/ECjuC7GbULxenjJAbTLWMri1eMRk3mRGtqg5j0XzvvNRFuJWq8X48MdGVjsD+ZVI/VR94+eQ==} + '@cspell/dict-filetypes@3.0.11': resolution: {integrity: sha512-bBtCHZLo7MiSRUqx5KEiPdGOmXIlDGY+L7SJEtRWZENpAKE+96rT7hj+TUUYWBbCzheqHr0OXZJFEKDgsG/uZg==} - '@cspell/dict-filetypes@3.0.4': - resolution: {integrity: sha512-IBi8eIVdykoGgIv5wQhOURi5lmCNJq0we6DvqKoPQJHthXbgsuO1qrHSiUVydMiQl/XvcnUWTMeAlVUlUClnVg==} - - '@cspell/dict-flutter@1.0.0': - resolution: {integrity: sha512-W7k1VIc4KeV8BjEBxpA3cqpzbDWjfb7oXkEb0LecBCBp5Z7kcfnjT1YVotTx/U9PGyAOBhDaEdgZACVGNQhayw==} - '@cspell/dict-flutter@1.1.0': resolution: {integrity: sha512-3zDeS7zc2p8tr9YH9tfbOEYfopKY/srNsAa+kE3rfBTtQERAZeOhe5yxrnTPoufctXLyuUtcGMUTpxr3dO0iaA==} - '@cspell/dict-fonts@4.0.0': - resolution: {integrity: sha512-t9V4GeN/m517UZn63kZPUYP3OQg5f0OBLSd3Md5CU3eH1IFogSvTzHHnz4Wqqbv8NNRiBZ3HfdY/pqREZ6br3Q==} - '@cspell/dict-fonts@4.0.4': resolution: {integrity: sha512-cHFho4hjojBcHl6qxidl9CvUb492IuSk7xIf2G2wJzcHwGaCFa2o3gRcxmIg1j62guetAeDDFELizDaJlVRIOg==} - '@cspell/dict-fsharp@1.0.1': - resolution: {integrity: sha512-23xyPcD+j+NnqOjRHgW3IU7Li912SX9wmeefcY0QxukbAxJ/vAN4rBpjSwwYZeQPAn3fxdfdNZs03fg+UM+4yQ==} - '@cspell/dict-fsharp@1.1.0': resolution: {integrity: sha512-oguWmHhGzgbgbEIBKtgKPrFSVAFtvGHaQS0oj+vacZqMObwkapcTGu7iwf4V3Bc2T3caf0QE6f6rQfIJFIAVsw==} - '@cspell/dict-fullstack@3.2.0': - resolution: {integrity: sha512-sIGQwU6G3rLTo+nx0GKyirR5dQSFeTIzFTOrURw51ISf+jKG9a3OmvsVtc2OANfvEAOLOC9Wfd8WYhmsO8KRDQ==} - '@cspell/dict-fullstack@3.2.4': resolution: {integrity: sha512-JRRvaOLBZ13BO9sP395W+06tyO1Jy/87aFlKe9xQiCWMiwpCo2kGq0xBGq0PDWe253lYLs+GKrNmLU0fSxrObg==} - '@cspell/dict-gaming-terms@1.0.5': - resolution: {integrity: sha512-C3riccZDD3d9caJQQs1+MPfrUrQ+0KHdlj9iUR1QD92FgTOF6UxoBpvHUUZ9YSezslcmpFQK4xQQ5FUGS7uWfw==} + '@cspell/dict-fullstack@3.2.6': + resolution: {integrity: sha512-cSaq9rz5RIU9j+0jcF2vnKPTQjxGXclntmoNp4XB7yFX2621PxJcekGjwf/lN5heJwVxGLL9toR0CBlGKwQBgA==} '@cspell/dict-gaming-terms@1.1.0': resolution: {integrity: sha512-46AnDs9XkgJ2f1Sqol1WgfJ8gOqp60fojpc9Wxch7x+BA63g4JfMV5/M5x0sI0TLlLY8EBSglcr8wQF/7C80AQ==} - '@cspell/dict-git@3.0.0': - resolution: {integrity: sha512-simGS/lIiXbEaqJu9E2VPoYW1OTC2xrwPPXNXFMa2uo/50av56qOuaxDrZ5eH1LidFXwoc8HROCHYeKoNrDLSw==} - '@cspell/dict-git@3.0.4': resolution: {integrity: sha512-C44M+m56rYn6QCsLbiKiedyPTMZxlDdEYAsPwwlL5bhMDDzXZ3Ic8OCQIhMbiunhCOJJT+er4URmOmM+sllnjg==} - '@cspell/dict-golang@6.0.13': - resolution: {integrity: sha512-uBUWi+AjFpluB6qF0rsC1gGyooqXeKPUdWHSmSXW/DCnS5PBSjRW6VWWp8efc1Fanob0QJxiZiYlc4U7oxuG6Q==} - '@cspell/dict-golang@6.0.18': resolution: {integrity: sha512-Mt+7NwfodDwUk7423DdaQa0YaA+4UoV3XSxQwZioqjpFBCuxfvvv4l80MxCTAAbK6duGj0uHbGTwpv8fyKYPKg==} - '@cspell/dict-google@1.0.1': - resolution: {integrity: sha512-dQr4M3n95uOhtloNSgB9tYYGXGGEGEykkFyRtfcp5pFuEecYUa0BSgtlGKx9RXVtJtKgR+yFT/a5uQSlt8WjqQ==} + '@cspell/dict-golang@6.0.20': + resolution: {integrity: sha512-b7nd9XXs+apMMzNSWorjirQsbmlwcTC0ViQJU8u+XNose3z0y7oNeEpbTPTVoN1+1sO9aOHuFwfwoOMFCDS14Q==} '@cspell/dict-google@1.0.8': resolution: {integrity: sha512-BnMHgcEeaLyloPmBs8phCqprI+4r2Jb8rni011A8hE+7FNk7FmLE3kiwxLFrcZnnb7eqM0agW4zUaNoB0P+z8A==} - '@cspell/dict-haskell@4.0.1': - resolution: {integrity: sha512-uRrl65mGrOmwT7NxspB4xKXFUenNC7IikmpRZW8Uzqbqcu7ZRCUfstuVH7T1rmjRgRkjcIjE4PC11luDou4wEQ==} - '@cspell/dict-haskell@4.0.5': resolution: {integrity: sha512-s4BG/4tlj2pPM9Ha7IZYMhUujXDnI0Eq1+38UTTCpatYLbQqDwRFf2KNPLRqkroU+a44yTUAe0rkkKbwy4yRtQ==} - '@cspell/dict-html-symbol-entities@4.0.0': - resolution: {integrity: sha512-HGRu+48ErJjoweR5IbcixxETRewrBb0uxQBd6xFGcxbEYCX8CnQFTAmKI5xNaIt2PKaZiJH3ijodGSqbKdsxhw==} - '@cspell/dict-html-symbol-entities@4.0.3': resolution: {integrity: sha512-aABXX7dMLNFdSE8aY844X4+hvfK7977sOWgZXo4MTGAmOzR8524fjbJPswIBK7GaD3+SgFZ2yP2o0CFvXDGF+A==} '@cspell/dict-html@4.0.11': resolution: {integrity: sha512-QR3b/PB972SRQ2xICR1Nw/M44IJ6rjypwzA4jn+GH8ydjAX9acFNfc+hLZVyNe0FqsE90Gw3evLCOIF0vy1vQw==} - '@cspell/dict-html@4.0.6': - resolution: {integrity: sha512-cLWHfuOhE4wqwC12up6Doxo2u1xxVhX1A8zriR4CUD+osFQzUIcBK1ykNXppga+rt1WyypaJdTU2eV6OpzYrgQ==} - '@cspell/dict-java@5.0.11': resolution: {integrity: sha512-T4t/1JqeH33Raa/QK/eQe26FE17eUCtWu+JsYcTLkQTci2dk1DfcIKo8YVHvZXBnuM43ATns9Xs0s+AlqDeH7w==} - '@cspell/dict-java@5.0.7': - resolution: {integrity: sha512-ejQ9iJXYIq7R09BScU2y5OUGrSqwcD+J5mHFOKbduuQ5s/Eh/duz45KOzykeMLI6KHPVxhBKpUPBWIsfewECpQ==} - - '@cspell/dict-julia@1.0.1': - resolution: {integrity: sha512-4JsCLCRhhLMLiaHpmR7zHFjj1qOauzDI5ZzCNQS31TUMfsOo26jAKDfo0jljFAKgw5M2fEG7sKr8IlPpQAYrmQ==} - '@cspell/dict-julia@1.1.0': resolution: {integrity: sha512-CPUiesiXwy3HRoBR3joUseTZ9giFPCydSKu2rkh6I2nVjXnl5vFHzOMLXpbF4HQ1tH2CNfnDbUndxD+I+7eL9w==} '@cspell/dict-k8s@1.0.10': resolution: {integrity: sha512-313haTrX9prep1yWO7N6Xw4D6tvUJ0Xsx+YhCP+5YrrcIKoEw5Rtlg8R4PPzLqe6zibw6aJ+Eqq+y76Vx5BZkw==} - '@cspell/dict-k8s@1.0.6': - resolution: {integrity: sha512-srhVDtwrd799uxMpsPOQqeDJY+gEocgZpoK06EFrb4GRYGhv7lXo9Fb+xQMyQytzOW9dw4DNOEck++nacDuymg==} - '@cspell/dict-kotlin@1.1.0': resolution: {integrity: sha512-vySaVw6atY7LdwvstQowSbdxjXG6jDhjkWVWSjg1XsUckyzH1JRHXe9VahZz1i7dpoFEUOWQrhIe5B9482UyJQ==} - '@cspell/dict-latex@4.0.0': - resolution: {integrity: sha512-LPY4y6D5oI7D3d+5JMJHK/wxYTQa2lJMSNxps2JtuF8hbAnBQb3igoWEjEbIbRRH1XBM0X8dQqemnjQNCiAtxQ==} - '@cspell/dict-latex@4.0.3': resolution: {integrity: sha512-2KXBt9fSpymYHxHfvhUpjUFyzrmN4c4P8mwIzweLyvqntBT3k0YGZJSriOdjfUjwSygrfEwiuPI1EMrvgrOMJw==} - '@cspell/dict-lorem-ipsum@4.0.0': - resolution: {integrity: sha512-1l3yjfNvMzZPibW8A7mQU4kTozwVZVw0AvFEdy+NcqtbxH+TvbSkNMqROOFWrkD2PjnKG0+Ea0tHI2Pi6Gchnw==} - '@cspell/dict-lorem-ipsum@4.0.4': resolution: {integrity: sha512-+4f7vtY4dp2b9N5fn0za/UR0kwFq2zDtA62JCbWHbpjvO9wukkbl4rZg4YudHbBgkl73HRnXFgCiwNhdIA1JPw==} - '@cspell/dict-lua@4.0.3': - resolution: {integrity: sha512-lDHKjsrrbqPaea13+G9s0rtXjMO06gPXPYRjRYawbNmo4E/e3XFfVzeci3OQDQNDmf2cPOwt9Ef5lu2lDmwfJg==} - '@cspell/dict-lua@4.0.7': resolution: {integrity: sha512-Wbr7YSQw+cLHhTYTKV6cAljgMgcY+EUAxVIZW3ljKswEe4OLxnVJ7lPqZF5JKjlXdgCjbPSimsHqyAbC5pQN/Q==} - '@cspell/dict-makefile@1.0.0': - resolution: {integrity: sha512-3W9tHPcSbJa6s0bcqWo6VisEDTSN5zOtDbnPabF7rbyjRpNo0uHXHRJQF8gAbFzoTzBBhgkTmrfSiuyQm7vBUQ==} - '@cspell/dict-makefile@1.0.4': resolution: {integrity: sha512-E4hG/c0ekPqUBvlkrVvzSoAA+SsDA9bLi4xSV3AXHTVru7Y2bVVGMPtpfF+fI3zTkww/jwinprcU1LSohI3ylw==} @@ -1743,152 +1656,113 @@ packages: '@cspell/dict-monkeyc@1.0.10': resolution: {integrity: sha512-7RTGyKsTIIVqzbvOtAu6Z/lwwxjGRtY5RkKPlXKHEoEAgIXwfDxb5EkVwzGQwQr8hF/D3HrdYbRT8MFBfsueZw==} - '@cspell/dict-monkeyc@1.0.6': - resolution: {integrity: sha512-oO8ZDu/FtZ55aq9Mb67HtaCnsLn59xvhO/t2mLLTHAp667hJFxpp7bCtr2zOrR1NELzFXmKln/2lw/PvxMSvrA==} - - '@cspell/dict-node@5.0.1': - resolution: {integrity: sha512-lax/jGz9h3Dv83v8LHa5G0bf6wm8YVRMzbjJPG/9rp7cAGPtdrga+XANFq+B7bY5+jiSA3zvj10LUFCFjnnCCg==} - '@cspell/dict-node@5.0.6': resolution: {integrity: sha512-CEbhPCpxGvRNByGolSBTrXXW2rJA4bGqZuTx1KKO85mwR6aadeOmUE7xf/8jiCkXSy+qvr9aJeh+jlfXcsrziQ==} '@cspell/dict-npm@5.1.26': resolution: {integrity: sha512-JU0/9P4nLPPC3Py+sF42tUKm9J4KAvwXaJubp2a4QwhCPzFVlOJTP2tTseFlLbdZn23d61pt0hZ+Jhyy7N76Mg==} - '@cspell/dict-npm@5.1.5': - resolution: {integrity: sha512-oAOGWuJYU3DlO+cAsStKMWN8YEkBue25cRC9EwdiL5Z84nchU20UIoYrLfIQejMlZca+1GyrNeyxRAgn4KiivA==} - - '@cspell/dict-php@4.0.10': - resolution: {integrity: sha512-NfTZdp6kcZDF1PvgQ6cY0zE4FUO5rSwNmBH/iwCBuaLfJAFQ97rgjxo+D2bic4CFwNjyHutnHPtjJBRANO5XQw==} + '@cspell/dict-npm@5.1.34': + resolution: {integrity: sha512-UrUYqRQX864Cx9QJkg7eEIxmjYGqcje+x1j7bzl+a3jCKwT6jm+p0off6VEOf3EReHP0dWUSYO3Q0+pLL/N+FQ==} '@cspell/dict-php@4.0.14': resolution: {integrity: sha512-7zur8pyncYZglxNmqsRycOZ6inpDoVd4yFfz1pQRe5xaRWMiK3Km4n0/X/1YMWhh3e3Sl/fQg5Axb2hlN68t1g==} - '@cspell/dict-powershell@5.0.10': - resolution: {integrity: sha512-U4H0zm94sNK+YP7jSFb7xb160XLf2dKIPVt5sOYctKlEyR9M16sP8FHbyWV2Yp1YtxXugoNdeCm2vwGEDAd8sg==} - '@cspell/dict-powershell@5.0.14': resolution: {integrity: sha512-ktjjvtkIUIYmj/SoGBYbr3/+CsRGNXGpvVANrY0wlm/IoGlGywhoTUDYN0IsGwI2b8Vktx3DZmQkfb3Wo38jBA==} '@cspell/dict-public-licenses@2.0.13': resolution: {integrity: sha512-1Wdp/XH1ieim7CadXYE7YLnUlW0pULEjVl9WEeziZw3EKCAw8ZI8Ih44m4bEa5VNBLnuP5TfqC4iDautAleQzQ==} - '@cspell/dict-public-licenses@2.0.8': - resolution: {integrity: sha512-Sup+tFS7cDV0fgpoKtUqEZ6+fA/H+XUgBiqQ/Fbs6vUE3WCjJHOIVsP+udHuyMH7iBfJ4UFYOYeORcY4EaKdMg==} - '@cspell/dict-python@4.2.15': resolution: {integrity: sha512-VNXhj0Eh+hdHN89MgyaoSAexBQKmYtJaMhucbMI7XmBs4pf8fuFFN3xugk51/A4TZJr8+RImdFFsGMOw+I4bDA==} - '@cspell/dict-python@4.2.8': - resolution: {integrity: sha512-4y5dynLiajvowhB3PqlcwJ2C4okK1y2Hombec1+TGcV9sUBfo8FYNw6VRFUUrpsxO+Ut/3ncIifdZS5/zAWi5w==} - - '@cspell/dict-r@2.0.1': - resolution: {integrity: sha512-KCmKaeYMLm2Ip79mlYPc8p+B2uzwBp4KMkzeLd5E6jUlCL93Y5Nvq68wV5fRLDRTf7N1LvofkVFWfDcednFOgA==} + '@cspell/dict-python@4.2.17': + resolution: {integrity: sha512-xqMKfVc8d7yDaOChFdL2uWAN3Mw9qObB/Zr6t5w1OHbi23gWs7V1lI9d0mXAoqSK6N3mosbum4OIq/FleQDnlw==} '@cspell/dict-r@2.1.0': resolution: {integrity: sha512-k2512wgGG0lTpTYH9w5Wwco+lAMf3Vz7mhqV8+OnalIE7muA0RSuD9tWBjiqLcX8zPvEJr4LdgxVju8Gk3OKyA==} - '@cspell/dict-ruby@5.0.4': - resolution: {integrity: sha512-URw0jScj5pv8sKCVLNnde11qVCQR442rUpSd12u46Swl+5qBaSdnOUoCWQk419kd9/dpC6bB/3l4kOSY2fdYHw==} - '@cspell/dict-ruby@5.0.7': resolution: {integrity: sha512-4/d0hcoPzi5Alk0FmcyqlzFW9lQnZh9j07MJzPcyVO62nYJJAGKaPZL2o4qHeCS/od/ctJC5AHRdoUm0ktsw6Q==} + '@cspell/dict-ruby@5.0.8': + resolution: {integrity: sha512-ixuTneU0aH1cPQRbWJvtvOntMFfeQR2KxT8LuAv5jBKqQWIHSxzGlp+zX3SVyoeR0kOWiu64/O5Yn836A5yMcQ==} + '@cspell/dict-rust@4.0.11': resolution: {integrity: sha512-OGWDEEzm8HlkSmtD8fV3pEcO2XBpzG2XYjgMCJCRwb2gRKvR+XIm6Dlhs04N/K2kU+iH8bvrqNpM8fS/BFl0uw==} - '@cspell/dict-rust@4.0.6': - resolution: {integrity: sha512-Buzy9PfLbdRPibSth8CV1D8ZsYqybo26yNIlAN+8ehU0pSBss0Jv4aleL4vKQ3FjouXeAC27rtEsLd7yaMZTog==} - - '@cspell/dict-scala@5.0.3': - resolution: {integrity: sha512-4yGb4AInT99rqprxVNT9TYb1YSpq58Owzq7zi3ZS5T0u899Y4VsxsBiOgHnQ/4W+ygi+sp+oqef8w8nABR2lkg==} - '@cspell/dict-scala@5.0.7': resolution: {integrity: sha512-yatpSDW/GwulzO3t7hB5peoWwzo+Y3qTc0pO24Jf6f88jsEeKmDeKkfgPbYuCgbE4jisGR4vs4+jfQZDIYmXPA==} '@cspell/dict-shell@1.1.0': resolution: {integrity: sha512-D/xHXX7T37BJxNRf5JJHsvziFDvh23IF/KvkZXNSh8VqcRdod3BAz9VGHZf6VDqcZXr1VRqIYR3mQ8DSvs3AVQ==} - '@cspell/dict-software-terms@4.1.7': - resolution: {integrity: sha512-+fFTALseXszDN8/khonF1DpTcYzwyNqYxhATLakr7CUPtUCO1fCH4lidMtBN4UtPVpE6tbjc5D8tj51PJxEOcw==} - '@cspell/dict-software-terms@4.2.5': resolution: {integrity: sha512-CaRzkWti3AgcXoxuRcMijaNG7YUk/MH1rHjB8VX34v3UdCxXXeqvRyElRKnxhFeVLB/robb2UdShqh/CpskxRg==} - '@cspell/dict-sql@2.1.5': - resolution: {integrity: sha512-FmxanytHXss7GAWAXmgaxl3icTCW7YxlimyOSPNfm+njqeUDjw3kEv4mFNDDObBJv8Ec5AWCbUDkWIpkE3IpKg==} + '@cspell/dict-software-terms@5.0.5': + resolution: {integrity: sha512-ZjAOa8FI8/JrxaRqKT3eS7AQXFjU174xxQoKYMkmdwSyNIj7WUCAg10UeLqeMjFVv36zIO0Hm0dD2+Bvn18SLA==} '@cspell/dict-sql@2.2.0': resolution: {integrity: sha512-MUop+d1AHSzXpBvQgQkCiok8Ejzb+nrzyG16E8TvKL2MQeDwnIvMe3bv90eukP6E1HWb+V/MA/4pnq0pcJWKqQ==} - '@cspell/dict-svelte@1.0.2': - resolution: {integrity: sha512-rPJmnn/GsDs0btNvrRBciOhngKV98yZ9SHmg8qI6HLS8hZKvcXc0LMsf9LLuMK1TmS2+WQFAan6qeqg6bBxL2Q==} - '@cspell/dict-svelte@1.0.6': resolution: {integrity: sha512-8LAJHSBdwHCoKCSy72PXXzz7ulGROD0rP1CQ0StOqXOOlTUeSFaJJlxNYjlONgd2c62XBQiN2wgLhtPN+1Zv7Q==} - '@cspell/dict-swift@2.0.1': - resolution: {integrity: sha512-gxrCMUOndOk7xZFmXNtkCEeroZRnS2VbeaIPiymGRHj5H+qfTAzAKxtv7jJbVA3YYvEzWcVE2oKDP4wcbhIERw==} - '@cspell/dict-swift@2.0.5': resolution: {integrity: sha512-3lGzDCwUmnrfckv3Q4eVSW3sK3cHqqHlPprFJZD4nAqt23ot7fic5ALR7J4joHpvDz36nHX34TgcbZNNZOC/JA==} - '@cspell/dict-terraform@1.0.2': - resolution: {integrity: sha512-UZdJwWIpib2Rx02w6vtXTU3z+M/VMZU0F1dhSL3Ab9otQsFntT8U1CX7wBSqQCLg8bJiCfnUyVvMK3UBm3SR8A==} - '@cspell/dict-terraform@1.1.0': resolution: {integrity: sha512-G55pcUUxeXAhejstmD35B47SkFd4uqCQimc+CMgq8Nx0dr03guL2iMsz8faRWQGkCnGimX8S91rbOhDv9p/heg==} - '@cspell/dict-typescript@3.1.6': - resolution: {integrity: sha512-1beC6O4P/j23VuxX+i0+F7XqPVc3hhiAzGJHEKqnWf5cWAXQtg0xz3xQJ5MvYx2a7iLaSa+lu7+05vG9UHyu9Q==} + '@cspell/dict-terraform@1.1.1': + resolution: {integrity: sha512-07KFDwCU7EnKl4hOZLsLKlj6Zceq/IsQ3LRWUyIjvGFfZHdoGtFdCp3ZPVgnFaAcd/DKv+WVkrOzUBSYqHopQQ==} '@cspell/dict-typescript@3.2.0': resolution: {integrity: sha512-Pk3zNePLT8qg51l0M4g1ISowYAEGxTuNfZlgkU5SvHa9Cu7x/BWoyYq9Fvc3kAyoisCjRPyvWF4uRYrPitPDFw==} - '@cspell/dict-vue@3.0.0': - resolution: {integrity: sha512-niiEMPWPV9IeRBRzZ0TBZmNnkK3olkOPYxC1Ny2AX4TGlYRajcW0WUtoSHmvvjZNfWLSg2L6ruiBeuPSbjnG6A==} - '@cspell/dict-vue@3.0.4': resolution: {integrity: sha512-0dPtI0lwHcAgSiQFx8CzvqjdoXROcH+1LyqgROCpBgppommWpVhbQ0eubnKotFEXgpUCONVkeZJ6Ql8NbTEu+w==} - '@cspell/dynamic-import@8.14.4': - resolution: {integrity: sha512-GjKsBJvPXp4dYRqsMn7n1zpnKbnpfJnlKLOVeoFBh8fi4n06G50xYr+G25CWX1WT3WFaALAavvVICEUPrVsuqg==} - engines: {node: '>=18.0'} - '@cspell/dynamic-import@8.17.4': resolution: {integrity: sha512-rUwFOVPnfEGzhzCRnE4esTTMgWtTORXfa5FJJR8653KwcvD6HJQfPTYepBG6n6Bmu3TssMa4ktq+ZJk4o1BF9A==} engines: {node: '>=18.0'} - '@cspell/eslint-plugin@8.14.4': - resolution: {integrity: sha512-Wv6Jkttp/rsEm1nadLFQrUrYg9nTWQFwJu47KO2cfWP39TeH0zXQpmyas1xNlcDx5QJ9JJw9urTT/iw2tsHeRA==} + '@cspell/dynamic-import@8.18.1': + resolution: {integrity: sha512-VJHfS/Iv0Rx7wn1pjPmwgsaw6r72N5Cx2gL0slWk8Cogc8YiK7/6jsGnsvxJZVkHntJoiT8PrkIvhNKb3awD3g==} + engines: {node: '>=18.0'} + + '@cspell/eslint-plugin@8.18.1': + resolution: {integrity: sha512-Knlp6M5zGKkjZSFPhsLZoARS8vbSiePK6AkNXujmlxM91KyHJsAEJiyAVnR5qwhYcsOkcngmO+pmLir+WjHlAw==} engines: {node: '>=18'} peerDependencies: eslint: ^7 || ^8 || ^9 - '@cspell/filetypes@8.14.4': - resolution: {integrity: sha512-qd68dD7xTA4Mnf/wjIKYz2SkiTBshIM+yszOUtLa06YJm0aocoNQ25FHXyYEQYm9NQXCYnRWWA02sFMGs8Sv/w==} - engines: {node: '>=18'} - '@cspell/filetypes@8.17.4': resolution: {integrity: sha512-zzYm0hr+lvctsy/65hjI0vsQJj2CAwSOTnVk+5ubJCkCaWH/rayI/SaVZA0Xynf08B/x0r/36nPH0lO2iMJ4aw==} engines: {node: '>=18'} - '@cspell/strong-weak-map@8.14.4': - resolution: {integrity: sha512-Uyfck64TfVU24wAP3BLGQ5EsAfzIZiLfN90NhttpEM7GlOBmbGrEJd4hNOwfpYsE/TT80eGWQVPRTLr5SDbXFA==} + '@cspell/filetypes@8.18.1': + resolution: {integrity: sha512-vTOb2itP0pjrccvt8wcKiTGyw0pFMTPI85H12T6n8ZhqXTktPgQH2gEf/SU/5tkPNnBKr4GJ+FdU5hJ27HzgXQ==} engines: {node: '>=18'} '@cspell/strong-weak-map@8.17.4': resolution: {integrity: sha512-Io4ffbMI9hQz+9CLe/oU1Om0H3SqAlvFTaS7ZQOg7joyJSXuGBsCcCg03uTRKWD+NoaxPNUlZOkucUBGil6djw==} engines: {node: '>=18'} - '@cspell/url@8.14.4': - resolution: {integrity: sha512-htHhNF8WrM/NfaLSWuTYw0NqVgFRVHYSyHlRT3i/Yv5xvErld8Gw7C6ldm+0TLjoGlUe6X1VV72JSir7+yLp/Q==} - engines: {node: '>=18.0'} + '@cspell/strong-weak-map@8.18.1': + resolution: {integrity: sha512-gsgv+5ZQD4aHNHDdfNGoafVYkqRynyYgaodt9Dp/3o0YKYcxGf2jrX8SJ35MfZ61qln0n7P4Djrg+bFV2zNH5w==} + engines: {node: '>=18'} '@cspell/url@8.17.4': resolution: {integrity: sha512-vWLySh0ARsI0+TdvA8W6btdeeQbSjBhDE8kwGlzIrOCLIfkeO9Bu++mkc1To1/uogkS2T5icmA24D0rL8ZqjNw==} engines: {node: '>=18.0'} + '@cspell/url@8.18.1': + resolution: {integrity: sha512-FRJbLYDC9ucpTOzbF6MohP2u5X3NU5L0RoVuoYCynqm/QOI38XP6WOEaI4H58CAn857bOIKZk0LZRPTGzi6Qlg==} + engines: {node: '>=18.0'} + '@csstools/color-helpers@5.0.1': resolution: {integrity: sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==} engines: {node: '>=18'} @@ -1975,8 +1849,8 @@ packages: '@emnapi/runtime@1.3.1': resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} - '@es-joy/jsdoccomment@0.48.0': - resolution: {integrity: sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw==} + '@es-joy/jsdoccomment@0.49.0': + resolution: {integrity: sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==} engines: {node: '>=16'} '@esbuild/aix-ppc64@0.21.5': @@ -2417,12 +2291,6 @@ packages: cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.4.1': - resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/eslint-utils@4.5.1': resolution: {integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2433,28 +2301,24 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.19.2': - resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} + '@eslint/config-array@0.20.0': + resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.11.0': - resolution: {integrity: sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==} + '@eslint/config-helpers@0.2.1': + resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/core@0.12.0': resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.2.0': - resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==} + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.12.0': - resolution: {integrity: sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.20.0': - resolution: {integrity: sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==} + '@eslint/js@9.24.0': + resolution: {integrity: sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.6': @@ -2797,6 +2661,10 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@pkgr/core@0.2.1': + resolution: {integrity: sha512-VzgHzGblFmUeBmmrk55zPyrQIArQN4vujc9shWytaPdB3P7qhi0cpaiKIr7tlCmFv2lYUwnLospIqjL9ZSAhhg==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@polka/url@1.0.0-next.28': resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} @@ -3366,6 +3234,9 @@ packages: '@types/web-bluetooth@0.0.20': resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@types/ws@8.5.12': resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} @@ -3381,35 +3252,35 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.24.1': - resolution: {integrity: sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==} + '@typescript-eslint/eslint-plugin@8.29.1': + resolution: {integrity: sha512-ba0rr4Wfvg23vERs3eB+P3lfj2E+2g3lhWcCVukUuhtcdUx5lSIFZlGFEBHKr+3zizDa/TvZTptdNHVZWAkSBg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.8.0' + typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/parser@8.24.1': - resolution: {integrity: sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==} + '@typescript-eslint/parser@8.29.1': + resolution: {integrity: sha512-zczrHVEqEaTwh12gWBIJWj8nx+ayDcCJs06yoNMY0kwjMWDM6+kppljY+BxWI06d2Ja+h4+WdufDcwMnnMEWmg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.8.0' + typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/scope-manager@8.24.1': resolution: {integrity: sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.8.1': - resolution: {integrity: sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==} + '@typescript-eslint/scope-manager@8.29.1': + resolution: {integrity: sha512-2nggXGX5F3YrsGN08pw4XpMLO1Rgtnn4AzTegC2MDesv6q3QaTU5yU7IbS1tf1IwCR0Hv/1EFygLn9ms6LIpDA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.24.1': - resolution: {integrity: sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==} + '@typescript-eslint/type-utils@8.29.1': + resolution: {integrity: sha512-DkDUSDwZVCYN71xA4wzySqqcZsHKic53A4BLqmrWFFpOpNSoxX233lwGu/2135ymTCR04PoKiEEEvN1gFYg4Tw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.8.0' + typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/types@7.18.0': resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} @@ -3419,8 +3290,8 @@ packages: resolution: {integrity: sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.8.1': - resolution: {integrity: sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==} + '@typescript-eslint/types@8.29.1': + resolution: {integrity: sha512-VT7T1PuJF1hpYC3AGm2rCgJBjHL3nc+A/bhOp9sGMKfi5v0WufsX/sHCFBfNTx2F+zA6qBc/PD0/kLRLjdt8mQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@7.18.0': @@ -3438,14 +3309,11 @@ packages: peerDependencies: typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/typescript-estree@8.8.1': - resolution: {integrity: sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==} + '@typescript-eslint/typescript-estree@8.29.1': + resolution: {integrity: sha512-l1enRoSaUkQxOQnbi0KPUtqeZkSiFlqrx9/3ns2rEDhGKfTa+88RmXqedC1zmVTOWrLc2e6DEJrTA51C9iLH5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/utils@8.24.1': resolution: {integrity: sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==} @@ -3454,11 +3322,12 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/utils@8.8.1': - resolution: {integrity: sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==} + '@typescript-eslint/utils@8.29.1': + resolution: {integrity: sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' '@typescript-eslint/visitor-keys@7.18.0': resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} @@ -3468,8 +3337,8 @@ packages: resolution: {integrity: sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.8.1': - resolution: {integrity: sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==} + '@typescript-eslint/visitor-keys@8.29.1': + resolution: {integrity: sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -3558,11 +3427,11 @@ packages: peerDependencies: vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 - '@vite-pwa/vitepress@0.5.3': - resolution: {integrity: sha512-ZNtBxZhS5Enp66z01gKuovTQzSorIpc6o9FEVwOk7kNivzuc4Q5RB04fcbBI1qqHE67rDmm+XqVQw0nj801gmw==} + '@vite-pwa/vitepress@1.0.0': + resolution: {integrity: sha512-i5RFah4urA6tZycYlGyBslVx8cVzbZBcARJLDg5rWMfAkRmyLtpRU6usGfVOwyN9kjJ2Bkm+gBHXF1hhr7HptQ==} peerDependencies: - '@vite-pwa/assets-generator': ^0.2.6 - vite-plugin-pwa: '>=0.20.5 <1' + '@vite-pwa/assets-generator': ^1.0.0 + vite-plugin-pwa: ^1.0.0 peerDependenciesMeta: '@vite-pwa/assets-generator': optional: true @@ -3666,6 +3535,11 @@ packages: '@vueuse/core@12.7.0': resolution: {integrity: sha512-jtK5B7YjZXmkGNHjviyGO4s3ZtEhbzSgrbX+s5o+Lr8i2nYqNyHuPVOeTdM1/hZ5Tkxg/KktAuAVDDiHMraMVA==} + '@vueuse/core@13.1.0': + resolution: {integrity: sha512-PAauvdRXZvTWXtGLg8cPUFjiZEddTqmogdwYpnn60t08AA5a8Q4hZokBnpTOnVNqySlFlTcRYIC8OqreV4hv3Q==} + peerDependencies: + vue: ^3.5.0 + '@vueuse/integrations@12.7.0': resolution: {integrity: sha512-IEq7K4bCl7mn3uKJaWtNXnd1CAPaHLUMuyj5K1/k/pVcItt0VONZW8xiGxdIovJcQjkzOHjImhX5t6gija+0/g==} peerDependencies: @@ -3710,9 +3584,17 @@ packages: '@vueuse/metadata@12.7.0': resolution: {integrity: sha512-4VvTH9mrjXqFN5LYa5YfqHVRI6j7R00Vy4995Rw7PQxyCL3z0Lli86iN4UemWqixxEvYfRjG+hF9wL8oLOn+3g==} + '@vueuse/metadata@13.1.0': + resolution: {integrity: sha512-+TDd7/a78jale5YbHX9KHW3cEDav1lz1JptwDvep2zSG8XjCsVE+9mHIzjTOaPbHUAk5XiE4jXLz51/tS+aKQw==} + '@vueuse/shared@12.7.0': resolution: {integrity: sha512-coLlUw2HHKsm7rPN6WqHJQr18WymN4wkA/3ThFaJ4v4gWGWAQQGK+MJxLuJTBs4mojQiazlVWAKNJNpUWGRkNw==} + '@vueuse/shared@13.1.0': + resolution: {integrity: sha512-IVS/qRRjhPTZ6C2/AM3jieqXACGwFZwWTdw5sNTSKk2m/ZpkuuN+ri+WCVUP8TqaKwJYt/KuMwmXspMAw8E6ew==} + peerDependencies: + vue: ^3.5.0 + '@wdio/config@7.31.1': resolution: {integrity: sha512-WAfswbCatwiaDVqy6kfF/5T8/WS/US/SRhBGUFrfBuGMIe+RRoHgy7jURFWSvUIE7CNHj8yvs46fLUcxhXjzcQ==} engines: {node: '>=12.0.0'} @@ -3835,6 +3717,10 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -4093,6 +3979,9 @@ packages: axios@1.7.9: resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==} + axios@1.8.4: + resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==} + babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4188,6 +4077,10 @@ packages: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} + bonjour-service@1.2.1: resolution: {integrity: sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==} @@ -4597,6 +4490,10 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} + content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} @@ -4614,6 +4511,10 @@ packages: cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} @@ -4684,69 +4585,69 @@ packages: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} - cspell-config-lib@8.14.4: - resolution: {integrity: sha512-cnUeJfniTiebqCaQmIUnbSrPrTH7xzKRQjJDHAEV0WYnOG2MhRXI13OzytdFdhkVBdStmgTzTCJKE7x+kmU2NA==} - engines: {node: '>=18'} - cspell-config-lib@8.17.4: resolution: {integrity: sha512-vOi3B5gnngGeI1HMVDosHTBCRROx7XQXpD6rcKFxxehrs3hw1/EGGEKPKWX5R1UKhOiUNVmvicpqTXU+4/tbZA==} engines: {node: '>=18'} - cspell-dictionary@8.14.4: - resolution: {integrity: sha512-pZvQHxpAW5fZAnt3ZKKy3s7M+3CX2t8tCS3uJrpEHIynlCawpG0fPF78rVE5o+g0dON36Lguc/BUuSN4IWKLmQ==} + cspell-config-lib@8.18.1: + resolution: {integrity: sha512-zdJ0uhLROSUrHoibysPw+AkxKPUmiG95hDtiL7s8smewkuaS1hpjqwsDBx981nHYs3xW3qDUfVATrAkSzb0VMw==} engines: {node: '>=18'} cspell-dictionary@8.17.4: resolution: {integrity: sha512-nzFc/+r6Q0wP5KpvKnjtnI+C2HMaLfrzMaY4VtoCzyqEF8inYQz430e6sSReBDzjshoU9YUxhShXl18aA3eAqA==} engines: {node: '>=18'} + cspell-dictionary@8.18.1: + resolution: {integrity: sha512-vKHEPSfkMKMR4S4tk6K2vHC+f3kdJK8Kdh/C0jDh6RRDjDsyAPxshtbremxOgAX6X8GaRUCROoMZ7FhB92+Y9w==} + engines: {node: '>=18'} + cspell-gitignore@8.17.4: resolution: {integrity: sha512-9KwnXwNwE1eXYRyqHAMFPowJd3yFh2pQnnrfdQRvdculqFY39G4g/d4OQV9W/iMpcednL9K01IhxuUvbF7ZrIA==} engines: {node: '>=18'} hasBin: true - cspell-glob@8.14.4: - resolution: {integrity: sha512-C/xTS5nujMRMuguibq92qMVP767mtxrur7DcVolCvpzcivm1RB5NtIN0OctQxTyMbnmKeQv1t4epRKQ9A8vWRg==} - engines: {node: '>=18'} - cspell-glob@8.17.4: resolution: {integrity: sha512-HbAyg/t6l2Um0kgeTZeTEyXgVkIQX/ir2uLW/W3T9foOkSZ016Os6GRYDRJX7ebfREk8cCZ0uFtOi1Yn56INEQ==} engines: {node: '>=18'} - cspell-grammar@8.14.4: - resolution: {integrity: sha512-yaSKAAJDiamsw3FChbw4HXb2RvTQrDsLelh1+T4MavarOIcAxXrqAJ8ysqm++g+S/ooJz2YO8YWIyzJKxcMf8g==} + cspell-glob@8.18.1: + resolution: {integrity: sha512-tlZXvzsN7dByHo69dz/HbJuQDUtrfhdioZ/LHaW7W9diG9NpaghgEfyX4fmsIXjU/2f66LDpYVY6osjtlOgyrg==} engines: {node: '>=18'} - hasBin: true cspell-grammar@8.17.4: resolution: {integrity: sha512-RgnpQPVSOdWxq7fLHUkjGJCkMNay4p2cZXRYwhTBJf2kWNsDC39tjRhugFweyxxZPamEbLERgkCaFzE54enuMw==} engines: {node: '>=18'} hasBin: true - cspell-io@8.14.4: - resolution: {integrity: sha512-o6OTWRyx/Az+PFhr1B0wMAwqG070hFC9g73Fkxd8+rHX0rfRS69QZH7LgSmZytqbZIMxCTDGdsLl33MFGWCbZQ==} + cspell-grammar@8.18.1: + resolution: {integrity: sha512-V6XTN1B++7EzJA0H4g4XbNJtqm6Y3/iXdLeZ6sMRDaNFKXXwTbWRtn8gukDQIytyw09AnCUKeqGSzCVqw26Omg==} engines: {node: '>=18'} + hasBin: true cspell-io@8.17.4: resolution: {integrity: sha512-lHvkxquov5XfIXSenzXrWcOWPiW79+uySoExb20UXHvPSMz0Bk7ZIqDf6lMwTquXbM4BvGGsKQbQE/D4SLD9jw==} engines: {node: '>=18'} - cspell-lib@8.14.4: - resolution: {integrity: sha512-qdkUkKtm+nmgpA4jQbmQTuepDfjHBDWvs3zDuEwVIVFq/h8gnXrRr75gJ3RYdTy+vOOqHPoLLqgxyqkUUrUGXA==} + cspell-io@8.18.1: + resolution: {integrity: sha512-mm9SUEF2yShuTXDSjCbsAqYTEb6jrtgcCnlqIzpsZOJOOe+zj/VyzTy2NJvOrdvR59dikdaqB75VGBMfHi804g==} engines: {node: '>=18'} cspell-lib@8.17.4: resolution: {integrity: sha512-BxQy4MDFSjMQ74SYptWJOLLPsNC8XDtKyey0IfMQaqeFmuxrz727GWcONQ2KROrPPs9dnmccDs6Kn8Tx7Wug4A==} engines: {node: '>=18'} - cspell-trie-lib@8.14.4: - resolution: {integrity: sha512-zu8EJ33CH+FA5lwTRGqS//Q6phO0qtgEmODMR1KPlD7WlrfTFMb3bWFsLo/tiv5hjpsn7CM6dYDAAgBOSkoyhQ==} + cspell-lib@8.18.1: + resolution: {integrity: sha512-t1j+XB7515yHmrczK6I1N6j0a72vmL/6OxsMJnCucHC6DO0WkOqmHulNRH7LpFacnns0dx15lmrAqPg7gQFcIg==} engines: {node: '>=18'} cspell-trie-lib@8.17.4: resolution: {integrity: sha512-Ou2MGBnZyC+Hti57m4T4D/Tq1P3G570rFPkxgi32f325xsLz1AVEvqrM5oVHDilFH2guUYFaelmL0UcGeP3L6w==} engines: {node: '>=18'} + cspell-trie-lib@8.18.1: + resolution: {integrity: sha512-UaB36wsyp2eWeMtrbS6Q2t2WFvpedmGXJ879yHn9qKD7ViyUpI4cAbh6v7gWMUu+gjqCulXtke64k1ddmBihPQ==} + engines: {node: '>=18'} + cspell@8.17.4: resolution: {integrity: sha512-cQ6KyYB7itXxc+roxvozIKksbOyBO1NY5Dt5RWHl1Uh4OO++RJAKxmVWrY0g1ubBxKWGXk8TvuunK1+L/jvjIQ==} engines: {node: '>=18'} @@ -5222,8 +5123,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.2.4: - resolution: {integrity: sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==} + dompurify@3.2.5: + resolution: {integrity: sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ==} domutils@3.1.0: resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} @@ -5419,14 +5320,14 @@ packages: engines: {node: '>=6.0'} hasBin: true - eslint-config-prettier@10.0.1: - resolution: {integrity: sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==} + eslint-config-prettier@10.1.1: + resolution: {integrity: sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==} hasBin: true peerDependencies: eslint: '>=7.0.0' - eslint-plugin-cypress@4.1.0: - resolution: {integrity: sha512-JhqkMY02mw74USwK9OFhectx3YSj6Co1NgWBxlGdKvlqiAp9vdEuQqt33DKGQFvvGS/NWtduuhWXWNnU29xDSg==} + eslint-plugin-cypress@4.2.1: + resolution: {integrity: sha512-WNhKkQPqXcbDL7pxGnNYBVLlAIOk6eHdFGQFRELsba871guZZe8zZe50GAjBXSZKcvUWbzCUopM+8ArlngdyGQ==} peerDependencies: eslint: '>=9' @@ -5434,8 +5335,8 @@ packages: resolution: {integrity: sha512-pbRchDV2SmqbCi/Ev/q3aAikzG9BcFe0IjjqjtMn8eTLq71ZUggyJB6CDmuwGAXmYZHrXI12XTfCqvgcnPRqGw==} engines: {node: '>=16.0.0'} - eslint-plugin-jest@28.8.3: - resolution: {integrity: sha512-HIQ3t9hASLKm2IhIOqnu+ifw7uLZkIlR7RYNv7fMcEi/p0CIiJmfriStQS2LDkgtY4nyLbIZAD+JL347Yc2ETQ==} + eslint-plugin-jest@28.11.0: + resolution: {integrity: sha512-QAfipLcNCWLVocVbZW8GimKn5p5iiMcgGbRzz8z/P5q7xw+cNEpYqyzFMtIF/ZgF2HLOyy+dYBut+DoYolvqig==} engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} peerDependencies: '@typescript-eslint/eslint-plugin': ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -5447,8 +5348,8 @@ packages: jest: optional: true - eslint-plugin-jsdoc@50.3.2: - resolution: {integrity: sha512-TjgZocG53N3a84PdCFGqVMWLWwDitOUuKjlJftwTu/iTiD7N/Q2Q3eEy/Q4GfJqpM4rTJCkzUYWQfol6RZNDcA==} + eslint-plugin-jsdoc@50.6.9: + resolution: {integrity: sha512-7/nHu3FWD4QRG8tCVqcv+BfFtctUtEDWc29oeDXB4bwmDM2/r1ndl14AG/2DUntdqH7qmpvdemJKwb3R97/QEw==} engines: {node: '>=18'} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -5486,8 +5387,8 @@ packages: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} - eslint-scope@8.2.0: - resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==} + eslint-scope@8.3.0: + resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint-visitor-keys@3.4.3: @@ -5498,8 +5399,8 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.20.1: - resolution: {integrity: sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==} + eslint@9.24.0: + resolution: {integrity: sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -5619,6 +5520,10 @@ packages: resolution: {integrity: sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==} engines: {node: '>= 0.10.0'} + express@5.1.0: + resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + engines: {node: '>= 18'} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -5647,10 +5552,6 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-equals@5.0.1: - resolution: {integrity: sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==} - engines: {node: '>=6.0.0'} - fast-equals@5.2.2: resolution: {integrity: sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==} engines: {node: '>=6.0.0'} @@ -5762,6 +5663,10 @@ packages: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} + finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + find-cache-dir@3.3.2: resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} engines: {node: '>=8'} @@ -5876,6 +5781,10 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + from@0.1.7: resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} @@ -6284,10 +6193,6 @@ packages: resolution: {integrity: sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==} engines: {node: '>= 4'} - import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -6510,6 +6415,9 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -7246,6 +7154,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + memfs@3.5.3: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} @@ -7257,6 +7169,10 @@ packages: merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -7379,10 +7295,18 @@ packages: resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -7496,6 +7420,10 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -7663,8 +7591,8 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - openapi-fetch@0.13.4: - resolution: {integrity: sha512-JHX7UYjLEiHuQGCPxa3CCCIqe/nc4bTIF9c4UYVC8BegAbWoS3g4gJxKX5XcG7UtYQs2060kY6DH64KkvNZahg==} + openapi-fetch@0.13.5: + resolution: {integrity: sha512-AQK8T9GSKFREFlN1DBXTYsLjs7YV2tZcJ7zUWxbjMoQmj8dDSFRrzhLCbHPZWA1TMV3vACqfCxLEZcwf2wxV6Q==} openapi-typescript-helpers@0.0.15: resolution: {integrity: sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==} @@ -7862,6 +7790,10 @@ packages: path-to-regexp@0.1.10: resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -8136,6 +8068,10 @@ packages: resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==} engines: {node: '>=0.6'} + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -8169,6 +8105,10 @@ packages: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} + raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} @@ -8417,6 +8357,10 @@ packages: roughjs@4.6.6: resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + rrweb-cssom@0.8.0: resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} @@ -8513,6 +8457,10 @@ packages: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -8524,6 +8472,10 @@ packages: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} + serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} @@ -8922,6 +8874,10 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + synckit@0.10.3: + resolution: {integrity: sha512-R1urvuyiTaWfeCggqEvpDJwAlDVdsT9NM+IP//Tk2x7qHCkSvBk/fwFgw/TLAHzZlrAnnazMcRw0ZD8HlYFTEQ==} + engines: {node: ^14.18.0 || >=16.0.0} + synckit@0.9.2: resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} engines: {node: ^14.18.0 || >=16.0.0} @@ -9176,6 +9132,10 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -9208,12 +9168,12 @@ packages: peerDependencies: typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x - typescript-eslint@8.24.1: - resolution: {integrity: sha512-cw3rEdzDqBs70TIcb0Gdzbt6h11BSs2pS0yaq7hDWDBtCCSei1pPSUXE9qUdQ/Wm9NgFg8mKtMt1b8fTHIl1jA==} + typescript-eslint@8.29.1: + resolution: {integrity: sha512-f8cDkvndhbQMPcysk6CUSGBWV+g1utqdn71P5YKwMumVMOG/5k7cHq0KyG4O52nB0oKS4aN2Tp5+wB4APJGC+w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.8.0' + typescript: '>=4.8.4 <5.9.0' typescript@5.7.3: resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} @@ -9427,11 +9387,11 @@ packages: peerDependencies: vite: '>=4 <=6' - vite-plugin-pwa@0.21.1: - resolution: {integrity: sha512-rkTbKFbd232WdiRJ9R3u+hZmf5SfQljX1b45NF6oLA6DSktEKpYllgTo1l2lkiZWMWV78pABJtFjNXfBef3/3Q==} + vite-plugin-pwa@1.0.0: + resolution: {integrity: sha512-X77jo0AOd5OcxmWj3WnVti8n7Kw2tBgV1c8MCXFclrSlDV23ePzv2eTDIALXI2Qo6nJ5pZJeZAuX0AawvRfoeA==} engines: {node: '>=16.0.0'} peerDependencies: - '@vite-pwa/assets-generator': ^0.2.6 + '@vite-pwa/assets-generator': ^1.0.0 vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 workbox-build: ^7.3.0 workbox-window: ^7.3.0 @@ -10380,20 +10340,20 @@ snapshots: '@applitools/utils@1.7.7': {} - '@argos-ci/api-client@0.8.0': + '@argos-ci/api-client@0.8.1': dependencies: debug: 4.4.0(supports-color@8.1.1) - openapi-fetch: 0.13.4 + openapi-fetch: 0.13.5 transitivePeerDependencies: - supports-color - '@argos-ci/browser@3.0.1': {} + '@argos-ci/browser@4.1.1': {} - '@argos-ci/core@3.1.0': + '@argos-ci/core@3.1.1': dependencies: - '@argos-ci/api-client': 0.8.0 - '@argos-ci/util': 2.3.0 - axios: 1.7.9(debug@4.4.0) + '@argos-ci/api-client': 0.8.1 + '@argos-ci/util': 2.3.1 + axios: 1.8.4(debug@4.4.0) convict: 6.2.4 debug: 4.4.0(supports-color@8.1.1) fast-glob: 3.3.3 @@ -10402,17 +10362,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@argos-ci/cypress@3.2.0(cypress@14.0.3)': + '@argos-ci/cypress@4.0.3(cypress@14.0.3)': dependencies: - '@argos-ci/browser': 3.0.1 - '@argos-ci/core': 3.1.0 - '@argos-ci/util': 2.3.0 + '@argos-ci/browser': 4.1.1 + '@argos-ci/core': 3.1.1 + '@argos-ci/util': 2.3.1 cypress: 14.0.3 cypress-wait-until: 3.0.2 transitivePeerDependencies: - supports-color - '@argos-ci/util@2.3.0': {} + '@argos-ci/util@2.3.1': {} '@asamuzakjp/css-color@2.8.3': dependencies: @@ -11331,62 +11291,6 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@cspell/cspell-bundled-dicts@8.14.4': - dependencies: - '@cspell/dict-ada': 4.0.2 - '@cspell/dict-aws': 4.0.4 - '@cspell/dict-bash': 4.1.5 - '@cspell/dict-companies': 3.1.4 - '@cspell/dict-cpp': 5.1.19 - '@cspell/dict-cryptocurrencies': 5.0.0 - '@cspell/dict-csharp': 4.0.2 - '@cspell/dict-css': 4.0.13 - '@cspell/dict-dart': 2.2.1 - '@cspell/dict-django': 4.1.0 - '@cspell/dict-docker': 1.1.7 - '@cspell/dict-dotnet': 5.0.5 - '@cspell/dict-elixir': 4.0.3 - '@cspell/dict-en-common-misspellings': 2.0.4 - '@cspell/dict-en-gb': 1.1.33 - '@cspell/dict-en_us': 4.3.23 - '@cspell/dict-filetypes': 3.0.4 - '@cspell/dict-flutter': 1.0.0 - '@cspell/dict-fonts': 4.0.0 - '@cspell/dict-fsharp': 1.0.1 - '@cspell/dict-fullstack': 3.2.0 - '@cspell/dict-gaming-terms': 1.0.5 - '@cspell/dict-git': 3.0.0 - '@cspell/dict-golang': 6.0.13 - '@cspell/dict-google': 1.0.1 - '@cspell/dict-haskell': 4.0.1 - '@cspell/dict-html': 4.0.6 - '@cspell/dict-html-symbol-entities': 4.0.0 - '@cspell/dict-java': 5.0.7 - '@cspell/dict-julia': 1.0.1 - '@cspell/dict-k8s': 1.0.6 - '@cspell/dict-latex': 4.0.0 - '@cspell/dict-lorem-ipsum': 4.0.0 - '@cspell/dict-lua': 4.0.3 - '@cspell/dict-makefile': 1.0.0 - '@cspell/dict-monkeyc': 1.0.6 - '@cspell/dict-node': 5.0.1 - '@cspell/dict-npm': 5.1.5 - '@cspell/dict-php': 4.0.10 - '@cspell/dict-powershell': 5.0.10 - '@cspell/dict-public-licenses': 2.0.8 - '@cspell/dict-python': 4.2.8 - '@cspell/dict-r': 2.0.1 - '@cspell/dict-ruby': 5.0.4 - '@cspell/dict-rust': 4.0.6 - '@cspell/dict-scala': 5.0.3 - '@cspell/dict-software-terms': 4.1.7 - '@cspell/dict-sql': 2.1.5 - '@cspell/dict-svelte': 1.0.2 - '@cspell/dict-swift': 2.0.1 - '@cspell/dict-terraform': 1.0.2 - '@cspell/dict-typescript': 3.1.6 - '@cspell/dict-vue': 3.0.0 - '@cspell/cspell-bundled-dicts@8.17.4': dependencies: '@cspell/dict-ada': 4.1.0 @@ -11448,176 +11352,179 @@ snapshots: '@cspell/dict-typescript': 3.2.0 '@cspell/dict-vue': 3.0.4 + '@cspell/cspell-bundled-dicts@8.18.1': + dependencies: + '@cspell/dict-ada': 4.1.0 + '@cspell/dict-al': 1.1.0 + '@cspell/dict-aws': 4.0.9 + '@cspell/dict-bash': 4.2.0 + '@cspell/dict-companies': 3.1.14 + '@cspell/dict-cpp': 6.0.7 + '@cspell/dict-cryptocurrencies': 5.0.4 + '@cspell/dict-csharp': 4.0.6 + '@cspell/dict-css': 4.0.17 + '@cspell/dict-dart': 2.3.0 + '@cspell/dict-data-science': 2.0.7 + '@cspell/dict-django': 4.1.4 + '@cspell/dict-docker': 1.1.12 + '@cspell/dict-dotnet': 5.0.9 + '@cspell/dict-elixir': 4.0.7 + '@cspell/dict-en-common-misspellings': 2.0.10 + '@cspell/dict-en-gb': 1.1.33 + '@cspell/dict-en_us': 4.4.0 + '@cspell/dict-filetypes': 3.0.11 + '@cspell/dict-flutter': 1.1.0 + '@cspell/dict-fonts': 4.0.4 + '@cspell/dict-fsharp': 1.1.0 + '@cspell/dict-fullstack': 3.2.6 + '@cspell/dict-gaming-terms': 1.1.0 + '@cspell/dict-git': 3.0.4 + '@cspell/dict-golang': 6.0.20 + '@cspell/dict-google': 1.0.8 + '@cspell/dict-haskell': 4.0.5 + '@cspell/dict-html': 4.0.11 + '@cspell/dict-html-symbol-entities': 4.0.3 + '@cspell/dict-java': 5.0.11 + '@cspell/dict-julia': 1.1.0 + '@cspell/dict-k8s': 1.0.10 + '@cspell/dict-kotlin': 1.1.0 + '@cspell/dict-latex': 4.0.3 + '@cspell/dict-lorem-ipsum': 4.0.4 + '@cspell/dict-lua': 4.0.7 + '@cspell/dict-makefile': 1.0.4 + '@cspell/dict-markdown': 2.0.9(@cspell/dict-css@4.0.17)(@cspell/dict-html-symbol-entities@4.0.3)(@cspell/dict-html@4.0.11)(@cspell/dict-typescript@3.2.0) + '@cspell/dict-monkeyc': 1.0.10 + '@cspell/dict-node': 5.0.6 + '@cspell/dict-npm': 5.1.34 + '@cspell/dict-php': 4.0.14 + '@cspell/dict-powershell': 5.0.14 + '@cspell/dict-public-licenses': 2.0.13 + '@cspell/dict-python': 4.2.17 + '@cspell/dict-r': 2.1.0 + '@cspell/dict-ruby': 5.0.8 + '@cspell/dict-rust': 4.0.11 + '@cspell/dict-scala': 5.0.7 + '@cspell/dict-shell': 1.1.0 + '@cspell/dict-software-terms': 5.0.5 + '@cspell/dict-sql': 2.2.0 + '@cspell/dict-svelte': 1.0.6 + '@cspell/dict-swift': 2.0.5 + '@cspell/dict-terraform': 1.1.1 + '@cspell/dict-typescript': 3.2.0 + '@cspell/dict-vue': 3.0.4 + '@cspell/cspell-json-reporter@8.17.4': dependencies: '@cspell/cspell-types': 8.17.4 - '@cspell/cspell-pipe@8.14.4': {} - '@cspell/cspell-pipe@8.17.4': {} - '@cspell/cspell-resolver@8.14.4': - dependencies: - global-directory: 4.0.1 + '@cspell/cspell-pipe@8.18.1': {} '@cspell/cspell-resolver@8.17.4': dependencies: global-directory: 4.0.1 - '@cspell/cspell-service-bus@8.14.4': {} + '@cspell/cspell-resolver@8.18.1': + dependencies: + global-directory: 4.0.1 '@cspell/cspell-service-bus@8.17.4': {} - '@cspell/cspell-types@8.14.4': {} + '@cspell/cspell-service-bus@8.18.1': {} '@cspell/cspell-types@8.17.4': {} - '@cspell/dict-ada@4.0.2': {} + '@cspell/cspell-types@8.18.1': {} '@cspell/dict-ada@4.1.0': {} '@cspell/dict-al@1.1.0': {} - '@cspell/dict-aws@4.0.4': {} - '@cspell/dict-aws@4.0.9': {} - '@cspell/dict-bash@4.1.5': {} - '@cspell/dict-bash@4.2.0': dependencies: '@cspell/dict-shell': 1.1.0 '@cspell/dict-companies@3.1.14': {} - '@cspell/dict-companies@3.1.4': {} - - '@cspell/dict-cpp@5.1.19': {} - '@cspell/dict-cpp@6.0.3': {} - '@cspell/dict-cryptocurrencies@5.0.0': {} + '@cspell/dict-cpp@6.0.7': {} '@cspell/dict-cryptocurrencies@5.0.4': {} - '@cspell/dict-csharp@4.0.2': {} - '@cspell/dict-csharp@4.0.6': {} - '@cspell/dict-css@4.0.13': {} - '@cspell/dict-css@4.0.17': {} - '@cspell/dict-dart@2.2.1': {} - '@cspell/dict-dart@2.3.0': {} - '@cspell/dict-data-science@2.0.2': {} - '@cspell/dict-data-science@2.0.7': {} - '@cspell/dict-django@4.1.0': {} + '@cspell/dict-data-science@2.0.8': {} '@cspell/dict-django@4.1.4': {} '@cspell/dict-docker@1.1.12': {} - '@cspell/dict-docker@1.1.7': {} - - '@cspell/dict-dotnet@5.0.5': {} - '@cspell/dict-dotnet@5.0.9': {} - '@cspell/dict-elixir@4.0.3': {} - '@cspell/dict-elixir@4.0.7': {} - '@cspell/dict-en-common-misspellings@2.0.4': {} + '@cspell/dict-en-common-misspellings@2.0.10': {} '@cspell/dict-en-common-misspellings@2.0.9': {} '@cspell/dict-en-gb@1.1.33': {} - '@cspell/dict-en_us@4.3.23': {} - '@cspell/dict-en_us@4.3.31': {} + '@cspell/dict-en_us@4.4.0': {} + '@cspell/dict-filetypes@3.0.11': {} - '@cspell/dict-filetypes@3.0.4': {} - - '@cspell/dict-flutter@1.0.0': {} - '@cspell/dict-flutter@1.1.0': {} - '@cspell/dict-fonts@4.0.0': {} - '@cspell/dict-fonts@4.0.4': {} - '@cspell/dict-fsharp@1.0.1': {} - '@cspell/dict-fsharp@1.1.0': {} - '@cspell/dict-fullstack@3.2.0': {} - '@cspell/dict-fullstack@3.2.4': {} - '@cspell/dict-gaming-terms@1.0.5': {} + '@cspell/dict-fullstack@3.2.6': {} '@cspell/dict-gaming-terms@1.1.0': {} - '@cspell/dict-git@3.0.0': {} - '@cspell/dict-git@3.0.4': {} - '@cspell/dict-golang@6.0.13': {} - '@cspell/dict-golang@6.0.18': {} - '@cspell/dict-google@1.0.1': {} + '@cspell/dict-golang@6.0.20': {} '@cspell/dict-google@1.0.8': {} - '@cspell/dict-haskell@4.0.1': {} - '@cspell/dict-haskell@4.0.5': {} - '@cspell/dict-html-symbol-entities@4.0.0': {} - '@cspell/dict-html-symbol-entities@4.0.3': {} '@cspell/dict-html@4.0.11': {} - '@cspell/dict-html@4.0.6': {} - '@cspell/dict-java@5.0.11': {} - '@cspell/dict-java@5.0.7': {} - - '@cspell/dict-julia@1.0.1': {} - '@cspell/dict-julia@1.1.0': {} '@cspell/dict-k8s@1.0.10': {} - '@cspell/dict-k8s@1.0.6': {} - '@cspell/dict-kotlin@1.1.0': {} - '@cspell/dict-latex@4.0.0': {} - '@cspell/dict-latex@4.0.3': {} - '@cspell/dict-lorem-ipsum@4.0.0': {} - '@cspell/dict-lorem-ipsum@4.0.4': {} - '@cspell/dict-lua@4.0.3': {} - '@cspell/dict-lua@4.0.7': {} - '@cspell/dict-makefile@1.0.0': {} - '@cspell/dict-makefile@1.0.4': {} '@cspell/dict-markdown@2.0.9(@cspell/dict-css@4.0.17)(@cspell/dict-html-symbol-entities@4.0.3)(@cspell/dict-html@4.0.11)(@cspell/dict-typescript@3.2.0)': @@ -11629,111 +11536,86 @@ snapshots: '@cspell/dict-monkeyc@1.0.10': {} - '@cspell/dict-monkeyc@1.0.6': {} - - '@cspell/dict-node@5.0.1': {} - '@cspell/dict-node@5.0.6': {} '@cspell/dict-npm@5.1.26': {} - '@cspell/dict-npm@5.1.5': {} - - '@cspell/dict-php@4.0.10': {} + '@cspell/dict-npm@5.1.34': {} '@cspell/dict-php@4.0.14': {} - '@cspell/dict-powershell@5.0.10': {} - '@cspell/dict-powershell@5.0.14': {} '@cspell/dict-public-licenses@2.0.13': {} - '@cspell/dict-public-licenses@2.0.8': {} - '@cspell/dict-python@4.2.15': dependencies: '@cspell/dict-data-science': 2.0.7 - '@cspell/dict-python@4.2.8': + '@cspell/dict-python@4.2.17': dependencies: - '@cspell/dict-data-science': 2.0.2 - - '@cspell/dict-r@2.0.1': {} + '@cspell/dict-data-science': 2.0.8 '@cspell/dict-r@2.1.0': {} - '@cspell/dict-ruby@5.0.4': {} - '@cspell/dict-ruby@5.0.7': {} + '@cspell/dict-ruby@5.0.8': {} + '@cspell/dict-rust@4.0.11': {} - '@cspell/dict-rust@4.0.6': {} - - '@cspell/dict-scala@5.0.3': {} - '@cspell/dict-scala@5.0.7': {} '@cspell/dict-shell@1.1.0': {} - '@cspell/dict-software-terms@4.1.7': {} - '@cspell/dict-software-terms@4.2.5': {} - '@cspell/dict-sql@2.1.5': {} + '@cspell/dict-software-terms@5.0.5': {} '@cspell/dict-sql@2.2.0': {} - '@cspell/dict-svelte@1.0.2': {} - '@cspell/dict-svelte@1.0.6': {} - '@cspell/dict-swift@2.0.1': {} - '@cspell/dict-swift@2.0.5': {} - '@cspell/dict-terraform@1.0.2': {} - '@cspell/dict-terraform@1.1.0': {} - '@cspell/dict-typescript@3.1.6': {} + '@cspell/dict-terraform@1.1.1': {} '@cspell/dict-typescript@3.2.0': {} - '@cspell/dict-vue@3.0.0': {} - '@cspell/dict-vue@3.0.4': {} - '@cspell/dynamic-import@8.14.4': - dependencies: - import-meta-resolve: 4.1.0 - '@cspell/dynamic-import@8.17.4': dependencies: '@cspell/url': 8.17.4 import-meta-resolve: 4.1.0 - '@cspell/eslint-plugin@8.14.4(eslint@9.20.1(jiti@2.4.2))': + '@cspell/dynamic-import@8.18.1': dependencies: - '@cspell/cspell-types': 8.14.4 - '@cspell/url': 8.14.4 - cspell-lib: 8.14.4 - eslint: 9.20.1(jiti@2.4.2) - synckit: 0.9.2 + '@cspell/url': 8.18.1 + import-meta-resolve: 4.1.0 - '@cspell/filetypes@8.14.4': {} + '@cspell/eslint-plugin@8.18.1(eslint@9.24.0(jiti@2.4.2))': + dependencies: + '@cspell/cspell-types': 8.18.1 + '@cspell/url': 8.18.1 + cspell-lib: 8.18.1 + eslint: 9.24.0(jiti@2.4.2) + synckit: 0.10.3 '@cspell/filetypes@8.17.4': {} - '@cspell/strong-weak-map@8.14.4': {} + '@cspell/filetypes@8.18.1': {} '@cspell/strong-weak-map@8.17.4': {} - '@cspell/url@8.14.4': {} + '@cspell/strong-weak-map@8.18.1': {} '@cspell/url@8.17.4': {} + '@cspell/url@8.18.1': {} + '@csstools/color-helpers@5.0.1': {} '@csstools/css-calc@2.1.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)': @@ -11849,7 +11731,7 @@ snapshots: tslib: 2.8.1 optional: true - '@es-joy/jsdoccomment@0.48.0': + '@es-joy/jsdoccomment@0.49.0': dependencies: comment-parser: 1.4.1 esquery: 1.6.0 @@ -12074,19 +11956,14 @@ snapshots: '@esbuild/win32-x64@0.25.0': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@9.20.1(jiti@2.4.2))': + '@eslint-community/eslint-utils@4.5.1(eslint@9.24.0(jiti@2.4.2))': dependencies: - eslint: 9.20.1(jiti@2.4.2) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/eslint-utils@4.5.1(eslint@9.20.1(jiti@2.4.2))': - dependencies: - eslint: 9.20.1(jiti@2.4.2) + eslint: 9.24.0(jiti@2.4.2) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/config-array@0.19.2': + '@eslint/config-array@0.20.0': dependencies: '@eslint/object-schema': 2.1.6 debug: 4.4.0(supports-color@8.1.1) @@ -12094,15 +11971,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/core@0.11.0': - dependencies: - '@types/json-schema': 7.0.15 + '@eslint/config-helpers@0.2.1': {} '@eslint/core@0.12.0': dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.2.0': + '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 debug: 4.4.0(supports-color@8.1.1) @@ -12116,9 +11991,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.12.0': {} - - '@eslint/js@9.20.0': {} + '@eslint/js@9.24.0': {} '@eslint/object-schema@2.1.6': {} @@ -12558,6 +12431,8 @@ snapshots: '@pkgr/core@0.1.1': {} + '@pkgr/core@0.2.1': {} + '@polka/url@1.0.0-next.28': {} '@rollup/plugin-babel@5.3.1(@babel/core@7.26.9)(@types/babel__core@7.20.5)(rollup@2.79.2)': @@ -13172,6 +13047,8 @@ snapshots: '@types/web-bluetooth@0.0.20': {} + '@types/web-bluetooth@0.0.21': {} + '@types/ws@8.5.12': dependencies: '@types/node': 22.13.5 @@ -13191,15 +13068,15 @@ snapshots: '@types/node': 22.13.5 optional: true - '@typescript-eslint/eslint-plugin@8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3))(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3)': + '@typescript-eslint/eslint-plugin@8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3) - '@typescript-eslint/scope-manager': 8.24.1 - '@typescript-eslint/type-utils': 8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3) - '@typescript-eslint/utils': 8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3) - '@typescript-eslint/visitor-keys': 8.24.1 - eslint: 9.20.1(jiti@2.4.2) + '@typescript-eslint/parser': 8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.29.1 + '@typescript-eslint/type-utils': 8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/utils': 8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.29.1 + eslint: 9.24.0(jiti@2.4.2) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -13208,14 +13085,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3)': + '@typescript-eslint/parser@8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: - '@typescript-eslint/scope-manager': 8.24.1 - '@typescript-eslint/types': 8.24.1 - '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.7.3) - '@typescript-eslint/visitor-keys': 8.24.1 + '@typescript-eslint/scope-manager': 8.29.1 + '@typescript-eslint/types': 8.29.1 + '@typescript-eslint/typescript-estree': 8.29.1(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.29.1 debug: 4.4.0(supports-color@8.1.1) - eslint: 9.20.1(jiti@2.4.2) + eslint: 9.24.0(jiti@2.4.2) typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -13225,17 +13102,17 @@ snapshots: '@typescript-eslint/types': 8.24.1 '@typescript-eslint/visitor-keys': 8.24.1 - '@typescript-eslint/scope-manager@8.8.1': + '@typescript-eslint/scope-manager@8.29.1': dependencies: - '@typescript-eslint/types': 8.8.1 - '@typescript-eslint/visitor-keys': 8.8.1 + '@typescript-eslint/types': 8.29.1 + '@typescript-eslint/visitor-keys': 8.29.1 - '@typescript-eslint/type-utils@8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3)': + '@typescript-eslint/type-utils@8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.7.3) - '@typescript-eslint/utils': 8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/typescript-estree': 8.29.1(typescript@5.7.3) + '@typescript-eslint/utils': 8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3) debug: 4.4.0(supports-color@8.1.1) - eslint: 9.20.1(jiti@2.4.2) + eslint: 9.24.0(jiti@2.4.2) ts-api-utils: 2.0.1(typescript@5.7.3) typescript: 5.7.3 transitivePeerDependencies: @@ -13245,7 +13122,7 @@ snapshots: '@typescript-eslint/types@8.24.1': {} - '@typescript-eslint/types@8.8.1': {} + '@typescript-eslint/types@8.29.1': {} '@typescript-eslint/typescript-estree@7.18.0(typescript@5.7.3)': dependencies: @@ -13276,42 +13153,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.8.1(typescript@5.7.3)': + '@typescript-eslint/typescript-estree@8.29.1(typescript@5.7.3)': dependencies: - '@typescript-eslint/types': 8.8.1 - '@typescript-eslint/visitor-keys': 8.8.1 + '@typescript-eslint/types': 8.29.1 + '@typescript-eslint/visitor-keys': 8.29.1 debug: 4.4.0(supports-color@8.1.1) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.7.1 - ts-api-utils: 1.3.0(typescript@5.7.3) - optionalDependencies: + ts-api-utils: 2.0.1(typescript@5.7.3) typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3)': + '@typescript-eslint/utils@8.24.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.5.1(eslint@9.24.0(jiti@2.4.2)) '@typescript-eslint/scope-manager': 8.24.1 '@typescript-eslint/types': 8.24.1 '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.7.3) - eslint: 9.20.1(jiti@2.4.2) + eslint: 9.24.0(jiti@2.4.2) typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.8.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3)': + '@typescript-eslint/utils@8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@2.4.2)) - '@typescript-eslint/scope-manager': 8.8.1 - '@typescript-eslint/types': 8.8.1 - '@typescript-eslint/typescript-estree': 8.8.1(typescript@5.7.3) - eslint: 9.20.1(jiti@2.4.2) + '@eslint-community/eslint-utils': 4.5.1(eslint@9.24.0(jiti@2.4.2)) + '@typescript-eslint/scope-manager': 8.29.1 + '@typescript-eslint/types': 8.29.1 + '@typescript-eslint/typescript-estree': 8.29.1(typescript@5.7.3) + eslint: 9.24.0(jiti@2.4.2) + typescript: 5.7.3 transitivePeerDependencies: - supports-color - - typescript '@typescript-eslint/visitor-keys@7.18.0': dependencies: @@ -13323,10 +13199,10 @@ snapshots: '@typescript-eslint/types': 8.24.1 eslint-visitor-keys: 4.2.0 - '@typescript-eslint/visitor-keys@8.8.1': + '@typescript-eslint/visitor-keys@8.29.1': dependencies: - '@typescript-eslint/types': 8.8.1 - eslint-visitor-keys: 3.4.3 + '@typescript-eslint/types': 8.29.1 + eslint-visitor-keys: 4.2.0 '@ungap/structured-clone@1.3.0': {} @@ -13475,9 +13351,9 @@ snapshots: transitivePeerDependencies: - vue - '@vite-pwa/vitepress@0.5.3(vite-plugin-pwa@0.21.1(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0))': + '@vite-pwa/vitepress@1.0.0(vite-plugin-pwa@1.0.0(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0))': dependencies: - vite-plugin-pwa: 0.21.1(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0) + vite-plugin-pwa: 1.0.0(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0) '@vitejs/plugin-vue@5.2.1(vite@5.4.14(@types/node@22.13.5)(terser@5.39.0))(vue@3.5.13(typescript@5.7.3))': dependencies: @@ -13648,25 +13524,38 @@ snapshots: transitivePeerDependencies: - typescript - '@vueuse/integrations@12.7.0(axios@1.7.9)(focus-trap@7.6.4)(typescript@5.7.3)': + '@vueuse/core@13.1.0(vue@3.5.13(typescript@5.7.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 13.1.0 + '@vueuse/shared': 13.1.0(vue@3.5.13(typescript@5.7.3)) + vue: 3.5.13(typescript@5.7.3) + + '@vueuse/integrations@12.7.0(axios@1.8.4)(focus-trap@7.6.4)(typescript@5.7.3)': dependencies: '@vueuse/core': 12.7.0(typescript@5.7.3) '@vueuse/shared': 12.7.0(typescript@5.7.3) vue: 3.5.13(typescript@5.7.3) optionalDependencies: - axios: 1.7.9(debug@4.4.0) + axios: 1.8.4(debug@4.4.0) focus-trap: 7.6.4 transitivePeerDependencies: - typescript '@vueuse/metadata@12.7.0': {} + '@vueuse/metadata@13.1.0': {} + '@vueuse/shared@12.7.0(typescript@5.7.3)': dependencies: vue: 3.5.13(typescript@5.7.3) transitivePeerDependencies: - typescript + '@vueuse/shared@13.1.0(vue@3.5.13(typescript@5.7.3))': + dependencies: + vue: 3.5.13(typescript@5.7.3) + '@wdio/config@7.31.1(typescript@5.7.3)': dependencies: '@types/glob': 8.1.0 @@ -13811,7 +13700,7 @@ snapshots: antlr4: 4.11.0 color-string: 1.9.1 dom-to-image-more: 2.16.0 - dompurify: 3.2.4 + dompurify: 3.2.5 file-saver: 2.0.5 highlight.js: 10.7.3 html-to-image: 1.11.13 @@ -13843,6 +13732,11 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + accepts@2.0.0: + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.12.1): dependencies: acorn: 8.12.1 @@ -14077,6 +13971,14 @@ snapshots: transitivePeerDependencies: - debug + axios@1.8.4(debug@4.4.0): + dependencies: + follow-redirects: 1.15.9(debug@4.4.0) + form-data: 4.0.2 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + babel-jest@29.7.0(@babel/core@7.26.9): dependencies: '@babel/core': 7.26.9 @@ -14215,6 +14117,20 @@ snapshots: transitivePeerDependencies: - supports-color + body-parser@2.2.0: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.0(supports-color@8.1.1) + http-errors: 2.0.0 + iconv-lite: 0.6.3 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 3.0.0 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + bonjour-service@1.2.1: dependencies: fast-deep-equal: 3.1.3 @@ -14626,6 +14542,10 @@ snapshots: dependencies: safe-buffer: 5.2.1 + content-disposition@1.0.0: + dependencies: + safe-buffer: 5.2.1 + content-type@1.0.5: {} convert-source-map@1.9.0: {} @@ -14639,6 +14559,8 @@ snapshots: cookie-signature@1.0.6: {} + cookie-signature@1.2.2: {} + cookie@0.6.0: {} cookie@0.7.2: {} @@ -14731,24 +14653,17 @@ snapshots: crypto-random-string@2.0.0: {} - cspell-config-lib@8.14.4: - dependencies: - '@cspell/cspell-types': 8.14.4 - comment-json: 4.2.5 - yaml: 2.7.0 - cspell-config-lib@8.17.4: dependencies: '@cspell/cspell-types': 8.17.4 comment-json: 4.2.5 yaml: 2.7.0 - cspell-dictionary@8.14.4: + cspell-config-lib@8.18.1: dependencies: - '@cspell/cspell-pipe': 8.14.4 - '@cspell/cspell-types': 8.14.4 - cspell-trie-lib: 8.14.4 - fast-equals: 5.0.1 + '@cspell/cspell-types': 8.18.1 + comment-json: 4.2.5 + yaml: 2.7.0 cspell-dictionary@8.17.4: dependencies: @@ -14757,6 +14672,13 @@ snapshots: cspell-trie-lib: 8.17.4 fast-equals: 5.2.2 + cspell-dictionary@8.18.1: + dependencies: + '@cspell/cspell-pipe': 8.18.1 + '@cspell/cspell-types': 8.18.1 + cspell-trie-lib: 8.18.1 + fast-equals: 5.2.2 + cspell-gitignore@8.17.4: dependencies: '@cspell/url': 8.17.4 @@ -14764,62 +14686,35 @@ snapshots: cspell-io: 8.17.4 find-up-simple: 1.0.0 - cspell-glob@8.14.4: - dependencies: - '@cspell/url': 8.14.4 - micromatch: 4.0.8 - cspell-glob@8.17.4: dependencies: '@cspell/url': 8.17.4 micromatch: 4.0.8 - cspell-grammar@8.14.4: + cspell-glob@8.18.1: dependencies: - '@cspell/cspell-pipe': 8.14.4 - '@cspell/cspell-types': 8.14.4 + '@cspell/url': 8.18.1 + micromatch: 4.0.8 cspell-grammar@8.17.4: dependencies: '@cspell/cspell-pipe': 8.17.4 '@cspell/cspell-types': 8.17.4 - cspell-io@8.14.4: + cspell-grammar@8.18.1: dependencies: - '@cspell/cspell-service-bus': 8.14.4 - '@cspell/url': 8.14.4 + '@cspell/cspell-pipe': 8.18.1 + '@cspell/cspell-types': 8.18.1 cspell-io@8.17.4: dependencies: '@cspell/cspell-service-bus': 8.17.4 '@cspell/url': 8.17.4 - cspell-lib@8.14.4: + cspell-io@8.18.1: dependencies: - '@cspell/cspell-bundled-dicts': 8.14.4 - '@cspell/cspell-pipe': 8.14.4 - '@cspell/cspell-resolver': 8.14.4 - '@cspell/cspell-types': 8.14.4 - '@cspell/dynamic-import': 8.14.4 - '@cspell/filetypes': 8.14.4 - '@cspell/strong-weak-map': 8.14.4 - '@cspell/url': 8.14.4 - clear-module: 4.1.2 - comment-json: 4.2.5 - cspell-config-lib: 8.14.4 - cspell-dictionary: 8.14.4 - cspell-glob: 8.14.4 - cspell-grammar: 8.14.4 - cspell-io: 8.14.4 - cspell-trie-lib: 8.14.4 - env-paths: 3.0.0 - fast-equals: 5.0.1 - gensequence: 7.0.0 - import-fresh: 3.3.0 - resolve-from: 5.0.0 - vscode-languageserver-textdocument: 1.0.12 - vscode-uri: 3.0.8 - xdg-basedir: 5.1.0 + '@cspell/cspell-service-bus': 8.18.1 + '@cspell/url': 8.18.1 cspell-lib@8.17.4: dependencies: @@ -14848,11 +14743,32 @@ snapshots: vscode-uri: 3.1.0 xdg-basedir: 5.1.0 - cspell-trie-lib@8.14.4: + cspell-lib@8.18.1: dependencies: - '@cspell/cspell-pipe': 8.14.4 - '@cspell/cspell-types': 8.14.4 + '@cspell/cspell-bundled-dicts': 8.18.1 + '@cspell/cspell-pipe': 8.18.1 + '@cspell/cspell-resolver': 8.18.1 + '@cspell/cspell-types': 8.18.1 + '@cspell/dynamic-import': 8.18.1 + '@cspell/filetypes': 8.18.1 + '@cspell/strong-weak-map': 8.18.1 + '@cspell/url': 8.18.1 + clear-module: 4.1.2 + comment-json: 4.2.5 + cspell-config-lib: 8.18.1 + cspell-dictionary: 8.18.1 + cspell-glob: 8.18.1 + cspell-grammar: 8.18.1 + cspell-io: 8.18.1 + cspell-trie-lib: 8.18.1 + env-paths: 3.0.0 + fast-equals: 5.2.2 gensequence: 7.0.0 + import-fresh: 3.3.1 + resolve-from: 5.0.0 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + xdg-basedir: 5.1.0 cspell-trie-lib@8.17.4: dependencies: @@ -14860,6 +14776,12 @@ snapshots: '@cspell/cspell-types': 8.17.4 gensequence: 7.0.0 + cspell-trie-lib@8.18.1: + dependencies: + '@cspell/cspell-pipe': 8.18.1 + '@cspell/cspell-types': 8.18.1 + gensequence: 7.0.0 + cspell@8.17.4: dependencies: '@cspell/cspell-json-reporter': 8.17.4 @@ -15414,7 +15336,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.2.4: + dompurify@3.2.5: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -15710,38 +15632,38 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@10.0.1(eslint@9.20.1(jiti@2.4.2)): + eslint-config-prettier@10.1.1(eslint@9.24.0(jiti@2.4.2)): dependencies: - eslint: 9.20.1(jiti@2.4.2) + eslint: 9.24.0(jiti@2.4.2) - eslint-plugin-cypress@4.1.0(eslint@9.20.1(jiti@2.4.2)): + eslint-plugin-cypress@4.2.1(eslint@9.24.0(jiti@2.4.2)): dependencies: - eslint: 9.20.1(jiti@2.4.2) + eslint: 9.24.0(jiti@2.4.2) globals: 15.15.0 eslint-plugin-html@8.1.2: dependencies: htmlparser2: 9.1.0 - eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3))(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3))(eslint@9.20.1(jiti@2.4.2))(jest@29.7.0(@types/node@22.13.5))(typescript@5.7.3): + eslint-plugin-jest@28.11.0(@typescript-eslint/eslint-plugin@8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.24.0(jiti@2.4.2))(jest@29.7.0(@types/node@22.13.5))(typescript@5.7.3): dependencies: - '@typescript-eslint/utils': 8.8.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3) - eslint: 9.20.1(jiti@2.4.2) + '@typescript-eslint/utils': 8.24.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3) + eslint: 9.24.0(jiti@2.4.2) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3))(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/eslint-plugin': 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3) jest: 29.7.0(@types/node@22.13.5) transitivePeerDependencies: - supports-color - typescript - eslint-plugin-jsdoc@50.3.2(eslint@9.20.1(jiti@2.4.2)): + eslint-plugin-jsdoc@50.6.9(eslint@9.24.0(jiti@2.4.2)): dependencies: - '@es-joy/jsdoccomment': 0.48.0 + '@es-joy/jsdoccomment': 0.49.0 are-docs-informative: 0.0.2 comment-parser: 1.4.1 debug: 4.4.0(supports-color@8.1.1) escape-string-regexp: 4.0.0 - eslint: 9.20.1(jiti@2.4.2) + eslint: 9.24.0(jiti@2.4.2) espree: 10.3.0 esquery: 1.6.0 parse-imports: 2.2.1 @@ -15756,14 +15678,14 @@ snapshots: lodash: 4.17.21 vscode-json-languageservice: 4.2.1 - eslint-plugin-lodash@8.0.0(eslint@9.20.1(jiti@2.4.2)): + eslint-plugin-lodash@8.0.0(eslint@9.24.0(jiti@2.4.2)): dependencies: - eslint: 9.20.1(jiti@2.4.2) + eslint: 9.24.0(jiti@2.4.2) lodash: 4.17.21 - eslint-plugin-markdown@5.1.0(eslint@9.20.1(jiti@2.4.2)): + eslint-plugin-markdown@5.1.0(eslint@9.24.0(jiti@2.4.2)): dependencies: - eslint: 9.20.1(jiti@2.4.2) + eslint: 9.24.0(jiti@2.4.2) mdast-util-from-markdown: 0.8.5 transitivePeerDependencies: - supports-color @@ -15775,15 +15697,15 @@ snapshots: '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - eslint-plugin-unicorn@58.0.0(eslint@9.20.1(jiti@2.4.2)): + eslint-plugin-unicorn@58.0.0(eslint@9.24.0(jiti@2.4.2)): dependencies: '@babel/helper-validator-identifier': 7.25.9 - '@eslint-community/eslint-utils': 4.5.1(eslint@9.20.1(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.5.1(eslint@9.24.0(jiti@2.4.2)) '@eslint/plugin-kit': 0.2.7 ci-info: 4.2.0 clean-regexp: 1.0.0 core-js-compat: 3.41.0 - eslint: 9.20.1(jiti@2.4.2) + eslint: 9.24.0(jiti@2.4.2) esquery: 1.6.0 globals: 16.0.0 indent-string: 5.0.0 @@ -15801,7 +15723,7 @@ snapshots: esrecurse: 4.3.0 estraverse: 4.3.0 - eslint-scope@8.2.0: + eslint-scope@8.3.0: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 @@ -15810,14 +15732,15 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.20.1(jiti@2.4.2): + eslint@9.24.0(jiti@2.4.2): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.5.1(eslint@9.24.0(jiti@2.4.2)) '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.19.2 - '@eslint/core': 0.11.0 - '@eslint/eslintrc': 3.2.0 - '@eslint/js': 9.20.0 + '@eslint/config-array': 0.20.0 + '@eslint/config-helpers': 0.2.1 + '@eslint/core': 0.12.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.24.0 '@eslint/plugin-kit': 0.2.7 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 @@ -15829,7 +15752,7 @@ snapshots: cross-spawn: 7.0.6 debug: 4.4.0(supports-color@8.1.1) escape-string-regexp: 4.0.0 - eslint-scope: 8.2.0 + eslint-scope: 8.3.0 eslint-visitor-keys: 4.2.0 espree: 10.3.0 esquery: 1.6.0 @@ -16007,6 +15930,38 @@ snapshots: transitivePeerDependencies: - supports-color + express@5.1.0: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.0(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.0 + serve-static: 2.2.0 + statuses: 2.0.1 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + extend@3.0.2: {} extendable-error@0.1.7: {} @@ -16035,8 +15990,6 @@ snapshots: fast-deep-equal@3.1.3: {} - fast-equals@5.0.1: {} - fast-equals@5.2.2: {} fast-glob@3.3.3: @@ -16185,6 +16138,17 @@ snapshots: transitivePeerDependencies: - supports-color + finalhandler@2.1.0: + dependencies: + debug: 4.4.0(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + find-cache-dir@3.3.2: dependencies: commondir: 1.0.1 @@ -16296,7 +16260,7 @@ snapshots: foreground-child@3.3.0: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 4.1.0 forever-agent@0.6.1: {} @@ -16318,6 +16282,8 @@ snapshots: fresh@0.5.2: {} + fresh@2.0.0: {} + from@0.1.7: {} fromentries@1.3.2: {} @@ -16777,11 +16743,6 @@ snapshots: ignore@7.0.3: {} - import-fresh@3.3.0: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -16964,6 +16925,8 @@ snapshots: is-potential-custom-element-name@1.0.1: {} + is-promise@4.0.0: {} + is-regex@1.2.1: dependencies: call-bound: 1.0.3 @@ -17079,7 +17042,7 @@ snapshots: istanbul-lib-processinfo@2.0.3: dependencies: archy: 1.0.0 - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 istanbul-lib-coverage: 3.2.2 p-map: 3.0.0 rimraf: 3.0.2 @@ -18013,6 +17976,8 @@ snapshots: media-typer@0.3.0: {} + media-typer@1.1.0: {} + memfs@3.5.3: dependencies: fs-monkey: 1.0.6 @@ -18021,6 +17986,8 @@ snapshots: merge-descriptors@1.0.3: {} + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -18250,10 +18217,16 @@ snapshots: mime-db@1.53.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: {} mimic-fn@2.1.0: {} @@ -18344,6 +18317,8 @@ snapshots: negotiator@0.6.3: {} + negotiator@1.0.0: {} + neo-async@2.6.2: {} nested-error-stacks@2.1.1: {} @@ -18549,7 +18524,7 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openapi-fetch@0.13.4: + openapi-fetch@0.13.5: dependencies: openapi-typescript-helpers: 0.0.15 @@ -18733,6 +18708,8 @@ snapshots: path-to-regexp@0.1.10: {} + path-to-regexp@8.2.0: {} + path-type@4.0.0: {} path-type@6.0.0: {} @@ -18998,6 +18975,10 @@ snapshots: dependencies: side-channel: 1.1.0 + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + queue-microtask@1.2.3: {} quick-format-unescaped@4.0.4: {} @@ -19025,6 +19006,13 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + raw-body@3.0.0: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + react-is@18.3.1: {} read-cache@1.0.0: @@ -19330,6 +19318,16 @@ snapshots: points-on-curve: 0.2.0 points-on-path: 0.2.1 + router@2.2.0: + dependencies: + debug: 4.4.0(supports-color@8.1.1) + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.2.0 + transitivePeerDependencies: + - supports-color + rrweb-cssom@0.8.0: {} run-parallel@1.2.0: @@ -19438,6 +19436,22 @@ snapshots: transitivePeerDependencies: - supports-color + send@1.2.0: + dependencies: + debug: 4.4.0(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 @@ -19463,6 +19477,15 @@ snapshots: transitivePeerDependencies: - supports-color + serve-static@2.2.0: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + set-blocking@2.0.0: {} set-cookie-parser@2.7.1: {} @@ -19952,6 +19975,11 @@ snapshots: symbol-tree@3.2.4: {} + synckit@0.10.3: + dependencies: + '@pkgr/core': 0.2.1 + tslib: 2.8.1 + synckit@0.9.2: dependencies: '@pkgr/core': 0.1.1 @@ -20204,6 +20232,12 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.3 @@ -20254,12 +20288,12 @@ snapshots: typescript: 5.7.3 yaml: 2.7.0 - typescript-eslint@8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3): + typescript-eslint@8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3))(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3) - '@typescript-eslint/parser': 8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3) - '@typescript-eslint/utils': 8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3) - eslint: 9.20.1(jiti@2.4.2) + '@typescript-eslint/eslint-plugin': 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/parser': 8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/utils': 8.29.1(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3) + eslint: 9.24.0(jiti@2.4.2) typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -20522,7 +20556,7 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-pwa@0.21.1(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0): + vite-plugin-pwa@1.0.0(vite@6.1.1(@types/node@22.13.5)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))(workbox-build@7.1.1(@types/babel__core@7.20.5))(workbox-window@7.3.0): dependencies: debug: 4.4.0(supports-color@8.1.1) pretty-bytes: 6.1.1 @@ -20556,17 +20590,17 @@ snapshots: tsx: 4.19.3 yaml: 2.7.0 - vitepress-plugin-search@1.0.4-alpha.22(flexsearch@0.7.43)(vitepress@1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.7.9)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)): + vitepress-plugin-search@1.0.4-alpha.22(flexsearch@0.7.43)(vitepress@1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.8.4)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3))(vue@3.5.13(typescript@5.7.3)): dependencies: '@types/flexsearch': 0.7.6 '@types/markdown-it': 12.2.3 flexsearch: 0.7.43 glob-to-regexp: 0.4.1 markdown-it: 13.0.2 - vitepress: 1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.7.9)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3) + vitepress: 1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.8.4)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3) vue: 3.5.13(typescript@5.7.3) - vitepress@1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.7.9)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3): + vitepress@1.6.3(@algolia/client-search@5.20.3)(@types/node@22.13.5)(axios@1.8.4)(postcss@8.5.3)(search-insights@2.17.2)(terser@5.39.0)(typescript@5.7.3): dependencies: '@docsearch/css': 3.8.2 '@docsearch/js': 3.8.2(@algolia/client-search@5.20.3)(search-insights@2.17.2) @@ -20579,7 +20613,7 @@ snapshots: '@vue/devtools-api': 7.7.2 '@vue/shared': 3.5.13 '@vueuse/core': 12.7.0(typescript@5.7.3) - '@vueuse/integrations': 12.7.0(axios@1.7.9)(focus-trap@7.6.4)(typescript@5.7.3) + '@vueuse/integrations': 12.7.0(axios@1.8.4)(focus-trap@7.6.4)(typescript@5.7.3) focus-trap: 7.6.4 mark.js: 8.11.1 minisearch: 7.1.2 diff --git a/scripts/compare-timings.ts b/scripts/compare-timings.ts new file mode 100644 index 000000000..1dbfc41d0 --- /dev/null +++ b/scripts/compare-timings.ts @@ -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();