From f22e93626b78deb858fd47a25a44ddcc76a59cf7 Mon Sep 17 00:00:00 2001 From: Tobias Ortmayr Date: Sun, 21 Jun 2026 15:07:17 +0200 Subject: [PATCH 1/2] GLSP-1635: Migrate test stack to Vitest - Replace Mocha/Chai/Sinon with Vitest across all packages; specs import the test API explicitly from 'vitest' (no globals). Remove the obsolete Mocha/nyc config, the chai-based test helpers, and the placeholder graph spec - Consume the shared @eclipse-glsp/vitest-config (via @eclipse-glsp/dev) through a single flat root vite.config.ts that globs every package's specs, so one `vitest run` covers the repo and produces a merged coverage report; drop the now-redundant per-package vite configs and test scripts - Type-check specs through a composite tsconfig.test.json (root plus a per-package config) built by `compile:test`, which `pnpm test` runs before `vitest run` - Extend the plain @eclipse-glsp/ts-config now that the separate '/vitest' variant and the vitest/globals types are gone - Run `pnpm test` / `pnpm test:coverage` in CI and drop the obsolete CTRF "Publish Test Report" step (Vitest's github-actions reporter annotates failures inline) along with the redundant `:ci` scripts - Update the VS Code launch configs to debug tests via Vitest Also: - Move the raw-http e2e helper out of '*.spec.ts' into a test/ folder so it is no longer treated as a spec or shipped in the published package - Tidy .gitignore: ignore '*.tsbuildinfo' and drop the now-dead **/ctrf, .nyc_output/, and yarn-error.log entries - Import GModelElement from the @eclipse-glsp/graph entry point instead of a deep lib/ path Part of: eclipse-glsp/glsp#1635 --- .github/workflows/ci.yml | 11 +- .gitignore | 5 +- .mocharc | 5 - .nycrc | 3 - .vscode/launch.json | 74 +- package.json | 10 +- packages/graph/package.json | 11 +- packages/graph/src/galignable.spec.ts | 18 +- packages/graph/src/gbounds-aware.spec.ts | 28 +- packages/graph/tsconfig.json | 3 +- packages/graph/tsconfig.test.json | 10 + packages/layout-elk/package.json | 11 +- packages/layout-elk/src/di.config.spec.ts | 24 +- packages/layout-elk/tsconfig.json | 2 +- packages/layout-elk/tsconfig.test.json | 10 + packages/server-mcp/package.json | 12 +- .../abstract-mcp-server-launcher.spec.ts | 76 +- .../src/common/server/glsp-mcp-server.spec.ts | 23 +- .../src/common/server/lru-event-store.spec.ts | 34 +- .../mcp-diagram-handler-dispatcher.spec.ts | 26 +- .../common/server/mcp-handler-shared.spec.ts | 24 +- .../server/mcp-id-alias-service.spec.ts | 46 +- .../server/mcp-log-level-registry.spec.ts | 38 +- .../src/common/server/mcp-logger.spec.ts | 26 +- .../server/mcp-progress-reporter.spec.ts | 14 +- .../common/server/mcp-tool-handler.spec.ts | 22 +- .../count-elements-mcp-tool-handler.spec.ts | 8 +- .../create-edges-mcp-tool-handler.spec.ts | 28 +- .../create-nodes-mcp-tool-handler.spec.ts | 34 +- .../query-elements-mcp-tool-handler.spec.ts | 34 +- .../session-info-mcp-tool-handler.spec.ts | 28 +- .../set-selection-mcp-tool-handler.spec.ts | 18 +- .../src/common/tools/tool-annotations.spec.ts | 14 +- .../server/mcp-http-transport-e2e.spec.ts | 50 +- .../server/node-mcp-server-launcher.spec.ts | 89 +- .../{raw-http.spec.ts => test/raw-http.ts} | 0 packages/server-mcp/tsconfig.json | 4 +- packages/server-mcp/tsconfig.test.json | 10 + packages/server/package.json | 12 +- .../di/browser-action-dispatch-scope.spec.ts | 25 +- .../actions/action-handler-registry.spec.ts | 14 +- .../actions/global-action-provider.spec.ts | 11 +- .../src/common/command/command-stack.spec.ts | 213 +- .../server/src/common/command/command.spec.ts | 106 +- .../common/command/recording-command.spec.ts | 12 +- .../src/common/di/binding-target.spec.ts | 140 +- .../src/common/di/multi-bindings.spec.ts | 34 +- .../context-actions-provider-registry.spec.ts | 10 +- .../request-context-actions-handler.spec.ts | 30 +- .../tool-palette-item-provider.spec.ts | 22 +- .../context-edit-validator-registry.spec.ts | 12 +- .../directediting/context-edit-validator.ts | 4 +- .../request-edit-validation-handler.spec.ts | 57 +- .../features/model/gmodel-serializer.spec.ts | 48 +- .../request-type-hints-action-handler.spec.ts | 8 +- .../operation-handler-registry.spec.ts | 26 +- .../src/common/protocol/glsp-server.spec.ts | 64 +- .../session/client-session-factory.spec.ts | 14 +- .../session/client-session-manager.spec.ts | 38 +- packages/server/src/common/test/mock-util.ts | 32 +- .../src/common/utils/action-queue.spec.ts | 29 +- .../src/common/utils/promise-queue.spec.ts | 10 +- .../server/src/common/utils/registry.spec.ts | 24 +- .../node/actions/action-dispatcher.spec.ts | 260 +- .../server/src/node/launch/cli-parser.spec.ts | 14 +- .../src/node/launch/socket-cli-parser.spec.ts | 14 +- .../launch/socket-server-launcher.spec.ts | 114 +- packages/server/tsconfig.json | 2 +- packages/server/tsconfig.test.json | 10 + pnpm-lock.yaml | 2560 ++++++----------- pnpm-workspace.yaml | 9 +- tsconfig.eslint.json | 4 +- tsconfig.json | 2 +- tsconfig.test.json | 22 + .../graph/src/index.spec.ts => vite.config.ts | 18 +- 75 files changed, 2101 insertions(+), 2806 deletions(-) delete mode 100644 .mocharc delete mode 100644 .nycrc create mode 100644 packages/graph/tsconfig.test.json create mode 100644 packages/layout-elk/tsconfig.test.json rename packages/server-mcp/src/node/server/{raw-http.spec.ts => test/raw-http.ts} (100%) create mode 100644 packages/server-mcp/tsconfig.test.json create mode 100644 packages/server/tsconfig.test.json create mode 100644 tsconfig.test.json rename packages/graph/src/index.spec.ts => vite.config.ts (62%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9dca8961..ae01de23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,14 +44,7 @@ jobs: node-version: 22.x cache: pnpm - name: Test - run: pnpm test:ci - - name: Publish Test Report - uses: ctrf-io/github-test-reporter@0f299074936c32ccaab5be5230511f6b2b9080aa # v1.0.28 - with: - report-path: 'packages/*/ctrf/*.json' - summary-report: true - file-report: true - if: always() + run: pnpm test lint: name: Lint timeout-minutes: 60 @@ -83,7 +76,7 @@ jobs: node-version: 22.x cache: pnpm - name: Run Coverage Tests - run: pnpm test:coverage:ci + run: pnpm test:coverage - name: Upload Coverage Report uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: diff --git a/.gitignore b/.gitignore index 21d84fc5..981196f3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,18 +2,15 @@ node_modules/ lib/ artifacts/ coverage/ -.nyc_output/ *.log *.jar /.metadata/ -yarn-error.log -tsconfig.tsbuildinfo +*.tsbuildinfo eslint.xml report.xml -**/ctrf wf-glsp-server-node.js wf-glsp-server-node.js.map diff --git a/.mocharc b/.mocharc deleted file mode 100644 index 32df1e53..00000000 --- a/.mocharc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/mocharc", - "extends": "@eclipse-glsp/mocha-config", - "node-option": ["no-experimental-strip-types"] -} diff --git a/.nycrc b/.nycrc deleted file mode 100644 index 98db690d..00000000 --- a/.nycrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@eclipse-glsp/nyc-config" -} diff --git a/.vscode/launch.json b/.vscode/launch.json index 463eb0db..bb724844 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,61 +5,61 @@ "name": "Run current test file", "type": "node", "request": "launch", - "program": "${workspaceFolder}/node_modules/.bin/mocha", - "args": ["--config", "${workspaceFolder}/.mocharc", "${relativeFile}"], + "program": "${workspaceFolder}/node_modules/vitest/vitest.mjs", + "args": ["run", "${relativeFile}"], + "autoAttachChildProcesses": true, + "skipFiles": ["/**"], + "smartStep": true, "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen", - "env": { - "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json" - } + "internalConsoleOptions": "neverOpen" }, { - "name": "Run server-node tests", + "name": "Run server tests", "type": "node", "request": "launch", - "program": "${workspaceFolder}/node_modules/.bin/mocha", - "args": [ - "--config", - "${workspaceFolder}/.mocharc", - "${workspaceFolder}/packages/server/src/**/*.spec.ts" - ], + "program": "${workspaceFolder}/node_modules/vitest/vitest.mjs", + "args": ["run", "packages/server/src"], + "autoAttachChildProcesses": true, + "skipFiles": ["/**"], + "smartStep": true, "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen", - "env": { - "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json" - } + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Run server-mcp tests", + "type": "node", + "request": "launch", + "program": "${workspaceFolder}/node_modules/vitest/vitest.mjs", + "args": ["run", "packages/server-mcp/src"], + "autoAttachChildProcesses": true, + "skipFiles": ["/**"], + "smartStep": true, + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" }, { "name": "Run graph tests", "type": "node", "request": "launch", - "program": "${workspaceFolder}/node_modules/.bin/mocha", - "args": [ - "--config", - "${workspaceFolder}/.mocharc", - "${workspaceFolder}/packages/graph/src/**/*.spec.ts" - ], + "program": "${workspaceFolder}/node_modules/vitest/vitest.mjs", + "args": ["run", "packages/graph/src"], + "autoAttachChildProcesses": true, + "skipFiles": ["/**"], + "smartStep": true, "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen", - "env": { - "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json" - } + "internalConsoleOptions": "neverOpen" }, { "name": "Run layout-elk tests", "type": "node", "request": "launch", - "program": "${workspaceFolder}/node_modules/.bin/mocha", - "args": [ - "--config", - "${workspaceRoot}/.mocharc", - "${workspaceRoot}/packages/layout-elk/src/**/*.spec.ts" - ], + "program": "${workspaceFolder}/node_modules/vitest/vitest.mjs", + "args": ["run", "packages/layout-elk/src"], + "autoAttachChildProcesses": true, + "skipFiles": ["/**"], + "smartStep": true, "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen", - "env": { - "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json" - } + "internalConsoleOptions": "neverOpen" }, { "type": "node", diff --git a/package.json b/package.json index c5eacb38..caa516d1 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,9 @@ "build": "pnpm compile && pnpm bundle", "bundle": "pnpm -C examples/workflow-server bundle", "check:all": "pnpm build && pnpm lint && pnpm test && pnpm format:check && pnpm headers:check", - "clean": "pnpm -r run clean && rimraf coverage .nyc_output", + "clean": "pnpm -r run clean && rimraf coverage", "compile": "tsc -b", + "compile:test": "pnpm compile && tsc -b tsconfig.test.json", "dev": "pnpm -C examples/workflow-server dev", "dev:ws": "pnpm -C examples/workflow-server dev:ws", "fix:all": "pnpm lint:fix && pnpm format && pnpm headers:fix", @@ -24,16 +25,13 @@ "start": "pnpm -C examples/workflow-server-bundled start", "start:mcp-demo": "pnpm -C examples/workflow-server build && pnpm -C examples/workflow-server-mcp-demo start", "start:websocket": "pnpm -C examples/workflow-server-bundled start:websocket", - "test": "pnpm compile && pnpm -r --no-bail test", - "test:ci": "pnpm compile && pnpm -r --no-bail test:ci", - "test:coverage": "pnpm compile && pnpm -r test:coverage", - "test:coverage:ci": "glsp coverageReport", + "test": "pnpm compile:test && vitest run", + "test:coverage": "pnpm test --coverage", "upgrade:next": "glsp updateNext" }, "devDependencies": { "@eclipse-glsp/dev": "next", "@types/node": "22.x", - "mocha-ctrf-json-reporter": "0.0.11", "typescript": "^5.9.2" }, "packageManager": "pnpm@11.7.0", diff --git a/packages/graph/package.json b/packages/graph/package.json index 1f0155d9..91f42191 100644 --- a/packages/graph/package.json +++ b/packages/graph/package.json @@ -36,17 +36,16 @@ "types": "lib/index", "files": [ "lib", - "src" + "src", + "!**/*.spec.ts", + "!**/*.spec.tsx" ], "scripts": { "build": "tsc -b", - "clean": "rimraf lib *.tsbuildinfo coverage .nyc_output", + "clean": "rimraf lib *.tsbuildinfo coverage", "generate:index": "glsp generateIndex src -f -s", "lint": "eslint ./src", - "prepublishOnly": "pnpm build", - "test": "mocha --config ../../.mocharc \"./src/**/*.spec.?(ts|tsx)\"", - "test:ci": "pnpm test --reporter mocha-ctrf-json-reporter", - "test:coverage": "nyc pnpm test" + "prepublishOnly": "pnpm build" }, "dependencies": { "@eclipse-glsp/protocol": "next" diff --git a/packages/graph/src/galignable.spec.ts b/packages/graph/src/galignable.spec.ts index c37df9b2..e623dee4 100644 --- a/packages/graph/src/galignable.spec.ts +++ b/packages/graph/src/galignable.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2024 EclipseSource and others. + * Copyright (c) 2024-2026 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ import { DefaultTypes } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { GAlignableBuilder, isGAlignable } from './galignable'; import { GLabel, GLabelBuilder } from './glabel'; import { GNode, GNodeBuilder } from './gnode'; @@ -27,7 +27,7 @@ describe('GAlignable Tests', () => { .build(); const result = isGAlignable(gLabelElement); - expect(result).to.be.true; + expect(result).toBe(true); }); it('should return false for a non-GAlignable element', () => { @@ -38,7 +38,7 @@ describe('GAlignable Tests', () => { .build(); const result = isGAlignable(gNodeElement); - expect(result).to.be.false; + expect(result).toBe(false); }); }); @@ -46,29 +46,29 @@ describe('GAlignable Tests', () => { it('should set alignment using a point object', () => { const builder = new GLabelBuilder(GLabel); GAlignableBuilder.alignment(builder, { x: 45, y: 90 }); - expect(builder['proxy'].alignment).to.deep.equal({ x: 45, y: 90 }); + expect(builder['proxy'].alignment).toEqual({ x: 45, y: 90 }); }); it('should set alignment using x and y parameters', () => { let builder = new GLabelBuilder(GLabel); GAlignableBuilder.alignment(builder, 8, 16); - expect(builder['proxy'].alignment).to.deep.equal({ x: 8, y: 16 }); + expect(builder['proxy'].alignment).toEqual({ x: 8, y: 16 }); builder = new GLabelBuilder(GLabel); GAlignableBuilder.alignment(builder, 12, 0); - expect(builder['proxy'].alignment).to.deep.equal({ x: 12, y: 0 }); + expect(builder['proxy'].alignment).toEqual({ x: 12, y: 0 }); }); it('should set alignment from point object if y is provided too', () => { const builder = new GLabelBuilder(GLabel); GAlignableBuilder.alignment(builder, { x: 17, y: 71 }, 15); - expect(builder['proxy'].alignment).to.deep.equal({ x: 17, y: 71 }); + expect(builder['proxy'].alignment).toEqual({ x: 17, y: 71 }); }); it('should default y to 0 if y is not provided', () => { const builder = new GLabelBuilder(GLabel); GAlignableBuilder.alignment(builder, 77); - expect(builder['proxy'].alignment).to.deep.equal({ x: 77, y: 0 }); + expect(builder['proxy'].alignment).toEqual({ x: 77, y: 0 }); }); }); }); diff --git a/packages/graph/src/gbounds-aware.spec.ts b/packages/graph/src/gbounds-aware.spec.ts index bc2a8615..897497fa 100644 --- a/packages/graph/src/gbounds-aware.spec.ts +++ b/packages/graph/src/gbounds-aware.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2024 EclipseSource and others. + * Copyright (c) 2024-2026 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ import { DefaultTypes } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { GBoundsAwareBuilder, isGBoundsAware } from './gbounds-aware'; import { GEdge, GEdgeBuilder } from './gedge'; import { GNode, GNodeBuilder } from './gnode'; @@ -30,7 +30,7 @@ describe('GBoundsAware Tests', () => { .build(); const result = isGBoundsAware(gNodeElement); - expect(result).to.be.true; + expect(result).toBe(true); }); it('should return false for a non-GBoundsAware element', () => { @@ -39,7 +39,7 @@ describe('GBoundsAware Tests', () => { .build(); const result = isGBoundsAware(gEdgeElement); - expect(result).to.be.false; + expect(result).toBe(false); }); }); @@ -47,29 +47,29 @@ describe('GBoundsAware Tests', () => { it('should set position using a point object', () => { const builder = new GShapeElementBuilder(GNode); GBoundsAwareBuilder.position(builder, { x: 5, y: 10 }); - expect(builder['proxy'].position).to.deep.equal({ x: 5, y: 10 }); + expect(builder['proxy'].position).toEqual({ x: 5, y: 10 }); }); it('should set position using x and y parameters', () => { let builder = new GShapeElementBuilder(GNode); GBoundsAwareBuilder.position(builder, 5, 10); - expect(builder['proxy'].position).to.deep.equal({ x: 5, y: 10 }); + expect(builder['proxy'].position).toEqual({ x: 5, y: 10 }); builder = new GShapeElementBuilder(GNode); GBoundsAwareBuilder.position(builder, 5, 0); - expect(builder['proxy'].position).to.deep.equal({ x: 5, y: 0 }); + expect(builder['proxy'].position).toEqual({ x: 5, y: 0 }); }); it('should set position from point object if y is provided too', () => { const builder = new GShapeElementBuilder(GNode); GBoundsAwareBuilder.position(builder, { x: 17, y: 71 }, 15); - expect(builder['proxy'].position).to.deep.equal({ x: 17, y: 71 }); + expect(builder['proxy'].position).toEqual({ x: 17, y: 71 }); }); it('should default y to 0 if y is not provided', () => { const builder = new GShapeElementBuilder(GNode); GBoundsAwareBuilder.position(builder, 35); - expect(builder['proxy'].position).to.deep.equal({ x: 35, y: 0 }); + expect(builder['proxy'].position).toEqual({ x: 35, y: 0 }); }); }); @@ -77,29 +77,29 @@ describe('GBoundsAware Tests', () => { it('should set size using a dimension object', () => { const builder = new GShapeElementBuilder(GNode); GBoundsAwareBuilder.size(builder, { width: 55, height: 15 }); - expect(builder['proxy'].size).to.deep.equal({ width: 55, height: 15 }); + expect(builder['proxy'].size).toEqual({ width: 55, height: 15 }); }); it('should set size using width and height parameters', () => { let builder = new GShapeElementBuilder(GNode); GBoundsAwareBuilder.size(builder, 50, 35); - expect(builder['proxy'].size).to.deep.equal({ width: 50, height: 35 }); + expect(builder['proxy'].size).toEqual({ width: 50, height: 35 }); builder = new GShapeElementBuilder(GNode); GBoundsAwareBuilder.size(builder, 70, 0); - expect(builder['proxy'].size).to.deep.equal({ width: 70, height: 0 }); + expect(builder['proxy'].size).toEqual({ width: 70, height: 0 }); }); it('should set size from dimension object if height is provided too', () => { const builder = new GShapeElementBuilder(GNode); GBoundsAwareBuilder.size(builder, { width: 11, height: 33 }, 15); - expect(builder['proxy'].size).to.deep.equal({ width: 11, height: 33 }); + expect(builder['proxy'].size).toEqual({ width: 11, height: 33 }); }); it('should default height to 0 if height is not provided', () => { const builder = new GShapeElementBuilder(GNode); GBoundsAwareBuilder.size(builder, 60); - expect(builder['proxy'].size).to.deep.equal({ width: 60, height: 0 }); + expect(builder['proxy'].size).toEqual({ width: 60, height: 0 }); }); }); }); diff --git a/packages/graph/tsconfig.json b/packages/graph/tsconfig.json index 6d917950..1632751f 100644 --- a/packages/graph/tsconfig.json +++ b/packages/graph/tsconfig.json @@ -5,7 +5,8 @@ "outDir": "lib", "composite": true, "reactNamespace": "JSX", - "types": ["node", "mocha"] + "types": ["node"] }, + "exclude": ["**/*.spec.ts"], "include": ["src"] } diff --git a/packages/graph/tsconfig.test.json b/packages/graph/tsconfig.test.json new file mode 100644 index 00000000..19a4102a --- /dev/null +++ b/packages/graph/tsconfig.test.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "composite": true, + "noEmit": true + }, + "include": ["src/**/*.spec.ts", "src/**/*.spec.tsx", "src/**/test/**/*"], + "exclude": ["lib", "node_modules"], + "references": [{ "path": "./tsconfig.json" }] +} diff --git a/packages/layout-elk/package.json b/packages/layout-elk/package.json index b2260456..88779789 100644 --- a/packages/layout-elk/package.json +++ b/packages/layout-elk/package.json @@ -36,17 +36,16 @@ "types": "lib/index", "files": [ "lib", - "src" + "src", + "!**/*.spec.ts", + "!**/*.spec.tsx" ], "scripts": { "build": "tsc -b", - "clean": "rimraf lib *.tsbuildinfo coverage .nyc_output", + "clean": "rimraf lib *.tsbuildinfo coverage", "generate:index": "glsp generateIndex src -f -s", "lint": "eslint ./src", - "prepublishOnly": "pnpm build", - "test": "mocha --config ../../.mocharc \"./src/**/*.spec.?(ts|tsx)\"", - "test:ci": "pnpm test --reporter mocha-ctrf-json-reporter", - "test:coverage": "nyc pnpm test" + "prepublishOnly": "pnpm build" }, "dependencies": { "@eclipse-glsp/server": "workspace:*", diff --git a/packages/layout-elk/src/di.config.spec.ts b/packages/layout-elk/src/di.config.spec.ts index 259c2888..b56bdc32 100644 --- a/packages/layout-elk/src/di.config.spec.ts +++ b/packages/layout-elk/src/di.config.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -23,9 +23,8 @@ import { ServerLayoutKind, ShapeTypeHint } from '@eclipse-glsp/server'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { Container, ContainerModule, injectable } from 'inversify'; -import * as sinon from 'sinon'; import { configureELKLayoutModule } from './di.config'; import { DefaultElementFilter, ElementFilter } from './element-filter'; import { AbstractLayoutConfigurator, FallbackLayoutConfigurator, LayoutConfigurator } from './layout-configurator'; @@ -51,12 +50,11 @@ class StubDiagramConfiguration implements DiagramConfiguration { } describe('test configureELKLayoutModule', () => { - const sandbox = sinon.createSandbox(); const mockDiagramConfiguration = new StubDiagramConfiguration(); const typeMappings = new Map(); typeMappings.set('graph', GGraph); - sandbox.stub(mockDiagramConfiguration, 'typeMapping').value(typeMappings); + mockDiagramConfiguration.typeMapping = typeMappings; const modelState = new DefaultModelState(); const baseModule = new ContainerModule(bind => { bind(ModelState).toConstantValue(modelState); @@ -67,12 +65,12 @@ describe('test configureELKLayoutModule', () => { const container = new Container(); container.load(baseModule, elkModule); const filter = container.get(ElementFilter); - expect(filter).to.be.an.instanceOf(DefaultElementFilter); + expect(filter).toBeInstanceOf(DefaultElementFilter); const configurator = container.get(LayoutConfigurator); - expect(configurator).to.be.an.instanceOf(FallbackLayoutConfigurator); + expect(configurator).toBeInstanceOf(FallbackLayoutConfigurator); const graphOptions = configurator.apply(new GGraph()); - expect(graphOptions).not.to.be.undefined; - expect(graphOptions!['elk.algorithm']).to.equal(algorithm); + expect(graphOptions).toBeDefined(); + expect(graphOptions!['elk.algorithm']).toBe(algorithm); }); it('configure with additional default layout options', () => { @@ -86,8 +84,8 @@ describe('test configureELKLayoutModule', () => { container.load(baseModule, elkModule); const configurator = container.get(LayoutConfigurator); const graphOptions = configurator.apply(new GGraph()); - expect(graphOptions).not.to.be.undefined; - expect(graphOptions).to.include(defaultLayoutOptions); + expect(graphOptions).toBeDefined(); + expect(graphOptions).toMatchObject(defaultLayoutOptions); }); it('configure with custom layout configurator', () => { @@ -96,7 +94,7 @@ describe('test configureELKLayoutModule', () => { const container = new Container(); container.load(baseModule, elkModule); const configurator = container.get(LayoutConfigurator); - expect(configurator).to.be.an.instanceOf(CustomLayoutConfigurator); + expect(configurator).toBeInstanceOf(CustomLayoutConfigurator); }); it('configure with custom element filter', () => { @@ -105,6 +103,6 @@ describe('test configureELKLayoutModule', () => { const container = new Container(); container.load(baseModule, elkModule); const filter = container.get(ElementFilter); - expect(filter).to.be.an.instanceOf(CustomElementFilter); + expect(filter).toBeInstanceOf(CustomElementFilter); }); }); diff --git a/packages/layout-elk/tsconfig.json b/packages/layout-elk/tsconfig.json index 56ca413d..cde8aa73 100644 --- a/packages/layout-elk/tsconfig.json +++ b/packages/layout-elk/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@eclipse-glsp/ts-config/mocha", + "extends": "@eclipse-glsp/ts-config", "compilerOptions": { "rootDir": "src", "outDir": "lib", diff --git a/packages/layout-elk/tsconfig.test.json b/packages/layout-elk/tsconfig.test.json new file mode 100644 index 00000000..19a4102a --- /dev/null +++ b/packages/layout-elk/tsconfig.test.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "composite": true, + "noEmit": true + }, + "include": ["src/**/*.spec.ts", "src/**/*.spec.tsx", "src/**/test/**/*"], + "exclude": ["lib", "node_modules"], + "references": [{ "path": "./tsconfig.json" }] +} diff --git a/packages/server-mcp/package.json b/packages/server-mcp/package.json index 10930a19..02c47626 100644 --- a/packages/server-mcp/package.json +++ b/packages/server-mcp/package.json @@ -42,17 +42,17 @@ "browser.js", "browser.d.ts", "common.js", - "common.d.ts" + "common.d.ts", + "!**/*.spec.ts", + "!**/*.spec.tsx", + "!**/test/**" ], "scripts": { "build": "tsc -b", - "clean": "rimraf lib *.tsbuildinfo coverage .nyc_output", + "clean": "rimraf lib *.tsbuildinfo coverage", "generate:index": "glsp generateIndex src/browser src/common src/node -f -s", "lint": "eslint --ext .ts,.tsx ./src", - "prepublishOnly": "pnpm build", - "test": "mocha --config ../../.mocharc \"./src/**/*.spec.?(ts|tsx)\"", - "test:ci": "pnpm test --reporter mocha-ctrf-json-reporter", - "test:coverage": "nyc pnpm test" + "prepublishOnly": "pnpm build" }, "dependencies": { "@eclipse-glsp/server": "workspace:*", diff --git a/packages/server-mcp/src/common/server/abstract-mcp-server-launcher.spec.ts b/packages/server-mcp/src/common/server/abstract-mcp-server-launcher.spec.ts index 1beffd59..2d21cf2e 100644 --- a/packages/server-mcp/src/common/server/abstract-mcp-server-launcher.spec.ts +++ b/packages/server-mcp/src/common/server/abstract-mcp-server-launcher.spec.ts @@ -23,7 +23,7 @@ import { McpInitializeResult } from '@eclipse-glsp/server'; import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js'; -import { expect } from 'chai'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import * as z from 'zod/v4'; import { AbstractMcpServerLauncher, FullMcpServerConfiguration, TransportEndpoint } from './abstract-mcp-server-launcher'; @@ -222,8 +222,8 @@ describe('AbstractMcpServerLauncher.handleRequest', () => { it('POST initialize creates a session and returns 200 with mcp-session-id header', async () => { const response = await launcher.handleRequest(postInit()); - expect(response.status).to.equal(200); - expect(response.headers.get('mcp-session-id'), 'must echo a session id after initialize').to.be.a('string'); + expect(response.status).toBe(200); + expect(response.headers.get('mcp-session-id'), 'must echo a session id after initialize').toBeTypeOf('string'); }); it('POST to a known session dispatches to its transport (tools/call round-trip)', async () => { @@ -243,29 +243,29 @@ describe('AbstractMcpServerLauncher.handleRequest', () => { params: { name: 'echo', arguments: { message: 'hello' } } }) ); - expect(callResponse.status).to.equal(200); + expect(callResponse.status).toBe(200); const payload = (await readSseFirstData(callResponse)) as { result?: { content?: Array<{ text?: string }> } }; - expect(payload.result?.content?.[0]?.text).to.equal('hello'); + expect(payload.result?.content?.[0]?.text).toBe('hello'); }); it('POST without session id, non-initialize body → 400 with JSON-RPC error envelope', async () => { const response = await launcher.handleRequest(postJson(undefined, { jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} })); - expect(response.status).to.equal(400); + expect(response.status).toBe(400); const payload = (await response.json()) as { jsonrpc: string; error: { code: number; message: string }; id: unknown }; - expect(payload.jsonrpc).to.equal('2.0'); + expect(payload.jsonrpc).toBe('2.0'); // eslint-disable-next-line no-null/no-null - expect(payload.id).to.equal(null); - expect(payload.error.code).to.equal(-32000); - expect(payload.error.message).to.match(/No valid session ID/); + expect(payload.id).toBe(null); + expect(payload.error.code).toBe(-32000); + expect(payload.error.message).toMatch(/No valid session ID/); }); it('POST with unknown session id → 404 with JSON-RPC error envelope', async () => { const response = await launcher.handleRequest( postJson('not-a-real-session', { jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} }) ); - expect(response.status).to.equal(404); + expect(response.status).toBe(404); const payload = (await response.json()) as { error: { code: number } }; - expect(payload.error.code).to.equal(-32001); + expect(payload.error.code).toBe(-32001); }); it('GET with accept: text/event-stream on a known session → 200, text/event-stream', async () => { @@ -279,8 +279,8 @@ describe('AbstractMcpServerLauncher.handleRequest', () => { headers: { accept: 'text/event-stream', 'mcp-session-id': sessionId } }) ); - expect(getResponse.status).to.equal(200); - expect(getResponse.headers.get('content-type')).to.match(/text\/event-stream/); + expect(getResponse.status).toBe(200); + expect(getResponse.headers.get('content-type')).toMatch(/text\/event-stream/); getResponse.body?.cancel().catch(() => undefined); }); @@ -291,7 +291,7 @@ describe('AbstractMcpServerLauncher.handleRequest', () => { headers: { accept: 'text/event-stream', 'mcp-session-id': 'nope' } }) ); - expect(response.status).to.equal(404); + expect(response.status).toBe(404); }); it('DELETE on known session fires onSessionClosed; subsequent POSTs return 404', async () => { @@ -305,11 +305,11 @@ describe('AbstractMcpServerLauncher.handleRequest', () => { const deleteResponse = await launcher.handleRequest( new Request('http://test/mcp', { method: 'DELETE', headers: { 'mcp-session-id': sessionId } }) ); - expect(deleteResponse.status).to.be.lessThan(300); - expect(closedIds).to.include(sessionId); + expect(deleteResponse.status).toBeLessThan(300); + expect(closedIds).toContain(sessionId); const followUp = await launcher.handleRequest(postJson(sessionId, { jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} })); - expect(followUp.status).to.equal(404); + expect(followUp.status).toBe(404); }); it('Non-init POST with unsupported MCP-Protocol-Version → 400 with JSON-RPC error envelope', async () => { @@ -324,10 +324,10 @@ describe('AbstractMcpServerLauncher.handleRequest', () => { body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} }) }) ); - expect(response.status).to.equal(400); + expect(response.status).toBe(400); const payload = (await response.json()) as { error: { code: number; message: string } }; - expect(payload.error.code).to.equal(-32000); - expect(payload.error.message).to.match(/Unsupported MCP-Protocol-Version/); + expect(payload.error.code).toBe(-32000); + expect(payload.error.message).toMatch(/Unsupported MCP-Protocol-Version/); }); it('POST with no MCP-Protocol-Version header passes the version gate (falls through to session-id check)', async () => { @@ -341,9 +341,9 @@ describe('AbstractMcpServerLauncher.handleRequest', () => { body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} }) }) ); - expect(response.status).to.equal(400); + expect(response.status).toBe(400); const payload = (await response.json()) as { error: { message: string } }; - expect(payload.error.message).to.match(/No valid session ID/); + expect(payload.error.message).toMatch(/No valid session ID/); }); it('authInfo from handleRequest reaches the registered tool handler extra', async () => { @@ -365,9 +365,9 @@ describe('AbstractMcpServerLauncher.handleRequest', () => { ); await readSseFirstData(callResponse).catch(() => undefined); - expect(launcher.authCapture.invoked).to.equal(true); - expect(launcher.authCapture.authInfo?.token).to.equal('bearer-xyz'); - expect(launcher.authCapture.authInfo?.clientId).to.equal('spec-client'); + expect(launcher.authCapture.invoked).toBe(true); + expect(launcher.authCapture.authInfo?.token).toBe('bearer-xyz'); + expect(launcher.authCapture.authInfo?.clientId).toBe('spec-client'); }); it('onSessionInitialized fires on initialize', async () => { @@ -376,20 +376,20 @@ describe('AbstractMcpServerLauncher.handleRequest', () => { const response = await launcher.handleRequest(postInit()); const sessionId = response.headers.get('mcp-session-id')!; - expect(sessionIds).to.include(sessionId); + expect(sessionIds).toContain(sessionId); }); it('Route mismatch (POST /other when launcher route is /mcp) → 404', async () => { const response = await launcher.handleRequest( new Request('http://test/other', { method: 'POST', body: '{}', headers: { 'content-type': 'application/json' } }) ); - expect(response.status).to.equal(404); + expect(response.status).toBe(404); }); it('Unsupported method (PUT /mcp) → 405 with Allow header', async () => { const response = await launcher.handleRequest(new Request('http://test/mcp', { method: 'PUT' })); - expect(response.status).to.equal(405); - expect(response.headers.get('Allow')).to.equal('POST, GET, DELETE'); + expect(response.status).toBe(405); + expect(response.headers.get('Allow')).toBe('POST, GET, DELETE'); }); }); @@ -405,7 +405,7 @@ describe('AbstractMcpServerLauncher · initializeServer lifecycle', () => { await initLauncher(launcher); await initLauncher(launcher); - expect(bindCount).to.equal(1); + expect(bindCount).toBe(1); launcher.dispose(); }); @@ -413,7 +413,7 @@ describe('AbstractMcpServerLauncher · initializeServer lifecycle', () => { const launcher = buildLauncher(); await initLauncher(launcher); const firstResponse = await launcher.handleRequest(postInit()); - expect(firstResponse.headers.get('mcp-session-id')).to.be.a('string'); + expect(firstResponse.headers.get('mcp-session-id')).toBeTypeOf('string'); await readSseFirstData(firstResponse).catch(() => undefined); launcher.dispose(); @@ -421,8 +421,8 @@ describe('AbstractMcpServerLauncher · initializeServer lifecycle', () => { // Re-init from the same instance — proves dispose() cleared the singleton state. await initLauncher(launcher, { route: '/mcp', name: 'spec-2' }); const secondResponse = await launcher.handleRequest(postInit()); - expect(secondResponse.status).to.equal(200); - expect(secondResponse.headers.get('mcp-session-id')).to.be.a('string'); + expect(secondResponse.status).toBe(200); + expect(secondResponse.headers.get('mcp-session-id')).toBeTypeOf('string'); launcher.dispose(); }); @@ -431,7 +431,7 @@ describe('AbstractMcpServerLauncher · initializeServer lifecycle', () => { await initLauncher(launcher, { route: '/custom' }); const wrongRoute = await launcher.handleRequest(postInit()); - expect(wrongRoute.status).to.equal(404); + expect(wrongRoute.status).toBe(404); const correctRoute = await launcher.handleRequest( new Request('http://test/custom', { @@ -440,7 +440,7 @@ describe('AbstractMcpServerLauncher · initializeServer lifecycle', () => { body: JSON.stringify(INIT_BODY) }) ); - expect(correctRoute.status).to.equal(200); + expect(correctRoute.status).toBe(200); launcher.dispose(); }); @@ -451,8 +451,8 @@ describe('AbstractMcpServerLauncher · initializeServer lifecycle', () => { url: 'http://announced.example/mcp' }); const result = await initLauncher(launcher); - expect(McpInitializeResult.is(result)).to.equal(true); - expect(McpInitializeResult.getServer(result)?.url).to.equal('http://announced.example/mcp'); + expect(McpInitializeResult.is(result)).toBe(true); + expect(McpInitializeResult.getServer(result)?.url).toBe('http://announced.example/mcp'); launcher.dispose(); }); }); diff --git a/packages/server-mcp/src/common/server/glsp-mcp-server.spec.ts b/packages/server-mcp/src/common/server/glsp-mcp-server.spec.ts index 2a97c0ea..e451a4e1 100644 --- a/packages/server-mcp/src/common/server/glsp-mcp-server.spec.ts +++ b/packages/server-mcp/src/common/server/glsp-mcp-server.spec.ts @@ -16,8 +16,7 @@ import { NullLogger } from '@eclipse-glsp/server'; import { McpServer, RegisteredResource } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { expect } from 'chai'; -import * as sinon from 'sinon'; +import { describe, expect, it, vi } from 'vitest'; import * as z from 'zod/v4'; import { DefaultGLSPMcpServer } from './glsp-mcp-server'; @@ -34,8 +33,8 @@ describe('DefaultGLSPMcpServer', () => { wrapper.registerTool('beta', { description: 'second' }, async () => ({ content: [] })); const names = wrapper.listTools().map(tool => tool.description); - expect(names).to.have.members(['first', 'second']); - expect(wrapper.listTools()).to.have.lengthOf(2); + expect([...names].sort()).toEqual(['first', 'second'].sort()); + expect(wrapper.listTools()).toHaveLength(2); }); it('tracks registerResource (static URI) and listResources reflects it by name', () => { @@ -45,9 +44,9 @@ describe('DefaultGLSPMcpServer', () => { })); const resources = wrapper.listResources(); - expect(resources).to.have.lengthOf(1); - expect((resources[0] as RegisteredResource).name).to.equal('my-resource'); - expect((resources[0] as RegisteredResource).title).to.equal('res'); + expect(resources).toHaveLength(1); + expect((resources[0] as RegisteredResource).name).toBe('my-resource'); + expect((resources[0] as RegisteredResource).title).toBe('res'); }); it('tracks registerPrompt and listPrompts reflects it by description', () => { @@ -55,19 +54,19 @@ describe('DefaultGLSPMcpServer', () => { wrapper.registerPrompt('describe', { description: 'desc' }, async () => ({ messages: [] })); const prompts = wrapper.listPrompts(); - expect(prompts).to.have.lengthOf(1); - expect(prompts[0].description).to.equal('desc'); + expect(prompts).toHaveLength(1); + expect(prompts[0].description).toBe('desc'); }); it('getRawServer() returns the exact SDK instance passed in (escape hatch identity)', () => { const { wrapper, sdk } = makeServer(); - expect(wrapper.getRawServer()).to.equal(sdk); + expect(wrapper.getRawServer()).toBe(sdk); }); it('dispose() invokes close() on the underlying SDK server', () => { const { wrapper, sdk } = makeServer(); - const closeSpy = sinon.spy(sdk, 'close'); + const closeSpy = vi.spyOn(sdk, 'close'); wrapper.dispose(); - expect(closeSpy.calledOnce).to.be.true; + expect(closeSpy).toHaveBeenCalledOnce(); }); }); diff --git a/packages/server-mcp/src/common/server/lru-event-store.spec.ts b/packages/server-mcp/src/common/server/lru-event-store.spec.ts index 630c151c..32abf5cd 100644 --- a/packages/server-mcp/src/common/server/lru-event-store.spec.ts +++ b/packages/server-mcp/src/common/server/lru-event-store.spec.ts @@ -16,7 +16,7 @@ import { Logger } from '@eclipse-glsp/server'; import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { LruEventStore } from './lru-event-store'; function jsonRpc(id: number): JSONRPCMessage { @@ -25,14 +25,14 @@ function jsonRpc(id: number): JSONRPCMessage { describe('LruEventStore', () => { it('rejects an invalid limit (< 1)', () => { - expect(() => new LruEventStore(0)).to.throw(/limit must be >= 1/); - expect(() => new LruEventStore(-5)).to.throw(/limit must be >= 1/); + expect(() => new LruEventStore(0)).toThrow(/limit must be >= 1/); + expect(() => new LruEventStore(-5)).toThrow(/limit must be >= 1/); }); it('storeEvent returns a streamId-prefixed event id', async () => { const store = new LruEventStore(); const id = await store.storeEvent('stream-A', jsonRpc(1)); - expect(id.split('_')[0]).to.equal('stream-A'); + expect(id.split('_')[0]).toBe('stream-A'); }); it('evicts the oldest event once the cap is exceeded', async () => { @@ -41,11 +41,11 @@ describe('LruEventStore', () => { const id2 = await store.storeEvent('s', jsonRpc(2)); await store.storeEvent('s', jsonRpc(3)); - expect(store.size).to.equal(3); + expect(store.size).toBe(3); // Adding a 4th event evicts the oldest (id1). const id4 = await store.storeEvent('s', jsonRpc(4)); - expect(store.size).to.equal(3); + expect(store.size).toBe(3); // Replay since id1 → can't find it (evicted) → returns ''. const replayed: string[] = []; @@ -54,8 +54,8 @@ describe('LruEventStore', () => { replayed.push(eventId); } }); - expect(streamId).to.equal(''); // id1 has been evicted - expect(replayed).to.have.lengthOf(0); + expect(streamId).toBe(''); // id1 has been evicted + expect(replayed).toHaveLength(0); // Replay since id2 still works — id3 (still in store) and id4 are sent in order. const replayedFromId2: string[] = []; @@ -64,8 +64,8 @@ describe('LruEventStore', () => { replayedFromId2.push(eventId); } }); - expect(replayedFromId2).to.have.lengthOf(2); - expect(replayedFromId2[1]).to.equal(id4); + expect(replayedFromId2).toHaveLength(2); + expect(replayedFromId2[1]).toBe(id4); }); it('replays only events from the same stream after the lastEventId', async () => { @@ -82,8 +82,8 @@ describe('LruEventStore', () => { } }); - expect(streamId).to.equal('A'); - expect(replayed.map(e => e.id)).to.deep.equal([a3, a4]); + expect(streamId).toBe('A'); + expect(replayed.map(e => e.id)).toEqual([a3, a4]); }); it('returns "" when lastEventId is unknown', async () => { @@ -96,7 +96,7 @@ describe('LruEventStore', () => { } }); - expect(streamId).to.equal(''); + expect(streamId).toBe(''); }); it('logs a cap-eviction warn when replaying an evicted last-event-id', async () => { @@ -113,9 +113,9 @@ describe('LruEventStore', () => { } }); - expect(streamId).to.equal(''); - expect(warns).to.have.lengthOf(1); - expect(warns[0]).to.match(/Replay miss/); - expect(warns[0]).to.include('Cap is 2'); + expect(streamId).toBe(''); + expect(warns).toHaveLength(1); + expect(warns[0]).toMatch(/Replay miss/); + expect(warns[0]).toContain('Cap is 2'); }); }); diff --git a/packages/server-mcp/src/common/server/mcp-diagram-handler-dispatcher.spec.ts b/packages/server-mcp/src/common/server/mcp-diagram-handler-dispatcher.spec.ts index 409a23af..bcfa4abd 100644 --- a/packages/server-mcp/src/common/server/mcp-diagram-handler-dispatcher.spec.ts +++ b/packages/server-mcp/src/common/server/mcp-diagram-handler-dispatcher.spec.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { CallToolResult, ReadResourceResult } from '@modelcontextprotocol/sdk/types.js'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { GLSPMcpServer } from './glsp-mcp-server'; import { DefaultMcpDiagramHandlerDispatcher, DiagramTypeCatalog } from './mcp-diagram-handler-dispatcher'; @@ -124,8 +124,8 @@ describe('DefaultMcpDiagramHandlerDispatcher · SDK-callback dispatch error enve dispatcher.registerAll(captured as unknown as GLSPMcpServer, false); const result = await captured.tools.get('fake-tool')!({}, {}); - expect(result.isError).to.equal(true); - expect((result.content as Array<{ text: string }>)[0].text).to.match(/sessionId/); + expect(result.isError).toBe(true); + expect((result.content as Array<{ text: string }>)[0].text).toMatch(/sessionId/); }); it('tool callback returns isError envelope when sessionId is unknown', async () => { @@ -142,8 +142,8 @@ describe('DefaultMcpDiagramHandlerDispatcher · SDK-callback dispatch error enve dispatcher.registerAll(captured as unknown as GLSPMcpServer, false); const result = await captured.tools.get('fake-tool')!({ sessionId: 'unknown-glsp-id' }, {}); - expect(result.isError).to.equal(true); - expect((result.content as Array<{ text: string }>)[0].text).to.match(/Session not found/); + expect(result.isError).toBe(true); + expect((result.content as Array<{ text: string }>)[0].text).toMatch(/Session not found/); }); it('tool callback returns isError envelope when registered handler is absent for the session', async () => { @@ -165,8 +165,8 @@ describe('DefaultMcpDiagramHandlerDispatcher · SDK-callback dispatch error enve dispatcher.registerAll(captured as unknown as GLSPMcpServer, false); const result = await captured.tools.get('fake-tool')!({ sessionId: 'session-1' }, {}); - expect(result.isError).to.equal(true); - expect((result.content as Array<{ text: string }>)[0].text).to.match(/No tool handler/); + expect(result.isError).toBe(true); + expect((result.content as Array<{ text: string }>)[0].text).toMatch(/No tool handler/); }); it('resource-as-tool callback returns isError envelope when sessionId is missing', async () => { @@ -181,8 +181,8 @@ describe('DefaultMcpDiagramHandlerDispatcher · SDK-callback dispatch error enve dispatcher.registerAll(captured as unknown as GLSPMcpServer, false); const result = await captured.tools.get('fake-resource')!({}, {}); - expect(result.isError).to.equal(true); - expect((result.content as Array<{ text: string }>)[0].text).to.match(/sessionId/); + expect(result.isError).toBe(true); + expect((result.content as Array<{ text: string }>)[0].text).toMatch(/sessionId/); }); it('static-URI resource read throws McpToolError when no GLSP session is open', async () => { @@ -205,8 +205,8 @@ describe('DefaultMcpDiagramHandlerDispatcher · SDK-callback dispatch error enve } catch (err: unknown) { rejection = err; } - expect(rejection).to.exist; - expect((rejection as Error).message).to.match(/No open GLSP session/); + expect(rejection).toBeDefined(); + expect((rejection as Error).message).toMatch(/No open GLSP session/); }); it('prompt callback rejects with McpToolError when sessionId is missing (no envelope wrap — by design)', async () => { @@ -225,7 +225,7 @@ describe('DefaultMcpDiagramHandlerDispatcher · SDK-callback dispatch error enve } catch (err: unknown) { rejection = err; } - expect(rejection).to.exist; - expect((rejection as Error).message).to.match(/sessionId/); + expect(rejection).toBeDefined(); + expect((rejection as Error).message).toMatch(/sessionId/); }); }); diff --git a/packages/server-mcp/src/common/server/mcp-handler-shared.spec.ts b/packages/server-mcp/src/common/server/mcp-handler-shared.spec.ts index c0fca3a8..404ca1f1 100644 --- a/packages/server-mcp/src/common/server/mcp-handler-shared.spec.ts +++ b/packages/server-mcp/src/common/server/mcp-handler-shared.spec.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { ClientSessionManager } from '@eclipse-glsp/server'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { McpToolError, resolveActiveSessionId } from './mcp-handler-shared'; function stubSessionManager(sessionIds: string[]): ClientSessionManager { @@ -25,29 +25,29 @@ function stubSessionManager(sessionIds: string[]): ClientSessionManager { describe('resolveActiveSessionId', () => { it('returns the explicit session id when it matches an open session', () => { const result = resolveActiveSessionId(stubSessionManager(['alpha', 'beta']), 'alpha'); - expect(result).to.equal('alpha'); + expect(result).toBe('alpha'); }); it('defaults to the only open session when sessionId is omitted', () => { const result = resolveActiveSessionId(stubSessionManager(['solo']), undefined); - expect(result).to.equal('solo'); + expect(result).toBe('solo'); }); it('throws McpToolError listing the open sessions when ambiguous', () => { - expect(() => resolveActiveSessionId(stubSessionManager(['session-a', 'session-b']), undefined)).to.throw( - McpToolError, - /Multiple sessions open.*session-a.*session-b/ - ); + const act = (): string => resolveActiveSessionId(stubSessionManager(['session-a', 'session-b']), undefined); + expect(act).toThrow(McpToolError); + expect(act).toThrow(/Multiple sessions open.*session-a.*session-b/); }); it('throws McpToolError when no sessions are open', () => { - expect(() => resolveActiveSessionId(stubSessionManager([]), undefined)).to.throw(McpToolError, /No open diagram sessions/); + const act = (): string => resolveActiveSessionId(stubSessionManager([]), undefined); + expect(act).toThrow(McpToolError); + expect(act).toThrow(/No open diagram sessions/); }); it('throws McpToolError when an explicit sessionId does not match any open session', () => { - expect(() => resolveActiveSessionId(stubSessionManager(['real-session']), 'ghost')).to.throw( - McpToolError, - /Unknown sessionId: ghost/ - ); + const act = (): string => resolveActiveSessionId(stubSessionManager(['real-session']), 'ghost'); + expect(act).toThrow(McpToolError); + expect(act).toThrow(/Unknown sessionId: ghost/); }); }); diff --git a/packages/server-mcp/src/common/server/mcp-id-alias-service.spec.ts b/packages/server-mcp/src/common/server/mcp-id-alias-service.spec.ts index eb1da6c0..2b7206b0 100644 --- a/packages/server-mcp/src/common/server/mcp-id-alias-service.spec.ts +++ b/packages/server-mcp/src/common/server/mcp-id-alias-service.spec.ts @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { DefaultMcpIdAliasService, NullMcpIdAliasService } from './mcp-id-alias-service'; describe('DefaultMcpIdAliasService', () => { @@ -25,18 +25,18 @@ describe('DefaultMcpIdAliasService', () => { const aliasA2 = service.alias('uuid-a'); const aliasB = service.alias('uuid-b'); - expect(aliasA).to.equal(aliasA2); - expect(aliasA).to.not.equal(aliasB); + expect(aliasA).toBe(aliasA2); + expect(aliasA).not.toBe(aliasB); // Aliases are integer strings, starting at "1". - expect(aliasA).to.match(/^\d+$/); - expect(aliasB).to.match(/^\d+$/); + expect(aliasA).toMatch(/^\d+$/); + expect(aliasB).toMatch(/^\d+$/); }); it('lookup(alias) returns the original id (round-trip)', () => { const service = new DefaultMcpIdAliasService(); const alias = service.alias('uuid-foo'); - expect(service.lookup(alias)).to.equal('uuid-foo'); + expect(service.lookup(alias)).toBe('uuid-foo'); }); it('lookup(unknown) returns the input verbatim (best-effort fallback)', () => { @@ -44,7 +44,7 @@ describe('DefaultMcpIdAliasService', () => { // Unknown ids may come from manual user input, copy-paste, or earlier server-side // state. The service passes them through; downstream existence checks decide. - expect(service.lookup('never-issued')).to.equal('never-issued'); + expect(service.lookup('never-issued')).toBe('never-issued'); }); it('skips alias candidates that collide with a known real id (no shadowing)', () => { @@ -57,18 +57,18 @@ describe('DefaultMcpIdAliasService', () => { const aliasOf1 = service.alias('1'); const aliasOfX = service.alias('uuid-other'); - expect(aliasOf1).to.not.equal('1'); - expect(aliasOfX).to.not.equal('1'); - expect(service.lookup('1')).to.equal('1'); - expect(service.lookup(aliasOf1)).to.equal('1'); - expect(service.lookup(aliasOfX)).to.equal('uuid-other'); + expect(aliasOf1).not.toBe('1'); + expect(aliasOfX).not.toBe('1'); + expect(service.lookup('1')).toBe('1'); + expect(service.lookup(aliasOf1)).toBe('1'); + expect(service.lookup(aliasOfX)).toBe('uuid-other'); // Multiple pre-known real ids: every issued alias is outside the known-real set. const service2 = new DefaultMcpIdAliasService(); const knownReals = ['1', '2', '3']; knownReals.forEach(id => service2.alias(id)); const fresh = service2.alias('uuid-fresh'); - expect(knownReals).to.not.include(fresh); + expect(knownReals).not.toContain(fresh); }); it('keeps independent counters and maps across separate instances (per-session isolation)', () => { @@ -81,17 +81,17 @@ describe('DefaultMcpIdAliasService', () => { const aliasB1 = sessionB.alias('uuid-z'); // Counters are independent: B's first alias is "1", same as A's first. - expect(aliasA1).to.equal('1'); - expect(aliasA2).to.equal('2'); - expect(aliasB1).to.equal('1'); + expect(aliasA1).toBe('1'); + expect(aliasA2).toBe('2'); + expect(aliasB1).toBe('1'); // Bleed-isolation: alias "1" in B resolves to uuid-z, NOT to uuid-x (A's "1"). - expect(sessionA.lookup('1')).to.equal('uuid-x'); - expect(sessionB.lookup('1')).to.equal('uuid-z'); + expect(sessionA.lookup('1')).toBe('uuid-x'); + expect(sessionB.lookup('1')).toBe('uuid-z'); // Unknown ids in either session fall through to the input verbatim. - expect(sessionA.lookup('3')).to.equal('3'); - expect(sessionB.lookup('2')).to.equal('2'); + expect(sessionA.lookup('3')).toBe('3'); + expect(sessionB.lookup('2')).toBe('2'); }); }); @@ -99,8 +99,8 @@ describe('NullMcpIdAliasService', () => { it('alias and lookup return the argument unchanged', () => { const service = new NullMcpIdAliasService(); - expect(service.alias('uuid-foo')).to.equal('uuid-foo'); - expect(service.lookup('uuid-foo')).to.equal('uuid-foo'); - expect(service.lookup('never-seen')).to.equal('never-seen'); + expect(service.alias('uuid-foo')).toBe('uuid-foo'); + expect(service.lookup('uuid-foo')).toBe('uuid-foo'); + expect(service.lookup('never-seen')).toBe('never-seen'); }); }); diff --git a/packages/server-mcp/src/common/server/mcp-log-level-registry.spec.ts b/packages/server-mcp/src/common/server/mcp-log-level-registry.spec.ts index a48ff66f..51d450e1 100644 --- a/packages/server-mcp/src/common/server/mcp-log-level-registry.spec.ts +++ b/packages/server-mcp/src/common/server/mcp-log-level-registry.spec.ts @@ -14,62 +14,62 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { DefaultMcpLogLevelRegistry, passesLogThreshold } from './mcp-log-level-registry'; describe('passesLogThreshold (G4 severity gate)', () => { it('passes a level whose severity is at or above the threshold (RFC 5424: lower number = more severe)', () => { // Threshold 'warning' (4) keeps emergency..warning, drops notice..debug. - expect(passesLogThreshold('emergency', 'warning')).to.equal(true); - expect(passesLogThreshold('error', 'warning')).to.equal(true); - expect(passesLogThreshold('warning', 'warning')).to.equal(true); - expect(passesLogThreshold('notice', 'warning')).to.equal(false); - expect(passesLogThreshold('info', 'warning')).to.equal(false); - expect(passesLogThreshold('debug', 'warning')).to.equal(false); + expect(passesLogThreshold('emergency', 'warning')).toBe(true); + expect(passesLogThreshold('error', 'warning')).toBe(true); + expect(passesLogThreshold('warning', 'warning')).toBe(true); + expect(passesLogThreshold('notice', 'warning')).toBe(false); + expect(passesLogThreshold('info', 'warning')).toBe(false); + expect(passesLogThreshold('debug', 'warning')).toBe(false); }); it('passes everything when the threshold is debug (the default)', () => { for (const level of ['emergency', 'alert', 'critical', 'error', 'warning', 'notice', 'info', 'debug'] as const) { - expect(passesLogThreshold(level, 'debug')).to.equal(true); + expect(passesLogThreshold(level, 'debug')).toBe(true); } }); it('passes only emergency when the threshold is emergency', () => { - expect(passesLogThreshold('emergency', 'emergency')).to.equal(true); - expect(passesLogThreshold('alert', 'emergency')).to.equal(false); - expect(passesLogThreshold('debug', 'emergency')).to.equal(false); + expect(passesLogThreshold('emergency', 'emergency')).toBe(true); + expect(passesLogThreshold('alert', 'emergency')).toBe(false); + expect(passesLogThreshold('debug', 'emergency')).toBe(false); }); }); describe('DefaultMcpLogLevelRegistry', () => { it('returns the default level for an unknown session id', () => { const registry = new DefaultMcpLogLevelRegistry(); - expect(registry.getLevel('never-set')).to.equal(DefaultMcpLogLevelRegistry.DEFAULT_LEVEL); + expect(registry.getLevel('never-set')).toBe(DefaultMcpLogLevelRegistry.DEFAULT_LEVEL); }); it('returns the default level when sessionId is undefined (out-of-band logger calls)', () => { const registry = new DefaultMcpLogLevelRegistry(); - expect(registry.getLevel(undefined)).to.equal(DefaultMcpLogLevelRegistry.DEFAULT_LEVEL); + expect(registry.getLevel(undefined)).toBe(DefaultMcpLogLevelRegistry.DEFAULT_LEVEL); }); it('persists the most recent setLevel value per session and isolates across sessions', () => { const registry = new DefaultMcpLogLevelRegistry(); registry.setLevel('A', 'warning'); registry.setLevel('B', 'error'); - expect(registry.getLevel('A')).to.equal('warning'); - expect(registry.getLevel('B')).to.equal('error'); + expect(registry.getLevel('A')).toBe('warning'); + expect(registry.getLevel('B')).toBe('error'); registry.setLevel('A', 'info'); - expect(registry.getLevel('A')).to.equal('info'); - expect(registry.getLevel('B')).to.equal('error'); + expect(registry.getLevel('A')).toBe('info'); + expect(registry.getLevel('B')).toBe('error'); }); it('clear(sessionId) drops the entry so a recycled session id starts at the default', () => { const registry = new DefaultMcpLogLevelRegistry(); registry.setLevel('reused', 'error'); - expect(registry.getLevel('reused')).to.equal('error'); + expect(registry.getLevel('reused')).toBe('error'); registry.clear('reused'); - expect(registry.getLevel('reused')).to.equal(DefaultMcpLogLevelRegistry.DEFAULT_LEVEL); + expect(registry.getLevel('reused')).toBe(DefaultMcpLogLevelRegistry.DEFAULT_LEVEL); }); }); diff --git a/packages/server-mcp/src/common/server/mcp-logger.spec.ts b/packages/server-mcp/src/common/server/mcp-logger.spec.ts index 1d7f9979..63d3a2f4 100644 --- a/packages/server-mcp/src/common/server/mcp-logger.spec.ts +++ b/packages/server-mcp/src/common/server/mcp-logger.spec.ts @@ -16,7 +16,7 @@ import { Logger, NullLogger } from '@eclipse-glsp/server'; import { ServerNotification } from '@modelcontextprotocol/sdk/types.js'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import { DefaultMcpLogLevelRegistry, McpLogLevelRegistry } from './mcp-log-level-registry'; import { McpLogger } from './mcp-logger'; @@ -91,7 +91,7 @@ describe('McpLogger', () => { logger.error('boom'); logger.debug('trace'); - expect(glspLogger.entries).to.deep.equal([ + expect(glspLogger.entries).toEqual([ { level: 'info', message: 'hello' }, { level: 'warn', message: 'careful' }, { level: 'error', message: 'boom' }, @@ -114,14 +114,14 @@ describe('McpLogger', () => { await new Promise(resolve => setImmediate(resolve)); }); - expect(glspLogger.entries.map(e => e.message)).to.deep.equal(['one', 'two', 'three', 'four']); + expect(glspLogger.entries.map(e => e.message)).toEqual(['one', 'two', 'three', 'four']); expect( sent.map(n => ({ method: n.method, level: (n.params as { level: string }).level, data: (n.params as { data: string }).data })) - ).to.deep.equal([ + ).toEqual([ { method: 'notifications/message', level: 'info', data: 'one' }, { method: 'notifications/message', level: 'warning', data: 'two' }, // GLSP warn → MCP warning { method: 'notifications/message', level: 'error', data: 'three' }, @@ -138,12 +138,12 @@ describe('McpLogger', () => { } as unknown as McpRequestExtra; await requestContext.run(failingExtra, async () => { - expect(() => logger.error('still works')).to.not.throw(); + expect(() => logger.error('still works')).not.toThrow(); await new Promise(resolve => setImmediate(resolve)); }); // Server-side log still fired. - expect(glspLogger.entries).to.deep.equal([{ level: 'error', message: 'still works' }]); + expect(glspLogger.entries).toEqual([{ level: 'error', message: 'still works' }]); }); }); @@ -166,8 +166,8 @@ describe('McpLogger', () => { }) ]); - expect(sentA.map(n => (n.params as { data: string }).data)).to.deep.equal(['A', 'A-after-yield']); - expect(sentB.map(n => (n.params as { data: string }).data)).to.deep.equal(['B', 'B-after-yield']); + expect(sentA.map(n => (n.params as { data: string }).data)).toEqual(['A', 'A-after-yield']); + expect(sentB.map(n => (n.params as { data: string }).data)).toEqual(['B', 'B-after-yield']); }); }); @@ -187,9 +187,9 @@ describe('McpLogger', () => { }); // GLSP-side log path is independent of the MCP threshold — keeps adopter logs intact. - expect(glspLogger.entries.map(entry => entry.message)).to.deep.equal(['chatty', 'verbose', 'important', 'critical']); + expect(glspLogger.entries.map(entry => entry.message)).toEqual(['chatty', 'verbose', 'important', 'critical']); // MCP side: only warn + error survive. - expect(sent.map(n => (n.params as { level: string }).level)).to.deep.equal(['warning', 'error']); + expect(sent.map(n => (n.params as { level: string }).level)).toEqual(['warning', 'error']); }); it('isolates thresholds across sessions (different setLevel per session id)', async () => { @@ -212,8 +212,8 @@ describe('McpLogger', () => { }) ]); - expect(sentA.map(n => (n.params as { data: string }).data)).to.deep.equal(['A-error']); - expect(sentB.map(n => (n.params as { data: string }).data).sort()).to.deep.equal(['B-error', 'B-info']); + expect(sentA.map(n => (n.params as { data: string }).data)).toEqual(['A-error']); + expect(sentB.map(n => (n.params as { data: string }).data).sort()).toEqual(['B-error', 'B-info']); }); it('default threshold (no setLevel sent) lets every level through (preserves prior behavior)', async () => { @@ -229,7 +229,7 @@ describe('McpLogger', () => { await new Promise(resolve => setImmediate(resolve)); }); - expect(sent.map(n => (n.params as { level: string }).level)).to.deep.equal(['debug', 'info', 'warning', 'error']); + expect(sent.map(n => (n.params as { level: string }).level)).toEqual(['debug', 'info', 'warning', 'error']); }); }); }); diff --git a/packages/server-mcp/src/common/server/mcp-progress-reporter.spec.ts b/packages/server-mcp/src/common/server/mcp-progress-reporter.spec.ts index cfa55cef..fbbcf797 100644 --- a/packages/server-mcp/src/common/server/mcp-progress-reporter.spec.ts +++ b/packages/server-mcp/src/common/server/mcp-progress-reporter.spec.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { ServerNotification } from '@modelcontextprotocol/sdk/types.js'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { McpProgressReporter } from './mcp-progress-reporter'; import { Container } from 'inversify'; import { NodeMcpRequestContext } from '../../node/server/node-mcp-request-context'; @@ -49,7 +49,7 @@ describe('McpProgressReporter', () => { await reporter.emit({ progress: 0, message: 'starting' }); }); - expect(sent).to.have.lengthOf(0); + expect(sent).toHaveLength(0); }); it('emits notifications/progress when the request carries a progressToken', async () => { @@ -61,12 +61,12 @@ describe('McpProgressReporter', () => { await reporter.emit({ progress: 1, total: 3, message: 'step 1/3' }); }); - expect(sent).to.have.lengthOf(2); - expect(sent[0]).to.deep.equal({ + expect(sent).toHaveLength(2); + expect(sent[0]).toEqual({ method: 'notifications/progress', params: { progressToken: 'tok-42', progress: 0, message: 'starting' } }); - expect(sent[1]).to.deep.equal({ + expect(sent[1]).toEqual({ method: 'notifications/progress', params: { progressToken: 'tok-42', progress: 1, total: 3, message: 'step 1/3' } }); @@ -80,8 +80,8 @@ describe('McpProgressReporter', () => { await reporter.emit({ progress: 0 }); }); - expect(sent).to.have.lengthOf(1); - expect(sent[0].params).to.deep.equal({ progressToken: 7, progress: 0 }); + expect(sent).toHaveLength(1); + expect(sent[0].params).toEqual({ progressToken: 7, progress: 0 }); }); it('swallows transport failures so a broken send never breaks the producing tool', async () => { diff --git a/packages/server-mcp/src/common/server/mcp-tool-handler.spec.ts b/packages/server-mcp/src/common/server/mcp-tool-handler.spec.ts index 0656fa8a..466c7e31 100644 --- a/packages/server-mcp/src/common/server/mcp-tool-handler.spec.ts +++ b/packages/server-mcp/src/common/server/mcp-tool-handler.spec.ts @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import * as z from 'zod/v4'; import { McpToolResult } from './mcp-handler-shared'; import { CreateEdgesMcpToolHandler, CreateEdgesOutputSchema } from '../tools/handlers/create-edges-mcp-tool-handler'; @@ -63,28 +63,28 @@ class WithOutputSchemaHandler extends AbstractMcpToolHandler { describe('Dual-emit framework', () => { it('success(message) without structured payload omits structuredContent', () => { const result = new WithoutOutputSchemaHandler().testSuccess('hi'); - expect(result.content).to.deep.equal([{ type: 'text', text: 'hi' }]); - expect(result.structuredContent).to.equal(undefined); - expect(result.isError).to.equal(false); + expect(result.content).toEqual([{ type: 'text', text: 'hi' }]); + expect(result.structuredContent).toBe(undefined); + expect(result.isError).toBe(false); }); it('success(message, structured) emits structuredContent', () => { const result = new WithoutOutputSchemaHandler().testSuccess('hi', { count: 3, ids: ['a'] }); - expect(result.content).to.deep.equal([{ type: 'text', text: 'hi' }]); - expect(result.structuredContent).to.deep.equal({ count: 3, ids: ['a'] }); + expect(result.content).toEqual([{ type: 'text', text: 'hi' }]); + expect(result.structuredContent).toEqual({ count: 3, ids: ['a'] }); }); it('toRegistrationConfig() omits outputSchema when not declared', () => { const config = new WithoutOutputSchemaHandler().toRegistrationConfig(); - expect(config.outputSchema).to.equal(undefined); + expect(config.outputSchema).toBe(undefined); }); it('toRegistrationConfig() forwards outputSchema when declared', () => { const config = new WithOutputSchemaHandler().toRegistrationConfig(); - expect(config.outputSchema).to.not.equal(undefined); + expect(config.outputSchema).not.toBe(undefined); // The SDK accepts a full `ZodObject` (or its raw shape); we pass the wrapped object so // strict-mode rejection of unknown keys can extend uniformly to outputs. - expect(Object.keys(config.outputSchema!.shape)).to.deep.equal(['ok']); + expect(Object.keys(config.outputSchema!.shape)).toEqual(['ok']); }); }); @@ -171,11 +171,11 @@ describe('Tool output schemas · per-handler matrix', () => { matrix.forEach(({ name, Constructor, schema, sample }) => { describe(name, () => { it('declares outputSchema referencing the exported schema constant', () => { - expect(new Constructor().outputSchema).to.equal(schema); + expect(new Constructor().outputSchema).toBe(schema); }); it('schema accepts a representative structured payload', () => { - expect(() => schema.parse(sample)).to.not.throw(); + expect(() => schema.parse(sample)).not.toThrow(); }); }); }); diff --git a/packages/server-mcp/src/common/tools/handlers/count-elements-mcp-tool-handler.spec.ts b/packages/server-mcp/src/common/tools/handlers/count-elements-mcp-tool-handler.spec.ts index 4e0b2c07..be3f90a2 100644 --- a/packages/server-mcp/src/common/tools/handlers/count-elements-mcp-tool-handler.spec.ts +++ b/packages/server-mcp/src/common/tools/handlers/count-elements-mcp-tool-handler.spec.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { ClientId, GModelElement, Logger, ModelState, NullLogger } from '@eclipse-glsp/server'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import { McpToolResult } from '../../server/mcp-handler-shared'; import { McpIdAliasService } from '../../server/mcp-id-alias-service'; @@ -71,7 +71,7 @@ describe('CountElementsMcpToolHandler', () => { ]); const result = await callCreateResult(handler); - expect(result.structuredContent).to.deep.equal({ + expect(result.structuredContent).toEqual({ total: 4, countsByType: { 'task:manual': 2, 'task:automated': 1, edge: 1 } }); @@ -95,7 +95,7 @@ describe('CountElementsMcpToolHandler', () => { expect( indices.every(i => i >= 0), 'expected all type rows to be rendered' - ).to.equal(true); - expect(indices).to.deep.equal([...indices].sort((a, b) => a - b)); + ).toBe(true); + expect(indices).toEqual([...indices].sort((a, b) => a - b)); }); }); diff --git a/packages/server-mcp/src/common/tools/handlers/create-edges-mcp-tool-handler.spec.ts b/packages/server-mcp/src/common/tools/handlers/create-edges-mcp-tool-handler.spec.ts index 11db7e0c..b8811547 100644 --- a/packages/server-mcp/src/common/tools/handlers/create-edges-mcp-tool-handler.spec.ts +++ b/packages/server-mcp/src/common/tools/handlers/create-edges-mcp-tool-handler.spec.ts @@ -26,7 +26,7 @@ import { ModelState, NullLogger } from '@eclipse-glsp/server'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import { McpToolResult } from '../../server/mcp-handler-shared'; import { McpIdAliasService } from '../../server/mcp-id-alias-service'; @@ -138,11 +138,11 @@ describe('CreateEdgesMcpToolHandler · dryRun', () => { ); const structured = result.structuredContent as unknown as DryRunStructured; - expect(structured.validationResults).to.have.lengthOf(1); - expect(structured.validationResults[0].isValid).to.equal(true); - expect(structured.validationResults[0].reason).to.match(/no dynamic edge-type hint/i); - expect(structured.createdEdges).to.deep.equal([]); - expect(dispatcher.dispatched).to.have.lengthOf(0); + expect(structured.validationResults).toHaveLength(1); + expect(structured.validationResults[0].isValid).toBe(true); + expect(structured.validationResults[0].reason).toMatch(/no dynamic edge-type hint/i); + expect(structured.createdEdges).toEqual([]); + expect(dispatcher.dispatched).toHaveLength(0); }); it('flags isValid:false with a config-gap reason when edgeType declares a dynamic hint but no checker is bound', async () => { @@ -154,9 +154,9 @@ describe('CreateEdgesMcpToolHandler · dryRun', () => { const result = await callCreateResult(handler, baseInput()); const structured = result.structuredContent as unknown as DryRunStructured; - expect(structured.validationResults[0].isValid).to.equal(false); - expect(structured.validationResults[0].reason).to.include('EdgeCreationChecker is not bound'); - expect(dispatcher.dispatched).to.have.lengthOf(0); + expect(structured.validationResults[0].isValid).toBe(false); + expect(structured.validationResults[0].reason).toContain('EdgeCreationChecker is not bound'); + expect(dispatcher.dispatched).toHaveLength(0); }); it('delegates to EdgeCreationChecker.isValidTarget when target + dynamic hint + checker are present', async () => { @@ -171,14 +171,14 @@ describe('CreateEdgesMcpToolHandler · dryRun', () => { const result = await callCreateResult(handler, baseInput()); - expect(checker.lastTargetCall).to.deep.equal({ + expect(checker.lastTargetCall).toEqual({ edgeType: 'edge:dynamic', source: sourceElement, target: targetElement }); const structured = result.structuredContent as unknown as DryRunStructured; - expect(structured.validationResults[0].isValid).to.equal(false); - expect(dispatcher.dispatched).to.have.lengthOf(0); + expect(structured.validationResults[0].isValid).toBe(false); + expect(dispatcher.dispatched).toHaveLength(0); }); it('reports source/target not-found inline as a per-edge validation failure (does not throw)', async () => { @@ -192,7 +192,7 @@ describe('CreateEdgesMcpToolHandler · dryRun', () => { baseInput({ edges: [{ elementTypeId: 'edge:dynamic', sourceElementId: 's', targetElementId: 'missing' }] }) ); const structured = result.structuredContent as unknown as DryRunStructured; - expect(structured.validationResults[0].isValid).to.equal(false); - expect(structured.validationResults[0].reason).to.include('Target element not found'); + expect(structured.validationResults[0].isValid).toBe(false); + expect(structured.validationResults[0].reason).toContain('Target element not found'); }); }); diff --git a/packages/server-mcp/src/common/tools/handlers/create-nodes-mcp-tool-handler.spec.ts b/packages/server-mcp/src/common/tools/handlers/create-nodes-mcp-tool-handler.spec.ts index 17e395d6..fb53db1a 100644 --- a/packages/server-mcp/src/common/tools/handlers/create-nodes-mcp-tool-handler.spec.ts +++ b/packages/server-mcp/src/common/tools/handlers/create-nodes-mcp-tool-handler.spec.ts @@ -26,7 +26,7 @@ import { ModelState, NullLogger } from '@eclipse-glsp/server'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import { McpToolResult } from '../../server/mcp-handler-shared'; import { McpIdAliasService } from '../../server/mcp-id-alias-service'; @@ -146,12 +146,12 @@ describe('CreateNodesMcpToolHandler', () => { }); const structured = result.structuredContent as unknown as CreatedElementsStructured; - expect(structured.createdNodes).to.have.lengthOf(2); - expect(structured.createdNodes[0].id).to.equal('task:manual#1'); - expect(structured.createdNodes[1].id).to.equal('task:manual#2'); - expect(structured.errors).to.deep.equal([]); - expect(structured.warnings).to.deep.equal([]); - expect(dispatcher.dispatched.filter(CreateNodeOperation.is)).to.have.lengthOf(2); + expect(structured.createdNodes).toHaveLength(2); + expect(structured.createdNodes[0].id).toBe('task:manual#1'); + expect(structured.createdNodes[1].id).toBe('task:manual#2'); + expect(structured.errors).toEqual([]); + expect(structured.warnings).toEqual([]); + expect(dispatcher.dispatched.filter(CreateNodeOperation.is)).toHaveLength(2); }); it('dispatches ApplyLabelEditOperation when `text` is supplied and the new element has a label', async () => { @@ -163,9 +163,9 @@ describe('CreateNodesMcpToolHandler', () => { }); const edits = dispatcher.dispatched.filter(ApplyLabelEditOperation.is); - expect(edits).to.have.lengthOf(1); - expect(edits[0].text).to.equal('Hello'); - expect(edits[0].labelId).to.equal('task:manual#1_label'); + expect(edits).toHaveLength(1); + expect(edits[0].text).toBe('Hello'); + expect(edits[0].labelId).toBe('task:manual#1_label'); }); it('emits a warning (no ApplyLabelEditOperation) when `text` is supplied but the element type has no label', async () => { @@ -177,9 +177,9 @@ describe('CreateNodesMcpToolHandler', () => { }); const structured = result.structuredContent as unknown as CreatedElementsStructured; - expect(structured.warnings).to.have.lengthOf(1); - expect(structured.warnings[0]).to.match(/no editable label/i); - expect(dispatcher.dispatched.filter(ApplyLabelEditOperation.is)).to.have.lengthOf(0); + expect(structured.warnings).toHaveLength(1); + expect(structured.warnings[0]).toMatch(/no editable label/i); + expect(dispatcher.dispatched.filter(ApplyLabelEditOperation.is)).toHaveLength(0); }); it('records an error and skips label-edit when the CreateNodeOperation produces no new element', async () => { @@ -191,9 +191,9 @@ describe('CreateNodesMcpToolHandler', () => { }); const structured = result.structuredContent as unknown as CreatedElementsStructured; - expect(structured.createdNodes).to.deep.equal([]); - expect(structured.errors).to.have.lengthOf(1); - expect(structured.errors[0]).to.include('ghost'); - expect(dispatcher.dispatched.filter(ApplyLabelEditOperation.is)).to.have.lengthOf(0); + expect(structured.createdNodes).toEqual([]); + expect(structured.errors).toHaveLength(1); + expect(structured.errors[0]).toContain('ghost'); + expect(dispatcher.dispatched.filter(ApplyLabelEditOperation.is)).toHaveLength(0); }); }); diff --git a/packages/server-mcp/src/common/tools/handlers/query-elements-mcp-tool-handler.spec.ts b/packages/server-mcp/src/common/tools/handlers/query-elements-mcp-tool-handler.spec.ts index 4d8ebc73..26dd6356 100644 --- a/packages/server-mcp/src/common/tools/handlers/query-elements-mcp-tool-handler.spec.ts +++ b/packages/server-mcp/src/common/tools/handlers/query-elements-mcp-tool-handler.spec.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { ClientId, GLabel, GModelElement, Logger, ModelState, NullLogger } from '@eclipse-glsp/server'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import { McpModelSerializer } from '../../resources/services/mcp-model-serializer'; import { McpElementsNotFoundError, McpToolResult } from '../../server/mcp-handler-shared'; @@ -110,9 +110,9 @@ describe('QueryElementsMcpToolHandler', () => { const result = await callCreateResult(handler, { sessionId: 's', types: ['task:manual'] }); const structured = result.structuredContent as unknown as ListStructured; - expect(structured.mode).to.equal('list'); - expect(structured.matches).to.have.lengthOf(1); - expect(structured.matches[0].id).to.equal('n1'); + expect(structured.mode).toBe('list'); + expect(structured.matches).toHaveLength(1); + expect(structured.matches[0].id).toBe('n1'); }); it('matches `labelMatch` case-insensitively against direct GLabel children', async () => { @@ -124,7 +124,7 @@ describe('QueryElementsMcpToolHandler', () => { const result = await callCreateResult(handler, { sessionId: 's', labelMatch: 'ARTIFACT' }); const ids = (result.structuredContent as unknown as ListStructured).matches.map(m => m.id); - expect(ids).to.have.members(['n1', 'n2']); + expect([...ids].sort()).toEqual(['n1', 'n2'].sort()); }); it('combines `types` and `labelMatch` as AND', async () => { @@ -139,8 +139,8 @@ describe('QueryElementsMcpToolHandler', () => { labelMatch: 'build' }); const matches = (result.structuredContent as unknown as ListStructured).matches; - expect(matches).to.have.lengthOf(1); - expect(matches[0].id).to.equal('n1'); + expect(matches).toHaveLength(1); + expect(matches[0].id).toBe('n1'); }); it('caps results at `limit` and reports `truncated: true`', async () => { @@ -149,8 +149,8 @@ describe('QueryElementsMcpToolHandler', () => { const result = await callCreateResult(handler, { sessionId: 's', limit: 3 }); const structured = result.structuredContent as unknown as ListStructured; - expect(structured.matches).to.have.lengthOf(3); - expect(structured.truncated).to.equal(true); + expect(structured.matches).toHaveLength(3); + expect(structured.truncated).toBe(true); }); it('surfaces a no-match message and empty matches when nothing matches', async () => { @@ -158,8 +158,8 @@ describe('QueryElementsMcpToolHandler', () => { const result = await callCreateResult(handler, { sessionId: 's', types: ['nonexistent'] }); const text = (result.content[0] as { text: string }).text; - expect(text).to.include('No elements matched'); - expect((result.structuredContent as unknown as ListStructured).matches).to.deep.equal([]); + expect(text).toContain('No elements matched'); + expect((result.structuredContent as unknown as ListStructured).matches).toEqual([]); }); }); @@ -175,12 +175,12 @@ describe('QueryElementsMcpToolHandler', () => { // GModelElement instances looked up from the model index — not just the ids. Inspect // mode also probes per-element to detect container expansion before rendering, so the // final array call is what produces the structuredContent — assert on that one. - expect(serializer.capturedArrays.length).to.be.greaterThan(0); + expect(serializer.capturedArrays.length).toBeGreaterThan(0); const finalCall = serializer.capturedArrays[serializer.capturedArrays.length - 1]; - expect(finalCall).to.deep.equal(elements); + expect(finalCall).toEqual(elements); const structured = result.structuredContent as unknown as InspectStructured; - expect(structured.mode).to.equal('inspect'); + expect(structured.mode).toBe('inspect'); }); it('throws McpElementsNotFoundError when an id is missing from the model', async () => { @@ -190,7 +190,7 @@ describe('QueryElementsMcpToolHandler', () => { await callCreateResult(handler, { sessionId: 's', elementIds: ['n1', 'unknown'] }); expect.fail('expected McpElementsNotFoundError'); } catch (err) { - expect(err).to.be.instanceOf(McpElementsNotFoundError); + expect(err).toBeInstanceOf(McpElementsNotFoundError); } }); @@ -205,8 +205,8 @@ describe('QueryElementsMcpToolHandler', () => { limit: 0 // intentionally would fail validation in list mode }); const structured = result.structuredContent as unknown as InspectStructured; - expect(structured.mode).to.equal('inspect'); - expect(structured.elements.map(e => e.id)).to.deep.equal(['n1']); + expect(structured.mode).toBe('inspect'); + expect(structured.elements.map(e => e.id)).toEqual(['n1']); }); }); }); diff --git a/packages/server-mcp/src/common/tools/handlers/session-info-mcp-tool-handler.spec.ts b/packages/server-mcp/src/common/tools/handlers/session-info-mcp-tool-handler.spec.ts index 29cd5390..82f5712b 100644 --- a/packages/server-mcp/src/common/tools/handlers/session-info-mcp-tool-handler.spec.ts +++ b/packages/server-mcp/src/common/tools/handlers/session-info-mcp-tool-handler.spec.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { ClientSession, ClientSessionManager, CommandStack, Logger, ModelState, NullLogger } from '@eclipse-glsp/server'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import { McpToolResult } from '../../server/mcp-handler-shared'; import { SessionInfoMcpToolHandler } from './session-info-mcp-tool-handler'; @@ -110,13 +110,13 @@ describe('SessionInfoMcpToolHandler', () => { const result = handler['createResult']({}); const text = asText(result); // Summary lists each session's id and diagram type — the load-bearing referenceable bits. - expect(text).to.include('session-alpha'); - expect(text).to.include('session-beta'); - expect(text).to.include('workflow-diagram'); - expect(text).to.include('state-diagram'); + expect(text).toContain('session-alpha'); + expect(text).toContain('session-beta'); + expect(text).toContain('workflow-diagram'); + expect(text).toContain('state-diagram'); // Full per-session detail goes via structuredContent. const sessions = (result.structuredContent as { sessions: SessionRow[] }).sessions; - expect(sessions.map(row => row.sessionId)).to.deep.equal(['session-alpha', 'session-beta']); + expect(sessions.map(row => row.sessionId)).toEqual(['session-alpha', 'session-beta']); }); it("passes through `sourceUri` and `readOnly` from each session container's ModelState via structuredContent", () => { @@ -124,12 +124,12 @@ describe('SessionInfoMcpToolHandler', () => { const result = handler['createResult']({}); const sessions = (result.structuredContent as { sessions: SessionRow[] }).sessions; - expect(sessions).to.have.lengthOf(1); - expect(sessions[0].sourceUri).to.equal('file:///only.wf'); - expect(sessions[0].readOnly).to.equal(true); - expect(sessions[0].dirty).to.equal(false); + expect(sessions).toHaveLength(1); + expect(sessions[0].sourceUri).toBe('file:///only.wf'); + expect(sessions[0].readOnly).toBe(true); + expect(sessions[0].dirty).toBe(false); // Read-only state is also surfaced in the text summary so content-only clients can see it. - expect(asText(result)).to.include('read-only'); + expect(asText(result)).toContain('read-only'); }); it('filters to a single session when `sessionId` matches', () => { @@ -140,13 +140,13 @@ describe('SessionInfoMcpToolHandler', () => { const text = asText(handler['createResult']({ sessionId: 'session-beta' })); - expect(text).to.include('session-beta'); - expect(text).to.not.include('session-alpha'); + expect(text).toContain('session-beta'); + expect(text).not.toContain('session-alpha'); }); it('throws McpToolError when the requested `sessionId` does not exist', () => { const handler = buildHandler([makeSession('session-alpha', 'workflow-diagram', 'file:///alpha.wf', false)]); - expect(() => handler['createResult']({ sessionId: 'unknown' })).to.throw(/Unknown sessionId: unknown/); + expect(() => handler['createResult']({ sessionId: 'unknown' })).toThrow(/Unknown sessionId: unknown/); }); }); diff --git a/packages/server-mcp/src/common/tools/handlers/set-selection-mcp-tool-handler.spec.ts b/packages/server-mcp/src/common/tools/handlers/set-selection-mcp-tool-handler.spec.ts index b4f58b9e..3b9e0360 100644 --- a/packages/server-mcp/src/common/tools/handlers/set-selection-mcp-tool-handler.spec.ts +++ b/packages/server-mcp/src/common/tools/handlers/set-selection-mcp-tool-handler.spec.ts @@ -25,7 +25,7 @@ import { SelectAction, SelectAllAction } from '@eclipse-glsp/server'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import { McpElementsNotFoundError, McpToolResult } from '../../server/mcp-handler-shared'; import { McpIdAliasService } from '../../server/mcp-id-alias-service'; @@ -87,10 +87,10 @@ describe('SetSelectionMcpToolHandler', () => { await callCreateResult(handler, { sessionId: 's', selectedElementIds: ['n1'], clear: true }); - expect(dispatched).to.have.lengthOf(2); - expect(SelectAllAction.is(dispatched[0])).to.equal(true); - expect((dispatched[0] as SelectAllAction).select).to.equal(false); - expect(SelectAction.is(dispatched[1])).to.equal(true); + expect(dispatched).toHaveLength(2); + expect(SelectAllAction.is(dispatched[0])).toBe(true); + expect((dispatched[0] as SelectAllAction).select).toBe(false); + expect(SelectAction.is(dispatched[1])).toBe(true); }); it('dispatches SelectAction with resolved selected and deselected ids', async () => { @@ -99,10 +99,10 @@ describe('SetSelectionMcpToolHandler', () => { await callCreateResult(handler, { sessionId: 's', selectedElementIds: ['a', 'b'], deselectedElementIds: ['c'] }); - expect(dispatched).to.have.lengthOf(1); + expect(dispatched).toHaveLength(1); const action = dispatched[0] as SelectAction; - expect(action.selectedElementsIDs).to.deep.equal(['a', 'b']); - expect(action.deselectedElementsIDs).to.deep.equal(['c']); + expect(action.selectedElementsIDs).toEqual(['a', 'b']); + expect(action.deselectedElementsIDs).toEqual(['c']); }); it('throws McpElementsNotFoundError when an id is missing from the model', async () => { @@ -115,6 +115,6 @@ describe('SetSelectionMcpToolHandler', () => { } catch (err: unknown) { error = err; } - expect(error).to.be.instanceOf(McpElementsNotFoundError); + expect(error).toBeInstanceOf(McpElementsNotFoundError); }); }); diff --git a/packages/server-mcp/src/common/tools/tool-annotations.spec.ts b/packages/server-mcp/src/common/tools/tool-annotations.spec.ts index 736b650e..24e1373d 100644 --- a/packages/server-mcp/src/common/tools/tool-annotations.spec.ts +++ b/packages/server-mcp/src/common/tools/tool-annotations.spec.ts @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { interfaces } from 'inversify'; import { SetViewMcpToolHandler } from './handlers/set-view-mcp-tool-handler'; import { CreateEdgesMcpToolHandler } from './handlers/create-edges-mcp-tool-handler'; @@ -75,7 +75,7 @@ describe('Tool annotations · per-handler matrix', () => { ]; readStyleHandlers.forEach(([name, Constructor]) => { it(`${name} matches the read-style default`, () => { - expect(hintsOf(Constructor)).to.deep.equal(READ_DEFAULT); + expect(hintsOf(Constructor)).toEqual(READ_DEFAULT); }); }); }); @@ -91,14 +91,14 @@ describe('Tool annotations · per-handler matrix', () => { ]; operationStyleHandlers.forEach(([name, Constructor]) => { it(`${name} matches the operation-style default`, () => { - expect(hintsOf(Constructor)).to.deep.equal(OPERATION_DEFAULT); + expect(hintsOf(Constructor)).toEqual(OPERATION_DEFAULT); }); }); }); describe('per-handler overrides', () => { it('delete-elements is destructiveHint:true (single-flag override)', () => { - expect(hintsOf(DeleteElementsMcpToolHandler)).to.deep.equal({ ...OPERATION_DEFAULT, destructiveHint: true }); + expect(hintsOf(DeleteElementsMcpToolHandler)).toEqual({ ...OPERATION_DEFAULT, destructiveHint: true }); }); it('save-model is NOT readOnly (writes to disk) and NOT destructive (creative)', () => { @@ -106,7 +106,7 @@ describe('Tool annotations · per-handler matrix', () => { // `destructiveHint` is for irreversible deletion / data loss; save is creative. // Save-model extends the read base (not the operation base) because it doesn't // dispatch a model-mutating Operation, but we override the flat fields explicitly. - expect(hintsOf(SaveModelMcpToolHandler)).to.deep.equal({ + expect(hintsOf(SaveModelMcpToolHandler)).toEqual({ readOnlyHint: false, destructiveHint: false, idempotentHint: false, @@ -118,7 +118,7 @@ describe('Tool annotations · per-handler matrix', () => { // Inherits from the read base, which would claim readOnlyHint:true. Override flips // it: dispatching a viewport action mutates client-side state, even though no // diagram model bytes change. - expect(hintsOf(SetViewMcpToolHandler)).to.deep.equal({ + expect(hintsOf(SetViewMcpToolHandler)).toEqual({ readOnlyHint: false, destructiveHint: undefined, idempotentHint: undefined, @@ -130,7 +130,7 @@ describe('Tool annotations · per-handler matrix', () => { describe('toRegistrationConfig() assembles the annotations object the SDK expects', () => { it('aggregates the flat fields into the SDK ToolAnnotations shape', () => { const config = new DeleteElementsMcpToolHandler().toRegistrationConfig(); - expect(config.annotations).to.deep.equal({ + expect(config.annotations).toEqual({ readOnlyHint: false, destructiveHint: true, idempotentHint: false, diff --git a/packages/server-mcp/src/node/server/mcp-http-transport-e2e.spec.ts b/packages/server-mcp/src/node/server/mcp-http-transport-e2e.spec.ts index 18cfe6b3..220c52fb 100644 --- a/packages/server-mcp/src/node/server/mcp-http-transport-e2e.spec.ts +++ b/packages/server-mcp/src/node/server/mcp-http-transport-e2e.spec.ts @@ -17,7 +17,7 @@ import { ClientSessionManager, InitializeParameters, InitializeResult, Logger, NullLogger } from '@eclipse-glsp/server'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; -import { expect } from 'chai'; +import { afterEach, describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import * as z from 'zod/v4'; import { FullMcpServerConfiguration } from '../../common/server/abstract-mcp-server-launcher'; @@ -26,7 +26,7 @@ import { McpDiagramHandlerDispatcher } from '../../common/server/mcp-diagram-han import { DefaultMcpLogLevelRegistry, McpLogLevelRegistry } from '../../common/server/mcp-log-level-registry'; import { McpServerDefaults, McpServerOptions } from '../../common/server/mcp-options'; import { NodeMcpServerLauncher } from './node-mcp-server-launcher'; -import { rawHttpRequest } from './raw-http.spec'; +import { rawHttpRequest } from './test/raw-http'; class StubDispatcher implements McpDiagramHandlerDispatcher { harvest(): void { @@ -160,20 +160,20 @@ describe('NodeMcpServerLauncher (e2e — real MCP SDK client over HTTP)', () => it('round-trips tools/list and tools/call against a registered echo tool', async () => { launcher = buildLauncher(); const url = await startLauncher(launcher); - expect(url, 'launcher must announce a URL after initializeServer').to.be.a('string'); + expect(url, 'launcher must announce a URL after initializeServer').toBeTypeOf('string'); client = new Client({ name: 'wn-058-test-client', version: '1.0.0' }); await client.connect(new StreamableHTTPClientTransport(new URL(url))); const tools = await client.listTools(); - expect(tools.tools.map(tool => tool.name)).to.include('echo'); + expect(tools.tools.map(tool => tool.name)).toContain('echo'); const result = await client.callTool({ name: 'echo', arguments: { message: 'hello GLSP' } }); - expect(result.isError).to.not.equal(true); - expect(result.content).to.have.lengthOf(1); + expect(result.isError).not.toBe(true); + expect(result.content).toHaveLength(1); const [block] = result.content as Array<{ type: string; text?: string }>; - expect(block.type).to.equal('text'); - expect(block.text).to.equal('hello GLSP'); + expect(block.type).toBe('text'); + expect(block.text).toBe('hello GLSP'); }); it('DELETE /mcp terminates the session; subsequent POSTs with the same id return 404 (§ #5)', async () => { @@ -184,12 +184,12 @@ describe('NodeMcpServerLauncher (e2e — real MCP SDK client over HTTP)', () => const clientTransport = new StreamableHTTPClientTransport(new URL(url)); await client.connect(clientTransport); const sessionId = clientTransport.sessionId; - expect(sessionId, 'SDK transport should expose the minted session id after initialize').to.be.a('string'); + expect(sessionId, 'SDK transport should expose the minted session id after initialize').toBeTypeOf('string'); const port = Number(new URL(url).port); const deleteRes = await rawHttpRequest(port, 'DELETE', { 'mcp-session-id': sessionId! }); - expect(deleteRes.status, 'DELETE should succeed for an active session').to.be.lessThan(300); + expect(deleteRes.status, 'DELETE should succeed for an active session').toBeLessThan(300); const followUp = await rawHttpRequest( port, @@ -197,9 +197,9 @@ describe('NodeMcpServerLauncher (e2e — real MCP SDK client over HTTP)', () => { 'mcp-session-id': sessionId! }, { jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} } ); - expect(followUp.status).to.equal(404); + expect(followUp.status).toBe(404); const payload = JSON.parse(followUp.body); - expect(payload.error.code).to.equal(-32001); + expect(payload.error.code).toBe(-32001); }); }); @@ -220,16 +220,16 @@ describe('NodeMcpServerLauncher (raw HTTP wire validation)', () => { it('binds an HTTP listener on a resolvable loopback port', async () => { launcher = buildLauncher(); const url = await startLauncher(launcher); - expect(url).to.match(/^http:\/\/(127\.0\.0\.1|localhost):\d+\/mcp$/); + expect(url).toMatch(/^http:\/\/(127\.0\.0\.1|localhost):\d+\/mcp$/); }); it('rejects a non-initialize POST without an Mcp-Session-Id header with 400 (§ #2)', async () => { const port = await startWith({}); const res = await rawHttpRequest(port, 'POST', {}, { jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} }); - expect(res.status).to.equal(400); + expect(res.status).toBe(400); const payload = JSON.parse(res.body); - expect(payload.error.code).to.equal(-32000); - expect(payload.error.message).to.match(/No valid session ID/); + expect(payload.error.code).toBe(-32000); + expect(payload.error.message).toMatch(/No valid session ID/); }); it('rejects a POST with an unknown Mcp-Session-Id with 404 (§ #3)', async () => { @@ -240,9 +240,9 @@ describe('NodeMcpServerLauncher (raw HTTP wire validation)', () => { { 'mcp-session-id': 'no-such-session' }, { jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} } ); - expect(res.status).to.equal(404); + expect(res.status).toBe(404); const payload = JSON.parse(res.body); - expect(payload.error.code).to.equal(-32001); + expect(payload.error.code).toBe(-32001); }); it('rejects a non-initialize POST whose MCP-Protocol-Version is unsupported with HTTP 400', async () => { @@ -253,9 +253,9 @@ describe('NodeMcpServerLauncher (raw HTTP wire validation)', () => { { 'mcp-session-id': 'doesnt-matter', 'mcp-protocol-version': '1999-01-01' }, { jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} } ); - expect(res.status).to.equal(400); + expect(res.status).toBe(400); const payload = JSON.parse(res.body); - expect(payload.error.message).to.match(/Unsupported MCP-Protocol-Version/); + expect(payload.error.message).toMatch(/Unsupported MCP-Protocol-Version/); }); it('rejects requests with a Host header outside the allowlist', async () => { @@ -272,7 +272,7 @@ describe('NodeMcpServerLauncher (raw HTTP wire validation)', () => { params: { protocolVersion: '2025-06-18', capabilities: {}, clientInfo: { name: 'x', version: '1' } } } ); - expect(res.status).to.equal(403); + expect(res.status).toBe(403); }); it('rejects start when the requested port is already in use with an actionable error', async () => { @@ -289,9 +289,9 @@ describe('NodeMcpServerLauncher (raw HTTP wire validation)', () => { firstLauncher.dispose(); secondLauncher.dispose(); } - expect(error, 'expected initializeServer to reject').to.not.equal(undefined); - expect(error!.message).to.match(/127\.0\.0\.1:\d+/); - expect(error!.message).to.include('mcpServer.port'); - expect(error!.message).to.match(/already in use/); + expect(error, 'expected initializeServer to reject').not.toBe(undefined); + expect(error!.message).toMatch(/127\.0\.0\.1:\d+/); + expect(error!.message).toContain('mcpServer.port'); + expect(error!.message).toMatch(/already in use/); }); }); diff --git a/packages/server-mcp/src/node/server/node-mcp-server-launcher.spec.ts b/packages/server-mcp/src/node/server/node-mcp-server-launcher.spec.ts index 6257fe2f..55075b78 100644 --- a/packages/server-mcp/src/node/server/node-mcp-server-launcher.spec.ts +++ b/packages/server-mcp/src/node/server/node-mcp-server-launcher.spec.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { McpServerInitOptions } from '@eclipse-glsp/server'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { version as packageVersion } from '../../../package.json'; import { SERVER_VERSION, pickInitOptions } from '../../common/server/abstract-mcp-server-launcher'; import { NodeMcpServerLauncher, assertLoopbackOrAcknowledged, isLoopbackHost } from './node-mcp-server-launcher'; @@ -25,7 +25,7 @@ describe('NodeMcpServerLauncher · SERVER_VERSION', () => { // Regression guard: the launcher used to hard-code '1.0.0'. Pull from package.json so // adopters and MCP clients can tell builds apart via the `serverInfo.version` handshake // field. - expect(SERVER_VERSION).to.equal(packageVersion); + expect(SERVER_VERSION).toBe(packageVersion); }); }); @@ -63,80 +63,79 @@ describe('NodeMcpServerLauncher · buildCapabilities', () => { it('omits `tools`, `resources`, and `prompts` when nothing is bound (regression: resources/list -32601)', () => { const caps = buildCaps({}, /* resourcesAsResources */ true); - expect(caps).to.have.property('logging'); - expect(caps).to.not.have.property('tools'); - expect(caps).to.not.have.property('resources'); - expect(caps).to.not.have.property('prompts'); + expect(caps).toHaveProperty('logging'); + expect(caps).not.toHaveProperty('tools'); + expect(caps).not.toHaveProperty('resources'); + expect(caps).not.toHaveProperty('prompts'); }); it('declares `tools` with listChanged: false when at least one tool handler binds', () => { const caps = buildCaps({ toolHandlers: [{}] }, true); - expect(caps.tools).to.deep.equal({ listChanged: false }); - expect(caps).to.not.have.property('resources'); - expect(caps).to.not.have.property('prompts'); + expect(caps.tools).toEqual({ listChanged: false }); + expect(caps).not.toHaveProperty('resources'); + expect(caps).not.toHaveProperty('prompts'); }); it('declares `prompts` when at least one prompt handler binds (server- or diagram-scope)', () => { - expect(buildCaps({ promptHandlers: [{}] }, true).prompts).to.deep.equal({ listChanged: false }); - expect(buildCaps({ hasDiagramPrompts: true }, true).prompts).to.deep.equal({ listChanged: false }); + expect(buildCaps({ promptHandlers: [{}] }, true).prompts).toEqual({ listChanged: false }); + expect(buildCaps({ hasDiagramPrompts: true }, true).prompts).toEqual({ listChanged: false }); }); it('declares `resources` only in dataMode=resources; otherwise resources count toward `tools`', () => { // Diagram-scope resources mutate per GLSP session add/remove → `listChanged: true` is honest. const asResources = buildCaps({ hasDiagramResources: true }, true); - expect(asResources.resources).to.deep.equal({ listChanged: true }); - expect(asResources).to.not.have.property('tools'); + expect(asResources.resources).toEqual({ listChanged: true }); + expect(asResources).not.toHaveProperty('tools'); const asTools = buildCaps({ hasDiagramResources: true }, false); - expect(asTools.tools).to.deep.equal({ listChanged: false }); - expect(asTools).to.not.have.property('resources'); + expect(asTools.tools).toEqual({ listChanged: false }); + expect(asTools).not.toHaveProperty('resources'); }); it('keeps resources.listChanged: false when only server-scope resources are bound (catalog static)', () => { const caps = buildCaps({ resourceHandlers: [{}] }, true); - expect(caps.resources).to.deep.equal({ listChanged: false }); + expect(caps.resources).toEqual({ listChanged: false }); }); }); describe('NodeMcpServerLauncher · isLoopbackHost', () => { it('treats 127.0.0.0/8, localhost, and ::1 as loopback', () => { - expect(isLoopbackHost('127.0.0.1')).to.equal(true); - expect(isLoopbackHost('127.55.0.1')).to.equal(true); - expect(isLoopbackHost('localhost')).to.equal(true); - expect(isLoopbackHost('::1')).to.equal(true); + expect(isLoopbackHost('127.0.0.1')).toBe(true); + expect(isLoopbackHost('127.55.0.1')).toBe(true); + expect(isLoopbackHost('localhost')).toBe(true); + expect(isLoopbackHost('::1')).toBe(true); }); it('treats unspecified, LAN, and public addresses as non-loopback', () => { - expect(isLoopbackHost('0.0.0.0')).to.equal(false); - expect(isLoopbackHost('::')).to.equal(false); - expect(isLoopbackHost('192.168.1.1')).to.equal(false); - expect(isLoopbackHost('10.0.0.1')).to.equal(false); - expect(isLoopbackHost('203.0.113.5')).to.equal(false); + expect(isLoopbackHost('0.0.0.0')).toBe(false); + expect(isLoopbackHost('::')).toBe(false); + expect(isLoopbackHost('192.168.1.1')).toBe(false); + expect(isLoopbackHost('10.0.0.1')).toBe(false); + expect(isLoopbackHost('203.0.113.5')).toBe(false); }); }); describe('NodeMcpServerLauncher · assertLoopbackOrAcknowledged (auth footgun)', () => { it('passes silently for a loopback bind without acknowledgement', () => { - expect(() => assertLoopbackOrAcknowledged('127.0.0.1', undefined)).to.not.throw(); - expect(() => assertLoopbackOrAcknowledged('localhost', undefined)).to.not.throw(); + expect(() => assertLoopbackOrAcknowledged('127.0.0.1', undefined)).not.toThrow(); + expect(() => assertLoopbackOrAcknowledged('localhost', undefined)).not.toThrow(); }); it('throws an actionable error for a non-loopback bind without acknowledgement', () => { - expect(() => assertLoopbackOrAcknowledged('0.0.0.0', undefined)) - .to.throw(Error) - .with.property('message') - .that.matches(/Refusing to bind/) - .and.matches(/0\.0\.0\.0/) - .and.matches(/acknowledgedNoAuth/); + const act = (): void => assertLoopbackOrAcknowledged('0.0.0.0', undefined); + expect(act).toThrow(Error); + expect(act).toThrow(/Refusing to bind/); + expect(act).toThrow(/0\.0\.0\.0/); + expect(act).toThrow(/acknowledgedNoAuth/); }); it('passes for a non-loopback bind when acknowledgedNoAuth is true', () => { - expect(() => assertLoopbackOrAcknowledged('0.0.0.0', true)).to.not.throw(); - expect(() => assertLoopbackOrAcknowledged('192.168.1.50', true)).to.not.throw(); + expect(() => assertLoopbackOrAcknowledged('0.0.0.0', true)).not.toThrow(); + expect(() => assertLoopbackOrAcknowledged('192.168.1.50', true)).not.toThrow(); }); it('still throws for a non-loopback bind when acknowledgedNoAuth is false (explicit denial)', () => { - expect(() => assertLoopbackOrAcknowledged('0.0.0.0', false)).to.throw(/Refusing to bind/); + expect(() => assertLoopbackOrAcknowledged('0.0.0.0', false)).toThrow(/Refusing to bind/); }); }); @@ -153,14 +152,14 @@ assertPickInitKeysExhaustive(true); describe('NodeMcpServerLauncher · pickInitOptions (deploy/init split — defense-in-depth)', () => { it('passes through every allowed init-side field unchanged', () => { const picked = pickInitOptions({ dataMode: 'resources', agentPersona: 'X', eventStoreLimit: 50 }); - expect(picked).to.deep.equal({ dataMode: 'resources', agentPersona: 'X', eventStoreLimit: 50 }); + expect(picked).toEqual({ dataMode: 'resources', agentPersona: 'X', eventStoreLimit: 50 }); }); it('omits init-side fields that the caller did not set (no `undefined` sneak-through)', () => { const picked = pickInitOptions({ dataMode: 'tools' }); - expect(picked).to.deep.equal({ dataMode: 'tools' }); - expect(picked).to.not.have.property('agentPersona'); - expect(picked).to.not.have.property('eventStoreLimit'); + expect(picked).toEqual({ dataMode: 'tools' }); + expect(picked).not.toHaveProperty('agentPersona'); + expect(picked).not.toHaveProperty('eventStoreLimit'); }); it('strips deploy-only keys smuggled in via JSON wire payload (host, allowedHosts, allowedOrigins, acknowledgedNoAuth)', () => { @@ -175,10 +174,10 @@ describe('NodeMcpServerLauncher · pickInitOptions (deploy/init split — defens }`) as McpServerInitOptions; const picked = pickInitOptions(wirePayload); - expect(picked).to.deep.equal({ dataMode: 'tools' }); - expect(picked).to.not.have.property('host'); - expect(picked).to.not.have.property('allowedHosts'); - expect(picked).to.not.have.property('allowedOrigins'); - expect(picked).to.not.have.property('acknowledgedNoAuth'); + expect(picked).toEqual({ dataMode: 'tools' }); + expect(picked).not.toHaveProperty('host'); + expect(picked).not.toHaveProperty('allowedHosts'); + expect(picked).not.toHaveProperty('allowedOrigins'); + expect(picked).not.toHaveProperty('acknowledgedNoAuth'); }); }); diff --git a/packages/server-mcp/src/node/server/raw-http.spec.ts b/packages/server-mcp/src/node/server/test/raw-http.ts similarity index 100% rename from packages/server-mcp/src/node/server/raw-http.spec.ts rename to packages/server-mcp/src/node/server/test/raw-http.ts diff --git a/packages/server-mcp/tsconfig.json b/packages/server-mcp/tsconfig.json index 3abf4d60..bc485f10 100644 --- a/packages/server-mcp/tsconfig.json +++ b/packages/server-mcp/tsconfig.json @@ -1,11 +1,11 @@ { - "extends": "@eclipse-glsp/ts-config/mocha", + "extends": "@eclipse-glsp/ts-config", "compilerOptions": { "rootDir": "src", "outDir": "lib", "composite": true }, - "exclude": ["**/*.spec.ts"], + "exclude": ["**/*.spec.ts", "**/test/**"], "include": ["src"], "references": [ { diff --git a/packages/server-mcp/tsconfig.test.json b/packages/server-mcp/tsconfig.test.json new file mode 100644 index 00000000..19a4102a --- /dev/null +++ b/packages/server-mcp/tsconfig.test.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "composite": true, + "noEmit": true + }, + "include": ["src/**/*.spec.ts", "src/**/*.spec.tsx", "src/**/test/**/*"], + "exclude": ["lib", "node_modules"], + "references": [{ "path": "./tsconfig.json" }] +} diff --git a/packages/server/package.json b/packages/server/package.json index d4535abd..b73834ce 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,17 +45,17 @@ "browser.d.ts", "browser.js", "common.d.ts", - "common.js" + "common.js", + "!**/*.spec.ts", + "!**/*.spec.tsx", + "!**/test/**" ], "scripts": { "build": "tsc -b", - "clean": "rimraf lib *.tsbuildinfo coverage .nyc_output", + "clean": "rimraf lib *.tsbuildinfo coverage", "generate:index": "glsp generateIndex src/browser src/common src/node -s -f", "lint": "eslint ./src", - "prepublishOnly": "pnpm build", - "test": "mocha --config ../../.mocharc \"./src/**/*.spec.?(ts|tsx)\"", - "test:ci": "pnpm test --reporter mocha-ctrf-json-reporter", - "test:coverage": "nyc pnpm test:ci" + "prepublishOnly": "pnpm build" }, "dependencies": { "@eclipse-glsp/graph": "workspace:*", diff --git a/packages/server/src/browser/di/browser-action-dispatch-scope.spec.ts b/packages/server/src/browser/di/browser-action-dispatch-scope.spec.ts index b9104969..32dc6f9a 100644 --- a/packages/server/src/browser/di/browser-action-dispatch-scope.spec.ts +++ b/packages/server/src/browser/di/browser-action-dispatch-scope.spec.ts @@ -14,9 +14,8 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ import { Action } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; +import { beforeEach, describe, expect, it } from 'vitest'; import { ClientAction } from '../../common/protocol/client-action'; -import * as mock from '../../common/test/mock-util'; import { BrowserActionDispatchScope } from './browser-action-dispatch-scope'; describe('BrowserActionDispatchScope', () => { @@ -33,14 +32,14 @@ describe('BrowserActionDispatchScope', () => { }); it('isReentrant is false outside enter()', () => { - expect(scope.isReentrant(action)).to.be.false; + expect(scope.isReentrant(action)).toBe(false); }); it('isReentrant is true during a synchronous enter()', () => { scope.enter(() => { - expect(scope.isReentrant(action)).to.be.true; + expect(scope.isReentrant(action)).toBe(true); }); - expect(scope.isReentrant(action)).to.be.false; + expect(scope.isReentrant(action)).toBe(false); }); it('isReentrant is true during an async enter() and false after settle', async () => { @@ -48,8 +47,8 @@ describe('BrowserActionDispatchScope', () => { await Promise.resolve(); return scope.isReentrant(action); }); - expect(await probe).to.be.true; - expect(scope.isReentrant(action)).to.be.false; + expect(await probe).toBe(true); + expect(scope.isReentrant(action)).toBe(false); }); it('resets active flag when callback throws synchronously', () => { @@ -57,19 +56,19 @@ describe('BrowserActionDispatchScope', () => { scope.enter(() => { throw new Error('boom'); }) - ).to.throw('boom'); - expect(scope.isReentrant(action)).to.be.false; + ).toThrow('boom'); + expect(scope.isReentrant(action)).toBe(false); }); it('resets active flag when async callback rejects', async () => { - await mock.expectToThrowAsync(() => scope.enter(() => Promise.reject(new Error('boom'))), 'boom'); - expect(scope.isReentrant(action)).to.be.false; + await expect(scope.enter(() => Promise.reject(new Error('boom')))).rejects.toThrow('boom'); + expect(scope.isReentrant(action)).toBe(false); }); it('isReentrant is false for client-originated actions even when scope is active', () => { scope.enter(() => { - expect(scope.isReentrant(markedClientAction)).to.be.false; - expect(scope.isReentrant(action)).to.be.true; + expect(scope.isReentrant(markedClientAction)).toBe(false); + expect(scope.isReentrant(action)).toBe(true); }); }); }); diff --git a/packages/server/src/common/actions/action-handler-registry.spec.ts b/packages/server/src/common/actions/action-handler-registry.spec.ts index b7a9d58c..14cc733c 100644 --- a/packages/server/src/common/actions/action-handler-registry.spec.ts +++ b/packages/server/src/common/actions/action-handler-registry.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,7 +15,7 @@ ********************************************************************************/ import * as mock from '../test/mock-util'; import { ActionHandlerRegistry } from './action-handler-registry'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; describe('Test ActionHandlerRegistry (only functionality that is not covered by "registry.spec.ts"', () => { const singleAction = 'singleHandledAction'; @@ -35,7 +35,7 @@ describe('Test ActionHandlerRegistry (only functionality that is not covered by registry.registerHandler(h4); const result = registry.getAll(); - expect(result).to.have.length(4); + expect(result).toHaveLength(4); expect(result.includes(h1)).true; expect(result.includes(h2)).true; expect(result.includes(h3)).true; @@ -44,9 +44,9 @@ describe('Test ActionHandlerRegistry (only functionality that is not covered by it('get - should return three handlers sorted by priority', () => { const result = registry.get(multiAction); - expect(result.length).to.be.equal(3); - expect(result[0]).to.be.deep.equal(h4); - expect(result[1]).to.be.deep.equal(h2); - expect(result[2]).to.be.deep.equal(h3); + expect(result.length).toBe(3); + expect(result[0]).toEqual(h4); + expect(result[1]).toEqual(h2); + expect(result[2]).toEqual(h3); }); }); diff --git a/packages/server/src/common/actions/global-action-provider.spec.ts b/packages/server/src/common/actions/global-action-provider.spec.ts index 061d0c26..300330c7 100644 --- a/packages/server/src/common/actions/global-action-provider.spec.ts +++ b/packages/server/src/common/actions/global-action-provider.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,9 +13,8 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { describe, expect, it, vi } from 'vitest'; import { Container, ContainerModule } from 'inversify'; -import * as sinon from 'sinon'; import { DiagramModules, InjectionContainer } from '../di/service-identifiers'; import { ClientSessionInitializer } from '../session/client-session-initializer'; import * as mock from '../test/mock-util'; @@ -36,7 +35,7 @@ describe('test DefaultGlobalActionProvider', () => { const h2 = new mock.StubActionHandler(handler2Actions); const handlerRegistry = new ActionHandlerRegistry(); - sinon.stub(handlerRegistry, 'getAll').returns([h1, h2]); + vi.spyOn(handlerRegistry, 'getAll').mockReturnValue([h1, h2]); const diagramModule1 = new ContainerModule(bind => { bind(ClientSessionInitializer).toConstantValue(new mock.StubClientSessionInitializer()); @@ -60,9 +59,9 @@ describe('test DefaultGlobalActionProvider', () => { it('serverActionsKinds', () => { const result = actionProvider.actionKinds; - expect(result.size).to.be.equal(1); + expect(result.size).toBe(1); const resultServerActions = result.get(diagramType); - expect(resultServerActions).to.not.be.undefined; + expect(resultServerActions).toBeDefined(); expect(serverActions.every(action => resultServerActions!.includes(action))).true; }); }); diff --git a/packages/server/src/common/command/command-stack.spec.ts b/packages/server/src/common/command/command-stack.spec.ts index 366a4c17..92e496bc 100644 --- a/packages/server/src/common/command/command-stack.spec.ts +++ b/packages/server/src/common/command/command-stack.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2023 EclipseSource and others. + * Copyright (c) 2023-2026 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,194 +13,213 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest'; import { Container, ContainerModule } from 'inversify'; -import * as sinon from 'sinon'; -import { expectToThrowAsync, StubCommand, StubLogger } from '../test/mock-util'; +import { StubLogger } from '../test/mock-util'; +import { Command } from '../command/command'; import { Logger } from '../utils/logger'; import { DefaultCommandStack } from './command-stack'; +function makeStubCommand(): Command & { + execute: Mock; + undo: Mock; + redo: Mock; + canUndo: Mock>; +} { + return { + execute: vi.fn(), + undo: vi.fn(), + redo: vi.fn(), + canUndo: vi.fn>() + }; +} + describe('test DefaultCommandStack', () => { - const sandbox = sinon.createSandbox(); const container = new Container(); - const command1 = sandbox.stub(new StubCommand()); - const command2 = sandbox.stub(new StubCommand()); - let commandStack: DefaultCommandStack; - container.load( new ContainerModule(bind => { bind(Logger).toConstantValue(new StubLogger()); }) ); - commandStack = container.resolve(DefaultCommandStack); - afterEach(() => { - sandbox.reset(); + let command1: ReturnType; + let command2: ReturnType; + let commandStack: DefaultCommandStack; + + beforeEach(() => { + command1 = makeStubCommand(); + command2 = makeStubCommand(); commandStack = container.resolve(DefaultCommandStack); }); describe('execute', () => { it('should execute the given command and become dirty', async () => { - expect(commandStack.isDirty).to.be.false; + expect(commandStack.isDirty).toBe(false); await commandStack.execute(command1); - expect(command1.execute.calledOnce).to.be.true; - expect(commandStack.isDirty).to.be.true; + expect(command1.execute).toHaveBeenCalledOnce(); + expect(commandStack.isDirty).toBe(true); }); it('should execute the given commands in order and become dirty', async () => { - expect(commandStack.isDirty).to.be.false; + expect(commandStack.isDirty).toBe(false); await commandStack.execute(command1); await commandStack.execute(command2); - expect(command1.execute.calledOnce).to.be.true; - expect(command2.execute.calledOnce).to.be.true; - expect(command2.execute.calledAfter(command1.execute)).to.be.true; - expect(commandStack.isDirty).to.be.true; + expect(command1.execute).toHaveBeenCalledOnce(); + expect(command2.execute).toHaveBeenCalledOnce(); + expect(command2.execute.mock.invocationCallOrder[0]).toBeGreaterThan(command1.execute.mock.invocationCallOrder[0]); + expect(commandStack.isDirty).toBe(true); }); it('should be able to undo after execute', async () => { - expect(commandStack.canUndo()).to.be.false; + expect(commandStack.canUndo()).toBe(false); await commandStack.execute(command1); - expect(commandStack.canUndo()).to.be.true; + expect(commandStack.canUndo()).toBe(true); }); it('should clear the redo stack after execution', async () => { commandStack['commands'].push(command2); commandStack['top'] = -1; - expect(commandStack.canRedo()).to.be.true; + expect(commandStack.canRedo()).toBe(true); await commandStack.execute(command1); - expect(commandStack.canRedo()).to.be.false; + expect(commandStack.canRedo()).toBe(false); }); it('should flush the stack in case of an execution error', async () => { - command2.execute.throwsException(); - const flushSpy = sandbox.spy(commandStack, 'flush'); - - await expectToThrowAsync(() => commandStack.execute(command2)); - expect(command2.execute.calledOnce).to.be.true; - expect(flushSpy.calledOnce).to.be.true; + command2.execute.mockImplementation(() => { + throw new Error('error'); + }); + const flushSpy = vi.spyOn(commandStack, 'flush'); + + await expect(commandStack.execute(command2)).rejects.toThrow(); + expect(command2.execute).toHaveBeenCalledOnce(); + expect(flushSpy).toHaveBeenCalledOnce(); }); }); describe('undo', () => { it('should do nothing if the command stack is empty', async () => { - expect(commandStack.isDirty).to.be.false; + expect(commandStack.isDirty).toBe(false); await commandStack.undo(); - expect(commandStack.canUndo()).to.be.false; - expect(commandStack.canRedo()).to.be.false; - expect(commandStack.isDirty).to.be.false; + expect(commandStack.canUndo()).toBe(false); + expect(commandStack.canRedo()).toBe(false); + expect(commandStack.isDirty).toBe(false); }); it('should undo the command and become non-dirty again', async () => { commandStack['commands'].push(command1); commandStack['top'] = 0; - expect(commandStack.isDirty).to.be.true; - expect(commandStack.canUndo()).to.be.true; - expect(commandStack.canRedo()).to.be.false; + expect(commandStack.isDirty).toBe(true); + expect(commandStack.canUndo()).toBe(true); + expect(commandStack.canRedo()).toBe(false); await commandStack.undo(); - expect(command1.undo.calledOnce).to.be.true; - expect(commandStack.isDirty).to.be.false; - expect(commandStack.canRedo()).to.be.true; - expect(commandStack.canUndo()).to.be.false; + expect(command1.undo).toHaveBeenCalledOnce(); + expect(commandStack.isDirty).toBe(false); + expect(commandStack.canRedo()).toBe(true); + expect(commandStack.canUndo()).toBe(false); }); it('should undo multiple command and become non-dirty again', async () => { commandStack['commands'].push(command1, command2); commandStack['top'] = 1; - expect(commandStack.isDirty).to.be.true; - expect(commandStack.canUndo()).to.be.true; - expect(commandStack.canRedo()).to.be.false; + expect(commandStack.isDirty).toBe(true); + expect(commandStack.canUndo()).toBe(true); + expect(commandStack.canRedo()).toBe(false); await commandStack.undo(); - expect(command2.undo.calledOnce).to.be.true; - expect(commandStack.canRedo()).to.be.true; - expect(commandStack.canUndo()).to.be.true; - expect(commandStack.isDirty).to.be.true; + expect(command2.undo).toHaveBeenCalledOnce(); + expect(commandStack.canRedo()).toBe(true); + expect(commandStack.canUndo()).toBe(true); + expect(commandStack.isDirty).toBe(true); await commandStack.undo(); - expect(command1.undo.calledOnce).to.be.true; - expect(command1.undo.calledAfter(command2.undo)).to.be.true; - expect(commandStack.isDirty).to.be.false; - expect(commandStack.canRedo()).to.be.true; - expect(commandStack.canUndo()).to.be.false; + expect(command1.undo).toHaveBeenCalledOnce(); + expect(command1.undo.mock.invocationCallOrder[0]).toBeGreaterThan(command2.undo.mock.invocationCallOrder[0]); + expect(commandStack.isDirty).toBe(false); + expect(commandStack.canRedo()).toBe(true); + expect(commandStack.canUndo()).toBe(false); }); it('should flush the stack in case of an execution error', async () => { - command2.undo.throwsException(); - const flushSpy = sandbox.spy(commandStack, 'flush'); + command2.undo.mockImplementation(() => { + throw new Error('error'); + }); + const flushSpy = vi.spyOn(commandStack, 'flush'); commandStack['commands'].push(command2); commandStack['top'] = 0; - await expectToThrowAsync(() => commandStack.undo()); - expect(command2.undo.calledOnce).to.be.true; - expect(flushSpy.calledOnce).to.be.true; + await expect(commandStack.undo()).rejects.toThrow(); + expect(command2.undo).toHaveBeenCalledOnce(); + expect(flushSpy).toHaveBeenCalledOnce(); }); }); describe('redo', () => { it('should do nothing if the command stack is empty', async () => { - expect(commandStack.isDirty).to.be.false; + expect(commandStack.isDirty).toBe(false); await commandStack.redo(); - expect(commandStack.canUndo()).to.be.false; - expect(commandStack.canRedo()).to.be.false; - expect(commandStack.isDirty).to.be.false; + expect(commandStack.canUndo()).toBe(false); + expect(commandStack.canRedo()).toBe(false); + expect(commandStack.isDirty).toBe(false); }); it('should redo the command and become dirty again', async () => { commandStack['commands'].push(command1); commandStack['top'] = -1; - expect(commandStack.isDirty).to.be.false; - expect(commandStack.canUndo()).to.be.false; - expect(commandStack.canRedo()).to.be.true; + expect(commandStack.isDirty).toBe(false); + expect(commandStack.canUndo()).toBe(false); + expect(commandStack.canRedo()).toBe(true); await commandStack.redo(); - expect(command1.redo.calledOnce).to.be.true; - expect(commandStack.isDirty).to.be.true; - expect(commandStack.canRedo()).to.be.false; - expect(commandStack.canUndo()).to.be.true; + expect(command1.redo).toHaveBeenCalledOnce(); + expect(commandStack.isDirty).toBe(true); + expect(commandStack.canRedo()).toBe(false); + expect(commandStack.canUndo()).toBe(true); }); it('should undo multiple command and become non-dirty again', async () => { commandStack['commands'].push(command2, command1); commandStack['top'] = -1; commandStack['saveIndex'] = -1; - expect(commandStack.isDirty).to.be.false; - expect(commandStack.canUndo()).to.be.false; - expect(commandStack.canRedo()).to.be.true; + expect(commandStack.isDirty).toBe(false); + expect(commandStack.canUndo()).toBe(false); + expect(commandStack.canRedo()).toBe(true); await commandStack.redo(); - expect(command2.redo.calledOnce).to.be.true; - expect(commandStack.canRedo()).to.be.true; - expect(commandStack.canUndo()).to.be.true; - expect(commandStack.isDirty).to.be.true; + expect(command2.redo).toHaveBeenCalledOnce(); + expect(commandStack.canRedo()).toBe(true); + expect(commandStack.canUndo()).toBe(true); + expect(commandStack.isDirty).toBe(true); await commandStack.redo(); - expect(command1.redo.calledOnce).to.be.true; - expect(command1.redo.calledAfter(command2.redo)).to.be.true; - expect(commandStack.isDirty).to.be.true; - expect(commandStack.canRedo()).to.be.false; - expect(commandStack.canUndo()).to.be.true; + expect(command1.redo).toHaveBeenCalledOnce(); + expect(command1.redo.mock.invocationCallOrder[0]).toBeGreaterThan(command2.redo.mock.invocationCallOrder[0]); + expect(commandStack.isDirty).toBe(true); + expect(commandStack.canRedo()).toBe(false); + expect(commandStack.canUndo()).toBe(true); }); it('should flush the stack in case of an execution error', async () => { - command2.redo.throwsException(); - const flushSpy = sandbox.spy(commandStack, 'flush'); + command2.redo.mockImplementation(() => { + throw new Error('error'); + }); + const flushSpy = vi.spyOn(commandStack, 'flush'); commandStack['commands'].push(command2); commandStack['top'] = -1; - await expectToThrowAsync(() => commandStack.redo()); - expect(command2.redo.calledOnce).to.be.true; - expect(flushSpy.calledOnce).to.be.true; + await expect(commandStack.redo()).rejects.toThrow(); + expect(command2.redo).toHaveBeenCalledOnce(); + expect(flushSpy).toHaveBeenCalledOnce(); }); it('should be able to undo after redo', async () => { commandStack['commands'].push(command1); commandStack['top'] = -1; - expect(commandStack.canUndo()).to.be.false; + expect(commandStack.canUndo()).toBe(false); await commandStack.redo(); - expect(commandStack.canUndo()).to.be.true; + expect(commandStack.canUndo()).toBe(true); }); }); @@ -210,9 +229,9 @@ describe('test DefaultCommandStack', () => { commandStack['top'] = 0; commandStack.flush(); - expect(commandStack.isDirty).to.be.false; - expect(commandStack.canUndo()).to.be.false; - expect(commandStack.canRedo()).to.be.false; + expect(commandStack.isDirty).toBe(false); + expect(commandStack.canUndo()).toBe(false); + expect(commandStack.canRedo()).toBe(false); }); }); @@ -220,20 +239,20 @@ describe('test DefaultCommandStack', () => { it('should become non-dirty after execution', () => { commandStack['commands'].push(command1); commandStack['top'] = 0; - expect(commandStack.isDirty).to.be.true; + expect(commandStack.isDirty).toBe(true); commandStack.saveIsDone(); - expect(commandStack.isDirty).to.be.false; + expect(commandStack.isDirty).toBe(false); }); it('should maintain undo/redo history after execution', () => { commandStack['commands'].push(command1, command2); commandStack['top'] = 0; - expect(commandStack.canUndo()).to.be.true; - expect(commandStack.canRedo()).to.be.true; + expect(commandStack.canUndo()).toBe(true); + expect(commandStack.canRedo()).toBe(true); commandStack.saveIsDone(); - expect(commandStack.canUndo()).to.be.true; - expect(commandStack.canRedo()).to.be.true; + expect(commandStack.canUndo()).toBe(true); + expect(commandStack.canRedo()).toBe(true); }); }); }); diff --git a/packages/server/src/common/command/command.spec.ts b/packages/server/src/common/command/command.spec.ts index a546f3ed..d5e15fc5 100644 --- a/packages/server/src/common/command/command.spec.ts +++ b/packages/server/src/common/command/command.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2023 EclipseSource and others. + * Copyright (c) 2023-2026 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,80 +13,92 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; -import * as sinon from 'sinon'; -import { expectToThrowAsync, StubCommand } from '../test/mock-util'; -import { CompoundCommand } from './command'; +import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest'; +import { Command, CompoundCommand } from './command'; -describe('CompoundCommand', () => { - const sandbox = sinon.createSandbox(); - - const command1 = sandbox.stub(new StubCommand()); - const command2 = sandbox.stub(new StubCommand()); - const command3 = sandbox.stub(new StubCommand()); +// Note: `canUndo` is intentionally left undefined (it is optional on `Command`). `Command.canUndo` +// returns `command.canUndo?.() ?? true`, so an absent `canUndo` counts as "can undo" — matching the +// original `StubCommand` (whose optional `canUndo` was never implemented). +function makeStubCommand(): Command & { + execute: Mock; + undo: Mock; + redo: Mock; +} { + return { + execute: vi.fn(), + undo: vi.fn(), + redo: vi.fn() + }; +} - const compoundCommand = new CompoundCommand(command1, command2, command3); +describe('CompoundCommand', () => { + let command1: ReturnType; + let command2: ReturnType; + let command3: ReturnType; + let compoundCommand: CompoundCommand; - afterEach(() => { - sandbox.reset(); + beforeEach(() => { + command1 = makeStubCommand(); + command2 = makeStubCommand(); + command3 = makeStubCommand(); + compoundCommand = new CompoundCommand(command1, command2, command3); }); describe('execute', () => { it('Should execute the subcommands in order', async () => { await compoundCommand.execute(); - expect(command1.execute.calledOnce).to.be.true; - expect(command2.execute.calledOnce).to.be.true; - expect(command3.execute.calledOnce).to.be.true; - expect(command1.execute.calledBefore(command2.execute)).to.be.true; - expect(command2.execute.calledBefore(command3.execute)).to.be.true; + expect(command1.execute).toHaveBeenCalledOnce(); + expect(command2.execute).toHaveBeenCalledOnce(); + expect(command3.execute).toHaveBeenCalledOnce(); + expect(command1.execute.mock.invocationCallOrder[0]).toBeLessThan(command2.execute.mock.invocationCallOrder[0]); + expect(command2.execute.mock.invocationCallOrder[0]).toBeLessThan(command3.execute.mock.invocationCallOrder[0]); }); it('Should undo partially executed subcommands in case of an error', async () => { - command3.execute.throwsException(); + command3.execute.mockImplementation(() => { + throw new Error('error'); + }); - await expectToThrowAsync(() => compoundCommand.execute()); + await expect(compoundCommand.execute()).rejects.toThrow(); - expect(command1.execute.calledOnce).to.be.true; - expect(command2.execute.calledOnce).to.be.true; - expect(command3.execute.calledOnce).to.be.true; - expect(command1.undo.calledOnce).to.be.true; - expect(command2.undo.calledOnce).to.be.true; + expect(command1.execute).toHaveBeenCalledOnce(); + expect(command2.execute).toHaveBeenCalledOnce(); + expect(command3.execute).toHaveBeenCalledOnce(); + expect(command1.undo).toHaveBeenCalledOnce(); + expect(command2.undo).toHaveBeenCalledOnce(); }); }); describe('undo', () => { it('Should undo the subcommands in reverse order', async () => { await compoundCommand.undo(); - expect(command1.undo.calledOnce).to.be.true; - expect(command2.undo.calledOnce).to.be.true; - expect(command3.undo.calledOnce).to.be.true; - expect(command1.undo.calledAfter(command2.undo)).to.be.true; - expect(command2.undo.calledAfter(command3.undo)).to.be.true; + expect(command1.undo).toHaveBeenCalledOnce(); + expect(command2.undo).toHaveBeenCalledOnce(); + expect(command3.undo).toHaveBeenCalledOnce(); + expect(command1.undo.mock.invocationCallOrder[0]).toBeGreaterThan(command2.undo.mock.invocationCallOrder[0]); + expect(command2.undo.mock.invocationCallOrder[0]).toBeGreaterThan(command3.undo.mock.invocationCallOrder[0]); }); it('Should redo partially undone subcommands in case of an error', async () => { - command1.undo.throwsException(); - await expectToThrowAsync(() => compoundCommand.undo()); + command1.undo.mockImplementation(() => { + throw new Error('error'); + }); + await expect(compoundCommand.undo()).rejects.toThrow(); - expect(command1.undo.calledOnce).to.be.true; - expect(command2.undo.calledOnce).to.be.true; - expect(command3.undo.calledOnce).to.be.true; - expect(command3.redo.calledOnce).to.be.true; - expect(command2.redo.calledOnce).to.be.true; + expect(command1.undo).toHaveBeenCalledOnce(); + expect(command2.undo).toHaveBeenCalledOnce(); + expect(command3.undo).toHaveBeenCalledOnce(); + expect(command3.redo).toHaveBeenCalledOnce(); + expect(command2.redo).toHaveBeenCalledOnce(); }); }); describe('canUndo', () => { it('should return true if all subcommands can be undone', () => { - command1.canUndo?.returns(true); - command2.canUndo?.returns(true); - command3.canUndo?.returns(true); - expect(compoundCommand.canUndo()).to.be.true; + expect(compoundCommand.canUndo()).toBe(true); }); - it('should return true if anyof the subcommands cannot be undone', () => { - command1.canUndo?.returns(true); - command2.canUndo?.returns(false); - command3.canUndo?.returns(true); - expect(compoundCommand.canUndo()).to.be.true; + it('should return false if any of the subcommands cannot be undone', () => { + command2.canUndo = vi.fn>().mockReturnValue(false); + expect(compoundCommand.canUndo()).toBe(false); }); }); }); diff --git a/packages/server/src/common/command/recording-command.spec.ts b/packages/server/src/common/command/recording-command.spec.ts index 91653b31..4309c571 100644 --- a/packages/server/src/common/command/recording-command.spec.ts +++ b/packages/server/src/common/command/recording-command.spec.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { AnyObject, MaybePromise } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; +import { beforeEach, describe, expect, it } from 'vitest'; import { AbstractRecordingCommand } from './recording-command'; interface TestModel { @@ -54,9 +54,9 @@ describe('RecordingCommand', () => { it('should be undoable after execution', async () => { const command = new TestRecordingCommand(jsonObject, () => {}); - expect(command.canUndo()).to.be.false; + expect(command.canUndo()).toBe(false); await command.execute(); - expect(command.canUndo()).to.be.true; + expect(command.canUndo()).toBe(true); }); it('should restore the pre execution state when undo is called', async () => { @@ -66,9 +66,9 @@ describe('RecordingCommand', () => { jsonObject.maybe = { hello: 'world' }; }); await command.execute(); - expect(jsonObject).to.not.be.deep.equals(beforeState); + expect(jsonObject).not.toEqual(beforeState); await command.undo(); - expect(jsonObject).to.be.deep.equals(beforeState); + expect(jsonObject).toEqual(beforeState); }); it('should restore the post execution state when redo is called', async () => { @@ -81,6 +81,6 @@ describe('RecordingCommand', () => { const afterState = JSON.parse(JSON.stringify(jsonObject)); jsonObject = JSON.parse(JSON.stringify(afterState)); await command.redo(); - expect(jsonObject).to.be.deep.equals(afterState); + expect(jsonObject).toEqual(afterState); }); }); diff --git a/packages/server/src/common/di/binding-target.spec.ts b/packages/server/src/common/di/binding-target.spec.ts index 2dab1526..4daa5088 100644 --- a/packages/server/src/common/di/binding-target.spec.ts +++ b/packages/server/src/common/di/binding-target.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 EclipseSource and others. + * Copyright (c) 2022-2026 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,9 +13,8 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; -import { Container, ContainerModule, interfaces } from 'inversify'; -import * as sinon from 'sinon'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { interfaces } from 'inversify'; import { applyBindingTarget } from './binding-target'; // Simple no op classes to construct inversify binding syntaxes. class Target {} @@ -26,47 +25,81 @@ describe('BindingTarget', () => { describe('bindTarget()', () => { // Setup nested spies for the fluent inversify binding API let context: { - bind: sinon.SinonStub<[serviceIdentifier: interfaces.ServiceIdentifier], interfaces.BindingToSyntax>; - isBound: sinon.SinonStub<[serviceIdentifier: interfaces.ServiceIdentifier], boolean>; + bind: interfaces.Bind; + isBound: interfaces.IsBound; }; - let toSyntax: sinon.SinonStubbedInstance>; - let whenOnSyntax: sinon.SinonStubbedInstance>; + let toSyntax: interfaces.BindingToSyntax; const setupStubs = (): { context: { - bind: sinon.SinonStub<[serviceIdentifier: interfaces.ServiceIdentifier], interfaces.BindingToSyntax>; - isBound: sinon.SinonStub<[serviceIdentifier: interfaces.ServiceIdentifier], boolean>; + bind: interfaces.Bind; + isBound: interfaces.IsBound; }; - toSyntax: sinon.SinonStubbedInstance>; - inWhenOnSyntax: sinon.SinonStubbedInstance>; - whenOnSyntax: sinon.SinonStubbedInstance>; + toSyntax: interfaces.BindingToSyntax; + inWhenOnSyntax: interfaces.BindingInWhenOnSyntax; + whenOnSyntax: interfaces.BindingWhenOnSyntax; } => { - const container = new Container(); - const bind = sinon.stub<[serviceIdentifier: interfaces.ServiceIdentifier], interfaces.BindingToSyntax>(); - const isBound = sinon.stub<[serviceIdentifier: interfaces.ServiceIdentifier], boolean>(); + const bind = vi.fn(); + const isBound = vi.fn(); - let toSyntax: sinon.SinonStubbedInstance> = {} as any; - let inWhenOnSyntax: sinon.SinonStubbedInstance> = {} as any; - container.load( - new ContainerModule(_bind => { - const toStub = _bind('StubMe'); - inWhenOnSyntax = sinon.stub(toStub.to(Target)); - whenOnSyntax = sinon.stub(toStub.toConstantValue('')); - toSyntax = sinon.stub(toStub); + const inWhenOnSyntax: interfaces.BindingInWhenOnSyntax = { + inRequestScope: vi.fn(), + inSingletonScope: vi.fn(), + inTransientScope: vi.fn(), + when: vi.fn(), + whenTargetNamed: vi.fn(), + whenTargetIsDefault: vi.fn(), + whenTargetTagged: vi.fn(), + whenInjectedInto: vi.fn(), + whenParentNamed: vi.fn(), + whenParentTagged: vi.fn(), + whenAnyAncestorIs: vi.fn(), + whenNoAncestorIs: vi.fn(), + whenAnyAncestorNamed: vi.fn(), + whenAnyAncestorTagged: vi.fn(), + whenNoAncestorNamed: vi.fn(), + whenNoAncestorTagged: vi.fn(), + whenAnyAncestorMatches: vi.fn(), + whenNoAncestorMatches: vi.fn(), + onActivation: vi.fn(), + onDeactivation: vi.fn() + } as unknown as interfaces.BindingInWhenOnSyntax; - bind.returns(toSyntax); - toSyntax.to.returns(inWhenOnSyntax); - toSyntax.toSelf.returns(inWhenOnSyntax); - toSyntax.toDynamicValue.returns(inWhenOnSyntax); - toSyntax.toService.returns(); - }) - ); + const _whenOnSyntax: interfaces.BindingWhenOnSyntax = { + when: vi.fn(), + whenTargetNamed: vi.fn(), + whenTargetIsDefault: vi.fn(), + whenTargetTagged: vi.fn(), + whenInjectedInto: vi.fn(), + whenParentNamed: vi.fn(), + whenParentTagged: vi.fn(), + whenAnyAncestorIs: vi.fn(), + whenNoAncestorIs: vi.fn(), + whenAnyAncestorNamed: vi.fn(), + whenAnyAncestorTagged: vi.fn(), + whenNoAncestorNamed: vi.fn(), + whenNoAncestorTagged: vi.fn(), + whenAnyAncestorMatches: vi.fn(), + whenNoAncestorMatches: vi.fn(), + onActivation: vi.fn(), + onDeactivation: vi.fn() + } as unknown as interfaces.BindingWhenOnSyntax; + + const _toSyntax: interfaces.BindingToSyntax = { + to: vi.fn().mockReturnValue(inWhenOnSyntax), + toSelf: vi.fn().mockReturnValue(inWhenOnSyntax), + toConstantValue: vi.fn().mockReturnValue(_whenOnSyntax), + toDynamicValue: vi.fn().mockReturnValue(inWhenOnSyntax), + toService: vi.fn() + } as unknown as interfaces.BindingToSyntax; + + bind.mockReturnValue(_toSyntax); return { - context: { bind, isBound }, - toSyntax, + context: { bind, isBound } as unknown as { bind: interfaces.Bind; isBound: interfaces.IsBound }, + toSyntax: _toSyntax, inWhenOnSyntax, - whenOnSyntax + whenOnSyntax: _whenOnSyntax }; }; @@ -74,42 +107,41 @@ describe('BindingTarget', () => { const stubs = setupStubs(); context = stubs.context; toSyntax = stubs.toSyntax; - whenOnSyntax = stubs.whenOnSyntax; }); describe('Bind to constructor', () => { it('Should bind the service identifier `to` the given target with no scope', () => { applyBindingTarget(context, Target, SubTarget); - expect(toSyntax.to.calledOnceWith(SubTarget)).to.be.true; + expect(vi.mocked(toSyntax.to)).toHaveBeenCalledExactlyOnceWith(SubTarget); }); it('Should bind the service identifier `toSelf` with no scope', () => { applyBindingTarget(context, Target, Target); - expect(toSyntax.toSelf.calledOnce).to.be.true; + expect(vi.mocked(toSyntax.toSelf)).toHaveBeenCalledOnce(); }); }); describe('Bind to service', () => { it('Should bind the service identifier `service` using the given target service with no scope', () => { - context.isBound.returns(true); + vi.mocked(context.isBound).mockReturnValue(true); applyBindingTarget(context, Target, { service: SubTarget }); - expect(toSyntax.toService.calledOnceWith(SubTarget)).to.be.true; + expect(vi.mocked(toSyntax.toService)).toHaveBeenCalledExactlyOnceWith(SubTarget); }); it('Should throw an error because the given target service is not bound', () => { - context.isBound.returns(false); - expect(() => applyBindingTarget(context, Target, { service: SubTarget, autoBind: false })).to.throw(); + vi.mocked(context.isBound).mockReturnValue(false); + expect(() => applyBindingTarget(context, Target, { service: SubTarget, autoBind: false })).toThrow(); }); it('Should bind the unbound target service to itself before applying the toService binding', () => { - context.isBound.returns(false); + vi.mocked(context.isBound).mockReturnValue(false); applyBindingTarget(context, Target, { service: SubTarget }); - expect(context.bind.calledWith(Target)).to.be.true; + expect(context.bind).toHaveBeenCalledWith(Target); }); it('The return syntax should be no op and invocation of a syntax function should throw an error', () => { - context.isBound.returns(true); + vi.mocked(context.isBound).mockReturnValue(true); const syntax = applyBindingTarget(context, Target, { service: SubTarget }); expect(() => { syntax.inRequestScope(); - }).to.throw( + }).toThrow( `${Target.toString()} has been bound to 'service'.` + "Using 'in','when' or 'on' bindings after" + "a 'toService' binding is not possible." @@ -121,26 +153,24 @@ describe('BindingTarget', () => { it('Should bind the service identifier `toConstantValue` using the given target with no scope', () => { const subTarget = new SubTarget(); applyBindingTarget(context, Target, { constantValue: subTarget }); - expect(toSyntax.toConstantValue.calledOnceWith(subTarget)).to.be.true; + expect(vi.mocked(toSyntax.toConstantValue)).toHaveBeenCalledExactlyOnceWith(subTarget); }); it("The return syntax's in functions should be no op and invocation should log a warning", () => { - const spy = sinon.spy(console, 'warn'); + const spy = vi.spyOn(console, 'warn'); const subTarget = new SubTarget(); const syntax = applyBindingTarget(context, Target, { constantValue: subTarget }); syntax.inSingletonScope(); - expect( - spy.calledWith( - `${Target.toString()} has been bound to 'constantValue'. Binding in Singleton scope has no effect.` + - 'Constant value bindings are effectively Singleton bindings.' - ) - ).to.be.true; + expect(spy).toHaveBeenCalledWith( + `${Target.toString()} has been bound to 'constantValue'. Binding in Singleton scope has no effect.` + + 'Constant value bindings are effectively Singleton bindings.' + ); }); }); describe('Bind to dynamic value', () => { it('Should bind the service identifier `toDynamicValue` using the given factory function with no scope', () => { - applyBindingTarget(context, Target, { dynamicValue: context => new SubTarget() }); - expect(toSyntax.toDynamicValue.calledOnce); + applyBindingTarget(context, Target, { dynamicValue: _context => new SubTarget() }); + expect(vi.mocked(toSyntax.toDynamicValue)).toHaveBeenCalledOnce(); }); }); }); diff --git a/packages/server/src/common/di/multi-bindings.spec.ts b/packages/server/src/common/di/multi-bindings.spec.ts index 72baa315..8357545d 100644 --- a/packages/server/src/common/di/multi-bindings.spec.ts +++ b/packages/server/src/common/di/multi-bindings.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,7 +13,7 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { Container, ContainerModule, injectable } from 'inversify'; import { InstanceMultiBinding, MultiBinding } from './multi-binding'; @@ -37,34 +37,34 @@ describe('test implementations of MultiBinding', () => { expect(binding.contains(TestClass1)).true; const result = binding.getAll(); - expect(result.length).to.be.equal(1); - expect(result[0]).to.be.equal(TestClass1); + expect(result.length).toBe(1); + expect(result[0]).toBe(TestClass1); }); it('add - existing binding', () => { binding.add(TestClass1); - expect(binding.getAll().length).to.be.equal(1); - expect(binding.getAll()[0]).to.be.equal(TestClass1); + expect(binding.getAll().length).toBe(1); + expect(binding.getAll()[0]).toBe(TestClass1); }); it('remove - existing binding', () => { expect(binding.contains(TestClass1)).true; binding.remove(TestClass1); expect(binding.contains(TestClass1)).false; - expect(binding.getAll()).to.have.length(0); + expect(binding.getAll()).toHaveLength(0); }); it('remove - non-existing binding', () => { const previousSize = binding.getAll().length; binding.remove(TestClass2); - expect(binding.getAll()).to.have.length(previousSize); + expect(binding.getAll()).toHaveLength(previousSize); }); it('addAll - TestClass1 & TestClass2', () => { binding.addAll([TestClass1, TestClass2]); const result = binding.getAll(); - expect(result.length).to.be.equal(2); + expect(result.length).toBe(2); expect(result.includes(TestClass1)).true; expect(result.includes(TestClass2)).true; }); @@ -72,7 +72,7 @@ describe('test implementations of MultiBinding', () => { it('rebind- TestClass2 to TestClass3', () => { binding.rebind(TestClass2, TestClass3); const result = binding.getAll(); - expect(result.length).to.be.equal(2); + expect(result.length).toBe(2); expect(result.includes(TestClass1)).true; expect(result.includes(TestClass3)).true; }); @@ -80,7 +80,7 @@ describe('test implementations of MultiBinding', () => { it('rebind- TestClass2 to TestClass3- should fail', () => { binding.rebind(TestClass2, TestClass3); const result = binding.getAll(); - expect(result.length).to.be.equal(2); + expect(result.length).toBe(2); expect(result.includes(TestClass1)).true; expect(result.includes(TestClass3)).true; }); @@ -88,7 +88,7 @@ describe('test implementations of MultiBinding', () => { it('removeAll- TestClass1 & TestClass3', () => { binding.removeAll([TestClass1, TestClass3]); const result = binding.getAll(); - expect(result).to.have.length(0); + expect(result).toHaveLength(0); }); }); @@ -103,10 +103,10 @@ describe('test implementations of MultiBinding', () => { }); testContainer.load(testModule); const result = testContainer.getAll('TestClass'); - expect(result).to.have.length(3); - expect(result.find(instance => instance instanceof TestClass1)).to.not.be.undefined; - expect(result.find(instance => instance instanceof TestClass2)).to.not.be.undefined; - expect(result.find(instance => instance instanceof TestClass3)).to.not.be.undefined; + expect(result).toHaveLength(3); + expect(result.find(instance => instance instanceof TestClass1)).toBeDefined(); + expect(result.find(instance => instance instanceof TestClass2)).toBeDefined(); + expect(result.find(instance => instance instanceof TestClass3)).toBeDefined(); }); it('apply binding of InstanceMultiBinding', () => { @@ -124,7 +124,7 @@ describe('test implementations of MultiBinding', () => { }); testContainer.load(testModule); const result = testContainer.get(identifier); - expect(result).to.have.length(3); + expect(result).toHaveLength(3); expect(result.includes(t1)).true; expect(result.includes(t2)).true; expect(result.includes(t3)).true; diff --git a/packages/server/src/common/features/contextactions/context-actions-provider-registry.spec.ts b/packages/server/src/common/features/contextactions/context-actions-provider-registry.spec.ts index 8f2eefd8..4d986eea 100644 --- a/packages/server/src/common/features/contextactions/context-actions-provider-registry.spec.ts +++ b/packages/server/src/common/features/contextactions/context-actions-provider-registry.spec.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { GModelElement } from '@eclipse-glsp/graph'; import { Args, LabeledAction, Point } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { CommandPaletteActionProvider } from './command-palette-action-provider'; import { ContextActionsProvider } from './context-actions-provider'; import { ContextActionsProviderRegistry } from './context-actions-provider-registry'; @@ -25,13 +25,13 @@ describe('Test DefaultContextActionsProviderRegistry', () => { it('check if default registry is empty', () => { const contextActionsProvider: ContextActionsProvider[] = []; const contextActionsProviderRegistry = new ContextActionsProviderRegistry(contextActionsProvider); - expect(contextActionsProviderRegistry.keys()).to.have.length(0); + expect(contextActionsProviderRegistry.keys()).toHaveLength(0); }); it('register DefaultToolPaletteItemProvider via ContextActionsProviders list', () => { const contextActionsProvider: ContextActionsProvider[] = [new DefaultToolPaletteItemProvider()]; const contextActionsProviderRegistry = new ContextActionsProviderRegistry(contextActionsProvider); - expect(contextActionsProviderRegistry.keys()).to.have.length(1); + expect(contextActionsProviderRegistry.keys()).toHaveLength(1); }); it('register DefaultToolPaletteItemProvider via ToolPaletteItemProvider', () => { @@ -42,7 +42,7 @@ describe('Test DefaultContextActionsProviderRegistry', () => { undefined, new DefaultToolPaletteItemProvider() ); - expect(contextActionsProviderRegistry.keys()).to.have.length(1); + expect(contextActionsProviderRegistry.keys()).toHaveLength(1); }); it('register CustomCommandPaletteActionProvider via CommandPaletteActionProvider', () => { @@ -64,6 +64,6 @@ describe('Test DefaultContextActionsProviderRegistry', () => { new CustomCommandPaletteActionProvider(), undefined ); - expect(contextActionsProviderRegistry.keys()).to.have.length(1); + expect(contextActionsProviderRegistry.keys()).toHaveLength(1); }); }); diff --git a/packages/server/src/common/features/contextactions/request-context-actions-handler.spec.ts b/packages/server/src/common/features/contextactions/request-context-actions-handler.spec.ts index caa3515e..e73b32c3 100644 --- a/packages/server/src/common/features/contextactions/request-context-actions-handler.spec.ts +++ b/packages/server/src/common/features/contextactions/request-context-actions-handler.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ import { PaletteItem, RequestContextActions, SetContextActions } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { OperationHandlerRegistry } from '../../operations/operation-handler-registry'; import * as mock from '../../test/mock-util'; import { ContextActionsProvider } from './context-actions-provider'; @@ -51,25 +51,25 @@ describe('Test RequestContextActionsHandler', () => { const actions = await requestContextActionsHandler.execute( RequestContextActions.create({ contextId: 'tool-palette', editorContext: { selectedElementIds: [] } }) ); - expect(actions).to.have.length(1); + expect(actions).toHaveLength(1); const action = actions[0]; - expect(SetContextActions.is(action)).to.be.true; + expect(SetContextActions.is(action)).toBe(true); const setContextActions = action as SetContextActions; - expect(setContextActions.actions).to.have.length(2); + expect(setContextActions.actions).toHaveLength(2); - expect(PaletteItem.is(setContextActions.actions[0])).to.be.true; + expect(PaletteItem.is(setContextActions.actions[0])).toBe(true); const firstPaletteItem = setContextActions.actions[0] as PaletteItem; - expect(firstPaletteItem.label).to.be.equal('Nodes'); - expect(firstPaletteItem.children).to.have.length(2); - expect(firstPaletteItem.children?.[0].label).to.be.equal('ANode'); - expect(firstPaletteItem.children?.[1].label).to.be.equal('BNode'); + expect(firstPaletteItem.label).toBe('Nodes'); + expect(firstPaletteItem.children).toHaveLength(2); + expect(firstPaletteItem.children?.[0].label).toBe('ANode'); + expect(firstPaletteItem.children?.[1].label).toBe('BNode'); - expect(PaletteItem.is(setContextActions.actions[1])).to.be.true; + expect(PaletteItem.is(setContextActions.actions[1])).toBe(true); const secondPaletteItem = setContextActions.actions[1] as PaletteItem; - expect(secondPaletteItem.label).to.be.equal('Edges'); - expect(secondPaletteItem.children).to.have.length(2); - expect(secondPaletteItem.children?.[0].label).to.be.equal('AEdge'); - expect(secondPaletteItem.children?.[1].label).to.be.equal('BEdge'); + expect(secondPaletteItem.label).toBe('Edges'); + expect(secondPaletteItem.children).toHaveLength(2); + expect(secondPaletteItem.children?.[0].label).toBe('AEdge'); + expect(secondPaletteItem.children?.[1].label).toBe('BEdge'); }); }); diff --git a/packages/server/src/common/features/contextactions/tool-palette-item-provider.spec.ts b/packages/server/src/common/features/contextactions/tool-palette-item-provider.spec.ts index ed865256..30e12861 100644 --- a/packages/server/src/common/features/contextactions/tool-palette-item-provider.spec.ts +++ b/packages/server/src/common/features/contextactions/tool-palette-item-provider.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -16,7 +16,7 @@ import { OperationHandlerRegistry } from '../../operations/operation-handler-registry'; import * as mock from '../../test/mock-util'; import { DefaultToolPaletteItemProvider } from './tool-palette-item-provider'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; describe('Test DefaultToolPaletteItemProvider', () => { const operationHandlerRegistry = new OperationHandlerRegistry(); @@ -33,14 +33,14 @@ describe('Test DefaultToolPaletteItemProvider', () => { const toolPaletteItemProvider = new DefaultToolPaletteItemProvider(); toolPaletteItemProvider.operationHandlerRegistry = operationHandlerRegistry; const items = toolPaletteItemProvider.getItems(); - expect(items).to.have.length(2); - expect(items[0].label).to.be.equal('Nodes'); - expect(items[0].children).to.have.length(2); - expect(items[0].children?.[0].label).to.be.equal('ANode'); - expect(items[0].children?.[1].label).to.be.equal('BNode'); - expect(items[1].label).to.be.equal('Edges'); - expect(items[1].children).to.have.length(2); - expect(items[1].children?.[0].label).to.be.equal('AEdge'); - expect(items[1].children?.[1].label).to.be.equal('BEdge'); + expect(items).toHaveLength(2); + expect(items[0].label).toBe('Nodes'); + expect(items[0].children).toHaveLength(2); + expect(items[0].children?.[0].label).toBe('ANode'); + expect(items[0].children?.[1].label).toBe('BNode'); + expect(items[1].label).toBe('Edges'); + expect(items[1].children).toHaveLength(2); + expect(items[1].children?.[0].label).toBe('AEdge'); + expect(items[1].children?.[1].label).toBe('BEdge'); }); }); diff --git a/packages/server/src/common/features/directediting/context-edit-validator-registry.spec.ts b/packages/server/src/common/features/directediting/context-edit-validator-registry.spec.ts index c729bfd7..b0053ca4 100644 --- a/packages/server/src/common/features/directediting/context-edit-validator-registry.spec.ts +++ b/packages/server/src/common/features/directediting/context-edit-validator-registry.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,7 +13,7 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { TestContextEditValidator, TestLabelEditValidator } from '../../test/mock-util'; import { DefaultModelState } from '../model/model-state'; import { ContextEditValidator } from './context-edit-validator'; @@ -23,13 +23,13 @@ describe('Test DefaultContextEditValidatorRegistry', () => { it('check if default registry is empty', () => { const contextEditValidators: ContextEditValidator[] = []; const contextEditValidatorRegistry = new DefaultContextEditValidatorRegistry(new DefaultModelState(), contextEditValidators); - expect(contextEditValidatorRegistry.keys()).to.have.length(0); + expect(contextEditValidatorRegistry.keys()).toHaveLength(0); }); it('register TestContextEditValidator via ContextEditValidators list', () => { const contextEditValidators: ContextEditValidator[] = [new TestContextEditValidator()]; const contextEditValidatorsRegistry = new DefaultContextEditValidatorRegistry(new DefaultModelState(), contextEditValidators); - expect(contextEditValidatorsRegistry.keys()).to.have.length(1); + expect(contextEditValidatorsRegistry.keys()).toHaveLength(1); }); it('register TestLabelEditValidator via LabelEditValidator', () => { @@ -39,7 +39,7 @@ describe('Test DefaultContextEditValidatorRegistry', () => { contextEditValidators, new TestLabelEditValidator() ); - expect(contextEditValidatorsRegistry.keys()).to.have.length(1); + expect(contextEditValidatorsRegistry.keys()).toHaveLength(1); }); it('register via ContextEditValidators list and LabelEditValidator', () => { @@ -49,6 +49,6 @@ describe('Test DefaultContextEditValidatorRegistry', () => { contextEditValidators, new TestLabelEditValidator() ); - expect(contextEditValidatorsRegistry.keys()).to.have.length(2); + expect(contextEditValidatorsRegistry.keys()).toHaveLength(2); }); }); diff --git a/packages/server/src/common/features/directediting/context-edit-validator.ts b/packages/server/src/common/features/directediting/context-edit-validator.ts index d692f59f..22ade918 100644 --- a/packages/server/src/common/features/directediting/context-edit-validator.ts +++ b/packages/server/src/common/features/directediting/context-edit-validator.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2024 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,7 +13,7 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { GModelElement } from '@eclipse-glsp/graph/lib/gmodel-element'; +import { GModelElement } from '@eclipse-glsp/graph'; import { RequestEditValidationAction, ValidationStatus } from '@eclipse-glsp/protocol'; import { ModelState } from '../model/model-state'; import { LabelEditValidator } from './label-edit-validator'; diff --git a/packages/server/src/common/features/directediting/request-edit-validation-handler.spec.ts b/packages/server/src/common/features/directediting/request-edit-validation-handler.spec.ts index c3d4b6ef..4974ced7 100644 --- a/packages/server/src/common/features/directediting/request-edit-validation-handler.spec.ts +++ b/packages/server/src/common/features/directediting/request-edit-validation-handler.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,8 +15,7 @@ ********************************************************************************/ import { GNode } from '@eclipse-glsp/graph'; import { RequestEditValidationAction, SetEditValidationResultAction, ValidationStatus } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; -import * as sinon from 'sinon'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { TestContextEditValidator, TestLabelEditValidator } from '../../test/mock-util'; import { GModelIndex } from '../model/gmodel-index'; import { DefaultModelState } from '../model/model-state'; @@ -29,7 +28,9 @@ describe('Test RequestEditValidationHandler', () => { const contextEditValidators: ContextEditValidator[] = [new TestContextEditValidator()]; const modelState = new DefaultModelState(); Object.defineProperty(modelState, 'index', { value: new GModelIndex() }); - sinon.stub(modelState.index, 'get').callsFake(() => new GNode()); + beforeEach(() => { + vi.spyOn(modelState.index, 'get').mockImplementation(() => new GNode()); + }); const contextEditValidatorsRegistry = new DefaultContextEditValidatorRegistry( modelState, contextEditValidators, @@ -43,89 +44,89 @@ describe('Test RequestEditValidationHandler', () => { const actions = await requestEditValidationHandler.execute( RequestEditValidationAction.create({ contextId: 'test', modelElementId: '', text: 'ok' }) ); - expect(actions).to.have.length(1); + expect(actions).toHaveLength(1); const action = actions[0]; - expect(SetEditValidationResultAction.is(action)).to.be.true; + expect(SetEditValidationResultAction.is(action)).toBe(true); const setEditValidationResultAction = action as SetEditValidationResultAction; const status = setEditValidationResultAction.status; - expect(status.severity).to.be.equal(ValidationStatus.Severity.OK); - expect(status.message).to.be.equal('ok'); + expect(status.severity).toBe(ValidationStatus.Severity.OK); + expect(status.message).toBe('ok'); }); it('requestContextEditValidation with warning result', async () => { const actions = await requestEditValidationHandler.execute( RequestEditValidationAction.create({ contextId: 'test', modelElementId: '', text: 'warning' }) ); - expect(actions).to.have.length(1); + expect(actions).toHaveLength(1); const action = actions[0]; - expect(SetEditValidationResultAction.is(action)).to.be.true; + expect(SetEditValidationResultAction.is(action)).toBe(true); const setEditValidationResultAction = action as SetEditValidationResultAction; const status = setEditValidationResultAction.status; - expect(status.severity).to.be.equal(ValidationStatus.Severity.WARNING); - expect(status.message).to.be.equal('warning'); + expect(status.severity).toBe(ValidationStatus.Severity.WARNING); + expect(status.message).toBe('warning'); }); it('requestContextEditValidation with error result', async () => { const actions = await requestEditValidationHandler.execute( RequestEditValidationAction.create({ contextId: 'test', modelElementId: '', text: 'error' }) ); - expect(actions).to.have.length(1); + expect(actions).toHaveLength(1); const action = actions[0]; - expect(SetEditValidationResultAction.is(action)).to.be.true; + expect(SetEditValidationResultAction.is(action)).toBe(true); const setEditValidationResultAction = action as SetEditValidationResultAction; const status = setEditValidationResultAction.status; - expect(status.severity).to.be.equal(ValidationStatus.Severity.ERROR); - expect(status.message).to.be.equal('error'); + expect(status.severity).toBe(ValidationStatus.Severity.ERROR); + expect(status.message).toBe('error'); }); it('requestLabelEditValidation with ok result', async () => { const actions = await requestEditValidationHandler.execute( RequestEditValidationAction.create({ contextId: LabelEditValidator.CONTEXT_ID, modelElementId: '', text: 'ok' }) ); - expect(actions).to.have.length(1); + expect(actions).toHaveLength(1); const action = actions[0]; - expect(SetEditValidationResultAction.is(action)).to.be.true; + expect(SetEditValidationResultAction.is(action)).toBe(true); const setEditValidationResultAction = action as SetEditValidationResultAction; const status = setEditValidationResultAction.status; - expect(status.severity).to.be.equal(ValidationStatus.Severity.OK); - expect(status.message).to.be.equal('ok'); + expect(status.severity).toBe(ValidationStatus.Severity.OK); + expect(status.message).toBe('ok'); }); it('requestLabelEditValidation with warning result', async () => { const actions = await requestEditValidationHandler.execute( RequestEditValidationAction.create({ contextId: LabelEditValidator.CONTEXT_ID, modelElementId: '', text: 'warning' }) ); - expect(actions).to.have.length(1); + expect(actions).toHaveLength(1); const action = actions[0]; - expect(SetEditValidationResultAction.is(action)).to.be.true; + expect(SetEditValidationResultAction.is(action)).toBe(true); const setEditValidationResultAction = action as SetEditValidationResultAction; const status = setEditValidationResultAction.status; - expect(status.severity).to.be.equal(ValidationStatus.Severity.WARNING); - expect(status.message).to.be.equal('warning'); + expect(status.severity).toBe(ValidationStatus.Severity.WARNING); + expect(status.message).toBe('warning'); }); it('requestLabelEditValidation with error result', async () => { const actions = await requestEditValidationHandler.execute( RequestEditValidationAction.create({ contextId: LabelEditValidator.CONTEXT_ID, modelElementId: '', text: 'error' }) ); - expect(actions).to.have.length(1); + expect(actions).toHaveLength(1); const action = actions[0]; - expect(SetEditValidationResultAction.is(action)).to.be.true; + expect(SetEditValidationResultAction.is(action)).toBe(true); const setEditValidationResultAction = action as SetEditValidationResultAction; const status = setEditValidationResultAction.status; - expect(status.severity).to.be.equal(ValidationStatus.Severity.ERROR); - expect(status.message).to.be.equal('error'); + expect(status.severity).toBe(ValidationStatus.Severity.ERROR); + expect(status.message).toBe('error'); }); }); diff --git a/packages/server/src/common/features/model/gmodel-serializer.spec.ts b/packages/server/src/common/features/model/gmodel-serializer.spec.ts index b8164fc4..322143c9 100644 --- a/packages/server/src/common/features/model/gmodel-serializer.spec.ts +++ b/packages/server/src/common/features/model/gmodel-serializer.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ import { GEdge, getDefaultMapping, GGraph, GNode } from '@eclipse-glsp/graph'; -import { expect } from 'chai'; +import { beforeEach, describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import { DiagramConfiguration } from '../../diagram/diagram-configuration'; import * as mock from '../../test/mock-util'; @@ -72,61 +72,61 @@ describe('test DefaultGModelSerializer', () => { it('createElement - unregistered type', () => { testNodeSchema['type'] = 'notRegistered'; - expect(() => serializer.createElement(testNodeSchema)).to.throw(GLSPServerError); + expect(() => serializer.createElement(testNodeSchema)).toThrow(GLSPServerError); }); it('createElement - with root schema', () => { - expect(() => serializer.createElement(testRootSchema)).to.throw(GLSPServerError); + expect(() => serializer.createElement(testRootSchema)).toThrow(GLSPServerError); }); it('createElement - with node schema', () => { const node = serializer.createElement(testNodeSchema); - expect(node).to.be.an.instanceOf(TestNode); - expect(node).to.be.deep.include(testNodeSchema); - expect((node as TestNode).foo).to.not.be.undefined; + expect(node).toBeInstanceOf(TestNode); + expect(node).toMatchObject(testNodeSchema); + expect((node as TestNode).foo).toBeDefined(); }); it('createElement- with sub type of registered schema', () => { testNodeSchema.type = 'node:rectangular'; const node = serializer.createElement(testNodeSchema); - expect(node).to.be.an.instanceOf(TestNode); - expect(node).to.be.deep.include(testNodeSchema); - expect((node as TestNode).foo).to.not.be.undefined; + expect(node).toBeInstanceOf(TestNode); + expect(node).toMatchObject(testNodeSchema); + expect((node as TestNode).foo).toBeDefined(); }); it('createElement - with parent', () => { const parent = new GNode(); const child = serializer.createElement(testNodeSchema, parent); - expect(child).to.be.an.instanceOf(TestNode); - expect(child).to.be.deep.include(testNodeSchemaWithParent); - expect(child.parent).to.be.equal(parent); + expect(child).toBeInstanceOf(TestNode); + expect(child).toMatchObject(testNodeSchemaWithParent); + expect(child.parent).toBe(parent); }); it('createRoot - unregistered type', () => { testRootSchema['type'] = 'notRegistered'; - expect(() => serializer.createRoot(testNodeSchema)).to.throw(GLSPServerError); + expect(() => serializer.createRoot(testNodeSchema)).toThrow(GLSPServerError); }); it('createRoot - with child schema ', () => { - expect(() => serializer.createRoot(testNodeSchema)).to.throw(GLSPServerError); + expect(() => serializer.createRoot(testNodeSchema)).toThrow(GLSPServerError); }); it('createRoot - with registered root schema', () => { const root = serializer.createRoot(testRootSchema); - expect(root).to.be.an.instanceOf(GGraph); - expect(root.children.length).to.be.equal(3); + expect(root).toBeInstanceOf(GGraph); + expect(root.children.length).toBe(3); const node1 = root.children[0]; - expect(node1).to.be.an.instanceOf(TestNode); + expect(node1).toBeInstanceOf(TestNode); const node2 = root.children[1]; - expect(node2).to.be.an.instanceOf(TestNode); - expect(root.children[2]).to.be.an.instanceOf(GEdge); + expect(node2).toBeInstanceOf(TestNode); + expect(root.children[2]).toBeInstanceOf(GEdge); const edge = root.children[2] as GEdge; - expect(edge.sourceId).to.be.equal(node1.id); - expect(edge.targetId).to.be.equal(node2.id); + expect(edge.sourceId).toBe(node1.id); + expect(edge.targetId).toBe(node2.id); }); it('createSchema- unregistered type', () => { - expect(() => serializer.createRoot({ id: 'id', type: 'unregistered' })).to.throw(GLSPServerError); + expect(() => serializer.createRoot({ id: 'id', type: 'unregistered' })).toThrow(GLSPServerError); }); it('createSchema- with node', () => { @@ -136,6 +136,6 @@ describe('test DefaultGModelSerializer', () => { testNode.layoutOptions = { ['my']: 'Options' }; const schema = serializer.createSchema(testNode); delete (testNode as Partial).foo; - expect(schema).to.be.deep.include(testNode); + expect(schema).toMatchObject(testNode); }); }); diff --git a/packages/server/src/common/features/type-hints/request-type-hints-action-handler.spec.ts b/packages/server/src/common/features/type-hints/request-type-hints-action-handler.spec.ts index 02289cf5..710a1a46 100644 --- a/packages/server/src/common/features/type-hints/request-type-hints-action-handler.spec.ts +++ b/packages/server/src/common/features/type-hints/request-type-hints-action-handler.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ import { EdgeTypeHint, RequestTypeHintsAction, SetTypeHintsAction, ShapeTypeHint } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import { DiagramConfiguration } from '../../diagram/diagram-configuration'; import * as mock from '../../test/mock-util'; @@ -50,9 +50,9 @@ describe('test RequestTypeHintsActionHandler', () => { it('execute with correct action', async () => { const result = await handler.execute(RequestTypeHintsAction.create()); - expect(result).to.have.length(1); + expect(result).toHaveLength(1); expect(SetTypeHintsAction.is(result[0])).true; - expect(result).to.be.deep.equal([ + expect(result).toEqual([ { edgeHints: [edgeTypeHint], kind: 'setTypeHints', shapeHints: [shapeTypeHint], responseId: '' } as SetTypeHintsAction ]); }); diff --git a/packages/server/src/common/operations/operation-handler-registry.spec.ts b/packages/server/src/common/operations/operation-handler-registry.spec.ts index 510e2889..cf42fea1 100644 --- a/packages/server/src/common/operations/operation-handler-registry.spec.ts +++ b/packages/server/src/common/operations/operation-handler-registry.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ import { CompoundOperation, CreateEdgeOperation, CreateNodeOperation } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import * as mock from '../test/mock-util'; import { CompoundOperationHandler } from './compound-operation-handler'; import { OperationHandlerRegistry } from './operation-handler-registry'; @@ -28,9 +28,9 @@ describe('Test OperationHandlerRegistry', () => { it('register OperationActionHandler', () => { operationHandlerRegistry.registerHandler(new CompoundOperationHandler()); - expect(operationHandlerRegistry.keys()).to.have.length(1); - expect(operationHandlerRegistry.keys()).to.contain(CompoundOperation.KIND); - expect(operationHandlerRegistry.get(CompoundOperation.KIND)).to.be.an.instanceOf(CompoundOperationHandler); + expect(operationHandlerRegistry.keys()).toHaveLength(1); + expect(operationHandlerRegistry.keys()).toContain(CompoundOperation.KIND); + expect(operationHandlerRegistry.get(CompoundOperation.KIND)).toBeInstanceOf(CompoundOperationHandler); }); it('register CreateOperationActionHandlers', () => { @@ -38,13 +38,13 @@ describe('Test OperationHandlerRegistry', () => { operationHandlerRegistry.registerHandler(stubBNode); operationHandlerRegistry.registerHandler(stubAEdge); operationHandlerRegistry.registerHandler(stubBEdge); - expect(operationHandlerRegistry.keys()).to.contain(`${CreateNodeOperation.KIND}_ANode`); - expect(operationHandlerRegistry.get(`${CreateNodeOperation.KIND}_ANode`)).to.be.equal(stubANode); - expect(operationHandlerRegistry.keys()).to.contain(`${CreateNodeOperation.KIND}_BNode`); - expect(operationHandlerRegistry.get(`${CreateNodeOperation.KIND}_BNode`)).to.be.equal(stubBNode); - expect(operationHandlerRegistry.keys()).to.contain(`${CreateEdgeOperation.KIND}_AEdge`); - expect(operationHandlerRegistry.get(`${CreateEdgeOperation.KIND}_AEdge`)).to.be.equal(stubAEdge); - expect(operationHandlerRegistry.keys()).to.contain(`${CreateEdgeOperation.KIND}_BEdge`); - expect(operationHandlerRegistry.get(`${CreateEdgeOperation.KIND}_BEdge`)).to.be.equal(stubBEdge); + expect(operationHandlerRegistry.keys()).toContain(`${CreateNodeOperation.KIND}_ANode`); + expect(operationHandlerRegistry.get(`${CreateNodeOperation.KIND}_ANode`)).toBe(stubANode); + expect(operationHandlerRegistry.keys()).toContain(`${CreateNodeOperation.KIND}_BNode`); + expect(operationHandlerRegistry.get(`${CreateNodeOperation.KIND}_BNode`)).toBe(stubBNode); + expect(operationHandlerRegistry.keys()).toContain(`${CreateEdgeOperation.KIND}_AEdge`); + expect(operationHandlerRegistry.get(`${CreateEdgeOperation.KIND}_AEdge`)).toBe(stubAEdge); + expect(operationHandlerRegistry.keys()).toContain(`${CreateEdgeOperation.KIND}_BEdge`); + expect(operationHandlerRegistry.get(`${CreateEdgeOperation.KIND}_BEdge`)).toBe(stubBEdge); }); }); diff --git a/packages/server/src/common/protocol/glsp-server.spec.ts b/packages/server/src/common/protocol/glsp-server.spec.ts index 56ac6ccb..b378a8f2 100644 --- a/packages/server/src/common/protocol/glsp-server.spec.ts +++ b/packages/server/src/common/protocol/glsp-server.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -21,9 +21,8 @@ import { InitializeParameters } from '@eclipse-glsp/protocol'; import * as assert from 'assert'; -import { expect } from 'chai'; +import { beforeEach, describe, expect, it, vi, type MockInstance } from 'vitest'; import { Container, ContainerModule } from 'inversify'; -import * as sinon from 'sinon'; import { GlobalActionProvider } from '../actions/global-action-provider'; import { ClientSessionManager } from '../session/client-session-manager'; import * as mock from '../test/mock-util'; @@ -39,14 +38,14 @@ describe('test DefaultGLSPServer', () => { const actionKinds = new Map(); actionKinds.set(diagramType, ['A1', 'A2']); const sessionManager = new mock.StubClientSessionManager(); - const spy_sessionManager_getOrCreate = sinon.spy(sessionManager, 'getOrCreateClientSession'); - const spy_sessionManager_dispose = sinon.spy(sessionManager, 'disposeClientSession'); + let spy_sessionManager_getOrCreate: MockInstance; + let spy_sessionManager_dispose: MockInstance; const listener1 = new mock.StubGLSPServerListener(); - const spy_listener1_initialize = sinon.spy(listener1, 'serverInitialized'); - const spy_listener1_shutdown = sinon.spy(listener1, 'serverShutDown'); + let spy_listener1_initialize: MockInstance; + let spy_listener1_shutdown: MockInstance; const listener2 = new mock.StubGLSPServerListener(); - const spy_listener2_initialize = sinon.spy(listener2, 'serverInitialized'); - const spy_listener2_shutdown = sinon.spy(listener2, 'serverShutDown'); + let spy_listener2_initialize: MockInstance; + let spy_listener2_shutdown: MockInstance; container.load( new ContainerModule(bind => { @@ -61,12 +60,13 @@ describe('test DefaultGLSPServer', () => { const glspServer = container.resolve(DefaultGLSPServer); beforeEach(() => { - spy_sessionManager_getOrCreate.restore(); - spy_sessionManager_dispose.restore(); - spy_listener1_initialize.restore(); - spy_listener1_shutdown.restore(); - spy_listener2_initialize.restore(); - spy_listener2_shutdown.restore(); + vi.restoreAllMocks(); + spy_sessionManager_getOrCreate = vi.spyOn(sessionManager, 'getOrCreateClientSession'); + spy_sessionManager_dispose = vi.spyOn(sessionManager, 'disposeClientSession'); + spy_listener1_initialize = vi.spyOn(listener1, 'serverInitialized'); + spy_listener1_shutdown = vi.spyOn(listener1, 'serverShutDown'); + spy_listener2_initialize = vi.spyOn(listener2, 'serverInitialized'); + spy_listener2_shutdown = vi.spyOn(listener2, 'serverShutDown'); }); it('Test calls before server initialization (should throw errors)', async () => { @@ -78,26 +78,26 @@ describe('test DefaultGLSPServer', () => { it('addListener - add existing listener', () => { const originalSize = glspServer['serverListeners'].length; glspServer.addListener(listener1); - expect(glspServer['serverListeners'].length).to.be.equal(originalSize); + expect(glspServer['serverListeners'].length).toBe(originalSize); }); it('addListener - add new listener', () => { const originalSize = glspServer['serverListeners'].length; glspServer.addListener(listener2); - expect(glspServer['serverListeners']).to.include(listener2); - expect(glspServer['serverListeners'].length).to.be.equal(originalSize + 1); + expect(glspServer['serverListeners']).toContain(listener2); + expect(glspServer['serverListeners'].length).toBe(originalSize + 1); }); it('removeListener - remove non-existing listener', () => { const originalSize = glspServer['serverListeners'].length; glspServer.removeListener({}); - expect(glspServer['serverListeners'].length).to.be.equal(originalSize); + expect(glspServer['serverListeners'].length).toBe(originalSize); }); it('removeListener - remove existing listener', () => { const originalSize = glspServer['serverListeners'].length; glspServer.removeListener(listener2); - expect(glspServer['serverListeners'].length).to.be.equal(originalSize - 1); + expect(glspServer['serverListeners'].length).toBe(originalSize - 1); }); it('initialize - with wrong protocol version', async () => { @@ -108,19 +108,19 @@ describe('test DefaultGLSPServer', () => { it('initialize - with correct parameters', async () => { const initializeParameters: InitializeParameters = { applicationId, protocolVersion }; const result = await glspServer.initialize(initializeParameters); - expect(result.protocolVersion).to.be.equal(protocolVersion); - expect(result.serverActions[diagramType]).to.be.equal(actionKinds.get(diagramType)); - expect(result.serverActions[diagramType]).to.be.equal(actionKinds.get(diagramType)); - expect(spy_listener1_initialize.calledWith(glspServer)); - expect(spy_listener2_initialize.notCalled); + expect(result.protocolVersion).toBe(protocolVersion); + expect(result.serverActions[diagramType]).toBe(actionKinds.get(diagramType)); + expect(result.serverActions[diagramType]).toBe(actionKinds.get(diagramType)); + expect(spy_listener1_initialize).toHaveBeenCalledWith(glspServer); + expect(spy_listener2_initialize).not.toHaveBeenCalled(); }); it('initialize - subsequent call with same parameters', async () => { const initializeParameters: InitializeParameters = { applicationId, protocolVersion }; const result = await glspServer.initialize(initializeParameters); - expect(result.protocolVersion).to.be.equal(protocolVersion); - expect(result.serverActions[diagramType]).to.be.equal(actionKinds.get(diagramType)); - expect(result.serverActions[diagramType]).to.be.equal(actionKinds.get(diagramType)); + expect(result.protocolVersion).toBe(protocolVersion); + expect(result.serverActions[diagramType]).toBe(actionKinds.get(diagramType)); + expect(result.serverActions[diagramType]).toBe(actionKinds.get(diagramType)); }); it('initialize - subsequent call with other parameters', async () => { @@ -135,7 +135,7 @@ describe('test DefaultGLSPServer', () => { clientActionKinds: [] }; await glspServer.initializeClientSession(initializeClientSessionParameters); - expect(spy_sessionManager_getOrCreate.calledWith(initializeClientSessionParameters)); + expect(spy_sessionManager_getOrCreate).toHaveBeenCalledWith(initializeClientSessionParameters); }); it('dispose client session', async () => { @@ -143,12 +143,12 @@ describe('test DefaultGLSPServer', () => { clientSessionId }; await glspServer.disposeClientSession(disposeClientSessionParameters); - expect(spy_sessionManager_dispose.calledWith(clientSessionId)); + expect(spy_sessionManager_dispose).toHaveBeenCalledWith(clientSessionId); }); it('shutdown server', async () => { glspServer.shutdown(); - expect(spy_listener1_shutdown.calledWith(glspServer)); - expect(spy_listener2_shutdown.notCalled); + expect(spy_listener1_shutdown).toHaveBeenCalledWith(glspServer); + expect(spy_listener2_shutdown).not.toHaveBeenCalled(); }); }); diff --git a/packages/server/src/common/session/client-session-factory.spec.ts b/packages/server/src/common/session/client-session-factory.spec.ts index b015c008..a4b95cf3 100644 --- a/packages/server/src/common/session/client-session-factory.spec.ts +++ b/packages/server/src/common/session/client-session-factory.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ import { GLSPClientProxy } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { Container, ContainerModule } from 'inversify'; import { ActionDispatcher } from '../actions/action-dispatcher'; import { DiagramModules, InjectionContainer } from '../di/service-identifiers'; @@ -48,13 +48,13 @@ describe('test DefaultClientSessionFactory', () => { it('create - new client session', () => { const session = factory.create({ clientSessionId, diagramType, clientActionKinds: [] }); - expect(session.id).to.be.equal(clientSessionId); - expect(session.diagramType).to.be.equal(diagramType); - expect(session.container.parent).to.be.equal(container); - expect(session.actionDispatcher).to.be.an.instanceOf(mock.StubActionDispatcher); + expect(session.id).toBe(clientSessionId); + expect(session.diagramType).toBe(diagramType); + expect(session.container.parent).toBe(container); + expect(session.actionDispatcher).toBeInstanceOf(mock.StubActionDispatcher); }); it('create - unknown diagram type', () => { - expect(() => factory.create({ clientSessionId, diagramType: 'unknown-type', clientActionKinds: [] })).to.throw(GLSPServerError); + expect(() => factory.create({ clientSessionId, diagramType: 'unknown-type', clientActionKinds: [] })).toThrow(GLSPServerError); }); }); diff --git a/packages/server/src/common/session/client-session-manager.spec.ts b/packages/server/src/common/session/client-session-manager.spec.ts index 0e79b751..172daf44 100644 --- a/packages/server/src/common/session/client-session-manager.spec.ts +++ b/packages/server/src/common/session/client-session-manager.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,9 +13,8 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { Container, ContainerModule } from 'inversify'; -import * as sinon from 'sinon'; import * as mock from '../test/mock-util'; import { Logger } from '../utils/logger'; import { ClientSessionFactory } from './client-session-factory'; @@ -26,7 +25,10 @@ describe('test DefaultClientSessionManager', () => { const testSessionListener = new mock.StubClientSessionListener(); const sessionFactory = new mock.StubClientSessionFactory(); - sinon.stub(sessionFactory, 'create').returns(testSession); + + beforeEach(() => { + vi.spyOn(sessionFactory, 'create').mockReturnValue(testSession); + }); const container = new Container(); container.load( @@ -43,41 +45,41 @@ describe('test DefaultClientSessionManager', () => { it('add create client session', () => { // Mock setup - const listener_create = sinon.spy(testSessionListener, 'sessionCreated'); + const listener_create = vi.spyOn(testSessionListener, 'sessionCreated'); // Test execution const createdSession = sessionManager.getOrCreateClientSession({ clientSessionId: testSession.id, diagramType: testSession.diagramType, clientActionKinds: [] }); - expect(createdSession).to.not.be.undefined; - expect(createdSession.id).to.be.equal(testSession.id); - expect(createdSession.diagramType).to.be.equal(testSession.diagramType); + expect(createdSession).toBeDefined(); + expect(createdSession.id).toBe(testSession.id); + expect(createdSession.diagramType).toBe(testSession.diagramType); const retrievedSession = sessionManager.getSession(testSession.id); - expect(retrievedSession).to.not.be.undefined; - expect(retrievedSession).to.be.equal(createdSession); - expect(listener_create.calledWith(testSession)); + expect(retrievedSession).toBeDefined(); + expect(retrievedSession).toBe(createdSession); + expect(listener_create).toHaveBeenCalledWith(testSession); }); it('get sessions by type', () => { const clientSessions = sessionManager.getSessionsByType(testSession.diagramType); - expect(clientSessions.length).to.be.equal(1); - expect(clientSessions[0]).to.be.equal(testSession); + expect(clientSessions.length).toBe(1); + expect(clientSessions[0]).toBe(testSession); }); it('get sessions by type that does no exist', async () => { const clientSessions = sessionManager.getSessionsByType('wrongType'); - expect(clientSessions.length).to.be.equal(0); + expect(clientSessions.length).toBe(0); }); it('dispose client session', () => { // Mock setup - const listener_dispose = sinon.spy(testSessionListener, 'sessionDisposed'); + const listener_dispose = vi.spyOn(testSessionListener, 'sessionDisposed'); // Test execution - expect(sessionManager.disposeClientSession(testSession.id)).to.be.equal(true); + expect(sessionManager.disposeClientSession(testSession.id)).toBe(true); const session = sessionManager.getSession(testSession.id); - expect(session).to.be.undefined; - expect(listener_dispose.calledWith(testSession)); + expect(session).toBeUndefined(); + expect(listener_dispose).toHaveBeenCalledWith(testSession); }); }); diff --git a/packages/server/src/common/test/mock-util.ts b/packages/server/src/common/test/mock-util.ts index 0c75796b..90192c2e 100644 --- a/packages/server/src/common/test/mock-util.ts +++ b/packages/server/src/common/test/mock-util.ts @@ -36,12 +36,10 @@ import { ShapeTypeHint, ValidationStatus } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; import { Container } from 'inversify'; import { MessageConnection } from 'vscode-jsonrpc'; import { ActionDispatcher } from '../actions/action-dispatcher'; -import { ActionHandler, ActionHandlerFactory } from '../actions/action-handler'; -import { Command } from '../command/command'; +import { ActionHandler } from '../actions/action-handler'; import { DiagramConfiguration, ServerLayoutKind } from '../diagram/diagram-configuration'; import { ContextEditValidator } from '../features/directediting/context-edit-validator'; import { LabelEditValidator } from '../features/directediting/label-edit-validator'; @@ -58,25 +56,6 @@ export async function delay(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } -/** - * Consumes a maybe async function and checks for error - * @param method - The function to check - * @param message - Optional message to match with error message - */ -export async function expectToThrowAsync(toEvaluate: () => MaybePromise, message?: string): Promise { - let err: Error | undefined = undefined; - try { - await toEvaluate(); - } catch (error: any) { - err = error; - } - if (message) { - expect(err?.message).to.be.equal(message); - } else { - expect(err).to.be.an('Error'); - } -} - export function createClientSession( id: string, diagramType: string, @@ -267,15 +246,6 @@ export class TestContextEditValidator implements ContextEditValidator { } } -export const stubActionHandlerFactory: ActionHandlerFactory = constructor => new constructor(); - export class StubClientSessionInitializer implements ClientSessionInitializer { initialize(args?: Args): void {} } - -export class StubCommand implements Command { - execute(): void {} - undo(): void {} - redo(): void {} - canUndo?(): boolean; -} diff --git a/packages/server/src/common/utils/action-queue.spec.ts b/packages/server/src/common/utils/action-queue.spec.ts index 86ae4825..31f52f0d 100644 --- a/packages/server/src/common/utils/action-queue.spec.ts +++ b/packages/server/src/common/utils/action-queue.spec.ts @@ -13,8 +13,7 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; -import { expectToThrowAsync } from '../test/mock-util'; +import { describe, expect, it } from 'vitest'; import { ActionQueue } from './action-queue'; describe('ActionQueue', () => { @@ -33,7 +32,7 @@ describe('ActionQueue', () => { channel.stop(); await consumer; - expect(consumed).to.deep.equal([1, 2, 3]); + expect(consumed).toEqual([1, 2, 3]); }); it('resolves the push promise once the consumer resolves the entry', async () => { @@ -51,7 +50,7 @@ describe('ActionQueue', () => { // Give the consumer a turn to pick up the entry. await Promise.resolve(); await consumer; - expect(entryResolver).to.exist; + expect(entryResolver).toBeDefined(); entryResolver!(); await pushed; }); @@ -68,13 +67,13 @@ describe('ActionQueue', () => { const pushed = channel.push(1); await consumer; - await expectToThrowAsync(() => pushed, 'boom'); + await expect(pushed).rejects.toThrow('boom'); }); it('rejects push() after stop()', async () => { const channel = new ActionQueue(); channel.stop(); - await expectToThrowAsync(() => channel.push(1), 'ActionQueue is stopped'); + await expect(channel.push(1)).rejects.toThrow('ActionQueue is stopped'); }); it('consumer exits after stop() and drain', async () => { @@ -93,21 +92,21 @@ describe('ActionQueue', () => { channel.stop(); await consumer; - expect(consumed).to.deep.equal([1, 2]); - expect(channel.isStopped).to.be.true; + expect(consumed).toEqual([1, 2]); + expect(channel.isStopped).toBe(true); }); it('rejectPending() rejects all queued push() promises without stopping', async () => { const channel = new ActionQueue(); const pushes = [channel.push(1), channel.push(2)]; - expect(channel.size).to.equal(2); + expect(channel.size).toBe(2); channel.rejectPending(new Error('cleared')); - await expectToThrowAsync(() => pushes[0], 'cleared'); - await expectToThrowAsync(() => pushes[1], 'cleared'); - expect(channel.size).to.equal(0); - expect(channel.isStopped).to.be.false; + await expect(pushes[0]).rejects.toThrow('cleared'); + await expect(pushes[1]).rejects.toThrow('cleared'); + expect(channel.size).toBe(0); + expect(channel.isStopped).toBe(false); }); it('size reflects the number of unconsumed entries', async () => { @@ -115,7 +114,7 @@ describe('ActionQueue', () => { channel.push(1); channel.push(2); channel.push(3); - expect(channel.size).to.equal(3); + expect(channel.size).toBe(3); }); it('throws when a second consumer is started', async () => { @@ -125,7 +124,7 @@ describe('ActionQueue', () => { const firstStep = first.next(); const second = channel.consume(); - await expectToThrowAsync(() => second.next().then(() => undefined), 'ActionQueue supports only a single consumer'); + await expect(second.next()).rejects.toThrow('ActionQueue supports only a single consumer'); channel.stop(); await firstStep; diff --git a/packages/server/src/common/utils/promise-queue.spec.ts b/packages/server/src/common/utils/promise-queue.spec.ts index ef195fca..9c64bd9e 100644 --- a/packages/server/src/common/utils/promise-queue.spec.ts +++ b/packages/server/src/common/utils/promise-queue.spec.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { delay } from '../test/mock-util'; -import { expect } from 'chai'; +import { beforeEach, describe, expect, it } from 'vitest'; // eslint-disable-next-line import-x/no-deprecated import { PromiseQueue } from './promise-queue'; @@ -108,7 +108,7 @@ describe('test PromiseQueue', () => { queue.enqueue(p1.promise); const queEnd = queue.enqueue(p2.promise); - expect(queue.size).to.be.equal(1); + expect(queue.size).toBe(1); await queEnd; }); @@ -121,7 +121,7 @@ describe('test PromiseQueue', () => { const p2 = newTestPromise(200); p2.state.onStart(() => { - expect(queue.size).to.be.equal(1); + expect(queue.size).toBe(1); expect(p1.state.stopped).true; expect(p3.state.started).false; }); @@ -134,9 +134,9 @@ describe('test PromiseQueue', () => { queue.enqueue(p1.promise); queue.enqueue(p2.promise); - expect(queue.size).to.be.equal(1); + expect(queue.size).toBe(1); const queueEnd = queue.enqueue(p3.promise); - expect(queue.size).to.be.equal(2); + expect(queue.size).toBe(2); await queueEnd; }); }); diff --git a/packages/server/src/common/utils/registry.spec.ts b/packages/server/src/common/utils/registry.spec.ts index ba35333e..5e08ee2e 100644 --- a/packages/server/src/common/utils/registry.spec.ts +++ b/packages/server/src/common/utils/registry.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,7 +13,7 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { beforeEach, describe, expect, it } from 'vitest'; import { NullLogger } from './logger'; import { MultiRegistry, Registry } from './registry'; @@ -92,7 +92,7 @@ describe('Test Registry', () => { registry.register(e3.key, e3.value); // Test execution const result = registry.getAll(); - expect(result).to.have.length(3); + expect(result).toHaveLength(3); expect(result.includes(e1.value)).true; expect(result.includes(e2.value)).true; expect(result.includes(e3.value)).true; @@ -108,7 +108,7 @@ describe('Test Registry', () => { registry.register(e3.key, e3.value); // Test execution const result = registry.keys(); - expect(result).to.have.length(3); + expect(result).toHaveLength(3); expect(result.includes(e1.key)).true; expect(result.includes(e2.key)).true; expect(result.includes(e3.key)).true; @@ -131,8 +131,8 @@ describe('Test MapMultiRegistry', () => { multiRegistry.register(e2.key, e2.value); const resultValue = multiRegistry.get(e1.key); - expect(resultValue).to.not.be.undefined; - expect(resultValue!.length).to.be.equal(2); + expect(resultValue).toBeDefined(); + expect(resultValue!.length).toBe(2); expect(resultValue!.includes(e1.value)).true; expect(resultValue!.includes(e2.value)).true; }); @@ -146,7 +146,7 @@ describe('Test MapMultiRegistry', () => { // Test execution expect(multiRegistry.deregister(key, existingValue[1])).true; const result = multiRegistry.get(key); - expect(result.length).to.be.equal(1); + expect(result.length).toBe(1); expect(result[0], existingValue[0]); }); @@ -161,7 +161,7 @@ describe('Test MapMultiRegistry', () => { multiRegistry.register(key, existingValue[0]); multiRegistry.register(key, existingValue[1]); expect(multiRegistry.deregisterAll(key)).true; - expect(multiRegistry.get(key)).to.have.length(0); + expect(multiRegistry.get(key)).toHaveLength(0); }); it('deregisterAll - with unregistered key', () => { @@ -187,12 +187,12 @@ describe('Test MapMultiRegistry', () => { const existingValue = 'value'; multiRegistry.register(key, existingValue); // Test execution - expect(multiRegistry.get(key).length).to.be.equal(1); + expect(multiRegistry.get(key).length).toBe(1); expect(multiRegistry.get(key).includes(existingValue)).true; }); it('get - with unregistered key', () => { - expect(multiRegistry.get('unregisteredKey')).to.have.length(0); + expect(multiRegistry.get('unregisteredKey')).toHaveLength(0); }); it('getAll', () => { @@ -204,7 +204,7 @@ describe('Test MapMultiRegistry', () => { multiRegistry.register(e2.key, e2.value[0]); // Test execution const result = multiRegistry.getAll(); - expect(result).to.have.length(3); + expect(result).toHaveLength(3); expect(e1.value.every(v => result.includes(v))).true; expect(e2.value.every(v => result.includes(v))).true; }); @@ -218,7 +218,7 @@ describe('Test MapMultiRegistry', () => { multiRegistry.register(e2.key, e2.value[0]); // Test execution const result = multiRegistry.keys(); - expect(result.length).to.be.equal(2); + expect(result.length).toBe(2); expect(result.includes(e1.key)).true; expect(result.includes(e2.key)).true; }); diff --git a/packages/server/src/node/actions/action-dispatcher.spec.ts b/packages/server/src/node/actions/action-dispatcher.spec.ts index eba984d7..d5e6fd6d 100644 --- a/packages/server/src/node/actions/action-dispatcher.spec.ts +++ b/packages/server/src/node/actions/action-dispatcher.spec.ts @@ -14,9 +14,8 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ import { Action, Deferred, RejectAction, RequestAction, ResponseAction, UpdateModelAction } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; +import { beforeEach, describe, expect, it, vi, type MockInstance } from 'vitest'; import { Container, ContainerModule } from 'inversify'; -import * as sinon from 'sinon'; import { ActionDispatchScope, DefaultActionDispatcher } from '../../common/actions/action-dispatcher'; import { ActionHandler } from '../../common/actions/action-handler'; import { ActionHandlerRegistry } from '../../common/actions/action-handler-registry'; @@ -39,10 +38,12 @@ describe('test DefaultActionDispatcher', () => { const container = new Container(); const clientId = 'myClientId'; const actionHandlerRegistry = new ActionHandlerRegistry(); - let registry_get_stub: sinon.SinonStub<[string], ActionHandler[]>; - const sandbox = sinon.createSandbox(); + let registry_get_stub: MockInstance<(kind: string) => ActionHandler[]>; - const clientActionForwarderStub = sinon.createStubInstance(ClientActionForwarder); + const clientActionForwarderStub = { + shouldForwardToClient: vi.fn(), + handle: vi.fn() + } as unknown as ClientActionForwarder; container.load( new ContainerModule(bind => { @@ -58,16 +59,12 @@ describe('test DefaultActionDispatcher', () => { const actionDispatcher = container.resolve(DefaultActionDispatcher); beforeEach(() => { - registry_get_stub = sandbox.stub(actionHandlerRegistry, 'get'); - }); - - afterEach(() => { - sandbox.restore(); + registry_get_stub = vi.spyOn(actionHandlerRegistry, 'get'); }); describe('test with one-way actions (no response actions)', () => { it('dispatch- unhandled action', async () => { - mock.expectToThrowAsync(() => actionDispatcher.dispatch({ kind: 'unhandled' })); + await expect(actionDispatcher.dispatch({ kind: 'unhandled' })).rejects.toThrow(); }); it('dispatch - one action', async () => { @@ -75,11 +72,11 @@ describe('test DefaultActionDispatcher', () => { const action = 'action'; const handler = new mock.StubActionHandler([action]); const getHandler = (kind: string): ActionHandler[] => (kind === action ? [handler] : []); - registry_get_stub.callsFake(getHandler); - const spy_handler_execute = sinon.spy(handler, 'execute'); + registry_get_stub.mockImplementation(getHandler); + const spy_handler_execute = vi.spyOn(handler, 'execute'); // Test execution await actionDispatcher.dispatch({ kind: action }); - expect(spy_handler_execute.calledOnce).true; + expect(spy_handler_execute).toHaveBeenCalledOnce(); }); describe('test multi dispatch with single-handled actions', () => { @@ -92,15 +89,15 @@ describe('test DefaultActionDispatcher', () => { const handler2 = new mock.StubActionHandler([action2]); const handler3 = new mock.StubActionHandler([action3]); - const spy_handler1_execute = sinon.stub(handler1, 'execute').returns([]); - const spy_handler2_execute = sinon.stub(handler2, 'execute').returns([]); - const spy_handler3_execute = sinon.stub(handler3, 'execute').returns([]); - // Stubs created at the describe-level survive sandbox.restore(), so call counts - // would accumulate across tests and break `.calledOnce` assertions. + let spy_handler1_execute: MockInstance; + let spy_handler2_execute: MockInstance; + let spy_handler3_execute: MockInstance; + // restoreMocks: true (from the shared Vitest preset) restores these spies between tests, + // dropping the mockReturnValue setup, so they have to be re-created here before each test. beforeEach(() => { - spy_handler1_execute.resetHistory(); - spy_handler2_execute.resetHistory(); - spy_handler3_execute.resetHistory(); + spy_handler1_execute = vi.spyOn(handler1, 'execute').mockReturnValue([]); + spy_handler2_execute = vi.spyOn(handler2, 'execute').mockReturnValue([]); + spy_handler3_execute = vi.spyOn(handler3, 'execute').mockReturnValue([]); }); const handlerMockImpl = (kind: string): ActionHandler[] => { switch (kind) { @@ -117,44 +114,46 @@ describe('test DefaultActionDispatcher', () => { it('dispatch - multiple actions', async () => { // Mock setup - registry_get_stub.callsFake(handlerMockImpl); + registry_get_stub.mockImplementation(handlerMockImpl); // Test execution actionDispatcher.dispatch({ kind: action1 }); actionDispatcher.dispatch({ kind: action2 }); await actionDispatcher.dispatch({ kind: action3 }); // Check if all handlers have been called - expect(spy_handler1_execute.called).true; - expect(spy_handler2_execute.called).true; - expect(spy_handler3_execute.called).true; + expect(spy_handler1_execute).toHaveBeenCalled(); + expect(spy_handler2_execute).toHaveBeenCalled(); + expect(spy_handler3_execute).toHaveBeenCalled(); // Check if all handlers have been called in the right order - sinon.assert.callOrder(spy_handler1_execute, spy_handler2_execute, spy_handler3_execute); + expect(spy_handler1_execute.mock.invocationCallOrder[0]).toBeLessThan(spy_handler2_execute.mock.invocationCallOrder[0]); + expect(spy_handler2_execute.mock.invocationCallOrder[0]).toBeLessThan(spy_handler3_execute.mock.invocationCallOrder[0]); }); it('dispatchAll- multiple actions', async () => { // Mock setup - registry_get_stub.callsFake(handlerMockImpl); + registry_get_stub.mockImplementation(handlerMockImpl); // Test execution await actionDispatcher.dispatchAll([{ kind: action1 }, { kind: action2 }, { kind: action3 }]); // Check if all handlers have been called - expect(spy_handler1_execute.calledOnce).to.be.true; - expect(spy_handler2_execute.calledOnce).to.be.true; - expect(spy_handler3_execute.calledOnce).to.be.true; + expect(spy_handler1_execute).toHaveBeenCalledOnce(); + expect(spy_handler2_execute).toHaveBeenCalledOnce(); + expect(spy_handler3_execute).toHaveBeenCalledOnce(); // Check if all handlers have been called in the right order - sinon.assert.callOrder(spy_handler1_execute, spy_handler2_execute, spy_handler3_execute); + expect(spy_handler1_execute.mock.invocationCallOrder[0]).toBeLessThan(spy_handler2_execute.mock.invocationCallOrder[0]); + expect(spy_handler2_execute.mock.invocationCallOrder[0]).toBeLessThan(spy_handler3_execute.mock.invocationCallOrder[0]); }); it('dispatch - multiple actions (racing execution times)', async () => { // Mock setup - registry_get_stub.callsFake(handlerMockImpl); - spy_handler1_execute.callsFake((_action: Action) => { + registry_get_stub.mockImplementation(handlerMockImpl); + spy_handler1_execute.mockImplementation((_action: Action) => { waitSync(500); return []; }); - spy_handler2_execute.callsFake((_action: Action) => { + spy_handler2_execute.mockImplementation((_action: Action) => { waitSync(200); return []; }); - spy_handler3_execute.callsFake((_action: Action) => { + spy_handler3_execute.mockImplementation((_action: Action) => { waitSync(100); return []; }); @@ -163,11 +162,12 @@ describe('test DefaultActionDispatcher', () => { actionDispatcher.dispatch({ kind: action2 }); await actionDispatcher.dispatch({ kind: action3 }); // Check if all handlers have been called - expect(spy_handler1_execute.calledOnce).to.be.true; - expect(spy_handler2_execute.calledOnce).to.be.true; - expect(spy_handler3_execute.calledOnce).to.be.true; + expect(spy_handler1_execute).toHaveBeenCalledOnce(); + expect(spy_handler2_execute).toHaveBeenCalledOnce(); + expect(spy_handler3_execute).toHaveBeenCalledOnce(); // Check if all handlers have been called in the right order - sinon.assert.callOrder(spy_handler1_execute, spy_handler2_execute, spy_handler3_execute); + expect(spy_handler1_execute.mock.invocationCallOrder[0]).toBeLessThan(spy_handler2_execute.mock.invocationCallOrder[0]); + expect(spy_handler2_execute.mock.invocationCallOrder[0]).toBeLessThan(spy_handler3_execute.mock.invocationCallOrder[0]); }); }); @@ -178,14 +178,14 @@ describe('test DefaultActionDispatcher', () => { const handler1 = new mock.StubActionHandler([action1]); const handler2 = new mock.StubActionHandler([action1]); - registry_get_stub.callsFake((kind: string) => (kind === action1 ? [handler1, handler2] : [])); - const spy_handler1_execute = sinon.spy(handler1, 'execute'); - const spy_handler2_execute = sinon.spy(handler2, 'execute'); + registry_get_stub.mockImplementation((kind: string) => (kind === action1 ? [handler1, handler2] : [])); + const spy_handler1_execute = vi.spyOn(handler1, 'execute'); + const spy_handler2_execute = vi.spyOn(handler2, 'execute'); // Test execution await actionDispatcher.dispatch({ kind: action1 }); - expect(spy_handler1_execute.calledOnce).to.be.true; - expect(spy_handler2_execute.calledOnce).to.be.true; - sinon.assert.callOrder(spy_handler1_execute, spy_handler2_execute); + expect(spy_handler1_execute).toHaveBeenCalledOnce(); + expect(spy_handler2_execute).toHaveBeenCalledOnce(); + expect(spy_handler1_execute.mock.invocationCallOrder[0]).toBeLessThan(spy_handler2_execute.mock.invocationCallOrder[0]); }); }); @@ -198,9 +198,9 @@ describe('test DefaultActionDispatcher', () => { const requestHandler = new mock.StubActionHandler([request]); const responseHandler = new mock.StubActionHandler([response]); - const spy_requestHandler_execute = sinon.stub(requestHandler, 'execute').returns([{ kind: response }]); - const spy_responseHandler_execute = sinon.spy(responseHandler, 'execute'); - registry_get_stub.callsFake((kind: string) => { + const spy_requestHandler_execute = vi.spyOn(requestHandler, 'execute').mockReturnValue([{ kind: response }]); + const spy_responseHandler_execute = vi.spyOn(responseHandler, 'execute'); + registry_get_stub.mockImplementation((kind: string) => { switch (kind) { case request: return [requestHandler]; @@ -215,8 +215,8 @@ describe('test DefaultActionDispatcher', () => { // Add a delay so that the action dispatcher has time to dispatch the handler response await mock.delay(200); // Check if all handlers have been called - expect(spy_requestHandler_execute.calledOnce).to.be.true; - expect(spy_responseHandler_execute.calledOnce).to.be.true; + expect(spy_requestHandler_execute).toHaveBeenCalledOnce(); + expect(spy_responseHandler_execute).toHaveBeenCalledOnce(); }); it('dispatch - multiple actions & multiple response', async () => { @@ -231,11 +231,13 @@ describe('test DefaultActionDispatcher', () => { const requestHandler1 = new mock.StubActionHandler([request1]); const requestHandler2 = new mock.StubActionHandler([request2]); - const spy_requestHandler1_execute = sinon.stub(requestHandler1, 'execute').returns([{ kind: response1 }, { kind: response2 }]); - const spy_requestHandler2_execute = sinon.stub(requestHandler2, 'execute').returns([{ kind: response2 }]); - const spy_responseHandler1_execute = sinon.spy(responseHandler1, 'execute'); - const spy_responseHandler2_execute = sinon.spy(responseHandler2, 'execute'); - registry_get_stub.callsFake((kind: string) => { + const spy_requestHandler1_execute = vi + .spyOn(requestHandler1, 'execute') + .mockReturnValue([{ kind: response1 }, { kind: response2 }]); + const spy_requestHandler2_execute = vi.spyOn(requestHandler2, 'execute').mockReturnValue([{ kind: response2 }]); + const spy_responseHandler1_execute = vi.spyOn(responseHandler1, 'execute'); + const spy_responseHandler2_execute = vi.spyOn(responseHandler2, 'execute'); + registry_get_stub.mockImplementation((kind: string) => { switch (kind) { case request1: return [requestHandler1]; @@ -256,13 +258,17 @@ describe('test DefaultActionDispatcher', () => { // Add a delay so that the action dispatcher has time to dispatch the handler response await mock.delay(100); // Check if all handlers have been called correctly - expect(spy_requestHandler1_execute.calledOnce).to.be.true; - expect(spy_requestHandler2_execute.calledOnce).to.be.true; - expect(spy_responseHandler1_execute.calledOnce).to.be.true; - expect(spy_responseHandler2_execute.calledThrice).to.be.true; + expect(spy_requestHandler1_execute).toHaveBeenCalledOnce(); + expect(spy_requestHandler2_execute).toHaveBeenCalledOnce(); + expect(spy_responseHandler1_execute).toHaveBeenCalledOnce(); + expect(spy_responseHandler2_execute).toHaveBeenCalledTimes(3); // Check if all handlers have been called in the right order - sinon.assert.callOrder(spy_requestHandler1_execute, spy_requestHandler2_execute); - sinon.assert.callOrder(spy_responseHandler1_execute, spy_responseHandler2_execute); + expect(spy_requestHandler1_execute.mock.invocationCallOrder[0]).toBeLessThan( + spy_requestHandler2_execute.mock.invocationCallOrder[0] + ); + expect(spy_responseHandler1_execute.mock.invocationCallOrder[0]).toBeLessThan( + spy_responseHandler2_execute.mock.invocationCallOrder[0] + ); }); }); @@ -284,19 +290,19 @@ describe('test DefaultActionDispatcher', () => { return []; }; - registry_get_stub.callsFake(getHandler); - const spy_postUpdateHandler_execute = sinon.spy(postUpdateHandler, 'execute'); + registry_get_stub.mockImplementation(getHandler); + const spy_postUpdateHandler_execute = vi.spyOn(postUpdateHandler, 'execute'); // Test execution actionDispatcher.dispatchAfterNextUpdate({ kind: postUpdateAction }); - expect(spy_postUpdateHandler_execute.called).to.be.false; + expect(spy_postUpdateHandler_execute).not.toHaveBeenCalled(); await actionDispatcher.dispatch({ kind: intermediateAction }); - expect(spy_postUpdateHandler_execute.called).to.be.false; + expect(spy_postUpdateHandler_execute).not.toHaveBeenCalled(); await actionDispatcher.dispatch(updateModelAction); - expect(spy_postUpdateHandler_execute.calledOnce).to.be.true; + expect(spy_postUpdateHandler_execute).toHaveBeenCalledOnce(); // Check that action does not get dispatched again await actionDispatcher.dispatch(updateModelAction); - expect(spy_postUpdateHandler_execute.calledOnce).to.be.true; + expect(spy_postUpdateHandler_execute).toHaveBeenCalledOnce(); }); }); @@ -312,15 +318,15 @@ describe('test DefaultActionDispatcher', () => { }; // Configure forwarder: testRequest is forwarded to the client - clientActionForwarderStub.shouldForwardToClient.callsFake(action => action.kind === 'testRequest'); - clientActionForwarderStub.handle.callsFake(action => action.kind === 'testRequest'); - registry_get_stub.callsFake(() => []); + vi.mocked(clientActionForwarderStub.shouldForwardToClient).mockImplementation(action => action.kind === 'testRequest'); + vi.mocked(clientActionForwarderStub.handle).mockImplementation(action => action.kind === 'testRequest'); + registry_get_stub.mockImplementation(() => []); const responsePromise = actionDispatcher.request(requestAction); await actionDispatcher.dispatch(responseAction); const result = await responsePromise; - expect(result.responseId).to.equal('req_1'); + expect(result.responseId).toBe('req_1'); }); it('request - response bypasses queue even when queue is busy', async () => { @@ -333,8 +339,8 @@ describe('test DefaultActionDispatcher', () => { responseId: 'req_deadlock' }; - clientActionForwarderStub.shouldForwardToClient.callsFake(action => action.kind === 'testRequest'); - clientActionForwarderStub.handle.callsFake(action => action.kind === 'testRequest'); + vi.mocked(clientActionForwarderStub.shouldForwardToClient).mockImplementation(action => action.kind === 'testRequest'); + vi.mocked(clientActionForwarderStub.handle).mockImplementation(action => action.kind === 'testRequest'); const handlerRunning = new Deferred(); @@ -344,10 +350,10 @@ describe('test DefaultActionDispatcher', () => { const resultPromise = actionDispatcher.request(requestAction); handlerRunning.resolve(); const result = await resultPromise; - expect(result.responseId).to.equal('req_deadlock'); + expect(result.responseId).toBe('req_deadlock'); return []; }; - registry_get_stub.callsFake((kind: string) => (kind === slowAction ? [slowHandler] : [])); + registry_get_stub.mockImplementation((kind: string) => (kind === slowAction ? [slowHandler] : [])); const dispatchPromise = actionDispatcher.dispatch({ kind: slowAction }); await handlerRunning.promise; @@ -362,11 +368,11 @@ describe('test DefaultActionDispatcher', () => { const localResponseKind = 'localResponse'; const handler = new mock.StubActionHandler([localRequestKind]); - sinon.stub(handler, 'execute').callsFake(() => { + vi.spyOn(handler, 'execute').mockImplementation(() => { const response: ResponseAction = { kind: localResponseKind, responseId: '' }; return [response]; }); - registry_get_stub.callsFake((kind: string) => (kind === localRequestKind ? [handler] : [])); + registry_get_stub.mockImplementation((kind: string) => (kind === localRequestKind ? [handler] : [])); const requestAction: RequestAction = { kind: localRequestKind, @@ -374,8 +380,8 @@ describe('test DefaultActionDispatcher', () => { }; const result = await actionDispatcher.request(requestAction); - expect(result).to.exist; - expect(result.responseId).to.equal(requestAction.requestId); + expect(result).toBeDefined(); + expect(result.responseId).toBe(requestAction.requestId); }); it('request - resolves for locally handled request called from inside a handler', async () => { @@ -384,7 +390,7 @@ describe('test DefaultActionDispatcher', () => { const outerActionKind = 'outerAction'; const innerHandler = new mock.StubActionHandler([innerRequestKind]); - sinon.stub(innerHandler, 'execute').callsFake(() => { + vi.spyOn(innerHandler, 'execute').mockImplementation(() => { const response: ResponseAction = { kind: innerResponseKind, responseId: '' }; return [response]; }); @@ -396,11 +402,11 @@ describe('test DefaultActionDispatcher', () => { requestId: '' }; const result = await actionDispatcher.request(innerRequest); - expect(result).to.exist; + expect(result).toBeDefined(); return []; }; - registry_get_stub.callsFake((kind: string) => { + registry_get_stub.mockImplementation((kind: string) => { if (kind === outerActionKind) return [outerHandler]; if (kind === innerRequestKind) return [innerHandler]; return []; @@ -416,15 +422,15 @@ describe('test DefaultActionDispatcher', () => { requestId: 'req_hard' }; - clientActionForwarderStub.shouldForwardToClient.callsFake(action => action.kind === 'testRequest'); - clientActionForwarderStub.handle.callsFake(action => action.kind === 'testRequest'); - registry_get_stub.callsFake(() => []); + vi.mocked(clientActionForwarderStub.shouldForwardToClient).mockImplementation(action => action.kind === 'testRequest'); + vi.mocked(clientActionForwarderStub.handle).mockImplementation(action => action.kind === 'testRequest'); + registry_get_stub.mockImplementation(() => []); try { await actionDispatcher.requestUntil(requestAction, 100, true); expect.fail('Should have thrown'); } catch (error: unknown) { - expect((error as Error).message).to.include('timed out'); + expect((error as Error).message).toContain('timed out'); } }); @@ -434,12 +440,12 @@ describe('test DefaultActionDispatcher', () => { requestId: 'req_soft' }; - clientActionForwarderStub.shouldForwardToClient.callsFake(action => action.kind === 'testRequest'); - clientActionForwarderStub.handle.callsFake(action => action.kind === 'testRequest'); - registry_get_stub.callsFake(() => []); + vi.mocked(clientActionForwarderStub.shouldForwardToClient).mockImplementation(action => action.kind === 'testRequest'); + vi.mocked(clientActionForwarderStub.handle).mockImplementation(action => action.kind === 'testRequest'); + registry_get_stub.mockImplementation(() => []); const result = await actionDispatcher.requestUntil(requestAction, 100, false); - expect(result).to.be.undefined; + expect(result).toBeUndefined(); }); it('request - auto-generates requestId when empty', async () => { @@ -448,12 +454,12 @@ describe('test DefaultActionDispatcher', () => { requestId: '' }; - clientActionForwarderStub.shouldForwardToClient.callsFake(action => action.kind === 'testRequest'); - clientActionForwarderStub.handle.callsFake(action => action.kind === 'testRequest'); - registry_get_stub.callsFake(() => []); + vi.mocked(clientActionForwarderStub.shouldForwardToClient).mockImplementation(action => action.kind === 'testRequest'); + vi.mocked(clientActionForwarderStub.handle).mockImplementation(action => action.kind === 'testRequest'); + registry_get_stub.mockImplementation(() => []); const responsePromise = actionDispatcher.request(requestAction); - expect(requestAction.requestId).to.match(/^server_.*_\d+$/); + expect(requestAction.requestId).toMatch(/^server_.*_\d+$/); await actionDispatcher.dispatch({ kind: 'testResponse', @@ -461,7 +467,7 @@ describe('test DefaultActionDispatcher', () => { } as ResponseAction); const result = await responsePromise; - expect(result).to.exist; + expect(result).toBeDefined(); }); it('request - rejects when dispatch fails (no handler, not a client action)', async () => { @@ -471,15 +477,15 @@ describe('test DefaultActionDispatcher', () => { }; // NOT forwarded to client, no handler registered → dispatch throws - clientActionForwarderStub.shouldForwardToClient.returns(false); - clientActionForwarderStub.handle.returns(false); - registry_get_stub.callsFake(() => []); + vi.mocked(clientActionForwarderStub.shouldForwardToClient).mockReturnValue(false); + vi.mocked(clientActionForwarderStub.handle).mockReturnValue(false); + registry_get_stub.mockImplementation(() => []); try { await actionDispatcher.request(requestAction); expect.fail('Should have thrown'); } catch (error: unknown) { - expect((error as Error).message).to.include('No handler registered'); + expect((error as Error).message).toContain('No handler registered'); } }); @@ -489,24 +495,24 @@ describe('test DefaultActionDispatcher', () => { requestId: 'req_late' }; - clientActionForwarderStub.shouldForwardToClient.callsFake(action => action.kind === 'testRequest'); - clientActionForwarderStub.handle.callsFake(action => action.kind === 'testRequest'); + vi.mocked(clientActionForwarderStub.shouldForwardToClient).mockImplementation(action => action.kind === 'testRequest'); + vi.mocked(clientActionForwarderStub.handle).mockImplementation(action => action.kind === 'testRequest'); // Register a no-op handler for testResponse so the late response can be dispatched normally const noopHandler = new mock.StubActionHandler(['testResponse']); - registry_get_stub.callsFake((kind: string) => (kind === 'testResponse' ? [noopHandler] : [])); + registry_get_stub.mockImplementation((kind: string) => (kind === 'testResponse' ? [noopHandler] : [])); // Request times out try { await actionDispatcher.requestUntil(requestAction, 50, true); expect.fail('Should have thrown'); } catch (error: unknown) { - expect((error as Error).message).to.include('timed out'); + expect((error as Error).message).toContain('timed out'); } // Late response arrives — responseId should be cleared, dispatched as normal action const lateResponse: ResponseAction = { kind: 'testResponse', responseId: 'req_late' }; await actionDispatcher.dispatch(lateResponse); - expect(lateResponse.responseId).to.equal(''); + expect(lateResponse.responseId).toBe(''); }); it('dispatch - drops a stale ResponseAction with no matching pending request and no handler', async () => { @@ -514,9 +520,9 @@ describe('test DefaultActionDispatcher', () => { // pending request is gone) used to throw "No handler registered" because the dispatcher // tried to route them as regular actions. They are protocol signals, not handler // invocations — `doDispatch` swallows them with a debug log instead. - clientActionForwarderStub.shouldForwardToClient.returns(false); - clientActionForwarderStub.handle.returns(false); - registry_get_stub.callsFake(() => []); + vi.mocked(clientActionForwarderStub.shouldForwardToClient).mockReturnValue(false); + vi.mocked(clientActionForwarderStub.handle).mockReturnValue(false); + registry_get_stub.mockImplementation(() => []); const lateReject = RejectAction.create('late reject', { responseId: 'never-pending' }); @@ -532,13 +538,13 @@ describe('test DefaultActionDispatcher', () => { const responseKind = 'inlineResponse'; const handler = new mock.StubActionHandler([requestKind]); - sinon.stub(handler, 'execute').callsFake(() => [{ kind: responseKind, responseId: '' } as ResponseAction]); - registry_get_stub.callsFake((kind: string) => (kind === requestKind ? [handler] : [])); + vi.spyOn(handler, 'execute').mockImplementation(() => [{ kind: responseKind, responseId: '' } as ResponseAction]); + registry_get_stub.mockImplementation((kind: string) => (kind === requestKind ? [handler] : [])); const requestAction: RequestAction = { kind: requestKind, requestId: '' }; const result = await actionDispatcher.request(requestAction); - expect(result.responseId).to.equal(requestAction.requestId); + expect(result.responseId).toBe(requestAction.requestId); }); }); @@ -551,7 +557,7 @@ describe('test DefaultActionDispatcher', () => { const events: string[] = []; const innerHandler = new mock.StubActionHandler([innerKind]); - sinon.stub(innerHandler, 'execute').callsFake(() => { + vi.spyOn(innerHandler, 'execute').mockImplementation(() => { events.push('inner'); return []; }); @@ -565,12 +571,12 @@ describe('test DefaultActionDispatcher', () => { }; const followerHandler = new mock.StubActionHandler([followerKind]); - sinon.stub(followerHandler, 'execute').callsFake(() => { + vi.spyOn(followerHandler, 'execute').mockImplementation(() => { events.push('follower'); return []; }); - registry_get_stub.callsFake((kind: string) => { + registry_get_stub.mockImplementation((kind: string) => { if (kind === outerKind) return [outerHandler]; if (kind === innerKind) return [innerHandler]; if (kind === followerKind) return [followerHandler]; @@ -580,7 +586,7 @@ describe('test DefaultActionDispatcher', () => { actionDispatcher.dispatch({ kind: outerKind }); await actionDispatcher.dispatch({ kind: followerKind }); - expect(events).to.deep.equal(['outer-start', 'inner', 'outer-end', 'follower']); + expect(events).toEqual(['outer-start', 'inner', 'outer-end', 'follower']); }); it('handler response actions are dispatched in order without an ephemeral queue', async () => { @@ -590,22 +596,22 @@ describe('test DefaultActionDispatcher', () => { const order: string[] = []; const requestHandler = new mock.StubActionHandler([requestKind]); - sinon.stub(requestHandler, 'execute').callsFake(() => [{ kind: firstResponse }, { kind: secondResponse }]); + vi.spyOn(requestHandler, 'execute').mockImplementation(() => [{ kind: firstResponse }, { kind: secondResponse }]); const firstHandler = new mock.StubActionHandler([firstResponse]); - sinon.stub(firstHandler, 'execute').callsFake(async () => { + vi.spyOn(firstHandler, 'execute').mockImplementation(async () => { await mock.delay(20); order.push(firstResponse); return []; }); const secondHandler = new mock.StubActionHandler([secondResponse]); - sinon.stub(secondHandler, 'execute').callsFake(() => { + vi.spyOn(secondHandler, 'execute').mockImplementation(() => { order.push(secondResponse); return []; }); - registry_get_stub.callsFake((kind: string) => { + registry_get_stub.mockImplementation((kind: string) => { if (kind === requestKind) return [requestHandler]; if (kind === firstResponse) return [firstHandler]; if (kind === secondResponse) return [secondHandler]; @@ -613,7 +619,7 @@ describe('test DefaultActionDispatcher', () => { }); await actionDispatcher.dispatch({ kind: requestKind }); - expect(order).to.deep.equal([firstResponse, secondResponse]); + expect(order).toEqual([firstResponse, secondResponse]); }); }); @@ -624,9 +630,9 @@ describe('test DefaultActionDispatcher', () => { requestId: 'req_dispose' }; - clientActionForwarderStub.shouldForwardToClient.callsFake(action => action.kind === 'testRequest'); - clientActionForwarderStub.handle.callsFake(action => action.kind === 'testRequest'); - registry_get_stub.callsFake(() => []); + vi.mocked(clientActionForwarderStub.shouldForwardToClient).mockImplementation(action => action.kind === 'testRequest'); + vi.mocked(clientActionForwarderStub.handle).mockImplementation(action => action.kind === 'testRequest'); + registry_get_stub.mockImplementation(() => []); const responsePromise = actionDispatcher.request(requestAction); actionDispatcher.dispose(); @@ -635,8 +641,8 @@ describe('test DefaultActionDispatcher', () => { await responsePromise; expect.fail('Should have thrown'); } catch (error: unknown) { - expect((error as Error).message).to.include('cancelled'); - expect((error as Error).message).to.include('req_dispose'); + expect((error as Error).message).toContain('cancelled'); + expect((error as Error).message).toContain('req_dispose'); } }); @@ -655,7 +661,7 @@ describe('test DefaultActionDispatcher', () => { return []; }; - registry_get_stub.callsFake((kind: string) => (kind === slowKind ? [slowHandler] : [])); + registry_get_stub.mockImplementation((kind: string) => (kind === slowKind ? [slowHandler] : [])); const slowPromise = localDispatcher.dispatch({ kind: slowKind }); await slowStarted.promise; @@ -667,7 +673,7 @@ describe('test DefaultActionDispatcher', () => { await queuedPromise; expect.fail('Queued dispatch should have rejected'); } catch (error: unknown) { - expect((error as Error).message).to.include('ActionDispatcher disposed'); + expect((error as Error).message).toContain('ActionDispatcher disposed'); } // Let the slow handler finish so the local dispatcher's consumer loop can exit cleanly. diff --git a/packages/server/src/node/launch/cli-parser.spec.ts b/packages/server/src/node/launch/cli-parser.spec.ts index f32c879c..a34bdc51 100644 --- a/packages/server/src/node/launch/cli-parser.spec.ts +++ b/packages/server/src/node/launch/cli-parser.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,7 +13,7 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import * as path from 'path'; import { LogLevel } from '../../common/utils/logger'; import { createCliParser, defaultLaunchOptions } from './cli-parser'; @@ -26,11 +26,11 @@ describe('test createCliParser', () => { it('parse - no args', () => { const options = parser.parse(argv); - expect(options).to.deep.equal(defaultLaunchOptions); + expect(options).toEqual(defaultLaunchOptions); }); it('parse - invalid log dir', () => { - expect(() => parser.parse([...argv, '--logDir', 'invalid.Path'])).to.throw(); + expect(() => parser.parse([...argv, '--logDir', 'invalid.Path'])).toThrow(); }); it('parse - valid log dir', () => { @@ -40,12 +40,12 @@ describe('test createCliParser', () => { }); it('parse - invalid logLevel', () => { - expect(() => parser.parse([...argv, '--logLevel', 'someRandomLevel'])).to.throw(); + expect(() => parser.parse([...argv, '--logLevel', 'someRandomLevel'])).toThrow(); }); it('parse - valid logLevel', () => { const result = parser.parse([...argv, '--logLevel', 'error']); - expect(result.logLevel).to.be.equal(LogLevel.error); + expect(result.logLevel).toBe(LogLevel.error); }); it('parse- no args with custom default options', () => { @@ -56,6 +56,6 @@ describe('test createCliParser', () => { fileLog: true }; const result = createCliParser(options).parse(argv); - expect(result).to.deep.equal(options); + expect(result).toEqual(options); }); }); diff --git a/packages/server/src/node/launch/socket-cli-parser.spec.ts b/packages/server/src/node/launch/socket-cli-parser.spec.ts index 7f661d0b..b1a1e5e5 100644 --- a/packages/server/src/node/launch/socket-cli-parser.spec.ts +++ b/packages/server/src/node/launch/socket-cli-parser.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,7 +13,7 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { expect } from 'chai'; +import { describe, expect, it } from 'vitest'; import { LogLevel } from '../../common/utils/logger'; import { createSocketCliParser, defaultSocketLaunchOptions, SocketLaunchOptions } from './socket-cli-parser'; @@ -25,21 +25,21 @@ describe('test createCliParser', () => { it('parse - no args', () => { const options = parser.parse(argv); - expect(options).to.deep.equal(defaultSocketLaunchOptions); + expect(options).toEqual(defaultSocketLaunchOptions); }); it('parse - invalid port (below lower range)', () => { - expect(() => parser.parse([...argv, '--port', '-1'])).to.throw(); + expect(() => parser.parse([...argv, '--port', '-1'])).toThrow(); }); it('parse - invalid port (below upper range)', () => { - expect(() => parser.parse([...argv, '--port', '65536'])).to.throw(); + expect(() => parser.parse([...argv, '--port', '65536'])).toThrow(); }); it('parse - valid port', () => { const port = 3000; const result = parser.parse([...argv, '--port', '3000']); - expect(result.port).to.equal(port); + expect(result.port).toBe(port); }); it('parse - --no-consoleLog', () => { @@ -68,6 +68,6 @@ describe('test createCliParser', () => { port: 3000 }; const result = createSocketCliParser(options).parse(argv); - expect(result).to.deep.equal(options); + expect(result).toEqual(options); }); }); diff --git a/packages/server/src/node/launch/socket-server-launcher.spec.ts b/packages/server/src/node/launch/socket-server-launcher.spec.ts index 3cad01f3..a55bd413 100644 --- a/packages/server/src/node/launch/socket-server-launcher.spec.ts +++ b/packages/server/src/node/launch/socket-server-launcher.spec.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022-2023 STMicroelectronics and others. + * Copyright (c) 2022-2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,60 +15,84 @@ ********************************************************************************/ import { GLSPServer } from '@eclipse-glsp/protocol'; -import { expect } from 'chai'; +import { afterEach, describe, expect, it, vi } from 'vitest'; import { Container } from 'inversify'; import * as net from 'net'; -import * as sinon from 'sinon'; -import { DefaultGLSPServer } from '../../common/protocol/glsp-server'; import { createAppModule } from '../di/app-module'; import { defaultSocketLaunchOptions } from './socket-cli-parser'; import { SocketServerLauncher } from './socket-server-launcher'; -const severPort = 5008; + +const serverPort = 5008; + +function delay(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +/** + * Resolves whether a TCP connection to the given port is currently accepted. + * + * The outcome is routed through the returned promise rather than asserted inside the socket event + * callbacks on purpose: an assertion thrown from a detached socket listener escapes the test's + * promise chain and surfaces as a Vitest "unhandled error" that fails the run *without* turning any + * individual test red. Resolving/rejecting keeps every outcome attributable to this test. + */ +function isReachable(port: number): Promise { + return new Promise(resolve => { + const socket = new net.Socket(); + socket.setTimeout(1000); + const finish = (reachable: boolean): void => { + socket.destroy(); + resolve(reachable); + }; + socket + .on('connect', () => finish(true)) + .on('error', () => finish(false)) + .on('timeout', () => finish(false)) + .connect(port); + }); +} + +/** Polls until the port reaches the expected reachability, or fails the test once the deadline elapses. */ +async function waitForReachable(port: number, expected: boolean, deadlineMs = 5000): Promise { + const start = Date.now(); + while (Date.now() - start < deadlineMs) { + if ((await isReachable(port)) === expected) { + return; + } + + await delay(50); + } + expect.fail(`Port ${port} did not become ${expected ? 'reachable' : 'unreachable'} within ${deadlineMs}ms`); +} + describe('test SocketServerLauncher', () => { + let launcher: SocketServerLauncher | undefined; + + afterEach(() => { + launcher?.shutdown(); + launcher = undefined; + }); + it('starts and stops', async () => { + const serverStub = { + initialize: vi.fn().mockResolvedValue({}), + initializeClientSession: vi.fn().mockResolvedValue(undefined), + disposeClientSession: vi.fn().mockResolvedValue(undefined), + process: vi.fn(), + shutdown: vi.fn(), + addListener: vi.fn().mockReturnValue(true), + removeListener: vi.fn().mockReturnValue(true) + } as unknown as GLSPServer; + const appContainer = new Container(); - const serverStub = sinon.createStubInstance(DefaultGLSPServer); appContainer.load(createAppModule(defaultSocketLaunchOptions)); - appContainer.bind(GLSPServer).toConstantValue(serverStub); - const launcher = appContainer.resolve(SocketServerLauncher); - launcher.start({ port: severPort }); - const sockStart = new net.Socket(); - sockStart.setTimeout(100); - const startPromise = new Promise(res => { - sockStart - .on('connect', () => { - expect(true); - sockStart.destroy(); - res(true); - }) - .on('error', e => { - expect.fail('Server is not reachable: ' + e.message); - }) - .on('timeout', () => { - expect.fail('Connection time outed.'); - }) - .connect(severPort); - }); - await startPromise; + launcher = appContainer.resolve(SocketServerLauncher); + + launcher.start({ port: serverPort }); + await waitForReachable(serverPort, true); + launcher.shutdown(); - const sockStop = new net.Socket(); - sockStop.setTimeout(100); - const stopPromise = new Promise(res => { - sockStop - .on('connect', () => { - expect.fail('Server still reachable.'); - }) - .on('error', () => { - expect(true); - sockStop.destroy(); - res(true); - }) - .on('timeout', () => { - expect.fail('Connection time outed.'); - }) - .connect(severPort); - }); - await stopPromise; + await waitForReachable(serverPort, false); }); }); diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index 3736ccd7..e8c13d18 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@eclipse-glsp/ts-config/mocha", + "extends": "@eclipse-glsp/ts-config", "compilerOptions": { "rootDir": "src", "outDir": "lib", diff --git a/packages/server/tsconfig.test.json b/packages/server/tsconfig.test.json new file mode 100644 index 00000000..19a4102a --- /dev/null +++ b/packages/server/tsconfig.test.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "composite": true, + "noEmit": true + }, + "include": ["src/**/*.spec.ts", "src/**/*.spec.tsx", "src/**/test/**/*"], + "exclude": ["lib", "node_modules"], + "references": [{ "path": "./tsconfig.json" }] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 723d2308..9fb85972 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,13 +15,10 @@ importers: devDependencies: '@eclipse-glsp/dev': specifier: next - version: 2.8.0-next.9(@types/node@22.19.21)(@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3))(supports-color@8.1.1)(typescript@5.9.3) + version: 2.8.0-next.16(@types/node@22.19.21)(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(typescript@5.9.3)(vite@8.0.16(@types/node@22.19.21)(esbuild@0.28.1)) '@types/node': specifier: 22.x version: 22.19.21 - mocha-ctrf-json-reporter: - specifier: 0.0.11 - version: 0.0.11 typescript: specifier: ^5.9.2 version: 5.9.3 @@ -69,7 +66,7 @@ importers: dependencies: '@eclipse-glsp/protocol': specifier: next - version: 2.8.0-next.10(inversify@6.2.2(reflect-metadata@0.2.2)) + version: 2.8.0-next.12(inversify@6.2.2(reflect-metadata@0.2.2))(reflect-metadata@0.2.2) packages/layout-elk: dependencies: @@ -93,7 +90,7 @@ importers: version: link:../graph '@eclipse-glsp/protocol': specifier: next - version: 2.8.0-next.10(inversify@6.2.2(reflect-metadata@0.2.2)) + version: 2.8.0-next.12(inversify@6.2.2(reflect-metadata@0.2.2))(reflect-metadata@0.2.2) commander: specifier: ^14.0.0 version: 14.0.3 @@ -130,7 +127,7 @@ importers: version: 1.19.14(hono@4.12.25) '@modelcontextprotocol/sdk': specifier: ^1.29.0 - version: 1.29.0(supports-color@8.1.1)(zod@4.4.3) + version: 1.29.0(zod@4.4.3) inversify: specifier: ^6.1.3 version: 6.2.2(reflect-metadata@0.2.2) @@ -143,40 +140,6 @@ importers: packages: - '@babel/code-frame@7.29.7': - resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.7': - resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.7': - resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.7': - resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.29.7': - resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.29.7': - resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.29.7': - resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.29.7': - resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@babel/helper-string-parser@7.29.7': resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} @@ -185,57 +148,41 @@ packages: resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.29.7': - resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.29.7': - resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} - engines: {node: '>=6.9.0'} - '@babel/parser@7.29.7': resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/template@7.29.7': - resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.7': - resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} - engines: {node: '>=6.9.0'} - '@babel/types@7.29.7': resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + '@colors/colors@1.6.0': resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} engines: {node: '>=0.1.90'} - '@cspotcode/source-map-support@0.8.1': - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - '@dabh/diagnostics@2.0.8': resolution: {integrity: sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==} - '@eclipse-glsp/cli@2.8.0-next.9': - resolution: {integrity: sha512-NPyJJCs7VAkGwtKdnTn9oTZ/fWA35bvfFKOcB3jxZvi2dkLaxlhb/kVH4KPUSmAJ/D00JXHnCnMts/as2fTrdw==} + '@eclipse-glsp/cli@2.8.0-next.16': + resolution: {integrity: sha512-PyIDa2YaXzXCiYEGEfFoDy0U6suclx8dLcX0DCoDQr4mPpfgU6H63zk9k+4FKr+u475XV3ch5kUPHMQVRv/Fag==} hasBin: true - '@eclipse-glsp/config-test@2.8.0-next.9': - resolution: {integrity: sha512-zYl7zBHjCTSsetV6oJAQenY44StTyl9elriQebCioWCPhdKg+sLy6f8pl/X3CK3Vj/5RJqaBLRzEGeq1dbJnxw==} + '@eclipse-glsp/config-test@2.8.0-next.16': + resolution: {integrity: sha512-7ihYKqjTIbfv1mTvrFsGy43f3h0jHNX1RJprAV9bp9zth2hfFQN/Y4xB564EwquE+suRc9ZJJvzJj/HNBa7BRg==} - '@eclipse-glsp/config@2.8.0-next.9': - resolution: {integrity: sha512-yvobLNQ/RRjPM3WaMtCj2WMpIW29ARICBDYu9zTyecWaIzTl7XUyGgD8uP67Wu8626qiAZgFusx8y+Inmt0R4A==} + '@eclipse-glsp/config@2.8.0-next.16': + resolution: {integrity: sha512-qM1PeD9UxvwKAf3G3ImOYFee7IvAFfL4TzwxPmPLnIdB4dAj7wDCY6COBcifAQD+jDoSuXFniQPcaUnHZKjfig==} - '@eclipse-glsp/dev@2.8.0-next.9': - resolution: {integrity: sha512-ngT+PkOd5sdh4F/yad6r/OzzL8wceZ7PWpdferq/GenRmMPEGMpYk1SHB0BkYrmDUS+qSk4Yk+8gQDfeR/fnCw==} + '@eclipse-glsp/dev@2.8.0-next.16': + resolution: {integrity: sha512-WUNk3B6MLkM8HZND1FqyccwQZ7A/DfqUBDGAypjj3JYMiAOTZwseQXB8ea4Z/iCTfEmq3wnYapbnm25SwSoFSQ==} - '@eclipse-glsp/eslint-config@2.8.0-next.9': - resolution: {integrity: sha512-hLEHaewvQTG5KzcC2aFkCufT+GU0ljhoyBOd2TyyNkYH8iCy10d53q4+wqPD309yrBp0yQjDWMc8HxIiH6bXcA==} + '@eclipse-glsp/eslint-config@2.8.0-next.16': + resolution: {integrity: sha512-FDWiHnTj/vv1+tBg7kNoUbsBm8OMIUhEsQfTNw53lqaXeNdcHRfv5Aur6tArRWbu0EoeEsqe79te3evP/tzReQ==} peerDependencies: '@eslint/js': ^10.0.1 '@stylistic/eslint-plugin': ^5.10.0 @@ -249,32 +196,31 @@ packages: globals: ^17.6.0 typescript-eslint: ^8.0.0 - '@eclipse-glsp/mocha-config@2.8.0-next.9': - resolution: {integrity: sha512-axu6xNd1wWxIiQv2F+Nm458fXum5JcGYQ7NCJ4kcWwV2paXWY6eWk3H2hO9HG004seOR+TQcR4kRfjwo3/ZoAQ==} - peerDependencies: - ignore-styles: ^5.0.1 - mocha: ^11.7.6 - reflect-metadata: ^0.2.2 - - '@eclipse-glsp/nyc-config@2.8.0-next.9': - resolution: {integrity: sha512-nBrEfGSfZluWaWIKj+T//WplxgC3EGgrioBTSaH4hOtWqGPG0BujwPz8jb0jJaUmBkKg8Vn6r9DroXhtx7/jnQ==} - peerDependencies: - '@istanbuljs/nyc-config-typescript': ^1.0.2 - nyc: ^18.0.0 - - '@eclipse-glsp/prettier-config@2.8.0-next.9': - resolution: {integrity: sha512-fpHLtKdhMZg2lwHWqOgnEEYQ30LrTcHaDMfLbu6rG43OVgZffNxi275s0IgWIbrzNZoLIEl8z5tMpTDr17i0Mg==} + '@eclipse-glsp/prettier-config@2.8.0-next.16': + resolution: {integrity: sha512-ZdYR+vVDBlbpiLwQhvPAFktPQMB5hvi15g4hsGBALwCWa7v5FYfzAahTgoH5imCf0zJNXt/VmbsonK7eWCBaEA==} - '@eclipse-glsp/protocol@2.8.0-next.10': - resolution: {integrity: sha512-i5poJQTYJ17rOgouq12H2ZrYd/7tOlEjlF+c16V4ETGoTWwyF0WA7s2QOEyyfmELYEoG35Xs3yC2lSZWoZv97Q==} + '@eclipse-glsp/protocol@2.8.0-next.12': + resolution: {integrity: sha512-asaLdnqtREilxO8+5ObuokYS8lh2EsbUlBW5LXIAtVGGrEwbyGMZyetq3nG+bSqNaDwp2qpkfAuMp8uCm6yEgg==} peerDependencies: inversify: ^6.1.3 + reflect-metadata: ^0.2.2 + peerDependenciesMeta: + inversify: + optional: true + reflect-metadata: + optional: true - '@eclipse-glsp/ts-config@2.8.0-next.9': - resolution: {integrity: sha512-6CqN1XcAIiHGSHvazlGCReEyzRGnQHhgk56NjAn2yNC1Vefi+IvhV70yz0V4p6ooGT51jvv5VdzibD6XGzggZg==} + '@eclipse-glsp/ts-config@2.8.0-next.16': + resolution: {integrity: sha512-0iLQOrjar/75XDYJjeLlIMBeWStLwf78wqypi+oTAfHpSliGd6hWSR8mHIA9G9YQNHrOZWxPgXI5ISJ6sHT14Q==} peerDependencies: typescript: '>=5.5' + '@eclipse-glsp/vitest-config@2.8.0-next.16': + resolution: {integrity: sha512-gK/Unmg+lq9OYTyBxkYsY8H56FxhVrEa1NogvruqLg5HKkJGdNLP4j5DFACCq/jdnVvcfdCHM4Dx+nr+WM69jw==} + peerDependencies: + '@vitest/coverage-v8': '>=4.0.0' + vitest: '>=4.0.0' + '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} @@ -516,30 +462,6 @@ packages: peerDependencies: reflect-metadata: 0.2.2 - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@istanbuljs/load-nyc-config@1.1.0': - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - - '@istanbuljs/nyc-config-typescript@1.0.2': - resolution: {integrity: sha512-iKGIyMoyJuFnJRSVTZ78POIRvNnwZaWIf8vG4ZS3rQq58MMDrqEX2nnzx0R28V2X8JvmKYiqY9FP2hlJsm8A0w==} - engines: {node: '>=8'} - peerDependencies: - nyc: '>=15' - - '@istanbuljs/schema@0.1.6': - resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} - engines: {node: '>=8'} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -550,9 +472,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@jridgewell/trace-mapping@0.3.9': - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@modelcontextprotocol/sdk@1.29.0': resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} engines: {node: '>=18'} @@ -569,25 +488,116 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + '@package-json/types@0.0.12': resolution: {integrity: sha512-uu43FGU34B5VM9mCNjXCwLaGHYjXdNincqKLaraaCW+7S2+SmiBg1Nv8bPnmschrIfZmfKNY9f3fC376MRrObw==} - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] - '@sinonjs/commons@3.0.1': - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@sinonjs/fake-timers@15.4.0': - resolution: {integrity: sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==} + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] - '@sinonjs/samsam@10.0.2': - resolution: {integrity: sha512-8lVwD1Df1BmzoaOLhMcGGcz/Jyr5QY2KSB75/YK1QgKzoabTeLdIVyhXNZK9ojfSKSdirbXqdbsXXqP9/Ve8+A==} + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} '@so-ric/colorspace@1.1.6': resolution: {integrity: sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@stylistic/eslint-plugin@5.10.0': resolution: {integrity: sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -599,23 +609,14 @@ packages: peerDependencies: eslint: '>=7.7.0' - '@tsconfig/node10@1.0.12': - resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} - - '@tsconfig/node12@1.0.11': - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - - '@tsconfig/node14@1.0.3': - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - - '@tsconfig/node16@1.0.4': - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - '@tybys/wasm-util@0.10.2': resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} - '@types/chai@4.3.20': - resolution: {integrity: sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} '@types/esrecurse@4.3.1': resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} @@ -626,81 +627,72 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/mocha@10.0.10': - resolution: {integrity: sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==} - '@types/node@22.19.21': resolution: {integrity: sha512-VMeFBSCKQKmm2swI2kW51SFusDqekC6q9trBCvJ/JliDchFSuoYYKN7yVNjPthP1HKZcx3U1gI/wTcEBjEFKTA==} - '@types/sinon@21.0.1': - resolution: {integrity: sha512-5yoJSqLbjH8T9V2bksgRayuhpZy+723/z6wBOR+Soe4ZlXC0eW8Na71TeaZPUWDQvM7LYKa9UGFc6LRqxiR5fQ==} - - '@types/sinonjs__fake-timers@15.0.1': - resolution: {integrity: sha512-Ko2tjWJq8oozHzHV+reuvS5KYIRAokHnGbDwGh/J64LntgpbuylF74ipEL24HCyRjf9FOlBiBHWBR1RlVKsI1w==} - '@types/triple-beam@1.3.5': resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@typescript-eslint/eslint-plugin@8.61.0': - resolution: {integrity: sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==} + '@typescript-eslint/eslint-plugin@8.61.1': + resolution: {integrity: sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.61.0 + '@typescript-eslint/parser': ^8.61.1 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.61.0': - resolution: {integrity: sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==} + '@typescript-eslint/parser@8.61.1': + resolution: {integrity: sha512-PJ5vePq5/ognBbrIcoC5+SHO5dfpeLPzP9FpLkzWrguoYQEeeSjlJpVwOpo1JRSTEi7dRcwNy4h4dzV70PqHcg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.61.0': - resolution: {integrity: sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==} + '@typescript-eslint/project-service@8.61.1': + resolution: {integrity: sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.61.0': - resolution: {integrity: sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==} + '@typescript-eslint/scope-manager@8.61.1': + resolution: {integrity: sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.61.0': - resolution: {integrity: sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==} + '@typescript-eslint/tsconfig-utils@8.61.1': + resolution: {integrity: sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.61.0': - resolution: {integrity: sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==} + '@typescript-eslint/type-utils@8.61.1': + resolution: {integrity: sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.61.0': - resolution: {integrity: sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==} + '@typescript-eslint/types@8.61.1': + resolution: {integrity: sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.61.0': - resolution: {integrity: sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==} + '@typescript-eslint/typescript-estree@8.61.1': + resolution: {integrity: sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.61.0': - resolution: {integrity: sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==} + '@typescript-eslint/utils@8.61.1': + resolution: {integrity: sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.61.0': - resolution: {integrity: sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==} + '@typescript-eslint/visitor-keys@8.61.1': + resolution: {integrity: sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@unrs/resolver-binding-android-arm-eabi@1.12.2': @@ -823,6 +815,44 @@ packages: cpu: [x64] os: [win32] + '@vitest/coverage-v8@4.1.9': + resolution: {integrity: sha512-G9/lgqibheLVBDRuya45EbsEXTYcWoSG+TLg7i2axuzx0Eq62eXn+aWXyaVdV5vKvFSWd6ywcX8hA7la9Pvu8g==} + peerDependencies: + '@vitest/browser': 4.1.9 + vitest: 4.1.9 + peerDependenciesMeta: + '@vitest/browser': + optional: true + + '@vitest/expect@4.1.9': + resolution: {integrity: sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==} + + '@vitest/mocker@4.1.9': + resolution: {integrity: sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.9': + resolution: {integrity: sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==} + + '@vitest/runner@4.1.9': + resolution: {integrity: sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==} + + '@vitest/snapshot@4.1.9': + resolution: {integrity: sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==} + + '@vitest/spy@4.1.9': + resolution: {integrity: sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==} + + '@vitest/utils@4.1.9': + resolution: {integrity: sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==} + accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} @@ -832,19 +862,11 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.5: - resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} - engines: {node: '>=0.4.0'} - acorn@8.17.0: resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} engines: {node: '>=0.4.0'} hasBin: true - aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} - ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -859,80 +881,32 @@ packages: ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - append-transform@2.0.0: - resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==} - engines: {node: '>=8'} - - archy@1.0.0: - resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} - - arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + ast-v8-to-istanbul@1.0.4: + resolution: {integrity: sha512-0bC0/4bTSrnwdhU3IsZDwEdojvuPrSg59OYZfKsLRtJZ0u8VBx9DebfqqG8bRdCC0I7vjgxmPi41P0lpkhJHtA==} async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - balanced-match@4.0.4: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.10.37: - resolution: {integrity: sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==} - engines: {node: '>=6.0.0'} - hasBin: true - - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} engines: {node: '>=18'} - brace-expansion@2.1.1: - resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} - brace-expansion@5.0.6: resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} - browser-stdout@1.3.1: - resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - caching-transform@4.0.0: - resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==} - engines: {node: '>=8'} - call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -941,61 +915,14 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - - camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - - caniuse-lite@1.0.30001799: - resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==} - - chai@4.5.0: - resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} - engines: {node: '>=4'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - charenc@0.0.2: - resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} - - check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} - - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - - cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - cliui@9.0.1: - resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} - engines: {node: '>=20'} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} color-convert@3.1.3: resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} engines: {node: '>=14.6'} - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-name@2.1.0: resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} engines: {node: '>=12.20'} @@ -1016,9 +943,6 @@ packages: resolution: {integrity: sha512-0h+uSNtQGW3D98eQt3jJ8L06Fves8hncB4V/PKdw/Qb8Hnk19VaKuTr55UNRYiSoVa7WwrFls+rh3ux9agmkeQ==} engines: {node: '>= 12.0.0'} - commondir@1.0.1: - resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - content-disposition@1.1.0: resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} engines: {node: '>=18'} @@ -1031,9 +955,6 @@ packages: resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} engines: {node: '>=18'} - convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -1049,21 +970,10 @@ packages: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} - create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - crypt@0.0.2: - resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} - - ctrf@0.2.1: - resolution: {integrity: sha512-iUo/eHcM5yG8aBS3Miqce9NNiZCtmVZxPpgmZEJIZ96bubwj7IpZx3IqsDqCH2FZjR71EH2NLtbBhtfzDjpaUg==} - engines: {node: '>=20.19.0'} - hasBin: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1073,25 +983,9 @@ packages: supports-color: optional: true - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - - decamelize@4.0.0: - resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} - engines: {node: '>=10'} - - deep-eql@4.1.4: - resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} - engines: {node: '>=6'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - default-require-extensions@3.0.1: - resolution: {integrity: sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==} - engines: {node: '>=8'} - depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -1100,39 +994,24 @@ packages: resolution: {integrity: sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==} engines: {node: '>=12.20'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + detect-newline@4.0.1: resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - diff@9.0.0: - resolution: {integrity: sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==} - engines: {node: '>=0.3.1'} - dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.372: - resolution: {integrity: sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==} - elkjs@0.11.1: resolution: {integrity: sha512-zxxR9k+rx5ktMwT/FwyLdPCrq7xN6e4VGGHH8hA01vVYKjTFik7nHOxBnAYtrgYUB1RpAiLvA1/U2YraWxyKKg==} - emoji-regex@10.6.0: - resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - enabled@2.0.0: resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} @@ -1148,22 +1027,18 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + es-object-atoms@1.1.2: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} - es6-error@4.1.1: - resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} - esbuild@0.28.1: resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} hasBin: true - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -1199,8 +1074,8 @@ packages: eslint-plugin-import-x: optional: true - eslint-plugin-chai-friendly@1.2.0: - resolution: {integrity: sha512-um2pBb4ZXNCoTRPRAWiUaXeIaw1dRaPOEZ+G/qcZqfyTdkCXXwOBctnfnbIRbZiQf4AXl3ImV1grt423SlK+mg==} + eslint-plugin-chai-friendly@1.2.1: + resolution: {integrity: sha512-mV3EOJLDr8+L+LS8uCkP711fnNHz+4PsmPyz18xwkvjJwfLRlnx0Eu6CFnb5B+dW5ahoav2jVer2KFYsmIuv3A==} engines: {node: '>=0.10.0'} peerDependencies: eslint: '>=3.0.0' @@ -1270,6 +1145,9 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -1286,6 +1164,10 @@ packages: resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} engines: {node: '>=18.0.0'} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + express-rate-limit@8.5.2: resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==} engines: {node: '>= 16'} @@ -1331,14 +1213,6 @@ packages: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} - find-cache-dir@3.3.2: - resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} - engines: {node: '>=8'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1347,24 +1221,12 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} fn.name@1.1.0: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} - foreground-child@2.0.0: - resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} - engines: {node: '>=8.0.0'} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -1373,35 +1235,18 @@ packages: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} - fromentries@1.3.2: - resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-east-asian-width@1.6.0: - resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} - engines: {node: '>=18'} - - get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -1416,11 +1261,6 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob@10.5.0: - resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - hasBin: true - glob@13.0.6: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} @@ -1433,9 +1273,6 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -1444,18 +1281,10 @@ packages: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} - hasha@5.2.2: - resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} - engines: {node: '>=8'} - hasown@2.0.4: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} - he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - hono@4.12.25: resolution: {integrity: sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==} engines: {node: '>=16.9.0'} @@ -1471,9 +1300,6 @@ packages: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} - ignore-styles@5.0.1: - resolution: {integrity: sha512-gQQmIznCETPLEzfg1UH4Cs2oRq+HBPl8quroEUNXT8oybEG7/0lqI3dGgDSRry6B9HcCXw3PVkFFS0FF3CMddg==} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1486,10 +1312,6 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -1506,9 +1328,6 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} - is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - is-bun-module@2.0.0: resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} @@ -1516,22 +1335,10 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - - is-plain-obj@2.1.0: - resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} - engines: {node: '>=8'} - is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} @@ -1543,17 +1350,6 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - - is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -1561,47 +1357,19 @@ packages: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} - istanbul-lib-hook@3.0.0: - resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==} - engines: {node: '>=8'} - - istanbul-lib-instrument@6.0.3: - resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} - engines: {node: '>=10'} - - istanbul-lib-processinfo@3.0.1: - resolution: {integrity: sha512-s3mX05h5wGZeScG6XnOanygPh4SJu5ujMc9YbvpnLGXWy1cRiGbp0NdVcjHxgoZt3WfQppfBsa0y+gWdYJ2pGQ==} - engines: {node: 20 || >=22} - istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} - istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} - istanbul-reports@3.2.0: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jose@6.2.3: resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.2.0: - resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} - hasBin: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -1618,11 +1386,6 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -1633,56 +1396,106 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] - lodash.flattendeep@4.4.0: - resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} logform@2.7.0: resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} engines: {node: '>= 12.0.0'} - loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.5.1: resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} engines: {node: 20 || >=22} - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} + magicast@0.5.3: + resolution: {integrity: sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==} make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - md5@2.3.0: - resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} - media-typer@1.1.0: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} @@ -1703,25 +1516,18 @@ packages: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} - minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} - minipass@7.1.3: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - mocha-ctrf-json-reporter@0.0.11: - resolution: {integrity: sha512-rZdmC/ykhpJYNQKI+CSxlpiZ/s8kTf7Ql0XbTlMKSRc4UOXQxpmb4pMFgf+1Yxb81VT3aoHih2IeZVYENnolWg==} - - mocha@11.7.6: - resolution: {integrity: sha512-nS9xOGbw2I3cjCpxwZAEJ9xK9lmJ08vEkQvLtz4du9ZrF9UrjRpeJGiIgl2Z+Qs++pmB4ecDe48Fwsh+j+j7xA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + napi-postinstall@0.3.4: resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -1734,19 +1540,6 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} - node-preload@0.2.1: - resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==} - engines: {node: '>=8'} - - node-releases@2.0.47: - resolution: {integrity: sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==} - engines: {node: '>=18'} - - nyc@18.0.0: - resolution: {integrity: sha512-G5UyHinFkB1BxqGTrmZdB6uIYH0+v7ZnVssuflUDi+J+RhKWyAhRT1RCehBSI6jLFLuUUgFDyLt49mUtdO1XeQ==} - engines: {node: 20 || >=22} - hasBin: true - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1755,6 +1548,10 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} + obug@2.1.3: + resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} + engines: {node: '>=12.20.0'} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -1769,34 +1566,14 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-map@3.0.0: - resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} - engines: {node: '>=8'} - - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - package-hash@4.0.0: - resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==} - engines: {node: '>=8'} - package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -1812,10 +1589,6 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.2: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} @@ -1823,8 +1596,8 @@ packages: path-to-regexp@8.4.2: resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} - pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1837,9 +1610,9 @@ packages: resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} - pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -1858,10 +1631,6 @@ packages: engines: {node: '>=14'} hasBin: true - process-on-spawn@1.1.0: - resolution: {integrity: sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==} - engines: {node: '>=8'} - proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -1886,32 +1655,13 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} - release-zalgo@1.0.0: - resolution: {integrity: sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==} - engines: {node: '>=4'} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -1920,6 +1670,11 @@ packages: engines: {node: 20 || >=22} hasBin: true + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} @@ -1934,10 +1689,6 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - semver@7.8.4: resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} engines: {node: '>=10'} @@ -1947,17 +1698,10 @@ packages: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} - serialize-javascript@7.0.5: - resolution: {integrity: sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==} - engines: {node: '>=20.0.0'} - serve-static@2.2.1: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -1985,15 +1729,8 @@ packages: resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} engines: {node: '>= 0.4'} - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - sinon@22.0.0: - resolution: {integrity: sha512-sq/6DpdXOrLyfbKlXLg/Usc7xu8YXPeLkOFZRvA3bNUSA2lhbrZ06yuXbH1fkzBPCbz9O10+7hznzUsjaYNm0Q==} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} sort-object-keys@2.1.0: resolution: {integrity: sha512-SOiEnthkJKPv2L6ec6HMwhUcN0/lppkeYuN1x63PbyPRrgSPIuBJCiYxYyvWRTtjMlOi14vQUCGUJqS6PLVm8g==} @@ -2003,14 +1740,10 @@ packages: engines: {node: '>=20'} hasBin: true - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - spawn-wrap@3.0.0: - resolution: {integrity: sha512-z+s5vv4KzFPJVddGab0xX2n7kQPGMdNUX5l9T8EJqsXdKTWpcxmAqWHpsgHEXoC1taGBCc7b79bi62M5kdbrxQ==} - engines: {node: '>=8'} - sprotty-protocol@1.4.0: resolution: {integrity: sha512-+AAskW3Mzcq5UhMnummp4wwJ1dYdgT7/utmWoHtjfrK7JTJq9G/VWWlHnTnQGzHHyma03Loy2AozToXoArQuAQ==} @@ -2021,60 +1754,41 @@ packages: stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string-width@7.2.0: - resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} - engines: {node: '>=18'} + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.2.0: - resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} - engines: {node: '>=12'} - - strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - - test-exclude@8.0.0: - resolution: {integrity: sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==} - engines: {node: 20 || >=22} - text-hex@1.0.0: resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -2089,20 +1803,6 @@ packages: peerDependencies: typescript: '>=4.8.4' - ts-node@10.9.2: - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -2110,27 +1810,12 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - - type-detect@4.1.0: - resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} - engines: {node: '>=4'} - - type-fest@0.8.1: - resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} - engines: {node: '>=8'} - type-is@2.1.0: resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} engines: {node: '>= 18'} - typedarray-to-buffer@3.1.5: - resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - - typescript-eslint@8.61.0: - resolution: {integrity: sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==} + typescript-eslint@8.61.1: + resolution: {integrity: sha512-V7PayAfJokV3pEHgN7/v03D1SpujhRfQtYLbLIiBfDDncdg4PAiRBfoS4cnCANK4jmAPncczi59QO3afiXUlNw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2151,12 +1836,6 @@ packages: unrs-resolver@1.12.2: resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -2167,25 +1846,108 @@ packages: resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==} hasBin: true - v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.9: + resolution: {integrity: sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.9 + '@vitest/browser-preview': 4.1.9 + '@vitest/browser-webdriverio': 4.1.9 + '@vitest/coverage-istanbul': 4.1.9 + '@vitest/coverage-v8': 4.1.9 + '@vitest/ui': 4.1.9 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vscode-jsonrpc@8.2.0: resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} engines: {node: '>=14.0.0'} - which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + winston-transport@4.9.0: resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} engines: {node: '>= 12.0.0'} @@ -2198,31 +1960,9 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - workerpool@9.3.4: - resolution: {integrity: sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==} - - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrap-ansi@9.0.2: - resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} - engines: {node: '>=18'} - wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - write-file-atomic@3.0.3: - resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} - ws@8.21.0: resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} engines: {node: '>=10.0.0'} @@ -2235,48 +1975,6 @@ packages: utf-8-validate: optional: true - y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs-parser@22.0.0: - resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=23} - - yargs-unparser@2.0.0: - resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} - engines: {node: '>=10'} - - yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yargs@18.0.0: - resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=23} - - yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -2291,111 +1989,22 @@ packages: snapshots: - '@babel/code-frame@7.29.7': - dependencies: - '@babel/helper-validator-identifier': 7.29.7 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.7': {} - - '@babel/core@7.29.7(supports-color@8.1.1)': - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 - '@babel/helper-compilation-targets': 7.29.7 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@8.1.1)) - '@babel/helpers': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@8.1.1) - '@babel/types': 7.29.7 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3(supports-color@8.1.1) - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.7': - dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.29.7': - dependencies: - '@babel/compat-data': 7.29.7 - '@babel/helper-validator-option': 7.29.7 - browserslist: 4.28.2 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.29.7': {} - - '@babel/helper-module-imports@7.29.7': - dependencies: - '@babel/traverse': 7.29.7(supports-color@8.1.1) - '@babel/types': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@8.1.1))': - dependencies: - '@babel/core': 7.29.7(supports-color@8.1.1) - '@babel/helper-module-imports': 7.29.7 - '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - '@babel/helper-string-parser@7.29.7': {} '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-option@7.29.7': {} - - '@babel/helpers@7.29.7': - dependencies: - '@babel/template': 7.29.7 - '@babel/types': 7.29.7 - '@babel/parser@7.29.7': dependencies: '@babel/types': 7.29.7 - '@babel/template@7.29.7': - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 - - '@babel/traverse@7.29.7(supports-color@8.1.1)': - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 - '@babel/helper-globals': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/template': 7.29.7 - '@babel/types': 7.29.7 - debug: 4.4.3(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - '@babel/types@7.29.7': dependencies: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@colors/colors@1.6.0': {} + '@bcoe/v8-coverage@1.0.2': {} - '@cspotcode/source-map-support@0.8.1': - dependencies: - '@jridgewell/trace-mapping': 0.3.9 + '@colors/colors@1.6.0': {} '@dabh/diagnostics@2.0.8': dependencies: @@ -2403,49 +2012,46 @@ snapshots: enabled: 2.0.0 kuler: 2.0.0 - '@eclipse-glsp/cli@2.8.0-next.9': {} + '@eclipse-glsp/cli@2.8.0-next.16': {} - '@eclipse-glsp/config-test@2.8.0-next.9(@types/node@22.19.21)(supports-color@8.1.1)(typescript@5.9.3)': + '@eclipse-glsp/config-test@2.8.0-next.16(@types/node@22.19.21)(vite@8.0.16(@types/node@22.19.21)(esbuild@0.28.1))': dependencies: - '@eclipse-glsp/mocha-config': 2.8.0-next.9(ignore-styles@5.0.1)(mocha@11.7.6)(reflect-metadata@0.2.2) - '@eclipse-glsp/nyc-config': 2.8.0-next.9(@istanbuljs/nyc-config-typescript@1.0.2(nyc@18.0.0(supports-color@8.1.1)))(nyc@18.0.0(supports-color@8.1.1)) - '@istanbuljs/nyc-config-typescript': 1.0.2(nyc@18.0.0(supports-color@8.1.1)) - '@types/chai': 4.3.20 - '@types/mocha': 10.0.10 - '@types/sinon': 21.0.1 - chai: 4.5.0 - ignore-styles: 5.0.1 - mocha: 11.7.6 - nyc: 18.0.0(supports-color@8.1.1) - reflect-metadata: 0.2.2 - sinon: 22.0.0 - ts-node: 10.9.2(@types/node@22.19.21)(typescript@5.9.3) + '@eclipse-glsp/vitest-config': 2.8.0-next.16(@vitest/coverage-v8@4.1.9)(vitest@4.1.9) + '@vitest/coverage-v8': 4.1.9(vitest@4.1.9) + vitest: 4.1.9(@types/node@22.19.21)(@vitest/coverage-v8@4.1.9)(vite@8.0.16(@types/node@22.19.21)(esbuild@0.28.1)) transitivePeerDependencies: - - '@swc/core' - - '@swc/wasm' + - '@edge-runtime/vm' + - '@opentelemetry/api' - '@types/node' - - supports-color - - typescript - - '@eclipse-glsp/config@2.8.0-next.9(@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3))(supports-color@8.1.1)(typescript@5.9.3)': - dependencies: - '@eclipse-glsp/eslint-config': 2.8.0-next.9(9cb1e08476e47f214c8711d1ef3c11ea) - '@eclipse-glsp/prettier-config': 2.8.0-next.9(prettier@3.8.4) - '@eclipse-glsp/ts-config': 2.8.0-next.9(typescript@5.9.3) - '@eslint/js': 10.0.1(eslint@10.5.0(supports-color@8.1.1)) - '@stylistic/eslint-plugin': 5.10.0(eslint@10.5.0(supports-color@8.1.1)) - '@tony.ganchev/eslint-plugin-header': 3.4.4(eslint@10.5.0(supports-color@8.1.1)) - eslint: 10.5.0(supports-color@8.1.1) - eslint-config-prettier: 10.1.8(eslint@10.5.0(supports-color@8.1.1)) - eslint-import-resolver-typescript: 4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1) - eslint-plugin-chai-friendly: 1.2.0(eslint@10.5.0(supports-color@8.1.1)) - eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1) - eslint-plugin-no-null: 1.0.2(eslint@10.5.0(supports-color@8.1.1)) + - '@vitest/browser' + - '@vitest/browser-playwright' + - '@vitest/browser-preview' + - '@vitest/browser-webdriverio' + - '@vitest/coverage-istanbul' + - '@vitest/ui' + - happy-dom + - jsdom + - msw + - vite + + '@eclipse-glsp/config@2.8.0-next.16(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(typescript@5.9.3)': + dependencies: + '@eclipse-glsp/eslint-config': 2.8.0-next.16(@eslint/js@10.0.1(eslint@10.5.0))(@stylistic/eslint-plugin@5.10.0(eslint@10.5.0))(@tony.ganchev/eslint-plugin-header@3.4.4(eslint@10.5.0))(eslint-config-prettier@10.1.8(eslint@10.5.0))(eslint-import-resolver-typescript@4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0))(eslint@10.5.0))(eslint-plugin-chai-friendly@1.2.1(eslint@10.5.0))(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0))(eslint-plugin-no-null@1.0.2(eslint@10.5.0))(eslint@10.5.0)(globals@17.6.0)(typescript-eslint@8.61.1(eslint@10.5.0)(typescript@5.9.3)) + '@eclipse-glsp/prettier-config': 2.8.0-next.16(prettier@3.8.4) + '@eclipse-glsp/ts-config': 2.8.0-next.16(typescript@5.9.3) + '@eslint/js': 10.0.1(eslint@10.5.0) + '@stylistic/eslint-plugin': 5.10.0(eslint@10.5.0) + '@tony.ganchev/eslint-plugin-header': 3.4.4(eslint@10.5.0) + eslint: 10.5.0 + eslint-config-prettier: 10.1.8(eslint@10.5.0) + eslint-import-resolver-typescript: 4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0))(eslint@10.5.0) + eslint-plugin-chai-friendly: 1.2.1(eslint@10.5.0) + eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0) + eslint-plugin-no-null: 1.0.2(eslint@10.5.0) globals: 17.6.0 prettier: 3.8.4 - reflect-metadata: 0.2.2 rimraf: 6.1.3 - typescript-eslint: 8.61.0(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) + typescript-eslint: 8.61.1(eslint@10.5.0)(typescript@5.9.3) transitivePeerDependencies: - '@typescript-eslint/utils' - eslint-import-resolver-node @@ -2454,64 +2060,70 @@ snapshots: - supports-color - typescript - '@eclipse-glsp/dev@2.8.0-next.9(@types/node@22.19.21)(@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3))(supports-color@8.1.1)(typescript@5.9.3)': + '@eclipse-glsp/dev@2.8.0-next.16(@types/node@22.19.21)(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(typescript@5.9.3)(vite@8.0.16(@types/node@22.19.21)(esbuild@0.28.1))': dependencies: - '@eclipse-glsp/cli': 2.8.0-next.9 - '@eclipse-glsp/config': 2.8.0-next.9(@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3))(supports-color@8.1.1)(typescript@5.9.3) - '@eclipse-glsp/config-test': 2.8.0-next.9(@types/node@22.19.21)(supports-color@8.1.1)(typescript@5.9.3) + '@eclipse-glsp/cli': 2.8.0-next.16 + '@eclipse-glsp/config': 2.8.0-next.16(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(typescript@5.9.3) + '@eclipse-glsp/config-test': 2.8.0-next.16(@types/node@22.19.21)(vite@8.0.16(@types/node@22.19.21)(esbuild@0.28.1)) transitivePeerDependencies: - - '@swc/core' - - '@swc/wasm' + - '@edge-runtime/vm' + - '@opentelemetry/api' - '@types/node' - '@typescript-eslint/utils' + - '@vitest/browser' + - '@vitest/browser-playwright' + - '@vitest/browser-preview' + - '@vitest/browser-webdriverio' + - '@vitest/coverage-istanbul' + - '@vitest/ui' - eslint-import-resolver-node - eslint-plugin-import + - happy-dom - jiti + - jsdom + - msw - supports-color - typescript - - '@eclipse-glsp/eslint-config@2.8.0-next.9(9cb1e08476e47f214c8711d1ef3c11ea)': - dependencies: - '@eslint/js': 10.0.1(eslint@10.5.0(supports-color@8.1.1)) - '@stylistic/eslint-plugin': 5.10.0(eslint@10.5.0(supports-color@8.1.1)) - '@tony.ganchev/eslint-plugin-header': 3.4.4(eslint@10.5.0(supports-color@8.1.1)) - eslint: 10.5.0(supports-color@8.1.1) - eslint-config-prettier: 10.1.8(eslint@10.5.0(supports-color@8.1.1)) - eslint-import-resolver-typescript: 4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1) - eslint-plugin-chai-friendly: 1.2.0(eslint@10.5.0(supports-color@8.1.1)) - eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1) - eslint-plugin-no-null: 1.0.2(eslint@10.5.0(supports-color@8.1.1)) + - vite + + '@eclipse-glsp/eslint-config@2.8.0-next.16(@eslint/js@10.0.1(eslint@10.5.0))(@stylistic/eslint-plugin@5.10.0(eslint@10.5.0))(@tony.ganchev/eslint-plugin-header@3.4.4(eslint@10.5.0))(eslint-config-prettier@10.1.8(eslint@10.5.0))(eslint-import-resolver-typescript@4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0))(eslint@10.5.0))(eslint-plugin-chai-friendly@1.2.1(eslint@10.5.0))(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0))(eslint-plugin-no-null@1.0.2(eslint@10.5.0))(eslint@10.5.0)(globals@17.6.0)(typescript-eslint@8.61.1(eslint@10.5.0)(typescript@5.9.3))': + dependencies: + '@eslint/js': 10.0.1(eslint@10.5.0) + '@stylistic/eslint-plugin': 5.10.0(eslint@10.5.0) + '@tony.ganchev/eslint-plugin-header': 3.4.4(eslint@10.5.0) + eslint: 10.5.0 + eslint-config-prettier: 10.1.8(eslint@10.5.0) + eslint-import-resolver-typescript: 4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0))(eslint@10.5.0) + eslint-plugin-chai-friendly: 1.2.1(eslint@10.5.0) + eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0) + eslint-plugin-no-null: 1.0.2(eslint@10.5.0) globals: 17.6.0 - typescript-eslint: 8.61.0(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) - - '@eclipse-glsp/mocha-config@2.8.0-next.9(ignore-styles@5.0.1)(mocha@11.7.6)(reflect-metadata@0.2.2)': - dependencies: - ignore-styles: 5.0.1 - mocha: 11.7.6 - reflect-metadata: 0.2.2 + typescript-eslint: 8.61.1(eslint@10.5.0)(typescript@5.9.3) - '@eclipse-glsp/nyc-config@2.8.0-next.9(@istanbuljs/nyc-config-typescript@1.0.2(nyc@18.0.0(supports-color@8.1.1)))(nyc@18.0.0(supports-color@8.1.1))': - dependencies: - '@istanbuljs/nyc-config-typescript': 1.0.2(nyc@18.0.0(supports-color@8.1.1)) - nyc: 18.0.0(supports-color@8.1.1) - - '@eclipse-glsp/prettier-config@2.8.0-next.9(prettier@3.8.4)': + '@eclipse-glsp/prettier-config@2.8.0-next.16(prettier@3.8.4)': dependencies: prettier-plugin-packagejson: 3.0.2(prettier@3.8.4) transitivePeerDependencies: - prettier - '@eclipse-glsp/protocol@2.8.0-next.10(inversify@6.2.2(reflect-metadata@0.2.2))': + '@eclipse-glsp/protocol@2.8.0-next.12(inversify@6.2.2(reflect-metadata@0.2.2))(reflect-metadata@0.2.2)': dependencies: - inversify: 6.2.2(reflect-metadata@0.2.2) sprotty-protocol: 1.4.0 uuid: 14.0.0 vscode-jsonrpc: 8.2.0 + optionalDependencies: + inversify: 6.2.2(reflect-metadata@0.2.2) + reflect-metadata: 0.2.2 - '@eclipse-glsp/ts-config@2.8.0-next.9(typescript@5.9.3)': + '@eclipse-glsp/ts-config@2.8.0-next.16(typescript@5.9.3)': dependencies: typescript: 5.9.3 + '@eclipse-glsp/vitest-config@2.8.0-next.16(@vitest/coverage-v8@4.1.9)(vitest@4.1.9)': + dependencies: + '@vitest/coverage-v8': 4.1.9(vitest@4.1.9) + vitest: 4.1.9(@types/node@22.19.21)(@vitest/coverage-v8@4.1.9)(vite@8.0.16(@types/node@22.19.21)(esbuild@0.28.1)) + '@emnapi/core@1.10.0': dependencies: '@emnapi/wasi-threads': 1.2.1 @@ -2606,17 +2218,17 @@ snapshots: '@esbuild/win32-x64@0.28.1': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.5.0(supports-color@8.1.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.5.0)': dependencies: - eslint: 10.5.0(supports-color@8.1.1) + eslint: 10.5.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.23.5(supports-color@8.1.1)': + '@eslint/config-array@0.23.5': dependencies: '@eslint/object-schema': 3.0.5 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3 minimatch: 10.2.5 transitivePeerDependencies: - supports-color @@ -2629,9 +2241,9 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.5.0(supports-color@8.1.1))': + '@eslint/js@10.0.1(eslint@10.5.0)': optionalDependencies: - eslint: 10.5.0(supports-color@8.1.1) + eslint: 10.5.0 '@eslint/object-schema@3.0.5': {} @@ -2673,40 +2285,6 @@ snapshots: dependencies: reflect-metadata: 0.2.2 - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.2.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@istanbuljs/load-nyc-config@1.1.0': - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 4.2.0 - resolve-from: 5.0.0 - - '@istanbuljs/nyc-config-typescript@1.0.2(nyc@18.0.0(supports-color@8.1.1))': - dependencies: - '@istanbuljs/schema': 0.1.6 - nyc: 18.0.0(supports-color@8.1.1) - - '@istanbuljs/schema@0.1.6': {} - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/sourcemap-codec@1.5.5': {} @@ -2716,12 +2294,7 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping@0.3.9': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@modelcontextprotocol/sdk@1.29.0(supports-color@8.1.1)(zod@4.4.3)': + '@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)': dependencies: '@hono/node-server': 1.19.14(hono@4.12.25) ajv: 8.20.0 @@ -2731,8 +2304,8 @@ snapshots: cross-spawn: 7.0.6 eventsource: 3.0.7 eventsource-parser: 3.1.0 - express: 5.2.1(supports-color@8.1.1) - express-rate-limit: 8.5.2(express@5.2.1(supports-color@8.1.1)) + express: 5.2.1 + express-rate-limit: 8.5.2(express@5.2.1) hono: 4.12.25 jose: 6.2.3 json-schema-typed: 8.0.2 @@ -2750,57 +2323,93 @@ snapshots: '@tybys/wasm-util': 0.10.2 optional: true + '@oxc-project/types@0.133.0': {} + '@package-json/types@0.0.12': {} - '@pkgjs/parseargs@0.11.0': + '@rolldown/binding-android-arm64@1.0.3': optional: true - '@sinonjs/commons@3.0.1': - dependencies: - type-detect: 4.0.8 + '@rolldown/binding-darwin-arm64@1.0.3': + optional: true - '@sinonjs/fake-timers@15.4.0': - dependencies: - '@sinonjs/commons': 3.0.1 + '@rolldown/binding-darwin-x64@1.0.3': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.3': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.3': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.3': + optional: true - '@sinonjs/samsam@10.0.2': + '@rolldown/binding-openharmony-arm64@1.0.3': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.3': dependencies: - '@sinonjs/commons': 3.0.1 - type-detect: 4.1.0 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.3': + optional: true + + '@rolldown/pluginutils@1.0.1': {} '@so-ric/colorspace@1.1.6': dependencies: color: 5.0.3 text-hex: 1.0.0 - '@stylistic/eslint-plugin@5.10.0(eslint@10.5.0(supports-color@8.1.1))': + '@standard-schema/spec@1.1.0': {} + + '@stylistic/eslint-plugin@5.10.0(eslint@10.5.0)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0(supports-color@8.1.1)) - '@typescript-eslint/types': 8.61.0 - eslint: 10.5.0(supports-color@8.1.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0) + '@typescript-eslint/types': 8.61.1 + eslint: 10.5.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.4 - '@tony.ganchev/eslint-plugin-header@3.4.4(eslint@10.5.0(supports-color@8.1.1))': + '@tony.ganchev/eslint-plugin-header@3.4.4(eslint@10.5.0)': dependencies: - eslint: 10.5.0(supports-color@8.1.1) - - '@tsconfig/node10@1.0.12': {} - - '@tsconfig/node12@1.0.11': {} - - '@tsconfig/node14@1.0.3': {} - - '@tsconfig/node16@1.0.4': {} + eslint: 10.5.0 '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true - '@types/chai@4.3.20': {} + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} '@types/esrecurse@4.3.1': {} @@ -2808,33 +2417,25 @@ snapshots: '@types/json-schema@7.0.15': {} - '@types/mocha@10.0.10': {} - '@types/node@22.19.21': dependencies: undici-types: 6.21.0 - '@types/sinon@21.0.1': - dependencies: - '@types/sinonjs__fake-timers': 15.0.1 - - '@types/sinonjs__fake-timers@15.0.1': {} - '@types/triple-beam@1.3.5': {} '@types/ws@8.18.1': dependencies: '@types/node': 22.19.21 - '@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.61.1(@typescript-eslint/parser@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.61.0(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.61.0 - '@typescript-eslint/type-utils': 8.61.0(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) - '@typescript-eslint/utils': 8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.61.0 - eslint: 10.5.0(supports-color@8.1.1) + '@typescript-eslint/parser': 8.61.1(eslint@10.5.0)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.61.1 + '@typescript-eslint/type-utils': 8.61.1(eslint@10.5.0)(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.1(eslint@10.5.0)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.61.1 + eslint: 10.5.0 ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -2842,57 +2443,57 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.61.0(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3)': + '@typescript-eslint/parser@8.61.1(eslint@10.5.0)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.61.0 - '@typescript-eslint/types': 8.61.0 - '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.61.0 - debug: 4.4.3(supports-color@8.1.1) - eslint: 10.5.0(supports-color@8.1.1) + '@typescript-eslint/scope-manager': 8.61.1 + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.61.1 + debug: 4.4.3 + eslint: 10.5.0 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.61.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.61.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@5.9.3) - '@typescript-eslint/types': 8.61.0 - debug: 4.4.3(supports-color@8.1.1) + '@typescript-eslint/tsconfig-utils': 8.61.1(typescript@5.9.3) + '@typescript-eslint/types': 8.61.1 + debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.61.0': + '@typescript-eslint/scope-manager@8.61.1': dependencies: - '@typescript-eslint/types': 8.61.0 - '@typescript-eslint/visitor-keys': 8.61.0 + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/visitor-keys': 8.61.1 - '@typescript-eslint/tsconfig-utils@8.61.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.61.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.61.1(eslint@10.5.0)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.61.0 - '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3) - debug: 4.4.3(supports-color@8.1.1) - eslint: 10.5.0(supports-color@8.1.1) + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.1(eslint@10.5.0)(typescript@5.9.3) + debug: 4.4.3 + eslint: 10.5.0 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.61.0': {} + '@typescript-eslint/types@8.61.1': {} - '@typescript-eslint/typescript-estree@8.61.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.61.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.61.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@5.9.3) - '@typescript-eslint/types': 8.61.0 - '@typescript-eslint/visitor-keys': 8.61.0 - debug: 4.4.3(supports-color@8.1.1) + '@typescript-eslint/project-service': 8.61.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.61.1(typescript@5.9.3) + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/visitor-keys': 8.61.1 + debug: 4.4.3 minimatch: 10.2.5 semver: 7.8.4 tinyglobby: 0.2.17 @@ -2901,20 +2502,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0(supports-color@8.1.1)) - '@typescript-eslint/scope-manager': 8.61.0 - '@typescript-eslint/types': 8.61.0 - '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) - eslint: 10.5.0(supports-color@8.1.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0) + '@typescript-eslint/scope-manager': 8.61.1 + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3) + eslint: 10.5.0 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.61.0': + '@typescript-eslint/visitor-keys@8.61.1': dependencies: - '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/types': 8.61.1 eslint-visitor-keys: 5.0.1 '@unrs/resolver-binding-android-arm-eabi@1.12.2': @@ -2987,6 +2588,61 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.12.2': optional: true + '@vitest/coverage-v8@4.1.9(vitest@4.1.9)': + dependencies: + '@bcoe/v8-coverage': 1.0.2 + '@vitest/utils': 4.1.9 + ast-v8-to-istanbul: 1.0.4 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.2.0 + magicast: 0.5.3 + obug: 2.1.3 + std-env: 4.1.0 + tinyrainbow: 3.1.0 + vitest: 4.1.9(@types/node@22.19.21)(@vitest/coverage-v8@4.1.9)(vite@8.0.16(@types/node@22.19.21)(esbuild@0.28.1)) + + '@vitest/expect@4.1.9': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.9 + '@vitest/utils': 4.1.9 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.9(vite@8.0.16(@types/node@22.19.21)(esbuild@0.28.1))': + dependencies: + '@vitest/spy': 4.1.9 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.16(@types/node@22.19.21)(esbuild@0.28.1) + + '@vitest/pretty-format@4.1.9': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.9': + dependencies: + '@vitest/utils': 4.1.9 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.9': + dependencies: + '@vitest/pretty-format': 4.1.9 + '@vitest/utils': 4.1.9 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.9': {} + + '@vitest/utils@4.1.9': + dependencies: + '@vitest/pretty-format': 4.1.9 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + accepts@2.0.0: dependencies: mime-types: 3.0.2 @@ -2996,17 +2652,8 @@ snapshots: dependencies: acorn: 8.17.0 - acorn-walk@8.3.5: - dependencies: - acorn: 8.17.0 - acorn@8.17.0: {} - aggregate-error@3.1.0: - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - ajv-formats@3.0.1(ajv@8.20.0): optionalDependencies: ajv: 8.20.0 @@ -3025,41 +2672,23 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ansi-regex@5.0.1: {} + assertion-error@2.0.1: {} - ansi-regex@6.2.2: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@6.2.3: {} - - append-transform@2.0.0: + ast-v8-to-istanbul@1.0.4: dependencies: - default-require-extensions: 3.0.1 - - archy@1.0.0: {} - - arg@4.1.3: {} - - argparse@2.0.1: {} - - assertion-error@1.1.0: {} + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 async@3.2.6: {} - balanced-match@1.0.2: {} - balanced-match@4.0.4: {} - baseline-browser-mapping@2.10.37: {} - - body-parser@2.2.2(supports-color@8.1.1): + body-parser@2.3.0: dependencies: bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.3(supports-color@8.1.1) + content-type: 2.0.0 + debug: 4.4.3 http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 @@ -3069,33 +2698,12 @@ snapshots: transitivePeerDependencies: - supports-color - brace-expansion@2.1.1: - dependencies: - balanced-match: 1.0.2 - brace-expansion@5.0.6: dependencies: balanced-match: 4.0.4 - browser-stdout@1.3.1: {} - - browserslist@4.28.2: - dependencies: - baseline-browser-mapping: 2.10.37 - caniuse-lite: 1.0.30001799 - electron-to-chromium: 1.5.372 - node-releases: 2.0.47 - update-browserslist-db: 1.2.3(browserslist@4.28.2) - bytes@3.1.2: {} - caching-transform@4.0.0: - dependencies: - hasha: 5.2.2 - make-dir: 3.1.0 - package-hash: 4.0.0 - write-file-atomic: 3.0.3 - call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -3106,67 +2714,12 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 - camelcase@5.3.1: {} - - camelcase@6.3.0: {} - - caniuse-lite@1.0.30001799: {} - - chai@4.5.0: - dependencies: - assertion-error: 1.1.0 - check-error: 1.0.3 - deep-eql: 4.1.4 - get-func-name: 2.0.2 - loupe: 2.3.7 - pathval: 1.1.1 - type-detect: 4.1.0 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - charenc@0.0.2: {} - - check-error@1.0.3: - dependencies: - get-func-name: 2.0.2 - - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - - clean-stack@2.2.0: {} - - cliui@6.0.0: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - cliui@9.0.1: - dependencies: - string-width: 7.2.0 - strip-ansi: 7.2.0 - wrap-ansi: 9.0.2 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 + chai@6.2.2: {} color-convert@3.1.3: dependencies: color-name: 2.1.0 - color-name@1.1.4: {} - color-name@2.1.0: {} color-string@2.1.4: @@ -3182,16 +2735,12 @@ snapshots: comment-parser@1.4.7: {} - commondir@1.0.1: {} - content-disposition@1.1.0: {} content-type@1.0.5: {} content-type@2.0.0: {} - convert-source-map@1.9.0: {} - convert-source-map@2.0.0: {} cookie-signature@1.2.2: {} @@ -3203,50 +2752,25 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - create-require@1.1.1: {} - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 - which: 2.0.2 - - crypt@0.0.2: {} - - ctrf@0.2.1: - dependencies: - ajv: 8.20.0 - ajv-formats: 3.0.1(ajv@8.20.0) - glob: 13.0.6 - yargs: 18.0.0 - - debug@4.4.3(supports-color@8.1.1): - dependencies: - ms: 2.1.3 - optionalDependencies: - supports-color: 8.1.1 - - decamelize@1.2.0: {} - - decamelize@4.0.0: {} + which: 2.0.2 - deep-eql@4.1.4: + debug@4.4.3: dependencies: - type-detect: 4.1.0 + ms: 2.1.3 deep-is@0.1.4: {} - default-require-extensions@3.0.1: - dependencies: - strip-bom: 4.0.0 - depd@2.0.0: {} detect-indent@7.0.2: {} - detect-newline@4.0.1: {} + detect-libc@2.1.2: {} - diff@9.0.0: {} + detect-newline@4.0.1: {} dunder-proto@1.0.1: dependencies: @@ -3254,20 +2778,10 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - eastasianwidth@0.2.0: {} - ee-first@1.1.1: {} - electron-to-chromium@1.5.372: {} - elkjs@0.11.1: {} - emoji-regex@10.6.0: {} - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - enabled@2.0.0: {} encodeurl@2.0.0: {} @@ -3276,12 +2790,12 @@ snapshots: es-errors@1.3.0: {} + es-module-lexer@2.1.0: {} + es-object-atoms@1.1.2: dependencies: es-errors: 1.3.0 - es6-error@4.1.1: {} - esbuild@0.28.1: optionalDependencies: '@esbuild/aix-ppc64': 0.28.1 @@ -3311,15 +2825,13 @@ snapshots: '@esbuild/win32-ia32': 0.28.1 '@esbuild/win32-x64': 0.28.1 - escalade@3.2.0: {} - escape-html@1.0.3: {} escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@10.5.0(supports-color@8.1.1)): + eslint-config-prettier@10.1.8(eslint@10.5.0): dependencies: - eslint: 10.5.0(supports-color@8.1.1) + eslint: 10.5.0 eslint-import-context@0.1.9(unrs-resolver@1.12.2): dependencies: @@ -3328,10 +2840,10 @@ snapshots: optionalDependencies: unrs-resolver: 1.12.2 - eslint-import-resolver-typescript@4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1): + eslint-import-resolver-typescript@4.4.5(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0))(eslint@10.5.0): dependencies: - debug: 4.4.3(supports-color@8.1.1) - eslint: 10.5.0(supports-color@8.1.1) + debug: 4.4.3 + eslint: 10.5.0 eslint-import-context: 0.1.9(unrs-resolver@1.12.2) get-tsconfig: 4.14.0 is-bun-module: 2.0.0 @@ -3339,21 +2851,21 @@ snapshots: tinyglobby: 0.2.17 unrs-resolver: 1.12.2 optionalDependencies: - eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1) + eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0) transitivePeerDependencies: - supports-color - eslint-plugin-chai-friendly@1.2.0(eslint@10.5.0(supports-color@8.1.1)): + eslint-plugin-chai-friendly@1.2.1(eslint@10.5.0): dependencies: - eslint: 10.5.0(supports-color@8.1.1) + eslint: 10.5.0 - eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1): + eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0): dependencies: '@package-json/types': 0.0.12 - '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/types': 8.61.1 comment-parser: 1.4.7 - debug: 4.4.3(supports-color@8.1.1) - eslint: 10.5.0(supports-color@8.1.1) + debug: 4.4.3 + eslint: 10.5.0 eslint-import-context: 0.1.9(unrs-resolver@1.12.2) is-glob: 4.0.3 minimatch: 10.2.5 @@ -3361,13 +2873,13 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.12.2 optionalDependencies: - '@typescript-eslint/utils': 8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.1(eslint@10.5.0)(typescript@5.9.3) transitivePeerDependencies: - supports-color - eslint-plugin-no-null@1.0.2(eslint@10.5.0(supports-color@8.1.1)): + eslint-plugin-no-null@1.0.2(eslint@10.5.0): dependencies: - eslint: 10.5.0(supports-color@8.1.1) + eslint: 10.5.0 eslint-scope@9.1.2: dependencies: @@ -3382,11 +2894,11 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.5.0(supports-color@8.1.1): + eslint@10.5.0: dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0(supports-color@8.1.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.5(supports-color@8.1.1) + '@eslint/config-array': 0.23.5 '@eslint/config-helpers': 0.6.0 '@eslint/core': 1.2.1 '@eslint/plugin-kit': 0.7.2 @@ -3396,7 +2908,7 @@ snapshots: '@types/estree': 1.0.9 ajv: 6.15.0 cross-spawn: 7.0.6 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3 escape-string-regexp: 4.0.0 eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 @@ -3439,6 +2951,10 @@ snapshots: estraverse@5.3.0: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + esutils@2.0.3: {} etag@1.8.1: {} @@ -3449,25 +2965,27 @@ snapshots: dependencies: eventsource-parser: 3.1.0 - express-rate-limit@8.5.2(express@5.2.1(supports-color@8.1.1)): + expect-type@1.3.0: {} + + express-rate-limit@8.5.2(express@5.2.1): dependencies: - express: 5.2.1(supports-color@8.1.1) + express: 5.2.1 ip-address: 10.2.0 - express@5.2.1(supports-color@8.1.1): + express@5.2.1: dependencies: accepts: 2.0.0 - body-parser: 2.2.2(supports-color@8.1.1) + body-parser: 2.3.0 content-disposition: 1.1.0 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3 depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 2.1.1(supports-color@8.1.1) + finalhandler: 2.1.1 fresh: 2.0.0 http-errors: 2.0.1 merge-descriptors: 2.0.0 @@ -3478,8 +2996,8 @@ snapshots: proxy-addr: 2.0.7 qs: 6.15.2 range-parser: 1.2.1 - router: 2.2.0(supports-color@8.1.1) - send: 1.2.1(supports-color@8.1.1) + router: 2.2.0 + send: 1.2.1 serve-static: 2.2.1 statuses: 2.0.2 type-is: 2.1.0 @@ -3507,9 +3025,9 @@ snapshots: dependencies: flat-cache: 4.0.1 - finalhandler@2.1.1(supports-color@8.1.1): + finalhandler@2.1.1: dependencies: - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3 encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -3518,17 +3036,6 @@ snapshots: transitivePeerDependencies: - supports-color - find-cache-dir@3.3.2: - dependencies: - commondir: 1.0.1 - make-dir: 3.1.0 - pkg-dir: 4.2.0 - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -3539,38 +3046,19 @@ snapshots: flatted: 3.4.2 keyv: 4.5.4 - flat@5.0.2: {} - flatted@3.4.2: {} fn.name@1.1.0: {} - foreground-child@2.0.0: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 3.0.7 - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - forwarded@0.2.0: {} fresh@2.0.0: {} - fromentries@1.3.2: {} + fsevents@2.3.3: + optional: true function-bind@1.1.2: {} - gensync@1.0.0-beta.2: {} - - get-caller-file@2.0.5: {} - - get-east-asian-width@1.6.0: {} - - get-func-name@2.0.2: {} - get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -3584,8 +3072,6 @@ snapshots: hasown: 2.0.4 math-intrinsics: 1.1.0 - get-package-type@0.1.0: {} - get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -3601,15 +3087,6 @@ snapshots: dependencies: is-glob: 4.0.3 - glob@10.5.0: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.9 - minipass: 7.1.3 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - glob@13.0.6: dependencies: minimatch: 10.2.5 @@ -3620,23 +3097,14 @@ snapshots: gopd@1.2.0: {} - graceful-fs@4.2.11: {} - has-flag@4.0.0: {} has-symbols@1.1.0: {} - hasha@5.2.2: - dependencies: - is-stream: 2.0.1 - type-fest: 0.8.1 - hasown@2.0.4: dependencies: function-bind: 1.1.2 - he@1.2.0: {} - hono@4.12.25: {} html-escaper@2.0.2: {} @@ -3653,16 +3121,12 @@ snapshots: dependencies: safer-buffer: 2.1.2 - ignore-styles@5.0.1: {} - ignore@5.3.2: {} ignore@7.0.5: {} imurmurhash@0.1.4: {} - indent-string@4.0.0: {} - inherits@2.0.4: {} inversify@6.2.2(reflect-metadata@0.2.2): @@ -3675,96 +3139,40 @@ snapshots: ipaddr.js@1.9.1: {} - is-buffer@1.1.6: {} - is-bun-module@2.0.0: dependencies: semver: 7.8.4 is-extglob@2.1.1: {} - is-fullwidth-code-point@3.0.0: {} - is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - is-path-inside@3.0.3: {} - - is-plain-obj@2.1.0: {} - is-plain-obj@4.1.0: {} is-promise@4.0.0: {} is-stream@2.0.1: {} - is-typedarray@1.0.0: {} - - is-unicode-supported@0.1.0: {} - - is-windows@1.0.2: {} - isexe@2.0.0: {} istanbul-lib-coverage@3.2.2: {} - istanbul-lib-hook@3.0.0: - dependencies: - append-transform: 2.0.0 - - istanbul-lib-instrument@6.0.3(supports-color@8.1.1): - dependencies: - '@babel/core': 7.29.7(supports-color@8.1.1) - '@babel/parser': 7.29.7 - '@istanbuljs/schema': 0.1.6 - istanbul-lib-coverage: 3.2.2 - semver: 7.8.4 - transitivePeerDependencies: - - supports-color - - istanbul-lib-processinfo@3.0.1: - dependencies: - archy: 1.0.0 - cross-spawn: 7.0.6 - istanbul-lib-coverage: 3.2.2 - p-map: 3.0.0 - rimraf: 6.1.3 - istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@4.0.1(supports-color@8.1.1): - dependencies: - debug: 4.4.3(supports-color@8.1.1) - istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - istanbul-reports@3.2.0: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - jose@6.2.3: {} - js-tokens@4.0.0: {} - - js-yaml@4.2.0: - dependencies: - argparse: 2.0.1 - - jsesc@3.1.0: {} + js-tokens@10.0.0: {} json-buffer@3.0.1: {} @@ -3776,8 +3184,6 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} - json5@2.2.3: {} - keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -3789,21 +3195,59 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - locate-path@5.0.0: + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: dependencies: - p-locate: 4.1.0 + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 locate-path@6.0.0: dependencies: p-locate: 5.0.0 - lodash.flattendeep@4.4.0: {} - - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - logform@2.7.0: dependencies: '@colors/colors': 1.6.0 @@ -3813,36 +3257,24 @@ snapshots: safe-stable-stringify: 2.5.0 triple-beam: 1.4.1 - loupe@2.3.7: - dependencies: - get-func-name: 2.0.2 - - lru-cache@10.4.3: {} - lru-cache@11.5.1: {} - lru-cache@5.1.1: + magic-string@0.30.21: dependencies: - yallist: 3.1.1 + '@jridgewell/sourcemap-codec': 1.5.5 - make-dir@3.1.0: + magicast@0.5.3: dependencies: - semver: 6.3.1 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + source-map-js: 1.2.1 make-dir@4.0.0: dependencies: semver: 7.8.4 - make-error@1.3.6: {} - math-intrinsics@1.1.0: {} - md5@2.3.0: - dependencies: - charenc: 0.0.2 - crypt: 0.0.2 - is-buffer: 1.1.6 - media-typer@1.1.0: {} merge-descriptors@2.0.0: {} @@ -3857,91 +3289,24 @@ snapshots: dependencies: brace-expansion: 5.0.6 - minimatch@9.0.9: - dependencies: - brace-expansion: 2.1.1 - minipass@7.1.3: {} - mocha-ctrf-json-reporter@0.0.11: - dependencies: - ctrf: 0.2.1 - md5: 2.3.0 - - mocha@11.7.6: - dependencies: - browser-stdout: 1.3.1 - chokidar: 4.0.3 - debug: 4.4.3(supports-color@8.1.1) - diff: 9.0.0 - escape-string-regexp: 4.0.0 - find-up: 5.0.0 - glob: 10.5.0 - he: 1.2.0 - is-path-inside: 3.0.3 - js-yaml: 4.2.0 - log-symbols: 4.1.0 - minimatch: 9.0.9 - ms: 2.1.3 - picocolors: 1.1.1 - serialize-javascript: 7.0.5 - strip-json-comments: 3.1.1 - supports-color: 8.1.1 - workerpool: 9.3.4 - yargs: 17.7.2 - yargs-parser: 21.1.1 - yargs-unparser: 2.0.0 - ms@2.1.3: {} + nanoid@3.3.12: {} + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} negotiator@1.0.0: {} - node-preload@0.2.1: - dependencies: - process-on-spawn: 1.1.0 - - node-releases@2.0.47: {} - - nyc@18.0.0(supports-color@8.1.1): - dependencies: - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.6 - caching-transform: 4.0.0 - convert-source-map: 1.9.0 - decamelize: 1.2.0 - find-cache-dir: 3.3.2 - find-up: 4.1.0 - foreground-child: 3.3.1 - get-package-type: 0.1.0 - glob: 13.0.6 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-hook: 3.0.0 - istanbul-lib-instrument: 6.0.3(supports-color@8.1.1) - istanbul-lib-processinfo: 3.0.1 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1(supports-color@8.1.1) - istanbul-reports: 3.2.0 - make-dir: 3.1.0 - node-preload: 0.2.1 - p-map: 3.0.0 - process-on-spawn: 1.1.0 - resolve-from: 5.0.0 - rimraf: 6.1.3 - signal-exit: 3.0.7 - spawn-wrap: 3.0.0 - test-exclude: 8.0.0 - yargs: 15.4.1 - transitivePeerDependencies: - - supports-color - object-assign@4.1.1: {} object-inspect@1.13.4: {} + obug@2.1.3: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -3963,35 +3328,14 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - p-locate@5.0.0: dependencies: p-limit: 3.1.0 - p-map@3.0.0: - dependencies: - aggregate-error: 3.1.0 - - p-try@2.2.0: {} - - package-hash@4.0.0: - dependencies: - graceful-fs: 4.2.11 - hasha: 5.2.2 - lodash.flattendeep: 4.4.0 - release-zalgo: 1.0.0 - package-json-from-dist@1.0.1: {} parseurl@1.3.3: {} @@ -4000,11 +3344,6 @@ snapshots: path-key@3.1.1: {} - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.3 - path-scurry@2.0.2: dependencies: lru-cache: 11.5.1 @@ -4012,7 +3351,7 @@ snapshots: path-to-regexp@8.4.2: {} - pathval@1.1.1: {} + pathe@2.0.3: {} picocolors@1.1.1: {} @@ -4020,9 +3359,11 @@ snapshots: pkce-challenge@5.0.1: {} - pkg-dir@4.2.0: + postcss@8.5.15: dependencies: - find-up: 4.1.0 + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 prelude-ls@1.2.1: {} @@ -4034,10 +3375,6 @@ snapshots: prettier@3.8.4: {} - process-on-spawn@1.1.0: - dependencies: - fromentries: 1.3.2 - proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -4064,22 +3401,10 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readdirp@4.1.2: {} - reflect-metadata@0.2.2: {} - release-zalgo@1.0.0: - dependencies: - es6-error: 4.1.1 - - require-directory@2.1.1: {} - require-from-string@2.0.2: {} - require-main-filename@2.0.0: {} - - resolve-from@5.0.0: {} - resolve-pkg-maps@1.0.0: {} rimraf@6.1.3: @@ -4087,9 +3412,30 @@ snapshots: glob: 13.0.6 package-json-from-dist: 1.0.1 - router@2.2.0(supports-color@8.1.1): + rolldown@1.0.3: + dependencies: + '@oxc-project/types': 0.133.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 + + router@2.2.0: dependencies: - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3 depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -4103,13 +3449,11 @@ snapshots: safer-buffer@2.1.2: {} - semver@6.3.1: {} - semver@7.8.4: {} - send@1.2.1(supports-color@8.1.1): + send@1.2.1: dependencies: - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -4123,19 +3467,15 @@ snapshots: transitivePeerDependencies: - supports-color - serialize-javascript@7.0.5: {} - serve-static@2.2.1: dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 1.2.1(supports-color@8.1.1) + send: 1.2.1 transitivePeerDependencies: - supports-color - set-blocking@2.0.0: {} - setprototypeof@1.2.0: {} shebang-command@2.0.0: @@ -4172,16 +3512,7 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 - signal-exit@3.0.7: {} - - signal-exit@4.1.0: {} - - sinon@22.0.0: - dependencies: - '@sinonjs/commons': 3.0.1 - '@sinonjs/fake-timers': 15.4.0 - '@sinonjs/samsam': 10.0.2 - diff: 9.0.0 + siginfo@2.0.0: {} sort-object-keys@2.1.0: {} @@ -4195,17 +3526,7 @@ snapshots: sort-object-keys: 2.1.0 tinyglobby: 0.2.17 - source-map@0.6.1: {} - - spawn-wrap@3.0.0: - dependencies: - cross-spawn: 7.0.6 - foreground-child: 2.0.0 - is-windows: 1.0.2 - make-dir: 3.1.0 - rimraf: 6.1.3 - signal-exit: 3.0.7 - which: 2.0.2 + source-map-js@1.2.1: {} sprotty-protocol@1.4.0: {} @@ -4213,63 +3534,33 @@ snapshots: stack-trace@0.0.10: {} - statuses@2.0.2: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 + stackback@0.0.2: {} - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.2.0 + statuses@2.0.2: {} - string-width@7.2.0: - dependencies: - emoji-regex: 10.6.0 - get-east-asian-width: 1.6.0 - strip-ansi: 7.2.0 + std-env@4.1.0: {} string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.2.0: - dependencies: - ansi-regex: 6.2.2 - - strip-bom@4.0.0: {} - - strip-json-comments@3.1.1: {} - supports-color@7.2.0: dependencies: has-flag: 4.0.0 - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 + text-hex@1.0.0: {} - test-exclude@8.0.0: - dependencies: - '@istanbuljs/schema': 0.1.6 - glob: 13.0.6 - minimatch: 10.2.5 + tinybench@2.9.0: {} - text-hex@1.0.0: {} + tinyexec@1.2.4: {} tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tinyrainbow@3.1.0: {} + toidentifier@1.0.1: {} triple-beam@1.4.1: {} @@ -4278,24 +3569,6 @@ snapshots: dependencies: typescript: 5.9.3 - ts-node@10.9.2(@types/node@22.19.21)(typescript@5.9.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.12 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 22.19.21 - acorn: 8.17.0 - acorn-walk: 8.3.5 - arg: 4.1.3 - create-require: 1.1.1 - diff: 9.0.0 - make-error: 1.3.6 - typescript: 5.9.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - tslib@2.8.1: optional: true @@ -4303,29 +3576,19 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-detect@4.0.8: {} - - type-detect@4.1.0: {} - - type-fest@0.8.1: {} - type-is@2.1.0: dependencies: content-type: 2.0.0 media-typer: 1.1.0 mime-types: 3.0.2 - typedarray-to-buffer@3.1.5: + typescript-eslint@8.61.1(eslint@10.5.0)(typescript@5.9.3): dependencies: - is-typedarray: 1.0.0 - - typescript-eslint@8.61.0(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3))(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) - '@typescript-eslint/parser': 8.61.0(eslint@10.5.0(supports-color@8.1.1))(supports-color@8.1.1)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.61.0(eslint@10.5.0(supports-color@8.1.1))(typescript@5.9.3) - eslint: 10.5.0(supports-color@8.1.1) + '@typescript-eslint/eslint-plugin': 8.61.1(@typescript-eslint/parser@8.61.1(eslint@10.5.0)(typescript@5.9.3))(eslint@10.5.0)(typescript@5.9.3) + '@typescript-eslint/parser': 8.61.1(eslint@10.5.0)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.1(eslint@10.5.0)(typescript@5.9.3) + eslint: 10.5.0 typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -4363,12 +3626,6 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 - update-browserslist-db@1.2.3(browserslist@4.28.2): - dependencies: - browserslist: 4.28.2 - escalade: 3.2.0 - picocolors: 1.1.1 - uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -4377,18 +3634,59 @@ snapshots: uuid@14.0.0: {} - v8-compile-cache-lib@3.0.1: {} - vary@1.1.2: {} - vscode-jsonrpc@8.2.0: {} + vite@8.0.16(@types/node@22.19.21)(esbuild@0.28.1): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.3 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 22.19.21 + esbuild: 0.28.1 + fsevents: 2.3.3 + + vitest@4.1.9(@types/node@22.19.21)(@vitest/coverage-v8@4.1.9)(vite@8.0.16(@types/node@22.19.21)(esbuild@0.28.1)): + dependencies: + '@vitest/expect': 4.1.9 + '@vitest/mocker': 4.1.9(vite@8.0.16(@types/node@22.19.21)(esbuild@0.28.1)) + '@vitest/pretty-format': 4.1.9 + '@vitest/runner': 4.1.9 + '@vitest/snapshot': 4.1.9 + '@vitest/spy': 4.1.9 + '@vitest/utils': 4.1.9 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.3 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.0.16(@types/node@22.19.21)(esbuild@0.28.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.19.21 + '@vitest/coverage-v8': 4.1.9(vitest@4.1.9) + transitivePeerDependencies: + - msw - which-module@2.0.1: {} + vscode-jsonrpc@8.2.0: {} which@2.0.2: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + winston-transport@4.9.0: dependencies: logform: 2.7.0 @@ -4411,100 +3709,10 @@ snapshots: word-wrap@1.2.5: {} - workerpool@9.3.4: {} - - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.3 - string-width: 5.1.2 - strip-ansi: 7.2.0 - - wrap-ansi@9.0.2: - dependencies: - ansi-styles: 6.2.3 - string-width: 7.2.0 - strip-ansi: 7.2.0 - wrappy@1.0.2: {} - write-file-atomic@3.0.3: - dependencies: - imurmurhash: 0.1.4 - is-typedarray: 1.0.0 - signal-exit: 3.0.7 - typedarray-to-buffer: 3.1.5 - ws@8.21.0: {} - y18n@4.0.3: {} - - y18n@5.0.8: {} - - yallist@3.1.1: {} - - yargs-parser@18.1.3: - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - - yargs-parser@21.1.1: {} - - yargs-parser@22.0.0: {} - - yargs-unparser@2.0.0: - dependencies: - camelcase: 6.3.0 - decamelize: 4.0.0 - flat: 5.0.2 - is-plain-obj: 2.1.0 - - yargs@15.4.1: - dependencies: - cliui: 6.0.0 - decamelize: 1.2.0 - find-up: 4.1.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 4.2.3 - which-module: 2.0.1 - y18n: 4.0.3 - yargs-parser: 18.1.3 - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yargs@18.0.0: - dependencies: - cliui: 9.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - string-width: 7.2.0 - y18n: 5.0.8 - yargs-parser: 22.0.0 - - yn@3.1.1: {} - yocto-queue@0.1.0: {} zod-to-json-schema@3.25.2(zod@4.4.3): diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 2a124a20..32bc50c5 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,7 +2,7 @@ packages: - 'packages/*' - 'examples/*' -# Tooling (eslint, prettier, mocha, ts-node, rimraf, @eclipse-glsp/*-config, ...) is provided +# Tooling (eslint, prettier, vitest, rimraf, @eclipse-glsp/*-config, ...) is provided # as transitive deps of @eclipse-glsp/dev and must resolve from the workspace root # (tsconfig `extends`, lint/test/build bins). Public-hoist only the dev tooling; app/runtime # deps stay strictly isolated. pnpm >=11 no longer reads non-auth settings from .npmrc, so @@ -15,12 +15,9 @@ publicHoistPattern: - '@typescript-eslint/*' - 'prettier' - 'prettier-plugin-*' - - 'mocha' - - 'chai' - - 'sinon' - - 'ts-node' + - 'vitest' + - '@vitest/*' - 'rimraf' - - 'nyc' - '@types/*' # type stubs are compile-time-only; hoist so `@types/` resolves at root # Force-resolve vulnerable transitive deps to patched versions (pnpm audit advisories). diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 30c4da7d..7da89089 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -1,7 +1,7 @@ { - "extends": "@eclipse-glsp/ts-config/mocha", + "extends": "@eclipse-glsp/ts-config", "compilerOptions": { "noEmit": true }, - "include": ["packages/*/src", "examples/*/src"] + "include": ["packages/*/src", "examples/*/src", "vite.config.ts"] } diff --git a/tsconfig.json b/tsconfig.json index f166222f..9630a3b6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@eclipse-glsp/ts-config/mocha", + "extends": "@eclipse-glsp/ts-config", "include": [], "compilerOptions": { "composite": true, diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 00000000..14af3e3b --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,22 @@ +{ + "extends": "@eclipse-glsp/ts-config", + "compilerOptions": { + "composite": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./packages/graph/tsconfig.test.json" + }, + { + "path": "./packages/layout-elk/tsconfig.test.json" + }, + { + "path": "./packages/server/tsconfig.test.json" + }, + { + "path": "./packages/server-mcp/tsconfig.test.json" + } + ] +} diff --git a/packages/graph/src/index.spec.ts b/vite.config.ts similarity index 62% rename from packages/graph/src/index.spec.ts rename to vite.config.ts index 4c03964c..bda9ca05 100644 --- a/packages/graph/src/index.spec.ts +++ b/vite.config.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 STMicroelectronics and others. + * Copyright (c) 2026 STMicroelectronics and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -13,15 +13,7 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ - -/* note: this bogus test file is required so that - we are able to run mocha unit tests on this - package, without having any actual unit tests in it. - This way a coverage report will be generated, - showing 0% coverage, instead of no report. - This file can be removed once we have real unit - tests in place. */ - -describe('graph package', () => { - it('should support code coverage statistics', () => true); -}); +// The shared config globs every package's specs (`**/src/**`), so a single `vitest run` from the +// repository root covers all packages and `--coverage` produces one merged report +// (replaces the former `glsp coverageReport`). +export { default } from '@eclipse-glsp/vitest-config'; From cd421f03202d0154d897600b3f6e81031e039680 Mon Sep 17 00:00:00 2001 From: Tobias Ortmayr Date: Tue, 23 Jun 2026 00:52:05 +0200 Subject: [PATCH 2/2] Address review comments - Assert the auto-bound service (`bind(SubTarget)`) in the binding-target spec instead of `bind(Target)`, which is bound unconditionally and so never actually verified the auto-bind behavior --- packages/server/src/common/di/binding-target.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/common/di/binding-target.spec.ts b/packages/server/src/common/di/binding-target.spec.ts index 4daa5088..b317ec80 100644 --- a/packages/server/src/common/di/binding-target.spec.ts +++ b/packages/server/src/common/di/binding-target.spec.ts @@ -134,7 +134,7 @@ describe('BindingTarget', () => { it('Should bind the unbound target service to itself before applying the toService binding', () => { vi.mocked(context.isBound).mockReturnValue(false); applyBindingTarget(context, Target, { service: SubTarget }); - expect(context.bind).toHaveBeenCalledWith(Target); + expect(context.bind).toHaveBeenCalledWith(SubTarget); }); it('The return syntax should be no op and invocation of a syntax function should throw an error', () => { vi.mocked(context.isBound).mockReturnValue(true);