diff --git a/.github/workflows/jest.yml b/.github/workflows/jest.yml deleted file mode 100644 index e186c3dc..00000000 --- a/.github/workflows/jest.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: Jest -on: - workflow_dispatch: - push: - branches: - - main - - '*.x' - pull_request: -jobs: - test: - runs-on: ${{ matrix.os }} - - strategy: - fail-fast: false - matrix: - os: [ ubuntu-latest, windows-latest, macos-latest ] - php: [ '7.1', '7.3', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5' ] - node: [ '20' ] - stability: [ prefer-stable ] - - name: ${{ matrix.os }} node-${{ matrix.node }} php-${{ matrix.php }} - env: - extensions: curl, dom, libxml, mbstring, pcntl, pdo, pdo_sqlite, sqlite, xdebug, zip - key: cache-v1 # can be any string, change to clear the extension cache. - GITHUB_ACTIONS: true - PHPUNIT_PROJECT: src/PHPUnit/__tests__/fixtures/phpunit-stub - PEST_PROJECT: src/PHPUnit/__tests__/fixtures/pest-stub - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup cache environment - id: extcache - uses: shivammathur/cache-extensions@v1 - with: - php-version: ${{ matrix.php }} - extensions: ${{ env.extensions }} - key: ${{ env.key }} - - - name: Cache extensions - uses: actions/cache@v3 - with: - path: ${{ steps.extcache.outputs.dir }} - key: ${{ steps.extcache.outputs.key }} - restore-keys: ${{ steps.extcache.outputs.key }} - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - extensions: ${{ env.extensions }} - tools: composer:v2 - coverage: xdebug - - - name: Install Composer dependencies (PHPUnit) - run: cd ${{ env.PHPUNIT_PROJECT }} && composer update --prefer-dist --no-interaction --no-progress - - - name: Install PHPUnit 10.5.30 for PHP 8.1 - if: matrix.php == '8.1' - run: cd ${{ env.PHPUNIT_PROJECT }} && composer require phpunit/phpunit:10.5.30 --prefer-dist --no-interaction --no-progress - - - name: Install Composer dependencies (PEST) - if: matrix.php >= '8.0' - run: cd ${{ env.PEST_PROJECT }} && composer update --prefer-dist --no-interaction --no-progress - - # Install required deps for action - - name: Install Dependencies - run: npm ci - - # Finally, run our tests - - name: Run the tests - run: npm run jest - - - name: Send to codecov - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos - flags: unittests - - # - name: RUN SSH - # if: failure() - # run: curl -sSf https://sshx.io/get | sh -s run diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..bdf74148 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,109 @@ +name: Tests +on: + workflow_dispatch: + push: + branches: + - main + - '*.x' + pull_request: +jobs: + test: + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] + php: ['7.4', '8.2', '8.4'] + node: ['20'] + + name: ${{ matrix.os }} node-${{ matrix.node }} php-${{ matrix.php }} + defaults: + run: + shell: bash + env: + extensions: curl, dom, libxml, mbstring, pcntl, pdo, pdo_sqlite, sqlite, xdebug, zip + key: cache-v1 + GITHUB_ACTIONS: true + PHPUNIT_PROJECT: src/PHPUnit/__tests__/fixtures/phpunit-stub + PEST_PROJECT: src/PHPUnit/__tests__/fixtures/pest-stub + # Minimum PHP version per stub (used to skip incompatible installs) + PHPUNIT_MIN_PHP: v9=7.3 v10=8.1 v11=8.2 v12=8.3 + PEST_MIN_PHP: v2=8.2 v3=8.2 v4=8.3 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup cache environment + id: extcache + uses: shivammathur/cache-extensions@v1 + with: + php-version: ${{ matrix.php }} + extensions: ${{ env.extensions }} + key: ${{ env.key }} + + - name: Cache extensions + uses: actions/cache@v4 + with: + path: ${{ steps.extcache.outputs.dir }} + key: ${{ steps.extcache.outputs.key }} + restore-keys: ${{ steps.extcache.outputs.key }} + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: ${{ env.extensions }} + tools: composer:v2 + coverage: xdebug + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: npm + + - name: Install Composer dependencies (PHPUnit stubs) + run: | + lookup="${{ env.PHPUNIT_MIN_PHP }}" + for dir in $(ls -d ${{ env.PHPUNIT_PROJECT }}/v*/ | sort -V); do + stub=$(basename "$dir") + min=$(echo "$lookup" | tr ' ' '\n' | grep "^${stub}=" | cut -d= -f2) + min=${min:-99} + if php -r "exit(version_compare('${{ matrix.php }}','$min','>=') ? 0 : 1);"; then + echo "::group::Installing $stub (PHP >= $min)" + (cd "$dir" && composer install --prefer-dist --no-interaction --no-progress) || true + echo "::endgroup::" + else + echo "Skipping $stub (requires PHP >= $min, have ${{ matrix.php }})" + fi + done + + - name: Install Composer dependencies (Pest stubs) + run: | + lookup="${{ env.PEST_MIN_PHP }}" + for dir in $(ls -d ${{ env.PEST_PROJECT }}/v*/ | sort -V); do + stub=$(basename "$dir") + min=$(echo "$lookup" | tr ' ' '\n' | grep "^${stub}=" | cut -d= -f2) + min=${min:-99} + if php -r "exit(version_compare('${{ matrix.php }}','$min','>=') ? 0 : 1);"; then + echo "::group::Installing $stub (PHP >= $min)" + (cd "$dir" && composer install --prefer-dist --no-interaction --no-progress) || true + echo "::endgroup::" + else + echo "Skipping $stub (requires PHP >= $min, have ${{ matrix.php }})" + fi + done + + - name: Install Dependencies + run: npm ci + + - name: Run the tests + run: npm run vitest + + - name: Send to codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: unittests diff --git a/.gitignore b/.gitignore index e7c5eeee..62490d33 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,10 @@ node_modules *.vsix .idea/ -coverage/ +/coverage/ +build/ .DS_Store *.zip + +.claude/ +CLAUDE.md diff --git a/.vscodeignore b/.vscodeignore index a2ae52c1..f8122c5b 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -5,10 +5,11 @@ node_modules/** src/** .gitignore .yarnrc -webpack.config.js +esbuild.mjs vsc-extension-quickstart.md **/tsconfig.json **/.eslintrc.json +biome.json **/*.map **/*.ts @@ -16,6 +17,6 @@ vsc-extension-quickstart.md .github/** coverage/** sample/** -jest.config.js +vitest.config.ts img/** !img/icon.png diff --git a/__mocks__/vscode.ts b/__mocks__/vscode.ts index 2f19f27b..869fa694 100644 --- a/__mocks__/vscode.ts +++ b/__mocks__/vscode.ts @@ -1,3 +1,4 @@ +import { vi } from 'vitest'; import { glob } from 'glob'; import { minimatch } from 'minimatch'; import { readFile } from 'node:fs/promises'; @@ -13,7 +14,7 @@ enum TestRunProfileKind { Coverage = 3, } -const TestRunRequest = jest.fn().mockImplementation((include: any) => { +const TestRunRequest = vi.fn().mockImplementation(function (include: any) { return { include, }; @@ -42,6 +43,13 @@ const Uri = new Proxy(URI, { }, }); +class FakeTestTag { + readonly id: string; + constructor(id: string) { + this.id = id; + } +} + class FakeTestItemCollection implements Iterable<[id: string, testItem: TestItem]> { private items = new Map(); private readonly parent: any; @@ -88,7 +96,7 @@ class FakeTestItemCollection implements Iterable<[id: string, testItem: TestItem } } -const createTestItem = jest +const createTestItem = vi .fn() .mockImplementation((id: string, label: string, uri?: URI): TestItem => { const testItem = { id, label, uri } as any; @@ -97,7 +105,7 @@ const createTestItem = jest return testItem; }); -const createRunProfile = jest +const createRunProfile = vi .fn() .mockImplementation(( label: string, @@ -110,26 +118,26 @@ const createRunProfile = jest tag?: TestTag, ) => ({ label, kind, isDefault, tag, runHandler })); -const createTestRun = jest +const createTestRun = vi .fn() .mockImplementation((_request: BaseTestRunRequest, name?: string, persist?: boolean) => { return { name: name, // token: CancellationToken; isPersisted: !!persist, - enqueued: jest.fn(), - started: jest.fn(), - skipped: jest.fn(), - failed: jest.fn(), - errored: jest.fn(), - passed: jest.fn(), - appendOutput: jest.fn(), - end: jest.fn(), - addCoverage: jest.fn(), + enqueued: vi.fn(), + started: vi.fn(), + skipped: vi.fn(), + failed: vi.fn(), + errored: vi.fn(), + passed: vi.fn(), + appendOutput: vi.fn(), + end: vi.fn(), + addCoverage: vi.fn(), }; }); -const createTestController = jest +const createTestController = vi .fn() .mockImplementation((id: string, label: string): TestController => { const testController = { @@ -147,7 +155,7 @@ const createTestController = jest const tests = { createTestController }; const TestMessage = { - diff: jest + diff: vi .fn() .mockImplementation( (message: string | MarkdownString, expected: string, actual: string) => { @@ -157,14 +165,14 @@ const TestMessage = { }; class Disposable { - dispose = (): any => jest.fn(); + dispose = (): any => vi.fn(); } -const Location = jest.fn().mockImplementation((uri: URI, rangeOrPosition: any) => { +const Location = vi.fn().mockImplementation(function (uri: URI, rangeOrPosition: any) { return { uri, range: rangeOrPosition }; }); -const Range = jest.fn().mockImplementation((start: any, end: any) => { +const Range = vi.fn().mockImplementation(function (start: any, end: any) { return { start, end }; }); @@ -176,14 +184,14 @@ class Position { } } -const DocumentLink = jest.fn().mockImplementation((range: Range, target?: URI) => { +const DocumentLink = vi.fn().mockImplementation(function (range: Range, target?: URI) { return { range, target }; }); -const CancellationTokenSource = jest.fn().mockImplementation(() => { +const CancellationTokenSource = vi.fn().mockImplementation(function () { return { - token: { isCancellationRequested: false, onCancellationRequested: jest.fn() }, - cancel: jest.fn(), + token: { isCancellationRequested: false, onCancellationRequested: vi.fn() }, + cancel: vi.fn(), dispose: new Disposable(), }; }); @@ -220,7 +228,7 @@ const configurations = new Map(); const workspace = { workspaceFolders: [], textDocuments: [], - getConfiguration: jest.fn().mockImplementation((section: string) => { + getConfiguration: vi.fn().mockImplementation((section: string) => { if (configurations.has(section)) { return configurations.get(section); } @@ -234,7 +242,7 @@ const workspace = { uri.toString().includes(folder.uri.toString()), ); }, - findFiles: jest.fn().mockImplementation(async (pattern, exclude: any | undefined) => { + findFiles: vi.fn().mockImplementation(async (pattern, exclude: any | undefined) => { const splitPattern = (pattern: string) => { return pattern.replace(/^{|}$/g, '').split(',').map((v) => v.trim()); }; @@ -244,21 +252,21 @@ const workspace = { cwd: pattern.uri.fsPath, })).map((file) => URI.file(file.replace(/^\w:/, (matched) => matched.toLowerCase()))); }), - createFileSystemWatcher: jest.fn().mockImplementation(() => { + createFileSystemWatcher: vi.fn().mockImplementation(() => { return { - onDidCreate: jest.fn(), - onDidChange: jest.fn(), - onDidDelete: jest.fn(), + onDidCreate: vi.fn(), + onDidChange: vi.fn(), + onDidDelete: vi.fn(), disposable: new Disposable(), }; }), - onDidChangeConfiguration: jest.fn().mockImplementation(() => { + onDidChangeConfiguration: vi.fn().mockImplementation(() => { return new Disposable(); }), - onDidOpenTextDocument: jest.fn().mockReturnValue(new Disposable()), - onDidChangeTextDocument: jest.fn().mockReturnValue(new Disposable()), + onDidOpenTextDocument: vi.fn().mockReturnValue(new Disposable()), + onDidChangeTextDocument: vi.fn().mockReturnValue(new Disposable()), fs: { - readFile: jest.fn().mockImplementation((uri: URI) => readFile(uri.fsPath)), + readFile: vi.fn().mockImplementation((uri: URI) => readFile(uri.fsPath)), }, }; @@ -271,12 +279,12 @@ const languages = { return minimatch(document.uri.fsPath, pattern) ? 10 : 0; }, - registerDocumentLinkProvider: jest.fn(), + registerDocumentLinkProvider: vi.fn(), }; -const RelativePattern = jest +const RelativePattern = vi .fn() - .mockImplementation((workspaceFolder: WorkspaceFolder | URI | string, pattern: string) => { + .mockImplementation(function (workspaceFolder: WorkspaceFolder | URI | string, pattern: string) { if (typeof workspaceFolder === 'string') { workspaceFolder = URI.file(workspaceFolder); } @@ -287,20 +295,21 @@ const RelativePattern = jest }); const window = { - createOutputChannel: jest.fn().mockImplementation(() => { + createOutputChannel: vi.fn().mockImplementation(() => { return { - append: jest.fn(), - appendLine: jest.fn(), - clear: jest.fn(), - show: jest.fn(), + append: vi.fn(), + appendLine: vi.fn(), + clear: vi.fn(), + show: vi.fn(), }; }), + showErrorMessage: vi.fn(), }; const commands = (function () { const commands = new Map void>(); return { - registerCommand: jest.fn().mockImplementation((command: string, callback: (...rest: any[]) => void) => { + registerCommand: vi.fn().mockImplementation((command: string, callback: (...rest: any[]) => void) => { commands.set(command, callback); return new Disposable(); }), @@ -310,17 +319,17 @@ const commands = (function () { }; })(); -const EventEmitter = jest.fn().mockImplementation(() => { +const EventEmitter = vi.fn().mockImplementation(function () { return { - fire: jest.fn(), - event: jest.fn(), + fire: vi.fn(), + event: vi.fn(), }; }); -const TestMessageStackFrame = jest.fn(); +const TestMessageStackFrame = vi.fn(); const extensions = { - getExtension: jest.fn().mockImplementation(() => { + getExtension: vi.fn().mockImplementation(() => { return true; }), }; @@ -339,8 +348,8 @@ class StatementCoverage { const debug = { activeDebugSession: { type: 'php' }, - startDebugging: jest.fn(), - stopDebugging: jest.fn(), + startDebugging: vi.fn(), + stopDebugging: vi.fn(), }; export { @@ -367,4 +376,5 @@ export { StatementCoverage, DocumentLink, debug, + FakeTestTag as TestTag, }; diff --git a/biome.json b/biome.json new file mode 100644 index 00000000..25ca8e71 --- /dev/null +++ b/biome.json @@ -0,0 +1,67 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.15/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "includes": ["**", "!**/out", "!**/dist", "!**/coverage", "!**/.vscode-test", "!**/*.d.ts"] + }, + "formatter": { + "indentStyle": "space", + "indentWidth": 4, + "lineWidth": 100 + }, + "javascript": { + "parser": { + "unsafeParameterDecoratorsEnabled": true + }, + "formatter": { + "quoteStyle": "single", + "trailingCommas": "all" + } + }, + "linter": { + "rules": { + "style": { + "noNonNullAssertion": "warn" + }, + "complexity": { + "noStaticOnlyClass": "warn", + "noBannedTypes": "warn" + }, + "performance": { + "noAccumulatingSpread": "warn" + }, + "suspicious": { + "noDoubleEquals": "warn", + "noExplicitAny": "error", + "noNonNullAssertedOptionalChain": "warn", + "useIterableCallbackReturn": "warn", + "noDuplicateTestHooks": "warn", + "noAssignInExpressions": "warn", + "noImplicitAnyLet": "warn", + "noExportsInTest": "warn", + "noTemplateCurlyInString": "warn" + }, + "correctness": { + "noUnusedVariables": "warn", + "noUnusedImports": "warn", + "noUnsafeOptionalChaining": "warn" + } + } + }, + "overrides": [ + { + "includes": ["**/*.test.ts"], + "linter": { + "rules": { + "suspicious": { "noConsole": "off", "noExportsInTest": "off" }, + "correctness": { "noUnusedFunctionParameters": "off" }, + "style": { "noNonNullAssertion": "off" } + } + } + } + ] +} diff --git a/esbuild.mjs b/esbuild.mjs new file mode 100644 index 00000000..ba38252b --- /dev/null +++ b/esbuild.mjs @@ -0,0 +1,47 @@ +import * as esbuild from 'esbuild'; + +const production = process.argv.includes('--production'); +const watch = process.argv.includes('--watch'); + +const esbuildProblemMatcherPlugin = { + name: 'esbuild-problem-matcher', + setup(build) { + build.onStart(() => { + console.log('[watch] build started'); + }); + build.onEnd((result) => { + result.errors.forEach(({ text, location }) => { + console.error(`✘ [ERROR] ${text}`); + console.error(` ${location.file}:${location.line}:${location.column}:`); + }); + console.log('[watch] build finished'); + }); + }, +}; + +const ctx = await esbuild.context({ + entryPoints: ['src/extension.ts'], + bundle: true, + format: 'cjs', + minify: production, + sourcemap: !production, + sourcesContent: false, + platform: 'node', + outfile: 'dist/extension.js', + external: ['vscode'], + logLevel: 'silent', + banner: { + js: 'var __import_meta_url = require("url").pathToFileURL(__filename).href;', + }, + define: { + 'import.meta.url': '__import_meta_url', + }, + plugins: [esbuildProblemMatcherPlugin], +}); + +if (watch) { + await ctx.watch(); +} else { + await ctx.rebuild(); + await ctx.dispose(); +} diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index 6d66336b..00000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,34 +0,0 @@ -import typescriptEslint from '@typescript-eslint/eslint-plugin'; -import tsParser from '@typescript-eslint/parser'; - -export default [{ - ignores: [ - '**/out', - '**/dist', - '**/*.d.ts', - '**/__tests__/*', - 'eslint.config.mjs', - ], -}, { - files: ['**/*.ts'], -}, { - plugins: { - '@typescript-eslint': typescriptEslint, - }, - - languageOptions: { - parser: tsParser, - ecmaVersion: 6, - sourceType: 'module', - }, - - rules: { - 'semi': [2, 'always'], - 'curly': ['warn'], - 'eqeqeq': ['warn'], - '@typescript-eslint/no-explicit-any': 0, - '@typescript-eslint/explicit-module-boundary-types': 0, - '@typescript-eslint/no-non-null-assertion': 0, - '@typescript-eslint/naming-convention': ['warn'], - }, -}]; \ No newline at end of file diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index c2b14a97..00000000 --- a/jest.config.js +++ /dev/null @@ -1,195 +0,0 @@ -/* - * For a detailed explanation regarding each configuration property, visit: - * https://jestjs.io/docs/configuration - */ - -module.exports = { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "C:\\Users\\recca\\AppData\\Local\\Temp\\jest", - - // Automatically clear mock calls, instances, contexts and results before every test - clearMocks: true, - - // Indicates whether the coverage information should be collected while executing the test - collectCoverage: true, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: undefined, - - // The directory where Jest should output its coverage files - coverageDirectory: 'coverage', - - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "\\\\node_modules\\\\" - // ], - - // Indicates which provider should be used to instrument code for coverage - coverageProvider: 'v8', - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // The default configuration for fake timers - // fakeTimers: { - // "enableGlobally": false - // }, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: undefined, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // A set of global variables that need to be available in all test environments - // globals: {}, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - // moduleFileExtensions: [ - // "js", - // "mjs", - // "cjs", - // "jsx", - // "ts", - // "tsx", - // "json", - // "node" - // ], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - // moduleNameMapper: {}, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - modulePathIgnorePatterns: [ - "/.vscode-test/" - ], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - preset: 'ts-jest', - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state before every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state and implementation before every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: undefined, - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - testEnvironment: 'jest-environment-node', - - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - testMatch: ['**/__tests__/**/*.test.[jt]s?(x)', '**/?(*.)+(spec|test).[tj]s?(x)'], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - testPathIgnorePatterns: ['/node_modules/', '/out/', '/src/test/', '/tests/fixtures'], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jest-circus/runner", - - // A map from regular expressions to paths to transformers - // transform: undefined, - transform: { - '^.+.tsx?$': ['ts-jest'], - }, - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "\\\\node_modules\\\\", - // "\\.pnp\\.[^\\\\]+$" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: undefined, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, -}; diff --git a/package-lock.json b/package-lock.json index 550883ab..aa0a22f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,55 +10,54 @@ "hasInstallScript": true, "license": "MIT", "devDependencies": { - "@types/chai": "^5.2.2", - "@types/glob": "^8.1.0", - "@types/jest": "^29.5.14", + "@biomejs/biome": "2.3.15", + "@types/chai": "^5.2.3", + "@types/glob": "^9.0.0", "@types/mocha": "^10.0.10", - "@types/node": "^20", - "@types/semver": "^7.7.0", - "@types/sinon": "^17.0.4", + "@types/node": "^25", + "@types/semver": "^7.7.1", + "@types/sinon": "^21.0.0", "@types/yargs-parser": "^21.0.3", - "@typescript-eslint/eslint-plugin": "^8.32.0", - "@typescript-eslint/parser": "^8.32.0", "@vscode/dts": "^0.4.1", "@vscode/test-electron": "^2.5.2", - "@vscode/vsce": "^3.3.2", - "chai": "^5.2.0", - "eslint": "^9.26.0", - "fast-xml-parser": "^5.2.3", - "glob": "^11.0.2", - "minimatch": "^10.0.1", - "mocha": "^11.2.2", - "php-parser": "^3.2.3", + "@vscode/vsce": "^3.7.1", + "chai": "^6.2.2", + "esbuild": "^0.27.3", + "fast-xml-parser": "^5.3.5", + "glob": "^13.0.3", + "inversify": "^7.11.0", + "minimatch": "^10.2.0", + "mocha": "^11.7.5", + "php-parser": "^3.2.5", + "reflect-metadata": "^0.2.2", "semi": "^4.0.5", - "semver": "^7.7.1", - "sinon": "^20.0.0", + "semver": "^7.7.4", + "sinon": "^21.0.1", "string-argv": "^0.3.2", - "ts-jest": "^29.3.2", - "ts-loader": "^9.5.2", - "typescript": "^5.8.3", + "typescript": "^5.9.3", + "vitest": "^4.0.18", "vscode-uri": "^3.1.0", - "webpack": "^5.99.8", - "webpack-cli": "^6.0.1", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" }, "engines": { "vscode": "^1.88.0" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "node_modules/@azu/format-text": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", + "integrity": "sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==", "dev": true, - "license": "Apache-2.0", - "peer": true, + "license": "BSD-3-Clause" + }, + "node_modules/@azu/style-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azu/style-format/-/style-format-1.0.1.tgz", + "integrity": "sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==", + "dev": true, + "license": "WTFPL", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" + "@azu/format-text": "^1.0.1" } }, "node_modules/@azure/abort-controller": { @@ -233,5699 +232,1323 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/compat-data": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", - "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "node_modules/@biomejs/biome": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.15.tgz", + "integrity": "sha512-u+jlPBAU2B45LDkjjNNYpc1PvqrM/co4loNommS9/sl9oSxsAQKsNZejYuUztvToB5oXi1tN/e62iNd6ESiY3g==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.21.3" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/babel" + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "2.3.15", + "@biomejs/cli-darwin-x64": "2.3.15", + "@biomejs/cli-linux-arm64": "2.3.15", + "@biomejs/cli-linux-arm64-musl": "2.3.15", + "@biomejs/cli-linux-x64": "2.3.15", + "@biomejs/cli-linux-x64-musl": "2.3.15", + "@biomejs/cli-win32-arm64": "2.3.15", + "@biomejs/cli-win32-x64": "2.3.15" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.15.tgz", + "integrity": "sha512-SDCdrJ4COim1r8SNHg19oqT50JfkI/xGZHSyC6mGzMfKrpNe/217Eq6y98XhNTc0vGWDjznSDNXdUc6Kg24jbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" } }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@biomejs/cli-darwin-x64": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.15.tgz", + "integrity": "sha512-RkyeSosBtn3C3Un8zQnl9upX0Qbq4E3QmBa0qjpOh1MebRbHhNlRC16jk8HdTe/9ym5zlfnpbb8cKXzW+vlTxw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" } }, - "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "node_modules/@biomejs/cli-linux-arm64": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.15.tgz", + "integrity": "sha512-FN83KxrdVWANOn5tDmW6UBC0grojchbGmcEz6JkRs2YY6DY63sTZhwkQ56x6YtKhDVV1Unz7FJexy8o7KwuIhg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=14.21.3" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", - "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.15.tgz", + "integrity": "sha512-SSSIj2yMkFdSkXqASzIBdjySBXOe65RJlhKEDlri7MN19RC4cpez+C0kEwPrhXOTgJbwQR9QH1F4+VnHkC35pg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/compat-data": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=14.21.3" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/@biomejs/cli-linux-x64": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.15.tgz", + "integrity": "sha512-T8n9p8aiIKOrAD7SwC7opiBM1LYGrE5G3OQRXWgbeo/merBk8m+uxJ1nOXMPzfYyFLfPlKF92QS06KN1UW+Zbg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "yallist": "^3.0.2" + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.15.tgz", + "integrity": "sha512-dbjPzTh+ijmmNwojFYbQNMFp332019ZDioBYAMMJj5Ux9d8MkM+u+J68SBJGVwVeSHMYj+T9504CoxEzQxrdNw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "node_modules/@biomejs/cli-win32-arm64": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.15.tgz", + "integrity": "sha512-puMuenu/2brQdgqtQ7geNwQlNVxiABKEZJhMRX6AGWcmrMO8EObMXniFQywy2b81qmC+q+SDvlOpspNwz0WiOA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "peer": true + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "node_modules/@biomejs/cli-win32-x64": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.15.tgz", + "integrity": "sha512-kDZr/hgg+igo5Emi0LcjlgfkoGZtgIpJKhnvKTRmMBv6FF/3SDyEV4khBwqNebZIyMZTzvpca9sQNSXJ39pI2A==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" + "node": ">=14.21.3" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helpers": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", - "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/parser": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", - "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/types": "^7.26.10" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/template": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", - "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "peer": true, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/@babel/types": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", - "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", - "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", + "node_modules/@inversifyjs/common": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@inversifyjs/common/-/common-1.5.2.tgz", + "integrity": "sha512-WlzR9xGadABS9gtgZQ+luoZ8V6qm4Ii6RQfcfC9Ho2SOlE6ZuemFo7PKJvKI0ikm8cmKbU8hw5UK6E4qovH21w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.17.0" - } + "license": "MIT" }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", - "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "node_modules/@inversifyjs/container": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@inversifyjs/container/-/container-1.15.0.tgz", + "integrity": "sha512-U2xYsPrJTz5za2TExi5lg8qOWf8TEVBpN+pQM7B8BVA2rajtbRE9A66SLRHk8c1eGXmg+0K4Hdki6tWAsSQBUA==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "@inversifyjs/common": "1.5.2", + "@inversifyjs/core": "9.2.0", + "@inversifyjs/plugin": "0.2.0", + "@inversifyjs/reflect-metadata-utils": "1.4.1" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "reflect-metadata": "~0.2.2" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "node_modules/@inversifyjs/core": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@inversifyjs/core/-/core-9.2.0.tgz", + "integrity": "sha512-Nm7BR6KmpgshIHpVQWuEDehqRVb6GBm8LFEuhc2s4kSZWrArZ15RmXQzROLk4m+hkj4kMXgvMm5Qbopot/D6Sg==", "dev": true, "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "dependencies": { + "@inversifyjs/common": "1.5.2", + "@inversifyjs/prototype-utils": "0.1.3", + "@inversifyjs/reflect-metadata-utils": "1.4.1" } }, - "node_modules/@eslint/config-array": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", - "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "node_modules/@inversifyjs/plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@inversifyjs/plugin/-/plugin-0.2.0.tgz", + "integrity": "sha512-R/JAdkTSD819pV1zi0HP54mWHyX+H2m8SxldXRgPQarS3ySV4KPyRdosWcfB8Se0JJZWZLHYiUNiS6JvMWSPjw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT" + }, + "node_modules/@inversifyjs/prototype-utils": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@inversifyjs/prototype-utils/-/prototype-utils-0.1.3.tgz", + "integrity": "sha512-EzRamZzNgE9Sn3QtZ8NncNa2lpPMZfspqbK6BWFguWnOpK8ymp2TUuH46ruFHZhrHKnknPd7fG22ZV7iF517TQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "@inversifyjs/common": "1.5.2" } }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@inversifyjs/reflect-metadata-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@inversifyjs/reflect-metadata-utils/-/reflect-metadata-utils-1.4.1.tgz", + "integrity": "sha512-Cp77C4d2wLaHXiUB7iH6Cxb7i1lD/YDuTIHLTDzKINqGSz0DCSoL/Dg2wVkW/6Qx03r/yQMLJ+32Agl32N2X8g==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "peerDependencies": { + "reflect-metadata": "~0.2.2" } }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": "*" + "node": ">=12" } }, - "node_modules/@eslint/config-helpers": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", - "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } + "license": "MIT" }, - "node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.15" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 8" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 8" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": "*" + "node": ">= 8" } }, - "node_modules/@eslint/js": { - "version": "9.26.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.26.0.tgz", - "integrity": "sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", + "optional": true, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=14" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "cpu": [ + "arm" + ], "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.13.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@jest/console/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@jest/console/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@jest/console/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } + "optional": true, + "os": [ + "openbsd" + ] }, - "node_modules/@jest/console/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true + "optional": true, + "os": [ + "openharmony" + ] }, - "node_modules/@jest/console/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@jest/console/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/core/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@jest/core/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@jest/reporters/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@jest/reporters/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/transform/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/transform/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.1.tgz", - "integrity": "sha512-9LfmxKTb1v+vUS1/emSk1f5ePmTLkb9Le9AxOB5T0XM59EUumwcS45z05h7aiZx3GI0Bl7mjb3FMEglYj+acuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.3", - "eventsource": "^3.0.2", - "express": "^5.0.1", - "express-rate-limit": "^7.5.0", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.23.8", - "zod-to-json-schema": "^3.24.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", - "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.1", - "lodash.get": "^4.4.2", - "type-detect": "^4.1.0" - } - }, - "node_modules/@sinonjs/samsam/node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/chai": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", - "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/minimatch": "^5.1.2", - "@types/node": "*" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.5.14", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", - "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mocha": { - "version": "10.0.10", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", - "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.17.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz", - "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/@types/semver": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", - "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/sinon": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.4.tgz", - "integrity": "sha512-RHnIrhfPO3+tJT0s7cFaXGZvsL4bbR3/k7z3P312qMS4JaS2Tk+KiwiLx1S0rQ56ERj00u1/BtdyVd0FY+Pdew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/sinonjs__fake-timers": "*" - } - }, - "node_modules/@types/sinonjs__fake-timers": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", - "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz", - "integrity": "sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.32.0", - "@typescript-eslint/type-utils": "8.32.0", - "@typescript-eslint/utils": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.0.tgz", - "integrity": "sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.32.0", - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/typescript-estree": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.0.tgz", - "integrity": "sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.0.tgz", - "integrity": "sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "8.32.0", - "@typescript-eslint/utils": "8.32.0", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.0.tgz", - "integrity": "sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.0.tgz", - "integrity": "sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/visitor-keys": "8.32.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.0.tgz", - "integrity": "sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.32.0", - "@typescript-eslint/types": "8.32.0", - "@typescript-eslint/typescript-estree": "8.32.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.0.tgz", - "integrity": "sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.32.0", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@vscode/dts": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@vscode/dts/-/dts-0.4.1.tgz", - "integrity": "sha512-o8cI5Vqt6S6Y5mCI7yCkSQdiLQaLG5DMUpciJV3zReZwE+dA5KERxSVX8H3cPEhyKw21XwKGmIrg6YmN6M5uZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "https-proxy-agent": "^7.0.0", - "minimist": "^1.2.8", - "prompts": "^2.4.2" - }, - "bin": { - "dts": "index.js" - } - }, - "node_modules/@vscode/test-electron": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz", - "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.5", - "jszip": "^3.10.1", - "ora": "^8.1.0", - "semver": "^7.6.2" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@vscode/vsce": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.3.2.tgz", - "integrity": "sha512-XQ4IhctYalSTMwLnMS8+nUaGbU7v99Qm2sOoGfIEf2QC7jpiLXZZMh7NwArEFsKX4gHTJLx0/GqAUlCdC3gKCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@azure/identity": "^4.1.0", - "@vscode/vsce-sign": "^2.0.0", - "azure-devops-node-api": "^12.5.0", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "cockatiel": "^3.1.2", - "commander": "^12.1.0", - "form-data": "^4.0.0", - "glob": "^11.0.0", - "hosted-git-info": "^4.0.2", - "jsonc-parser": "^3.2.0", - "leven": "^3.1.0", - "markdown-it": "^14.1.0", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^7.5.2", - "tmp": "^0.2.3", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.5.0", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "bin": { - "vsce": "vsce" - }, - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "keytar": "^7.7.0" - } - }, - "node_modules/@vscode/vsce-sign": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.0.5.tgz", - "integrity": "sha512-GfYWrsT/vypTMDMgWDm75iDmAOMe7F71sZECJ+Ws6/xyIfmB3ELVnVN+LwMFAvmXY+e6eWhR2EzNGF/zAhWY3Q==", - "dev": true, - "hasInstallScript": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optionalDependencies": { - "@vscode/vsce-sign-alpine-arm64": "2.0.2", - "@vscode/vsce-sign-alpine-x64": "2.0.2", - "@vscode/vsce-sign-darwin-arm64": "2.0.2", - "@vscode/vsce-sign-darwin-x64": "2.0.2", - "@vscode/vsce-sign-linux-arm": "2.0.2", - "@vscode/vsce-sign-linux-arm64": "2.0.2", - "@vscode/vsce-sign-linux-x64": "2.0.2", - "@vscode/vsce-sign-win32-arm64": "2.0.2", - "@vscode/vsce-sign-win32-x64": "2.0.2" - } - }, - "node_modules/@vscode/vsce-sign-darwin-arm64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.2.tgz", - "integrity": "sha512-rz8F4pMcxPj8fjKAJIfkUT8ycG9CjIp888VY/6pq6cuI2qEzQ0+b5p3xb74CJnBbSC0p2eRVoe+WgNCAxCLtzQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@vscode/vsce/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@vscode/vsce/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", - "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", - "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", - "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true, - "license": "MIT" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/azure-devops-node-api": { - "version": "12.5.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", - "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", - "dev": true, - "license": "MIT", - "dependencies": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/babel-jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/babel-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", - "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true - }, - "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, - "license": "ISC" - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true, - "license": "ISC" - }, - "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001677", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz", - "integrity": "sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chai": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", - "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", - "dev": true, - "license": "MIT", - "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - } - }, - "node_modules/cheerio": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", - "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", - "dev": true, - "license": "MIT", - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.1.0", - "encoding-sniffer": "^0.2.0", - "htmlparser2": "^9.1.0", - "parse5": "^7.1.2", - "parse5-htmlparser2-tree-adapter": "^7.0.0", - "parse5-parser-stream": "^7.1.2", - "undici": "^6.19.5", - "whatwg-mimetype": "^4.0.0" - }, - "engines": { - "node": ">=18.17" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", - "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz", - "integrity": "sha512-eMU2akIeEIkCxGXUNmDnJq1KzOIiPnJ+rKqRe6hcxE3vIOPvpMrBYOn/Bl7zNlYJj/zQxXquAnozHUCf9Whnsg==", - "dev": true, - "license": "ISC" - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/cliui/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/cliui/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/cockatiel": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", - "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cors/node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/create-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/create-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/create-jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/create-jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/create-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/create-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/d": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", - "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/dedent": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/doctrine": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz", - "integrity": "sha512-FSGvDB23RFdm/Z2hEINXN1AcBW5I4YBqpGD/lScJV34vuOwrPFyLHN9bwCzLa6lUmqS6ipdp5XlVJRQ6yJ5iSA==", - "dev": true, - "dependencies": { - "esutils": "^1.1.6", - "isarray": "0.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/doctrine/node_modules/esutils": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz", - "integrity": "sha512-RG1ZkUT7iFJG9LSHr7KDuuMSlujfeTtMNIcInURxKAxhMtwQhI3NrQhz26gZQYlsYZQKzsnwtpKrFKj9K9Qu1A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/doctrine/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.51", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.51.tgz", - "integrity": "sha512-kKeWV57KSS8jH4alKt/jKnvHPmJgBxXzGUSbMd4eQF+iOsVPl7bz2KUmu6eo80eMP8wVioTfTyTzdMgM15WXNg==", - "dev": true, - "license": "ISC" - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding-sniffer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", - "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "^0.6.3", - "whatwg-encoding": "^3.1.1" - }, - "funding": { - "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/envinfo": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", - "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", - "dev": true, - "license": "MIT", - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "dev": true, - "hasInstallScript": true, - "license": "ISC", - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", - "dev": true, - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" - } - }, - "node_modules/es6-set": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", - "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "es6-iterator": "~2.0.3", - "es6-symbol": "^3.1.3", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "ext": "^1.7.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escope": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "es6-map": "^0.1.3", - "es6-weak-map": "^2.0.1", - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/escope/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint": { - "version": "9.26.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.26.0.tgz", - "integrity": "sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.13.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.26.0", - "@eslint/plugin-kit": "^0.2.8", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@modelcontextprotocol/sdk": "^1.8.0", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "zod": "^3.24.2" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", - "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse-fb": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.2.tgz", - "integrity": "sha512-wp3lfRrWy5EQD9TqesuYM1SKVP4ERT0cUatb4e8Vznf4K5IOpREhuyXZxGj3a9s9mvX5vGZKNHA4R9D4kp9Q9A==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "estraverse": "*" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.1.tgz", - "integrity": "sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/execa/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "license": "(MIT OR WTFPL)", "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.0", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz", - "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": "^4.11 || 5 || ^5.0.0-beta.1" - } - }, - "node_modules/express/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dev": true, - "license": "ISC", - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" + "os": [ + "win32" + ] }, - "node_modules/fast-xml-parser": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.3.tgz", - "integrity": "sha512-OdCYfRqfpuLUFonTNjvd30rCBZUneHpSQkCqfaeWQ9qrKcl6XlWeDBNVwGb+INAIxRshuN2jF+BE0L6gbBO2mw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" ], - "license": "MIT", - "dependencies": { - "strnum": "^2.1.0" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/figures/node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/@secretlint/config-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz", + "integrity": "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==", "dev": true, "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "@secretlint/types": "^10.2.2" }, "engines": { - "node": ">=8" + "node": ">=20.0.0" } }, - "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "node_modules/@secretlint/config-loader": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-10.2.2.tgz", + "integrity": "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" + "@secretlint/profiler": "^10.2.2", + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "ajv": "^8.17.1", + "debug": "^4.4.1", + "rc-config-loader": "^4.1.3" }, "engines": { - "node": ">= 0.8" + "node": ">=20.0.0" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/@secretlint/config-loader/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/findit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", - "integrity": "sha512-ENZS237/Hr8bjczn5eKuBohLgaD0JyUd0arxretR1f9RO46vZHA1b2y0VorgGV3WaOT3c+78P8h7v4JGJ1i/rg==", + "node_modules/@secretlint/config-loader/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "node_modules/@secretlint/core": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz", + "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==", "dev": true, "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true, - "license": "ISC" - }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" + "@secretlint/profiler": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "structured-source": "^4.0.0" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=20.0.0" } }, - "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "node_modules/@secretlint/formatter": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-10.2.2.tgz", + "integrity": "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==", "dev": true, "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "@textlint/linter-formatter": "^15.2.0", + "@textlint/module-interop": "^15.2.0", + "@textlint/types": "^15.2.0", + "chalk": "^5.4.1", + "debug": "^4.4.1", + "pluralize": "^8.0.0", + "strip-ansi": "^7.1.0", + "table": "^6.9.0", + "terminal-link": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">=20.0.0" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "node_modules/@secretlint/formatter/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "node_modules/@secretlint/node": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-10.2.2.tgz", + "integrity": "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==", "dev": true, "license": "MIT", + "dependencies": { + "@secretlint/config-loader": "^10.2.2", + "@secretlint/core": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "@secretlint/source-creator": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "p-map": "^7.0.3" + }, "engines": { - "node": ">= 0.8" + "node": ">=20.0.0" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "node_modules/@secretlint/profiler": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz", + "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==", "dev": true, - "license": "ISC", - "peer": true + "license": "MIT" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/@secretlint/resolver": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-10.2.2.tgz", + "integrity": "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==", "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } + "license": "MIT" }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "node_modules/@secretlint/secretlint-formatter-sarif": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz", + "integrity": "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==", "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "node-sarif-builder": "^3.2.0" } }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "node_modules/@secretlint/secretlint-rule-no-dotenv": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", + "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==", "dev": true, "license": "MIT", "dependencies": { - "is-property": "^1.0.2" + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" } }, - "node_modules/generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", + "node_modules/@secretlint/secretlint-rule-preset-recommend": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", + "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==", "dev": true, "license": "MIT", - "dependencies": { - "is-property": "^1.0.0" + "engines": { + "node": ">=20.0.0" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "node_modules/@secretlint/source-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz", + "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==", "dev": true, "license": "MIT", - "peer": true, + "dependencies": { + "@secretlint/types": "^10.2.2", + "istextorbinary": "^9.5.0" + }, "engines": { - "node": ">=6.9.0" + "node": ">=20.0.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/@secretlint/types": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz", + "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=20.0.0" } }, - "node_modules/get-east-asian-width": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", - "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", "dev": true, "license": "MIT", "engines": { @@ -5935,972 +1558,1046 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8.0.0" + "type-detect": "4.0.8" } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "node_modules/@sinonjs/fake-timers": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.0.tgz", + "integrity": "sha512-cqfapCxwTGsrR80FEgOoPsTonoefMBY7dnUEbQ+GRcved0jvkJLzvX6F4WtN+HBqbPX/SiFsIRUp+IrCW/2I2w==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "@sinonjs/commons": "^3.0.1" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/@sinonjs/samsam": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", + "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "type-detect": "^4.1.0" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, "license": "MIT", - "optional": true - }, - "node_modules/glob": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz", - "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=4" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } + "license": "MIT" }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "node_modules/@textlint/ast-node-types": { + "version": "15.5.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.5.1.tgz", + "integrity": "sha512-2ABQSaQoM9u9fycXLJKcCv4XQulJWTUSwjo6F0i/ujjqOH8/AZ2A0RDKKbAddqxDhuabVB20lYoEsZZgzehccg==", "dev": true, - "license": "BSD-2-Clause" + "license": "MIT" }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "node_modules/@textlint/linter-formatter": { + "version": "15.5.1", + "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.5.1.tgz", + "integrity": "sha512-7wfzpcQtk7TZ3UJO2deTI71mJCm4VvPGUmSwE4iuH6FoaxpdWpwSBiMLcZtjYrt/oIFOtNz0uf5rI+xJiHTFww==", "dev": true, "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "@azu/format-text": "^1.0.2", + "@azu/style-format": "^1.0.1", + "@textlint/module-interop": "15.5.1", + "@textlint/resolver": "15.5.1", + "@textlint/types": "15.5.1", + "chalk": "^4.1.2", + "debug": "^4.4.3", + "js-yaml": "^4.1.1", + "lodash": "^4.17.21", + "pluralize": "^2.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "table": "^6.9.0", + "text-table": "^0.2.0" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "node_modules/@textlint/linter-formatter/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "node_modules/@textlint/linter-formatter/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "node_modules/@textlint/linter-formatter/node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true, "license": "MIT" }, - "node_modules/has-ansi": { + "node_modules/@textlint/linter-formatter/node_modules/pluralize": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-2.0.0.tgz", + "integrity": "sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "node_modules/@textlint/linter-formatter/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/@textlint/module-interop": { + "version": "15.5.1", + "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.5.1.tgz", + "integrity": "sha512-Y1jcFGCKNSmHxwsLO3mshOfLYX4Wavq2+w5BG6x5lGgZv0XrF1xxURRhbnhns4LzCu0fAcx6W+3V8/1bkyTZCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/resolver": { + "version": "15.5.1", + "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.5.1.tgz", + "integrity": "sha512-CVHxMIm8iNGccqM12CQ/ycvh+HjJId4RyC6as5ynCcp2E1Uy1TCe0jBWOpmLsbT4Nx15Ke29BmspyByawuIRyA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/types": { + "version": "15.5.1", + "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.5.1.tgz", + "integrity": "sha512-IY1OVZZk8LOOrbapYCsaeH7XSJT89HVukixDT8CoiWMrKGCTCZ3/Kzoa3DtMMbY8jtY777QmPOVCNnR+8fF6YQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=4" + "dependencies": { + "@textlint/ast-node-types": "15.5.1" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/glob": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-9.0.0.tgz", + "integrity": "sha512-00UxlRaIUvYm4R4W9WYkN8/J+kV8fmOQ7okeH6YFtGWFMt3odD45tpG5yA5wnL7HE6lLgjaTW5n14ju2hl2NNA==", + "deprecated": "This is a stub types definition. glob provides its own type definitions, so you do not need this installed.", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" + "glob": "*" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", "dev": true, "license": "MIT", - "bin": { - "he": "bin/he" + "dependencies": { + "undici-types": "~7.16.0" } }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true, - "license": "ISC", + "license": "MIT" + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sinon": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-21.0.0.tgz", + "integrity": "sha512-+oHKZ0lTI+WVLxx1IbJDNmReQaIsQJjN2e7UUrJHEeByG7bFeKJYsv1E75JxTQ9QKJDp21bAa/0W2Xo4srsDnw==", + "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" + "@types/sinonjs__fake-timers": "*" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", "dev": true, "license": "MIT", - "peer": true + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "node_modules/htmlparser2": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", - "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], "license": "MIT", "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.1.0", - "entities": "^4.5.0" + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "tinyrainbow": "^3.0.3" }, - "engines": { - "node": ">= 0.8" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" }, - "engines": { - "node": ">= 14" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" }, - "engines": { - "node": ">= 14" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", "dev": true, - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=10.17.0" + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/@vscode/dts": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@vscode/dts/-/dts-0.4.1.tgz", + "integrity": "sha512-o8cI5Vqt6S6Y5mCI7yCkSQdiLQaLG5DMUpciJV3zReZwE+dA5KERxSVX8H3cPEhyKw21XwKGmIrg6YmN6M5uZA==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 4" + "dependencies": { + "https-proxy-agent": "^7.0.0", + "minimist": "^1.2.8", + "prompts": "^2.4.2" + }, + "bin": { + "dts": "index.js" } }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "node_modules/@vscode/test-electron": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz", + "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==", "dev": true, "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "jszip": "^3.10.1", + "ora": "^8.1.0", + "semver": "^7.6.2" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16" } }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "node_modules/@vscode/vsce": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.7.1.tgz", + "integrity": "sha512-OTm2XdMt2YkpSn2Nx7z2EJtSuhRHsTPYsSK59hr3v8jRArK+2UEoju4Jumn1CmpgoBLGI6ReHLJ/czYltNUW3g==", "dev": true, "license": "MIT", "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" + "@azure/identity": "^4.1.0", + "@secretlint/node": "^10.1.2", + "@secretlint/secretlint-formatter-sarif": "^10.1.2", + "@secretlint/secretlint-rule-no-dotenv": "^10.1.2", + "@secretlint/secretlint-rule-preset-recommend": "^10.1.2", + "@vscode/vsce-sign": "^2.0.0", + "azure-devops-node-api": "^12.5.0", + "chalk": "^4.1.2", + "cheerio": "^1.0.0-rc.9", + "cockatiel": "^3.1.2", + "commander": "^12.1.0", + "form-data": "^4.0.0", + "glob": "^11.0.0", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", + "leven": "^3.1.0", + "markdown-it": "^14.1.0", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "secretlint": "^10.1.2", + "semver": "^7.5.2", + "tmp": "^0.2.3", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" }, "bin": { - "import-local-fixture": "fixtures/cli.js" + "vsce": "vsce" }, "engines": { - "node": ">=8" + "node": ">= 20" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" + "optionalDependencies": { + "keytar": "^7.7.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "node_modules/@vscode/vsce-sign": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.0.5.tgz", + "integrity": "sha512-GfYWrsT/vypTMDMgWDm75iDmAOMe7F71sZECJ+Ws6/xyIfmB3ELVnVN+LwMFAvmXY+e6eWhR2EzNGF/zAhWY3Q==", "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optionalDependencies": { + "@vscode/vsce-sign-alpine-arm64": "2.0.2", + "@vscode/vsce-sign-alpine-x64": "2.0.2", + "@vscode/vsce-sign-darwin-arm64": "2.0.2", + "@vscode/vsce-sign-darwin-x64": "2.0.2", + "@vscode/vsce-sign-linux-arm": "2.0.2", + "@vscode/vsce-sign-linux-arm64": "2.0.2", + "@vscode/vsce-sign-linux-x64": "2.0.2", + "@vscode/vsce-sign-win32-arm64": "2.0.2", + "@vscode/vsce-sign-win32-x64": "2.0.2" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "node_modules/@vscode/vsce-sign-darwin-arm64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.2.tgz", + "integrity": "sha512-rz8F4pMcxPj8fjKAJIfkUT8ycG9CjIp888VY/6pq6cuI2qEzQ0+b5p3xb74CJnBbSC0p2eRVoe+WgNCAxCLtzQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "optional": true + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/inquirer": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz", - "integrity": "sha512-+rksrtdqQ8do7yOsmP5YIgbSdbZYuCIrnfH5vjFYGAr1XgJpMksb3rFZMJ3jiKuUyDVEA4MVDYbkA3ribJn3Tg==", + "node_modules/@vscode/vsce/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^1.1.1", - "chalk": "^1.0.0", - "cli-width": "^1.0.1", - "figures": "^1.3.5", - "lodash": "^3.3.1", - "readline2": "^0.1.1", - "rx": "^2.4.3", - "through": "^2.3.6" - } - }, - "node_modules/inquirer/node_modules/ansi-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", - "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "node_modules/@vscode/vsce/node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "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", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, "engines": { - "node": ">=0.10.0" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/inquirer/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "node_modules/@vscode/vsce/node_modules/glob/node_modules/balanced-match": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.2.tgz", + "integrity": "sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "jackspeak": "^4.2.3" }, "engines": { - "node": ">=0.10.0" + "node": "20 || >=22" } }, - "node_modules/inquirer/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "node_modules/@vscode/vsce/node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", + "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=0.10.0" + "node": "20 || >=22" } }, - "node_modules/inquirer/node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "node_modules/@vscode/vsce/node_modules/glob/node_modules/minimatch": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.0.tgz", + "integrity": "sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "node_modules/@vscode/vsce/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=0.8.0" + "node": "*" } }, - "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, "engines": { - "node": ">=10.13.0" + "node": ">= 14" } }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", "dev": true, "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, "engines": { - "node": ">= 0.10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", - "bin": { - "is-docker": "cli.js" + "dependencies": { + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } + "license": "MIT" }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/azure-devops-node-api": { + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", + "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" } }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", + "optional": true + }, + "node_modules/binaryextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", + "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, "engines": { - "node": ">=12" + "node": ">=4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://bevry.me/fund" } }, - "node_modules/is-my-ip-valid": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", - "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/is-my-json-valid": { - "version": "2.20.6", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", - "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", + "node_modules/boundary": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz", + "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==", "dev": true, - "license": "MIT", - "dependencies": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^5.0.0", - "xtend": "^4.0.0" - } + "license": "BSD-2-Clause" }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.12.0" + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, "engines": { "node": ">=8" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": "*" } }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", "dev": true, - "license": "MIT" + "license": "BSD-3-Clause" }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, "license": "MIT" }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.4" } }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", "dev": true, "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "node_modules/cheerio": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", + "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", "dev": true, - "license": "BSD-3-Clause", - "peer": true, + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "encoding-sniffer": "^0.2.0", + "htmlparser2": "^9.1.0", + "parse5": "^7.1.2", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^6.19.5", + "whatwg-mimetype": "^4.0.0" + }, "engines": { - "node": ">=8" + "node": ">=18.17" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" } }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", "dev": true, - "license": "BSD-3-Clause", - "peer": true, + "license": "BSD-2-Clause", "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, - "license": "BSD-3-Clause", - "peer": true, + "license": "MIT", "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">=10" + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } + "license": "ISC", + "optional": true }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "has-flag": "^4.0.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "node_modules/cli-width": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz", + "integrity": "sha512-eMU2akIeEIkCxGXUNmDnJq1KzOIiPnJ+rKqRe6hcxE3vIOPvpMrBYOn/Bl7zNlYJj/zQxXquAnozHUCf9Whnsg==", "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "ISC" }, - "node_modules/jackspeak": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", - "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "ISC", "dependencies": { - "@isaacs/cliui": "^8.0.2" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=12" } }, - "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/jake/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jake/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/jake/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/cockatiel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", + "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" } }, - "node_modules/jake/node_modules/color-convert": { + "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -6913,1886 +2610,1673 @@ "node": ">=7.0.0" } }, - "node_modules/jake/node_modules/color-name": { + "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, "license": "MIT" }, - "node_modules/jake/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/jake/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/jake/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, + "engines": [ + "node >= 0.8" + ], "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, - "node_modules/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", "dev": true, - "license": "MIT", - "peer": true, + "license": "ISC", "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" + "es5-ext": "^0.10.64", + "type": "^2.7.2" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.12" } }, - "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "ms": "^2.1.3" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, "license": "MIT", - "peer": true, + "optional": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "mimic-response": "^3.1.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, + "optional": true, "engines": { - "node": ">=7.0.0" + "node": ">=4.0.0" } }, - "node_modules/jest-circus/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, - "node_modules/jest-circus/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } }, - "node_modules/jest-circus/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.4.0" } }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, + "license": "Apache-2.0", + "optional": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": ">=8" } }, - "node_modules/jest-cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.3.1" } }, - "node_modules/jest-cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/doctrine": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz", + "integrity": "sha512-FSGvDB23RFdm/Z2hEINXN1AcBW5I4YBqpGD/lScJV34vuOwrPFyLHN9bwCzLa6lUmqS6ipdp5XlVJRQ6yJ5iSA==", "dev": true, - "license": "MIT", - "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "esutils": "^1.1.6", + "isarray": "0.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/jest-cli/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/doctrine/node_modules/esutils": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz", + "integrity": "sha512-RG1ZkUT7iFJG9LSHr7KDuuMSlujfeTtMNIcInURxKAxhMtwQhI3NrQhz26gZQYlsYZQKzsnwtpKrFKj9K9Qu1A==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-cli/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/jest-cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/doctrine/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/jest-cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "has-flag": "^4.0.0" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" } - } + ], + "license": "BSD-2-Clause" }, - "node_modules/jest-config/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, - "license": "MIT", - "peer": true, + "license": "BSD-2-Clause", "dependencies": { - "color-convert": "^2.0.1" + "domelementtype": "^2.3.0" }, "engines": { - "node": ">=8" + "node": ">= 4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, - "license": "MIT", - "peer": true, + "license": "BSD-2-Clause", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/jest-config/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "color-name": "~1.1.4" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, "engines": { - "node": ">=7.0.0" + "node": ">= 0.4" } }, - "node_modules/jest-config/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, - "node_modules/jest-config/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "dev": true, - "license": "ISC", - "peer": true, + "license": "Apache-2.0", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/jest-config/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" + "safe-buffer": "^5.0.1" } }, - "node_modules/jest-config/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", "dev": true, - "license": "ISC", - "peer": true, + "license": "Artistic-2.0", "dependencies": { - "brace-expansion": "^1.1.7" + "version-range": "^4.15.0" }, "engines": { - "node": "*" + "ecmascript": ">= es5", + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" } }, - "node_modules/jest-config/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/encoding-sniffer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", + "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "has-flag": "^4.0.0" + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" } }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "once": "^1.4.0" } }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">=8" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">= 0.4" } }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "detect-newline": "^3.0.0" + "es-errors": "^1.3.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 0.4" } }, - "node_modules/jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", "dev": true, - "license": "MIT", - "peer": true, + "hasInstallScript": true, + "license": "ISC", "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.10" } }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" } }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" } }, - "node_modules/jest-each/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/es6-set": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", + "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", "dev": true, - "license": "MIT", - "peer": true, + "license": "ISC", "dependencies": { - "color-name": "~1.1.4" + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "es6-iterator": "~2.0.3", + "es6-symbol": "^3.1.3", + "event-emitter": "^0.3.5", + "type": "^2.7.2" }, "engines": { - "node": ">=7.0.0" + "node": ">=0.12" } }, - "node_modules/jest-each/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/jest-each/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", "dev": true, - "license": "MIT", - "peer": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, "engines": { - "node": ">=8" + "node": ">=0.12" } }, - "node_modules/jest-each/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", "dev": true, - "license": "MIT", - "peer": true, + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" } }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "peer": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" } }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=6" } }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "node": ">=0.8.0" } }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "node_modules/escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==", "dev": true, - "license": "MIT", - "peer": true, + "license": "BSD-2-Clause", "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.4.0" } }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "node_modules/escope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, + "license": "BSD-2-Clause", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=4.0" } }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "color-convert": "^2.0.1" + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.10" } }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=4" } }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "color-name": "~1.1.4" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=4.0" } }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "MIT" + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/estraverse-fb": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.2.tgz", + "integrity": "sha512-wp3lfRrWy5EQD9TqesuYM1SKVP4ERT0cUatb4e8Vznf4K5IOpREhuyXZxGj3a9s9mvX5vGZKNHA4R9D4kp9Q9A==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "peerDependencies": { + "estraverse": "*" } }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@types/estree": "^1.0.0" } }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "d": "1", + "es5-ext": "~0.10.14" } }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.8.x" } }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "(MIT OR WTFPL)", + "optional": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=6" } }, - "node_modules/jest-message-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, + "license": "Apache-2.0", "engines": { - "node": ">=7.0.0" + "node": ">=12.0.0" } }, - "node_modules/jest-message-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/jest-message-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, - "node_modules/jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "MIT", - "peer": true, + "license": "ISC", "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" + "is-glob": "^4.0.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 6" } }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-xml-parser": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.5.tgz", + "integrity": "sha512-JeaA2Vm9ffQKp9VjvfzObuMCjUYAp5WDYhRYL5LrBPY/jUDlUtOvDfot0vKSkB9tuX885BDHjtw4fZadD95wnA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" + "dependencies": { + "strnum": "^2.1.2" }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" } }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "license": "MIT", - "peer": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "dependencies": { + "pend": "~1.2.0" } }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "node_modules/figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "node_modules/figures/node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-resolve/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "color-convert": "^2.0.1" + "to-regex-range": "^5.0.1" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-resolve/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/findit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", + "integrity": "sha512-ENZS237/Hr8bjczn5eKuBohLgaD0JyUd0arxretR1f9RO46vZHA1b2y0VorgGV3WaOT3c+78P8h7v4JGJ1i/rg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, - "node_modules/jest-resolve/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" } }, - "node_modules/jest-resolve/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, - "license": "MIT", - "peer": true, + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=8" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 6" } }, - "node_modules/jest-runner/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } + "optional": true }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/fs-extra": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", + "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=14.14" } }, - "node_modules/jest-runner/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=7.0.0" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/jest-runner/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, "license": "MIT", - "peer": true + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/jest-runner/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", "dev": true, "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" + "dependencies": { + "is-property": "^1.0.2" } }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "has-flag": "^4.0.0" - }, + "is-property": "^1.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", "engines": { - "node": ">=8" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-runtime/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "color-convert": "^2.0.1" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-runtime/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "dev": true, "license": "MIT", - "peer": true, + "optional": true + }, + "node_modules/glob": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.3.tgz", + "integrity": "sha512-/g3B0mC+4x724v1TgtBlBtt2hPi/EWptsIAmXUx9Z2rvBYleQcsrmaOzd5LyL50jf/Soi83ZDJmw2+XqvH/EeA==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "minimatch": "^10.2.0", + "minipass": "^7.1.2", + "path-scurry": "^2.0.0" }, "engines": { - "node": ">=10" + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-runtime/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "color-name": "~1.1.4" + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-runtime/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/globby/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", - "peer": true + "engines": { + "node": ">= 4" + } }, - "node_modules/jest-runtime/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": "*" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-runtime/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } + "license": "ISC" }, - "node_modules/jest-runtime/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "dev": true, - "license": "ISC", - "peer": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "ansi-regex": "^2.0.0" }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/jest-runtime/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "function-bind": "^1.1.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 0.4" } }, - "node_modules/jest-snapshot/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, "license": "MIT", - "peer": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", "dependencies": { - "color-name": "~1.1.4" + "lru-cache": "^6.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=10" } }, - "node_modules/jest-snapshot/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/htmlparser2": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], "license": "MIT", - "peer": true + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" + } }, - "node_modules/jest-snapshot/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "license": "MIT", - "peer": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, "engines": { - "node": ">=8" + "node": ">= 14" } }, - "node_modules/jest-snapshot/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "has-flag": "^4.0.0" + "agent-base": "^7.0.2", + "debug": "4" }, "engines": { - "node": ">=8" + "node": ">= 14" } }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/inquirer": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz", + "integrity": "sha512-+rksrtdqQ8do7yOsmP5YIgbSdbZYuCIrnfH5vjFYGAr1XgJpMksb3rFZMJ3jiKuUyDVEA4MVDYbkA3ribJn3Tg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "ansi-regex": "^1.1.1", + "chalk": "^1.0.0", + "cli-width": "^1.0.1", + "figures": "^1.3.5", + "lodash": "^3.3.1", + "readline2": "^0.1.1", + "rx": "^2.4.3", + "through": "^2.3.6" } }, - "node_modules/jest-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/inquirer/node_modules/ansi-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha512-q5i8bFLg2wDfsuR56c1NzlJFPzVD+9mxhDrhqOGigEFa87OZHlF+9dWeGWzVTP/0ECiA/JUGzfzRr2t3eYORRw==", "dev": true, "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/inquirer/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "node_modules/inquirer/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" + "ansi-regex": "^2.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/inquirer/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/inquirer/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.8.0" } }, - "node_modules/jest-validate/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/inversify": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-7.11.0.tgz", + "integrity": "sha512-yZDprSSr8TyVeMGI/AOV4ws6gwjX22hj9Z8/oHAVpJORY6WRFTcUzhnZtibBUHEw2U8ArvHcR+i863DplQ3Cwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "@inversifyjs/common": "1.5.2", + "@inversifyjs/container": "1.15.0", + "@inversifyjs/core": "9.2.0" } }, - "node_modules/jest-validate/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": ">=7.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-validate/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/jest-validate/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-validate/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { "node": ">=8" } }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" + "is-extglob": "^2.1.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-watcher/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/is-my-ip-valid": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", + "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-my-json-valid": { + "version": "2.20.6", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", + "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^5.0.0", + "xtend": "^4.0.0" } }, - "node_modules/jest-watcher/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=0.12.0" } }, - "node_modules/jest-watcher/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "license": "MIT", - "peer": true + "engines": { + "node": ">=8" + } }, - "node_modules/jest-watcher/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } }, - "node_modules/jest-watcher/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "is-docker": "^2.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "license": "MIT", - "peer": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istextorbinary": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", + "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "binaryextensions": "^6.11.0", + "editions": "^6.21.0", + "textextensions": "^6.11.0" + }, "engines": { - "node": ">=8" + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" } }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/jackspeak": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", + "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", "dev": true, - "license": "MIT", - "peer": true, + "license": "BlueOak-1.0.0", "dependencies": { - "has-flag": "^4.0.0" + "@isaacs/cliui": "^9.0.0" }, "engines": { - "node": ">=10" + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jackspeak/node_modules/@isaacs/cliui": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", + "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, "node_modules/js-tokens": { @@ -8803,9 +4287,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -8815,48 +4299,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -8877,6 +4319,19 @@ "dev": true, "license": "MIT" }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jsonpointer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", @@ -8982,26 +4437,6 @@ "prebuild-install": "^7.0.1" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -9022,20 +4457,6 @@ "node": ">=6" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/lie": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", @@ -9046,14 +4467,6 @@ "immediate": "~3.0.5" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", @@ -9064,16 +4477,6 @@ "uc.micro": "^2.0.0" } }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.11.5" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -9097,13 +4500,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -9146,20 +4542,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -9167,6 +4549,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -9184,89 +4573,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/loupe": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", - "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", - "dev": true, - "license": "MIT" - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -9280,39 +4586,14 @@ "node": ">=10" } }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", - "peer": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, "dependencies": { - "tmpl": "1.0.5" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/markdown-it": { @@ -9350,36 +4631,6 @@ "dev": true, "license": "MIT" }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -9440,17 +4691,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/mimic-function": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", @@ -9479,13 +4719,13 @@ } }, "node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.0.tgz", + "integrity": "sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^5.0.2" }, "engines": { "node": "20 || >=22" @@ -9494,6 +4734,32 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimatch/node_modules/balanced-match": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.2.tgz", + "integrity": "sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "jackspeak": "^4.2.3" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/minimatch/node_modules/brace-expansion": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", + "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -9536,29 +4802,30 @@ "optional": true }, "node_modules/mocha": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.2.2.tgz", - "integrity": "sha512-VlSBxrPYHK4YNOEbFdkCxHQbZMoNzBkoPprqtZRW6311EUF/DlSxoycE2e/2NtRk4WKkIXzyrXDTrlikJMWgbw==", + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", "dev": true, "license": "MIT", "dependencies": { "browser-stdout": "^1.3.1", "chokidar": "^4.0.1", "debug": "^4.3.5", - "diff": "^5.2.0", + "diff": "^7.0.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", + "minimatch": "^9.0.5", "ms": "^2.1.3", "picocolors": "^1.1.1", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", - "workerpool": "^6.5.1", + "workerpool": "^9.2.0", "yargs": "^17.7.2", "yargs-parser": "^21.1.1", "yargs-unparser": "^2.0.0" @@ -9605,32 +4872,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/mocha/node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -9655,16 +4896,19 @@ "license": "ISC" }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mocha/node_modules/path-scurry": { @@ -9700,6 +4944,16 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -9714,6 +4968,25 @@ "dev": true, "license": "ISC" }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", @@ -9722,30 +4995,6 @@ "license": "MIT", "optional": true }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "license": "MIT" - }, "node_modules/next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -9775,46 +5024,55 @@ "license": "MIT", "optional": true }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "node_modules/node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", "dev": true, "license": "MIT", - "peer": true - }, - "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true, - "license": "MIT" + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=20" + } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", "dev": true, - "license": "MIT", - "peer": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", "dev": true, - "license": "MIT", - "peer": true, + "license": "ISC", "dependencies": { - "path-key": "^3.0.0" + "lru-cache": "^10.0.1" }, "engines": { - "node": ">=8" + "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -9851,18 +5109,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" }, "node_modules/once": { "version": "1.4.0", @@ -9870,27 +5126,11 @@ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "license": "ISC", + "optional": true, "dependencies": { "wrappy": "1" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/open": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", @@ -9909,24 +5149,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/ora": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", @@ -10064,14 +5286,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/package-json-from-dist": { @@ -10088,34 +5313,19 @@ "dev": true, "license": "(MIT AND Zlib)" }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -10181,16 +5391,6 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -10221,13 +5421,6 @@ "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, "node_modules/path-scurry": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", @@ -10255,25 +5448,25 @@ "node": "20 || >=22" } }, - "node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pathval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.16" - } + "license": "MIT" }, "node_modules/pend": { "version": "1.2.0", @@ -10283,9 +5476,9 @@ "license": "MIT" }, "node_modules/php-parser": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/php-parser/-/php-parser-3.2.3.tgz", - "integrity": "sha512-Kyu33y36aRed6HUi7ZS8EDG9/ZBz4lx/cJgoQui1B/x0L0ZCbCiBstdGnlGgufk8YwcLsk4J9VK9auXoL4Jz8A==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/php-parser/-/php-parser-3.2.5.tgz", + "integrity": "sha512-M1ZYlALFFnESbSdmRtTQrBFUHSriHgPhgqtTF/LCbZM4h7swR5PHtUceB2Kzby5CfqcsYwBn7OXTJ0+8Sajwkw==", "dev": true, "license": "BSD-3-Clause" }, @@ -10309,94 +5502,43 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", - "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true, "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=8" + "node": "^10 || ^12 || >=14" } }, "node_modules/prebuild-install": { @@ -10427,44 +5569,6 @@ "node": ">=10" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -10486,20 +5590,6 @@ "node": ">= 6" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/pump": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", @@ -10512,16 +5602,6 @@ "once": "^1.3.1" } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/punycode.js": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", @@ -10530,25 +5610,7 @@ "license": "MIT", "engines": { "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT", - "peer": true + } }, "node_modules/qs": { "version": "6.14.0", @@ -10597,32 +5659,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.6.3", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -10640,6 +5676,19 @@ "rc": "cli.js" } }, + "node_modules/rc-config-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", + "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "js-yaml": "^4.1.0", + "json5": "^2.2.2", + "require-from-string": "^2.0.2" + } + }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -10651,13 +5700,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, "node_modules/read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -10671,6 +5713,39 @@ "node": ">=0.8" } }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -10752,18 +5827,12 @@ "node": ">=0.10.0" } }, - "node_modules/rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", "dev": true, - "license": "MIT", - "dependencies": { - "resolve": "^1.20.0" - }, - "engines": { - "node": ">= 10.13.0" - } + "license": "Apache-2.0" }, "node_modules/require-directory": { "version": "2.1.1", @@ -10785,68 +5854,6 @@ "node": ">=0.10.0" } }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - } - }, "node_modules/restore-cursor": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", @@ -10891,21 +5898,49 @@ "node": ">=0.10.0" } }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "node_modules/rollup": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">= 18" + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", + "fsevents": "~2.3.2" } }, "node_modules/run-parallel": { @@ -10974,63 +6009,28 @@ "dev": true, "license": "ISC" }, - "node_modules/schema-utils": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", - "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "node_modules/secretlint": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/secretlint/-/secretlint-10.2.2.tgz", + "integrity": "sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "@secretlint/config-creator": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/node": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "debug": "^4.4.1", + "globby": "^14.1.0", + "read-pkg": "^9.0.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/schema-utils/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" + "bin": { + "secretlint": "bin/secretlint.js" }, - "peerDependencies": { - "ajv": "^8.8.2" + "engines": { + "node": ">=20.0.0" } }, - "node_modules/schema-utils/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/semi": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/semi/-/semi-4.0.5.tgz", @@ -11317,9 +6317,9 @@ } }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -11329,52 +6329,6 @@ "node": ">=10" } }, - "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/send/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", @@ -11385,22 +6339,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -11408,26 +6346,6 @@ "dev": true, "license": "MIT" }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -11527,6 +6445,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -11590,16 +6515,16 @@ } }, "node_modules/sinon": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-20.0.0.tgz", - "integrity": "sha512-+FXOAbdnj94AQIxH0w1v8gzNxkawVvNqE3jUzRLptR71Oykeu2RrQXXl/VQjKay+Qnh73fDt/oDfMo6xMeDQbQ==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.1.tgz", + "integrity": "sha512-Z0NVCW45W8Mg5oC/27/+fCqIHFnW8kpkFOq0j9XJIev4Ld0mKmERaZv5DMLAb9fGCevjKwaEeIQz5+MBXfZcDw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^13.0.5", - "@sinonjs/samsam": "^8.0.1", - "diff": "^7.0.0", + "@sinonjs/fake-timers": "^15.1.0", + "@sinonjs/samsam": "^8.0.3", + "diff": "^8.0.2", "supports-color": "^7.2.0" }, "funding": { @@ -11607,49 +6532,16 @@ "url": "https://opencollective.com/sinon" } }, - "node_modules/sinon/node_modules/@sinonjs/fake-timers": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", - "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.1" - } - }, "node_modules/sinon/node_modules/diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, - "node_modules/sinon/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/sinon/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -11658,76 +6550,102 @@ "license": "MIT" }, "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, - "license": "MIT", - "peer": true, + "license": "Apache-2.0", "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true, - "license": "BSD-3-Clause" + "license": "CC-BY-3.0" }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "license": "MIT", "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } + "license": "MIT" }, "node_modules/stdin-discarder": { "version": "0.2.2", @@ -11780,46 +6698,6 @@ "node": ">=0.6.19" } }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-length/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -11924,28 +6802,6 @@ "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -11960,9 +6816,9 @@ } }, "node_modules/strnum": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.0.tgz", - "integrity": "sha512-w0S//9BqZZGw0L0Y8uLSelFGnDJgTyyNQLmSlPnVz43zPAiqu3w4t8J8sDqqANOGeZIZ/9jWuPguYcEnsoHv4A==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", + "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", "dev": true, "funding": [ { @@ -11972,305 +6828,234 @@ ], "license": "MIT" }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/structured-source": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", + "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" + "boundary": "^2.0.0" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "has-flag": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", "dev": true, - "license": "MIT", - "optional": true, + "license": "BSD-3-Clause", "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=6" + "node": ">=10.0.0" } }, - "node_modules/tar-stream/node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "node_modules/table/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/tar-stream/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "license": "MIT", - "optional": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "engines": { + "node": ">=8" } }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/table/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } + "license": "MIT" }, - "node_modules/terser": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", - "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.12", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.12.tgz", - "integrity": "sha512-jDLYqo7oF8tJIttjXO6jBY5Hk8p3A8W4ttih7cCEq64fQFWmgJ4VqAQjKr7WwIDlmXKEc6QeoRb5ecjZ+2afcg==", + "node_modules/table/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", - "terser": "^5.31.1" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/terser-webpack-plugin/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">= 10.13.0" + "node": ">=8" } }, - "node_modules/terser-webpack-plugin/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" } }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/terser/node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" } }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "node_modules/tar-stream/node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, - "license": "ISC", - "peer": true, + "license": "MIT", + "optional": true, "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/tar-stream/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", - "peer": true, + "optional": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, - "license": "ISC", - "peer": true, + "license": "MIT", + "optional": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 6" } }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/terminal-link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-4.0.0.tgz", + "integrity": "sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==", "dev": true, - "license": "ISC", - "peer": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "ansi-escapes": "^7.0.0", + "supports-hyperlinks": "^3.2.0" }, "engines": { - "node": "*" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/text-table": { @@ -12280,6 +7065,22 @@ "dev": true, "license": "MIT" }, + "node_modules/textextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", + "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -12287,228 +7088,102 @@ "dev": true, "license": "MIT" }, - "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } + "license": "MIT" }, - "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", "dev": true, "license": "MIT", "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" + "node": ">=18" } }, - "node_modules/ts-jest": { - "version": "29.3.2", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.3.2.tgz", - "integrity": "sha512-bJJkrWc6PjFVz5g2DGCNUo8z7oFEYaz1xP1NpeDU7KNLMWPpEyV8Chbpkn8xjzgRDpQhnGMyvyldoL7h8JXyug==", + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", "dependencies": { - "bs-logger": "^0.2.6", - "ejs": "^3.1.10", - "fast-json-stable-stringify": "^2.1.0", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.7.1", - "type-fest": "^4.39.1", - "yargs-parser": "^21.1.1" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/type-fest": { - "version": "4.39.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.39.1.tgz", - "integrity": "sha512-uW9qzd66uyHYxwyVBYiwS4Oi0qZyUqwjU+Oevr6ZogYiXt99EOYtwvzMSLw1c3lYo2HzJsep/NB23iEVEgjG/w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=16" + "node": ">=12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/ts-loader": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.2.tgz", - "integrity": "sha512-Qo4piXvOTWcMGIgRiuFa6nHNm+54HbYaZCKqc9eeZCLRy3XqafQgwX2F7mofrbJG3g7EEb+lkiR+z2Lic2s3Zw==", + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4", - "source-map": "^0.7.4" - }, "engines": { "node": ">=12.0.0" }, "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/ts-loader/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" + "picomatch": "^3 || ^4" }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/ts-loader/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/ts-loader/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", "dev": true, "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=14.0.0" } }, - "node_modules/ts-loader/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ts-loader/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/ts-loader/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 8" + "node": ">=14.14" } }, - "node_modules/ts-loader/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "is-number": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=8.0" } }, "node_modules/tslib": { @@ -12546,82 +7221,30 @@ "version": "2.7.3", "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } + "dev": true, + "license": "ISC" }, - "node_modules/type-is/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=4" } }, - "node_modules/type-is/node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">= 0.6" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/typed-rest-client": { @@ -12644,9 +7267,9 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -12682,61 +7305,33 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.0" - }, - "bin": { - "update-browserslist-db": "cli.js" + "node": ">=18" }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" + "license": "MIT", + "engines": { + "node": ">= 10.0.0" } }, "node_modules/url-join": { @@ -12776,203 +7371,233 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "license": "ISC", - "peer": true, + "license": "Apache-2.0", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "node_modules/version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", "dev": true, - "license": "MIT", + "license": "Artistic-2.0", "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vscode-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", - "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "makeerror": "1.0.12" + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" } }, - "node_modules/watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">=10.13.0" + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.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 + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "node_modules/webpack": { - "version": "5.99.8", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.8.tgz", - "integrity": "sha512-lQ3CPiSTpfOnrEGeXDwoq5hIGzSjmwD72GdfVzF7CQAI7t47rJG9eDWvcEkEn3CUQymAElVvDg3YNTlCYj+qUQ==", + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", - "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.14.0", - "browserslist": "^4.24.0", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^4.3.2", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.11", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, "engines": { - "node": ">=10.13.0" + "node": ">=12.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "peerDependencies": { + "picomatch": "^3 || ^4" }, "peerDependenciesMeta": { - "webpack-cli": { + "picomatch": { "optional": true } } }, - "node_modules/webpack-cli": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", - "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "dependencies": { - "@discoveryjs/json-ext": "^0.6.1", - "@webpack-cli/configtest": "^3.0.1", - "@webpack-cli/info": "^3.0.1", - "@webpack-cli/serve": "^3.0.1", - "colorette": "^2.0.14", - "commander": "^12.1.0", - "cross-spawn": "^7.0.3", - "envinfo": "^7.14.0", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", - "webpack-merge": "^6.0.1" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" }, "bin": { - "webpack-cli": "bin/cli.js" + "vitest": "vitest.mjs" }, "engines": { - "node": ">=18.12.0" + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "webpack": "^5.82.0" + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" }, "peerDependenciesMeta": { - "webpack-bundle-analyzer": { + "@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/ui": { + "optional": true + }, + "happy-dom": { "optional": true }, - "webpack-dev-server": { + "jsdom": { "optional": true } } }, - "node_modules/webpack-merge": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", - "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "node": ">=12" }, - "engines": { - "node": ">=8.0.0" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } + "license": "MIT" }, "node_modules/whatwg-encoding": { "version": "3.1.1", @@ -13013,21 +7638,21 @@ "node": ">= 8" } }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/wordwrap": { @@ -13041,9 +7666,9 @@ } }, "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", "dev": true, "license": "Apache-2.0" }, @@ -13094,42 +7719,6 @@ "node": ">=8" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -13183,30 +7772,8 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/write-file-atomic/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, "license": "ISC", - "peer": true + "optional": true }, "node_modules/xml-escape": { "version": "1.0.0", @@ -13286,13 +7853,13 @@ } }, "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "dev": true, "license": "ISC", "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yargs-unparser": { @@ -13369,6 +7936,16 @@ "node": ">=8" } }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", @@ -13402,26 +7979,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/zod": { - "version": "3.24.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.4.tgz", - "integrity": "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.24.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", - "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", - "dev": true, - "license": "ISC", - "peerDependencies": { - "zod": "^3.24.1" - } } } } diff --git a/package.json b/package.json index 5c5241bb..ab906893 100644 --- a/package.json +++ b/package.json @@ -66,10 +66,6 @@ { "command": "phpunit.rerun", "title": "PHPUnit: Repeat the last test run" - }, - { - "command": "phpunit.run-by-group", - "title": "PHPUnit: Run tests by group" } ], "keybindings": [ @@ -159,58 +155,52 @@ } }, "main": "./dist/extension.js", - "prettier": { - "printWidth": 100, - "singleQuote": true, - "tabWidth": 4, - "useTabs": false - }, "scripts": { "vscode:prepublish": "npm run package", - "compile": "webpack", - "watch": "webpack --mode development --watch", - "package": "webpack --mode production --devtool hidden-source-map", + "typecheck": "tsc --noEmit", + "compile": "npm run typecheck && node esbuild.mjs", + "watch": "node esbuild.mjs --watch", + "package": "npm run typecheck && node esbuild.mjs --production", "compile-tests": "tsc -p . --outDir out", "watch-tests": "tsc -p . -w --outDir out", "pretest": "npm run compile-tests && npm run compile && npm run lint", - "lint": "eslint src -c eslint.config.mjs --ignore-pattern '**/phpunit'", + "lint": "biome check src", + "lint:fix": "biome check --write src", + "format": "biome format --write src", "test": "node ./out/test/runTest.js", - "jest": "jest", - "jest:watch": "jest --watch-all", + "vitest": "vitest run", + "vitest:watch": "vitest", "download-api": "npx vscode-dts main && npx vscode-dts dev", "postinstall": "npm run download-api" }, "devDependencies": { - "@types/chai": "^5.2.2", - "@types/glob": "^8.1.0", - "@types/jest": "^29.5.14", + "@biomejs/biome": "2.3.15", + "@types/chai": "^5.2.3", + "@types/glob": "^9.0.0", "@types/mocha": "^10.0.10", - "@types/node": "^20", - "@types/semver": "^7.7.0", - "@types/sinon": "^17.0.4", + "@types/node": "^25", + "@types/semver": "^7.7.1", + "@types/sinon": "^21.0.0", "@types/yargs-parser": "^21.0.3", - "@typescript-eslint/eslint-plugin": "^8.32.0", - "@typescript-eslint/parser": "^8.32.0", "@vscode/dts": "^0.4.1", "@vscode/test-electron": "^2.5.2", - "@vscode/vsce": "^3.3.2", - "chai": "^5.2.0", - "eslint": "^9.26.0", - "fast-xml-parser": "^5.2.3", - "glob": "^11.0.2", - "minimatch": "^10.0.1", - "mocha": "^11.2.2", - "php-parser": "^3.2.3", + "@vscode/vsce": "^3.7.1", + "chai": "^6.2.2", + "esbuild": "^0.27.3", + "fast-xml-parser": "^5.3.5", + "glob": "^13.0.3", + "inversify": "^7.11.0", + "minimatch": "^10.2.0", + "mocha": "^11.7.5", + "php-parser": "^3.2.5", + "reflect-metadata": "^0.2.2", "semi": "^4.0.5", - "semver": "^7.7.1", - "sinon": "^20.0.0", + "semver": "^7.7.4", + "sinon": "^21.0.1", "string-argv": "^0.3.2", - "ts-jest": "^29.3.2", - "ts-loader": "^9.5.2", - "typescript": "^5.8.3", + "typescript": "^5.9.3", + "vitest": "^4.0.18", "vscode-uri": "^3.1.0", - "webpack": "^5.99.8", - "webpack-cli": "^6.0.1", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" } } diff --git a/src/CommandHandler.ts b/src/CommandHandler.ts deleted file mode 100644 index 4c779be3..00000000 --- a/src/CommandHandler.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { CancellationTokenSource, commands, TestItem, TestRunProfile, TestRunRequest, window } from 'vscode'; -import { Handler } from './Handler'; -import { GroupRegistry, TestCollection } from './TestCollection'; - -export class CommandHandler { - constructor(private testCollection: TestCollection, private testRunProfile: TestRunProfile) {} - - reload(callback: () => void) { - return commands.registerCommand('phpunit.reload', async () => { - callback(); - }); - } - - runAll() { - return commands.registerCommand('phpunit.run-all', async () => { - await this.run(undefined); - }); - } - - runFile() { - return commands.registerCommand('phpunit.run-file', async () => { - const uri = window.activeTextEditor?.document.uri; - if (!uri) { - return; - } - - const tests = this.testCollection.findTestsByFile(uri); - if (tests.length > 0) { - await this.run(tests); - } - }); - } - - runTestAtCursor() { - return commands.registerCommand('phpunit.run-test-at-cursor', async () => { - const uri = window.activeTextEditor?.document.uri; - if (!uri) { - return; - } - - const tests = this.testCollection.findTestsByPosition(uri, window.activeTextEditor!.selection.active!); - if (tests.length > 0) { - await this.run(tests); - } - }); - } - - rerun(handler: Handler) { - return commands.registerCommand('phpunit.rerun', () => { - return this.run( - this.testCollection.findTestsByRequest(handler.getPreviousRequest()), - ); - }); - } - - runByGroup(handler: Handler) { - return commands.registerCommand('phpunit.run-by-group', async () => { - const groups = GroupRegistry.getInstance().getAll(); - if (groups.length === 0) { - window.showInformationMessage('No PHPUnit groups found. Add @group annotations or #[Group] attributes to your tests.'); - return; - } - - const selectedGroup = await window.showQuickPick(groups, { - placeHolder: 'Select a PHPUnit group to run', - title: 'Run Tests by Group', - }); - - if (!selectedGroup || !handler) { - return; - } - - const cancellation = new CancellationTokenSource().token; - await handler.startGroupTestRun(selectedGroup, cancellation); - }); - } - - private async run(include: readonly TestItem[] | undefined) { - const cancellation = new CancellationTokenSource().token; - - await this.testRunProfile.runHandler(new TestRunRequest(include, undefined, this.testRunProfile), cancellation); - } -} \ No newline at end of file diff --git a/src/PHPUnitLinkProvider.test.ts b/src/Commands/PHPUnitLinkProvider.test.ts similarity index 68% rename from src/PHPUnitLinkProvider.test.ts rename to src/Commands/PHPUnitLinkProvider.test.ts index c1a03ec2..90c51ae3 100644 --- a/src/PHPUnitLinkProvider.test.ts +++ b/src/Commands/PHPUnitLinkProvider.test.ts @@ -1,11 +1,15 @@ import { relative } from 'node:path'; -import { DocumentLink, Position, Range } from 'vscode'; -import { PHPUnitXML } from './PHPUnit'; -import { phpUnitProject } from './PHPUnit/__tests__/utils'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { type DocumentLink, Position, Range } from 'vscode'; +import { PHPUnitXML } from '../PHPUnit'; +import { phpUnitProject } from '../PHPUnit/__tests__/utils'; import { PHPUnitLinkProvider } from './PHPUnitLinkProvider'; class TextLine { - constructor(public text: string, public range: Range) {} + constructor( + public text: string, + public range: Range, + ) {} } class TextDocument { @@ -14,9 +18,12 @@ class TextDocument { constructor(text: string) { this.lines = text .split('\n') - .map((line, index) => new TextLine( - line, - new Range(new Position(index, 0), new Position(index, text.length))), + .map( + (line, index) => + new TextLine( + line, + new Range(new Position(index, 0), new Position(index, text.length)), + ), ); } @@ -37,11 +44,12 @@ describe('PHPUnitLinkProvider', () => { }; let provider: PHPUnitLinkProvider; - beforeEach(() => provider = new PHPUnitLinkProvider(phpUnitXML)); + beforeEach(() => (provider = new PHPUnitLinkProvider(phpUnitXML))); it('get PHPUnit links', () => { - const document = new TextDocument(`❌ FAILED Calculator (Tests\Calculator) > Sum item method not call -Mockery\Exception\InvalidCountException: Method test() from Mockery_0_App_Item_App_Item should be called + const document = + new TextDocument(`❌ FAILED Calculator (TestsCalculator) > Sum item method not call +MockeryExceptionInvalidCountException: Method test() from Mockery_0_App_Item_App_Item should be called exactly 1 times but called 0 times. 1. ${phpUnitProject('vendor/mockery/mockery/library/Mockery/CountValidator/Exact.php')}:32 @@ -54,8 +62,12 @@ Mockery\Exception\InvalidCountException: Method test() from Mocke 8. ${phpUnitProject('vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegration.php')}:61 9. ${phpUnitProject('vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegrationAssertPostConditions.php')}:19`); - const links = (provider.provideDocumentLinks(document as any, {} as any) as DocumentLink[]) - .map((link) => [normalizePath(link.target!.fsPath), link.target!.fragment]); + const links = ( + provider.provideDocumentLinks( + document as unknown as import('vscode').TextDocument, + {} as unknown as import('vscode').CancellationToken, + ) as DocumentLink[] + ).map((link) => [normalizePath(link.target!.fsPath), link.target!.fragment]); expect(links).toEqual([ ['vendor/mockery/mockery/library/Mockery/CountValidator/Exact.php', 'L32'], @@ -64,9 +76,18 @@ Mockery\Exception\InvalidCountException: Method test() from Mocke ['vendor/mockery/mockery/library/Mockery/Container.php', 'L583'], ['vendor/mockery/mockery/library/Mockery/Container.php', 'L519'], ['vendor/mockery/mockery/library/Mockery.php', 'L176'], - ['vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegration.php', 'L49'], - ['vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegration.php', 'L61'], - ['vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegrationAssertPostConditions.php', 'L19'], + [ + 'vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegration.php', + 'L49', + ], + [ + 'vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegration.php', + 'L61', + ], + [ + 'vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegrationAssertPostConditions.php', + 'L19', + ], ]); }); @@ -99,8 +120,12 @@ at src/Calculator.php:7 11. vendor/pestphp/pest-plugin-arch/src/SingleArchExpectation.php:156 12. vendor/pestphp/pest-plugin-arch/src/SingleArchExpectation.php:140`); - const links = (provider.provideDocumentLinks(document as any, {} as any) as DocumentLink[]) - .map((link) => [normalizePath(link.target!.fsPath), link.target!.fragment]); + const links = ( + provider.provideDocumentLinks( + document as unknown as import('vscode').TextDocument, + {} as unknown as import('vscode').CancellationToken, + ) as DocumentLink[] + ).map((link) => [normalizePath(link.target!.fsPath), link.target!.fragment]); expect(links).toEqual([ ['src/Calculator.php', 'L7'], @@ -118,4 +143,4 @@ at src/Calculator.php:7 ['vendor/pestphp/pest-plugin-arch/src/SingleArchExpectation.php', 'L140'], ]); }); -}); \ No newline at end of file +}); diff --git a/src/PHPUnitLinkProvider.ts b/src/Commands/PHPUnitLinkProvider.ts similarity index 65% rename from src/PHPUnitLinkProvider.ts rename to src/Commands/PHPUnitLinkProvider.ts index 7962f2a8..62e23cd7 100644 --- a/src/PHPUnitLinkProvider.ts +++ b/src/Commands/PHPUnitLinkProvider.ts @@ -1,15 +1,26 @@ +import { inject, injectable } from 'inversify'; import { - CancellationToken, DocumentLink, DocumentLinkProvider, Position, ProviderResult, Range, TextDocument, + type CancellationToken, + DocumentLink, + type DocumentLinkProvider, + Position, + type ProviderResult, + Range, + type TextDocument, } from 'vscode'; import { URI } from 'vscode-uri'; -import { PHPUnitXML } from './PHPUnit'; +import { PHPUnitXML } from '../PHPUnit'; +@injectable() export class PHPUnitLinkProvider implements DocumentLinkProvider { private regex = /((?:[A-Z]:)?(?:\.{0,2}[\\/])?[^\s:]+\.php):(\d+)(?::(\d+))?/gi; - constructor(private phpUnitXML: PHPUnitXML) {} + constructor(@inject(PHPUnitXML) private phpUnitXML: PHPUnitXML) {} - provideDocumentLinks(document: TextDocument, _token: CancellationToken): ProviderResult { + provideDocumentLinks( + document: TextDocument, + _token: CancellationToken, + ): ProviderResult { const links: DocumentLink[] = []; for (let lineIndex = 0; lineIndex < document.lineCount; lineIndex++) { @@ -20,7 +31,9 @@ export class PHPUnitLinkProvider implements DocumentLinkProvider { const [fullMatch, filePath, lineStr] = match; const lineNumber = parseInt(lineStr, 10); - const targetUri = URI.file(this.phpUnitXML.path(filePath)).with({ fragment: `L${lineNumber}` }); + const targetUri = URI.file(this.phpUnitXML.path(filePath)).with({ + fragment: `L${lineNumber}`, + }); const start = new Position(lineIndex, match.index); const end = new Position(lineIndex, match.index + fullMatch.length); const range = new Range(start, end); @@ -31,4 +44,4 @@ export class PHPUnitLinkProvider implements DocumentLinkProvider { return links; } -} \ No newline at end of file +} diff --git a/src/Commands/TestCommandRegistry.ts b/src/Commands/TestCommandRegistry.ts new file mode 100644 index 00000000..9d1f645d --- /dev/null +++ b/src/Commands/TestCommandRegistry.ts @@ -0,0 +1,87 @@ +import { inject, injectable } from 'inversify'; +import { + CancellationTokenSource, + commands, + type TestItem, + type TestRunProfile, + TestRunRequest, + window, +} from 'vscode'; +import { TestCollection } from '../TestCollection'; +import { TestFileDiscovery } from '../TestDiscovery'; +import { TestRunHandler } from '../TestExecution'; + +@injectable() +export class TestCommandRegistry { + private testRunProfile!: TestRunProfile; + + constructor( + @inject(TestCollection) private testCollection: TestCollection, + @inject(TestRunHandler) private handler: TestRunHandler, + @inject(TestFileDiscovery) private testFileDiscovery: TestFileDiscovery, + ) {} + + setTestRunProfile(profile: TestRunProfile) { + this.testRunProfile = profile; + } + + reload() { + return commands.registerCommand('phpunit.reload', async () => { + await this.testFileDiscovery.reloadAll(); + }); + } + + runAll() { + return commands.registerCommand('phpunit.run-all', async () => { + await this.run(undefined); + }); + } + + runFile() { + return commands.registerCommand('phpunit.run-file', async () => { + const uri = window.activeTextEditor?.document.uri; + if (!uri) { + return; + } + + const tests = this.testCollection.findTestsByFile(uri); + if (tests.length > 0) { + await this.run(tests); + } + }); + } + + runTestAtCursor() { + return commands.registerCommand('phpunit.run-test-at-cursor', async () => { + const uri = window.activeTextEditor?.document.uri; + if (!uri) { + return; + } + + const tests = this.testCollection.findTestsByPosition( + uri, + window.activeTextEditor?.selection.active!, + ); + if (tests.length > 0) { + await this.run(tests); + } + }); + } + + rerun() { + return commands.registerCommand('phpunit.rerun', () => { + return this.run( + this.testCollection.findTestsByRequest(this.handler.getPreviousRequest()), + ); + }); + } + + private async run(include: readonly TestItem[] | undefined) { + const cancellation = new CancellationTokenSource().token; + + await this.testRunProfile.runHandler( + new TestRunRequest(include, undefined, this.testRunProfile), + cancellation, + ); + } +} diff --git a/src/Commands/index.ts b/src/Commands/index.ts new file mode 100644 index 00000000..41350a74 --- /dev/null +++ b/src/Commands/index.ts @@ -0,0 +1,2 @@ +export * from './PHPUnitLinkProvider'; +export * from './TestCommandRegistry'; diff --git a/src/Configuration.ts b/src/Configuration.ts index 65308617..8bdbaa03 100644 --- a/src/Configuration.ts +++ b/src/Configuration.ts @@ -1,4 +1,4 @@ -import { WorkspaceConfiguration } from 'vscode'; +import type { WorkspaceConfiguration } from 'vscode'; import { BaseConfiguration } from './PHPUnit'; export class Configuration extends BaseConfiguration { @@ -14,11 +14,11 @@ export class Configuration extends BaseConfiguration { return this.workspaceConfiguration.get(key, defaultValue); } - has(key: string): any { + has(key: string): boolean { return this.workspaceConfiguration.has(key); } - async update(key: string, value: any): Promise { + async update(key: string, value: unknown): Promise { return this.workspaceConfiguration.update(key, value); } } diff --git a/src/CloverParser.test.ts b/src/Coverage/CloverParser.test.ts similarity index 72% rename from src/CloverParser.test.ts rename to src/Coverage/CloverParser.test.ts index 40614a75..42de584d 100644 --- a/src/CloverParser.test.ts +++ b/src/Coverage/CloverParser.test.ts @@ -1,10 +1,12 @@ -import { describe, expect, it } from '@jest/globals'; +import { describe, expect, it } from 'vitest'; import { Position } from 'vscode'; import { CloverParser } from './CloverParser'; describe('CloverParser test', () => { it('parseClover', async () => { - const cf = await CloverParser.parseClover('src/PHPUnit/__tests__/fixtures/test1.clover.xml'); + const cf = await CloverParser.parseClover( + 'src/PHPUnit/__tests__/fixtures/test1.clover.xml', + ); expect(cf.length).toEqual(3); const dc = cf[1].generateDetailedCoverage(); expect(dc.length).toEqual(6); diff --git a/src/CloverParser.ts b/src/Coverage/CloverParser.ts similarity index 53% rename from src/CloverParser.ts rename to src/Coverage/CloverParser.ts index 691c1834..ebba3c81 100644 --- a/src/CloverParser.ts +++ b/src/Coverage/CloverParser.ts @@ -1,39 +1,42 @@ -import { FileCoverage, FileCoverageDetail, Position, StatementCoverage, TestCoverageCount, Uri } from 'vscode'; -import { Element } from './PHPUnit'; - +import { + FileCoverage, + type FileCoverageDetail, + Position, + StatementCoverage, + TestCoverageCount, + Uri, +} from 'vscode'; +import { XmlElement } from '../PHPUnit'; export class CloverParser { static async parseClover(file: string): Promise { try { - const element = await Element.loadFile(file); + const element = await XmlElement.loadFile(file); return [ ...element.querySelectorAll('coverage project file'), ...element.querySelectorAll('coverage project package file'), - ].map((node: Element) => new PHPUnitFileCoverage(node)); - } catch (ex) { + ].map((node: XmlElement) => new PHPUnitFileCoverage(node)); + } catch (_ex) { return []; } } } export class PHPUnitFileCoverage extends FileCoverage { - constructor(private element: Element) { - super( - Uri.file(element.getAttribute('name')), - new TestCoverageCount(0, 0), - ); + constructor(private element: XmlElement) { + super(Uri.file(element.getAttribute('name')!), new TestCoverageCount(0, 0)); const metrics = this.element.querySelector('metrics'); - this.statementCoverage.covered = parseInt(metrics?.getAttribute('coveredstatements'), 10); - this.statementCoverage.total = parseInt(metrics?.getAttribute('statements'), 10); + this.statementCoverage.covered = parseInt(metrics?.getAttribute('coveredstatements')!, 10); + this.statementCoverage.total = parseInt(metrics?.getAttribute('statements')!, 10); } public generateDetailedCoverage(): FileCoverageDetail[] { - return this.element.querySelectorAll('line').map((line: Element) => { + return this.element.querySelectorAll('line').map((line: XmlElement) => { return new StatementCoverage( - parseInt(line.getAttribute('count'), 10), - new Position(parseInt(line.getAttribute('num'), 10) - 1, 0), + parseInt(line.getAttribute('count')!, 10), + new Position(parseInt(line.getAttribute('num')!, 10) - 1, 0), ); }); } -} \ No newline at end of file +} diff --git a/src/Coverage/CoverageCollector.test.ts b/src/Coverage/CoverageCollector.test.ts new file mode 100644 index 00000000..f70cd612 --- /dev/null +++ b/src/Coverage/CoverageCollector.test.ts @@ -0,0 +1,51 @@ +import { rm } from 'node:fs/promises'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import type { TestRun } from 'vscode'; +import { CloverParser } from './CloverParser'; +import { CoverageCollector } from './CoverageCollector'; + +vi.mock('node:fs/promises', () => ({ + rm: vi.fn().mockResolvedValue(undefined), +})); + +describe('CoverageCollector', () => { + let collector: CoverageCollector; + let testRun: TestRun; + + beforeEach(() => { + collector = new CoverageCollector(); + testRun = { addCoverage: vi.fn() } as unknown as TestRun; + }); + + afterEach(() => vi.restoreAllMocks()); + + it('should parse clover files and add coverage to test run', async () => { + const fakeCoverage = [{ file: 'a.php' }, { file: 'b.php' }]; + vi.spyOn(CloverParser, 'parseClover').mockResolvedValue( + fakeCoverage as unknown as import('../Coverage').PHPUnitFileCoverage[], + ); + + const processes = [ + { getCloverFile: () => '/tmp/coverage/phpunit-0.xml' }, + { getCloverFile: () => '/tmp/coverage/phpunit-1.xml' }, + ] as unknown as import('../PHPUnit').TestRunnerProcess[]; + + await collector.collect(processes, testRun); + + expect(CloverParser.parseClover).toHaveBeenCalledWith('/tmp/coverage/phpunit-0.xml'); + expect(CloverParser.parseClover).toHaveBeenCalledWith('/tmp/coverage/phpunit-1.xml'); + expect(testRun.addCoverage).toHaveBeenCalledTimes(4); + expect(rm).toHaveBeenCalledWith('/tmp/coverage', { recursive: true, force: true }); + }); + + it('should skip when no clover files', async () => { + const processes = [ + { getCloverFile: () => undefined }, + ] as unknown as import('../PHPUnit').TestRunnerProcess[]; + + await collector.collect(processes, testRun); + + expect(testRun.addCoverage).not.toHaveBeenCalled(); + expect(rm).not.toHaveBeenCalled(); + }); +}); diff --git a/src/Coverage/CoverageCollector.ts b/src/Coverage/CoverageCollector.ts new file mode 100644 index 00000000..c6fa5fda --- /dev/null +++ b/src/Coverage/CoverageCollector.ts @@ -0,0 +1,27 @@ +import { rm } from 'node:fs/promises'; +import { dirname } from 'node:path'; +import { injectable } from 'inversify'; +import type { TestRun } from 'vscode'; +import type { TestRunnerProcess } from '../PHPUnit'; +import { CloverParser } from './CloverParser'; + +@injectable() +export class CoverageCollector { + async collect(processes: TestRunnerProcess[], testRun: TestRun): Promise { + const cloverFiles = processes + .map((process) => process.getCloverFile()) + .filter((file): file is string => !!file); + + await Promise.all( + cloverFiles.map(async (file) => { + (await CloverParser.parseClover(file)).forEach((coverage) => { + testRun.addCoverage(coverage); + }); + }), + ); + + if (cloverFiles.length > 0) { + await rm(dirname(cloverFiles[0]), { recursive: true, force: true }); + } + } +} diff --git a/src/Coverage/index.ts b/src/Coverage/index.ts new file mode 100644 index 00000000..e22c50c7 --- /dev/null +++ b/src/Coverage/index.ts @@ -0,0 +1,2 @@ +export * from './CloverParser'; +export * from './CoverageCollector'; diff --git a/src/Handler.ts b/src/Handler.ts deleted file mode 100644 index b9a4e2d3..00000000 --- a/src/Handler.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { rm } from 'node:fs/promises'; -import { dirname } from 'node:path'; -import { - CancellationToken, debug, OutputChannel, TestController, TestItem, TestItemCollection, TestRun, TestRunRequest, - workspace, -} from 'vscode'; -import { CloverParser } from './CloverParser'; -import { Configuration } from './Configuration'; -import { OutputChannelObserver, Printer, TestResultObserver } from './Observers'; -import { MessageObserver } from './Observers/MessageObserver'; -import { Builder, PHPUnitXML, TestRunner, TestRunnerEvent, TestType } from './PHPUnit'; -import { Mode, Xdebug } from './PHPUnit/CommandBuilder/Xdebug'; -import { TestCase, TestCollection } from './TestCollection'; - -export class Handler { - private previousRequest: TestRunRequest | undefined; - - constructor( - private ctrl: TestController, - private phpUnitXML: PHPUnitXML, - private configuration: Configuration, - private testCollection: TestCollection, - private outputChannel: OutputChannel, - private printer: Printer, - ) { } - - getPreviousRequest() { - return this.previousRequest; - } - - async startTestRun(request: TestRunRequest, cancellation?: CancellationToken) { - const wsf = workspace.getWorkspaceFolder(this.testCollection.getWorkspace()); - const builder = new Builder(this.configuration, { cwd: this.phpUnitXML.root() }); - - const xdebug = new Xdebug(this.configuration); - builder.setXdebug(xdebug); - - await xdebug.setMode(request.profile?.kind); - if (xdebug.mode === Mode.debug) { - // TODO: perhaps wait for the debug session - await debug.startDebugging(wsf, xdebug.name ?? await xdebug.getDebugConfiguration()); - } - - const testRun = this.ctrl.createTestRun(request); - await this.runTestQueue(builder, testRun, request, cancellation); - - if (xdebug.mode === Mode.debug && debug.activeDebugSession?.type === 'php') { - debug.stopDebugging(debug.activeDebugSession); - } - - this.previousRequest = request; - } - - async startGroupTestRun(group: string, cancellation?: CancellationToken) { - const builder = new Builder(this.configuration, { cwd: this.phpUnitXML.root() }); - builder.setArguments(`--group ${group}`); - - const request = new TestRunRequest(); - const testRun = this.ctrl.createTestRun(request); - - const runner = new TestRunner(); - const queue = await this.discoverTests(this.gatherTestItems(this.ctrl.items), request); - queue.forEach((testItem) => testRun.enqueued(testItem)); - - runner.observe(new TestResultObserver(queue, testRun)); - runner.observe(new OutputChannelObserver(this.outputChannel, this.configuration, this.printer, request)); - runner.observe(new MessageObserver(this.configuration)); - - runner.emit(TestRunnerEvent.start, undefined); - - const process = runner.run(builder); - cancellation?.onCancellationRequested(() => process.abort()); - - await process.run(); - runner.emit(TestRunnerEvent.done, undefined); - testRun.end(); - } - - private async runTestQueue(builder: Builder, testRun: TestRun, request: TestRunRequest, cancellation?: CancellationToken) { - const queue = await this.discoverTests(request.include ?? this.gatherTestItems(this.ctrl.items), request); - queue.forEach((testItem) => testRun.enqueued(testItem)); - - const runner = new TestRunner(); - runner.observe(new TestResultObserver(queue, testRun)); - runner.observe(new OutputChannelObserver(this.outputChannel, this.configuration, this.printer, request)); - runner.observe(new MessageObserver(this.configuration)); - - runner.emit(TestRunnerEvent.start, undefined); - - const processes = !request.include - ? [runner.run(builder)] - : request.include - .map((testItem) => this.testCollection.getTestCase(testItem)!) - .map((testCase, index) => testCase.update(builder, index)) - .map((builder) => runner.run(builder)); - - cancellation?.onCancellationRequested(() => processes.forEach((process) => process.abort())); - - await Promise.all(processes.map((process) => process.run())); - - await Promise.all( - processes - .map((process) => process.getCloverFile()) - .filter((file) => !!file) - .map(async (file) => { - return (await CloverParser.parseClover(file!)).map(coverage => { - testRun.addCoverage(coverage); - }); - }), - ); - - const cloverFile = processes[0].getCloverFile(); - if (cloverFile) { - await rm(dirname(cloverFile), { recursive: true, force: true }); - } - - runner.emit(TestRunnerEvent.done, undefined); - }; - - private async discoverTests(tests: Iterable, request: TestRunRequest, queue = new Map()) { - for (const testItem of tests) { - if (request.exclude?.includes(testItem)) { - continue; - } - - const testCase = this.testCollection.getTestCase(testItem); - if (testCase?.type === TestType.method) { - queue.set(testCase, testItem); - } else { - await this.discoverTests(this.gatherTestItems(testItem.children), request, queue); - } - } - - return queue; - }; - - private gatherTestItems(collection: TestItemCollection) { - const items: TestItem[] = []; - collection.forEach((item) => items.push(item)); - - return items; - } -} \ No newline at end of file diff --git a/src/Observers/ErrorDialogObserver.test.ts b/src/Observers/ErrorDialogObserver.test.ts new file mode 100644 index 00000000..14c244d3 --- /dev/null +++ b/src/Observers/ErrorDialogObserver.test.ts @@ -0,0 +1,65 @@ +import { afterAll, beforeEach, describe, expect, it, type Mock, vi } from 'vitest'; +import { window } from 'vscode'; +import { Configuration, type IConfiguration } from '../PHPUnit'; +import { ErrorDialogObserver } from './ErrorDialogObserver'; + +describe('ErrorDialogObserver', () => { + let errorDialogObserver: ErrorDialogObserver; + let configuration: IConfiguration; + beforeEach(() => { + window.showErrorMessage = vi.fn(); + window.showWarningMessage = vi.fn(); + window.showInformationMessage = vi.fn(); + configuration = new Configuration(); + errorDialogObserver = new ErrorDialogObserver(configuration); + }); + + beforeEach(() => { + (window.showErrorMessage as Mock).mockReset(); + (window.showWarningMessage as Mock).mockReset(); + (window.showInformationMessage as Mock).mockReset(); + }); + + afterAll(() => vi.restoreAllMocks()); + + it('show error message', async () => { + const message = 'something went wrong'; + + await errorDialogObserver.error(message); + + expect(window.showErrorMessage).toHaveBeenCalledWith(message); + }); + + it('click Yes and set phpunit to vendor/bin/pest', async () => { + const message = + '"\n Pest\\Exceptions\\InvalidPestCommand \n\n Please run [./vendor/bin/pest] instead.\n\n"'; + + (window.showWarningMessage as Mock).mockReturnValue('Yes'); + + await errorDialogObserver.error(message); + + expect(window.showErrorMessage).not.toHaveBeenCalled(); + expect(window.showWarningMessage).toHaveBeenCalled(); + expect(configuration.get('phpunit')).toEqual('vendor/bin/pest'); + }); + + it('click Cancel and do not set phpunit to vendor/bin/pest', async () => { + const message = + '"\n Pest\\Exceptions\\InvalidPestCommand \n\n Please run [./vendor/bin/pest] instead.\n\n"'; + + (window.showWarningMessage as Mock).mockReturnValue('Cancel'); + + await errorDialogObserver.error(message); + + expect(window.showErrorMessage).not.toHaveBeenCalled(); + expect(window.showWarningMessage).toHaveBeenCalled(); + expect(configuration.get('phpunit')).not.toEqual('vendor/bin/pest'); + }); + + it('other pest exception', async () => { + const message = + '"\\n TypeError \\n\\n it(): Argument #2 ($closure) must be of type ?Closure, Pest\\\\Expectation given, called in /Users/recca0120/Desktop/vscode-phpunit/src/PHPUnit/__tests__/fixtures/pest-stub/tests/Unit/ExampleTest.php on line 2\\n\\n at vendor/pestphp/pest/src/Functions.php:159\\n 155▕ * @param-closure-this TestCase $closure\\n 156▕ *\\n 157▕ * @return Expectable|TestCall|TestCase|mixed\\n 158▕ */\\n ➜ 159▕ function it(string $description, ?Closure $closure = null): TestCall\\n 160▕ {\\n 161▕ $description = sprintf(\'it %s\', $description);\\n 162▕ \\n 163▕ /** @var TestCall $test */\\n\\n 1 tests/Unit/ExampleTest.php:2\\n \u001b[2m+2 vendor frames \u001b[22m\\n 4 tests/Unit/ExampleTest.php:2\\n\\n\\n"'; + + await errorDialogObserver.error(message); + }); +}); diff --git a/src/Observers/MessageObserver.ts b/src/Observers/ErrorDialogObserver.ts similarity index 64% rename from src/Observers/MessageObserver.ts rename to src/Observers/ErrorDialogObserver.ts index 1733e4de..581ec902 100644 --- a/src/Observers/MessageObserver.ts +++ b/src/Observers/ErrorDialogObserver.ts @@ -1,9 +1,11 @@ +import { inject, injectable } from 'inversify'; import { window } from 'vscode'; +import { Configuration } from '../Configuration'; +import type { IConfiguration, TestRunnerObserver } from '../PHPUnit'; -import { IConfiguration, TestRunnerObserver } from '../PHPUnit'; - -export class MessageObserver implements TestRunnerObserver { - constructor(private configuration: IConfiguration) {} +@injectable() +export class ErrorDialogObserver implements TestRunnerObserver { + constructor(@inject(Configuration) private configuration: IConfiguration) {} async error(error: string) { if (error.indexOf('Pest\\Exceptions\\InvalidPestCommand') === -1) { @@ -19,4 +21,4 @@ export class MessageObserver implements TestRunnerObserver { await this.configuration.update('phpunit', command); } } -} \ No newline at end of file +} diff --git a/src/Observers/MessageObserver.test.ts b/src/Observers/MessageObserver.test.ts deleted file mode 100644 index 1b687593..00000000 --- a/src/Observers/MessageObserver.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { window } from 'vscode'; -import { Configuration, IConfiguration } from '../PHPUnit'; -import { MessageObserver } from './MessageObserver'; -import Mock = jest.Mock; - -describe('MessageObserver', () => { - let messageObserver: MessageObserver; - let configuration: IConfiguration; - beforeEach(() => { - window.showErrorMessage = jest.fn(); - window.showWarningMessage = jest.fn(); - window.showInformationMessage = jest.fn(); - configuration = new Configuration(); - messageObserver = new MessageObserver(configuration); - }); - - beforeEach(() => { - (window.showErrorMessage as Mock).mockReset(); - (window.showWarningMessage as Mock).mockReset(); - (window.showInformationMessage as Mock).mockReset(); - }); - - afterAll(() => jest.restoreAllMocks()); - - it('show error message', async () => { - const message = 'something went wrong'; - - await messageObserver.error(message); - - expect(window.showErrorMessage).toHaveBeenCalledWith(message); - }); - - it('click Yes and set phpunit to vendor/bin/pest', async () => { - const message = '"\n Pest\\Exceptions\\InvalidPestCommand \n\n Please run [./vendor/bin/pest] instead.\n\n"'; - - (window.showWarningMessage as Mock).mockReturnValue('Yes'); - - await messageObserver.error(message); - - expect(window.showErrorMessage).not.toHaveBeenCalled(); - expect(window.showWarningMessage).toHaveBeenCalled(); - expect(configuration.get('phpunit')).toEqual('vendor/bin/pest'); - }); - - it('click Cancel and do not set phpunit to vendor/bin/pest', async () => { - const message = '"\n Pest\\Exceptions\\InvalidPestCommand \n\n Please run [./vendor/bin/pest] instead.\n\n"'; - - (window.showWarningMessage as Mock).mockReturnValue('Cancel'); - - await messageObserver.error(message); - - expect(window.showErrorMessage).not.toHaveBeenCalled(); - expect(window.showWarningMessage).toHaveBeenCalled(); - expect(configuration.get('phpunit')).not.toEqual('vendor/bin/pest'); - }); - - it('other pest exception', async () => { - const message = '"\\n TypeError \\n\\n it(): Argument #2 ($closure) must be of type ?Closure, Pest\\\\Expectation given, called in /Users/recca0120/Desktop/vscode-phpunit/src/PHPUnit/__tests__/fixtures/pest-stub/tests/Unit/ExampleTest.php on line 2\\n\\n at vendor/pestphp/pest/src/Functions.php:159\\n 155▕ * @param-closure-this TestCase $closure\\n 156▕ *\\n 157▕ * @return Expectable|TestCall|TestCase|mixed\\n 158▕ */\\n ➜ 159▕ function it(string $description, ?Closure $closure = null): TestCall\\n 160▕ {\\n 161▕ $description = sprintf(\'it %s\', $description);\\n 162▕ \\n 163▕ /** @var TestCall $test */\\n\\n 1 tests/Unit/ExampleTest.php:2\\n \u001b[2m+2 vendor frames \u001b[22m\\n 4 tests/Unit/ExampleTest.php:2\\n\\n\\n"'; - - await messageObserver.error(message); - }); -}); \ No newline at end of file diff --git a/src/Observers/OutputChannelObserver.test.ts b/src/Observers/OutputChannelObserver.test.ts index 8e3854a5..34fae874 100644 --- a/src/Observers/OutputChannelObserver.test.ts +++ b/src/Observers/OutputChannelObserver.test.ts @@ -1,13 +1,18 @@ -import 'jest'; import * as semver from 'semver'; +import { beforeEach, describe, expect, it, type Mock } from 'vitest'; +import type { OutputChannel, TestRunRequest } from 'vscode'; import * as vscode from 'vscode'; -import { OutputChannel, TestRunRequest } from 'vscode'; -import { Builder, Configuration, EOL, PHPUnitXML, TestRunner } from '../PHPUnit'; -import { getPhpUnitVersion, phpUnitProject } from '../PHPUnit/__tests__/utils'; -import { OutputChannelObserver, Printer } from './index'; +import { Configuration, EOL, PHPUnitXML, ProcessBuilder, TestRunner } from '../PHPUnit'; +import { detectPhpUnitStubs, phpUnitProject } from '../PHPUnit/__tests__/utils'; +import { OutputChannelObserver, OutputFormatter } from './index'; import { PrettyPrinter } from './Printers'; -describe('OutputChannelObserver', () => { +describe.each(detectPhpUnitStubs())('OutputChannelObserver on $name (PHPUnit $phpUnitVersion)', ({ + root, + phpUnitVersion, + binary, + args: stubArgs, +}) => { let testRunner: TestRunner; let outputChannel: OutputChannel; let configuration: Configuration; @@ -15,8 +20,8 @@ describe('OutputChannelObserver', () => { beforeEach(() => { configuration = new Configuration({ php: 'php', - phpunit: 'vendor/bin/phpunit', - args: ['-c', 'phpunit.xml'], + phpunit: binary, + args: ['-c', 'phpunit.xml', ...stubArgs], clearOutputOnRun: true, showAfterExecution: 'onFailure', }); @@ -26,20 +31,13 @@ describe('OutputChannelObserver', () => { outputChannel, configuration, new PrettyPrinter(new PHPUnitXML()), - { continuous: false } as TestRunRequest, ); + observer.setRequest({ continuous: false } as TestRunRequest); testRunner.observe(observer); }); - const PHPUNIT_VERSION: string = getPhpUnitVersion(); - function getOutputChannel(): OutputChannel { - return (vscode.window.createOutputChannel as jest.Mock).mock.results[0].value; - } - - function debug(outputChannel: OutputChannel) { - console.log((outputChannel.appendLine as jest.Mock).mock.calls); - console.log((outputChannel.append as jest.Mock).mock.calls); + return (vscode.window.createOutputChannel as Mock).mock.results[0].value; } async function run(file?: string, filter?: string) { @@ -47,8 +45,8 @@ describe('OutputChannelObserver', () => { filter = `--filter='^.*::(${filter})( with data set .*)?$'`; } - const cwd = phpUnitProject(''); - const builder = new Builder(configuration, { cwd }); + const cwd = root; + const builder = new ProcessBuilder(configuration, { cwd }); builder.setArguments([file, filter].join(' ')); await testRunner.run(builder).run(); @@ -60,7 +58,11 @@ describe('OutputChannelObserver', () => { const outputChannel = getOutputChannel(); expect(outputChannel.clear).toHaveBeenCalled(); expect(outputChannel.appendLine).toHaveBeenCalledWith( - `php vendor/bin/phpunit --configuration=phpunit.xml ${testFile} --colors=never --teamcity`, + expect.stringMatching( + new RegExp( + `php .+phpunit .+${testFile.replace(/[/\\]/g, '.')} --colors=never --teamcity`, + ), + ), ); }); @@ -75,7 +77,7 @@ describe('OutputChannelObserver', () => { }); it('should trigger testRuntime', async () => { - if (semver.lt(PHPUNIT_VERSION, '10.0.0')) { + if (semver.lt(phpUnitVersion, '10.0.0')) { return; } @@ -89,7 +91,7 @@ describe('OutputChannelObserver', () => { }); it('should trigger testConfiguration', async () => { - if (semver.lt(PHPUNIT_VERSION, '10.0.0')) { + if (semver.lt(phpUnitVersion, '10.0.0')) { return; } @@ -145,12 +147,14 @@ describe('OutputChannelObserver', () => { expect.stringMatching(/\s+❌\sfailed\s\d+\sms/), ); expect(outputChannel.appendLine).toHaveBeenCalledWith( - expect.stringContaining([ - ` ┐ `, - ` ├ Failed asserting that false is true.`, - ` │ `, - ` │ ${Printer.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 22)}`, - ].join(EOL)), + expect.stringContaining( + [ + ` ┐ `, + ` ├ Failed asserting that false is true.`, + ` │ `, + ` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`, + ].join(EOL), + ), ); }); @@ -158,7 +162,7 @@ describe('OutputChannelObserver', () => { let DOT = ''; let ARRAY_OPEN = '('; let ARRAY_CLOSE = ')'; - if (semver.gte(PHPUNIT_VERSION, '10.4.2')) { + if (semver.gte(phpUnitVersion, '10.4.2')) { DOT = ','; ARRAY_OPEN = '['; ARRAY_CLOSE = ']'; @@ -173,21 +177,23 @@ describe('OutputChannelObserver', () => { expect.stringMatching(/\s+❌\sis_not_same\s\d+\sms/), ); expect(outputChannel.appendLine).toHaveBeenCalledWith( - expect.stringContaining([ - ` ┐ `, - ` ├ Failed asserting that two arrays are identical.`, - ` ┊ ---·Expected Array &0 ${ARRAY_OPEN}`, - ` ┊ 'a' => 'b'${DOT}`, - ` ┊ 'c' => 'd'${DOT}`, - ` ┊ ${ARRAY_CLOSE}`, - ` ┊ +++·Actual Array &0 ${ARRAY_OPEN}`, - ` ┊ 'e' => 'f'${DOT}`, - ` ┊ 0 => 'g'${DOT}`, - ` ┊ 1 => 'h'${DOT}`, - ` ┊ ${ARRAY_CLOSE}`, - ` │ `, - ` │ ${Printer.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`, - ].join(EOL)), + expect.stringContaining( + [ + ` ┐ `, + ` ├ Failed asserting that two arrays are identical.`, + ` ┊ ---·Expected Array &0 ${ARRAY_OPEN}`, + ` ┊ 'a' => 'b'${DOT}`, + ` ┊ 'c' => 'd'${DOT}`, + ` ┊ ${ARRAY_CLOSE}`, + ` ┊ +++·Actual Array &0 ${ARRAY_OPEN}`, + ` ┊ 'e' => 'f'${DOT}`, + ` ┊ 0 => 'g'${DOT}`, + ` ┊ 1 => 'h'${DOT}`, + ` ┊ ${ARRAY_CLOSE}`, + ` │ `, + ` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 32)}`, + ].join(EOL), + ), ); }); @@ -203,7 +209,7 @@ describe('OutputChannelObserver', () => { }); it('should trigger testResultSummary', async () => { - if (semver.lt(PHPUNIT_VERSION, '10.0.0')) { + if (semver.lt(phpUnitVersion, '10.0.0')) { return; } @@ -217,7 +223,7 @@ describe('OutputChannelObserver', () => { }); it('should trigger testDuration', async () => { - if (semver.lt(PHPUNIT_VERSION, '10.0.0')) { + if (semver.lt(phpUnitVersion, '10.0.0')) { return; } @@ -237,7 +243,9 @@ describe('OutputChannelObserver', () => { const outputChannel = getOutputChannel(); expect(outputChannel.clear).toHaveBeenCalled(); expect(outputChannel.appendLine).toHaveBeenCalledWith(expect.stringMatching('❌')); - expect(outputChannel.appendLine).toHaveBeenCalledWith(expect.stringMatching(/NotFound\.php/)); + expect(outputChannel.appendLine).toHaveBeenCalledWith( + expect.stringMatching(/NotFound\.php/), + ); }); it('always show output channel', async () => { @@ -299,7 +307,7 @@ describe('OutputChannelObserver', () => { expect(outputChannel.show).not.toHaveBeenCalled(); }); - it('never show output channel when failure', async () => { + it('never show output channel when not found', async () => { await configuration.update('showAfterExecution', 'never'); const testFile = phpUnitProject('tests/NotFound.php'); await run(testFile, undefined); @@ -334,7 +342,16 @@ describe('OutputChannelObserver', () => { await run(testFile, filter); const outputChannel = getOutputChannel(); - expect(outputChannel.appendLine).toHaveBeenCalledWith('🟨 printed output when die'); + if (semver.gte(phpUnitVersion, '12.0.0')) { + expect(outputChannel.appendLine).toHaveBeenCalledWith( + expect.stringMatching(/🟨 printed output when die/), + ); + expect(outputChannel.appendLine).toHaveBeenCalledWith( + expect.stringMatching(/Fatal error: Premature end of PHP process/), + ); + } else { + expect(outputChannel.appendLine).toHaveBeenCalledWith('🟨 printed output when die'); + } expect(outputChannel.show).toHaveBeenCalled(); }); }); diff --git a/src/Observers/OutputChannelObserver.ts b/src/Observers/OutputChannelObserver.ts index e9a5afdc..99ac6b72 100644 --- a/src/Observers/OutputChannelObserver.ts +++ b/src/Observers/OutputChannelObserver.ts @@ -1,10 +1,26 @@ -import { OutputChannel, TestRunRequest } from 'vscode'; -import { - Builder, IConfiguration, TestConfiguration, TestDuration, TestFailed, TestFinished, TestIgnored, TestProcesses, - TestResult, TestResultSummary, TestRunnerObserver, TestRuntime, TestStarted, TestSuiteFinished, TestSuiteStarted, +import { inject, injectable } from 'inversify'; +import type { OutputChannel, TestRunRequest } from 'vscode'; +import { Configuration } from '../Configuration'; +import type { + IConfiguration, + ProcessBuilder, + TestConfiguration, + TestDuration, + TestFailed, + TestFinished, + TestIgnored, + TestProcesses, + TestResult, + TestResultSummary, + TestRunnerObserver, + TestRuntime, + TestStarted, + TestSuiteFinished, + TestSuiteStarted, TestVersion, } from '../PHPUnit'; -import { Printer } from './Printers'; +import { TYPES } from '../types'; +import { OutputFormatter } from './Printers'; enum ShowOutputState { always = 'always', @@ -12,44 +28,54 @@ enum ShowOutputState { never = 'never', } +@injectable() export class OutputChannelObserver implements TestRunnerObserver { private lastCommand = ''; + private request!: TestRunRequest; - constructor(private outputChannel: OutputChannel, private configuration: IConfiguration, private printer: Printer, private request: TestRunRequest) {} + constructor( + @inject(TYPES.OutputChannel) private outputChannel: OutputChannel, + @inject(Configuration) private configuration: IConfiguration, + @inject(OutputFormatter) private outputFormatter: OutputFormatter, + ) {} - run(builder: Builder): void { + setRequest(request: TestRunRequest) { + this.request = request; + } + + run(builder: ProcessBuilder): void { this.clearOutputOnRun(); this.showOutputChannel(ShowOutputState.always); - this.printer.start(); - this.appendLine(this.lastCommand = builder.toString()); + this.outputFormatter.start(); + this.appendLine((this.lastCommand = builder.toString())); } error(error: string): void { this.outputChannel.clear(); this.appendLine(this.lastCommand); - this.appendLine(this.printer.error(error)); + this.appendLine(this.outputFormatter.error(error)); this.showOutputChannel(ShowOutputState.onFailure); } line(line: string): void { - this.printer.append(line); + this.outputFormatter.append(line); } testVersion(result: TestVersion) { - this.appendLine(this.printer.testVersion(result)); + this.appendLine(this.outputFormatter.testVersion(result)); } testProcesses(result: TestProcesses) { - this.appendLine(this.printer.testProcesses(result)); + this.appendLine(this.outputFormatter.testProcesses(result)); } testRuntime(result: TestRuntime) { - this.appendLine(this.printer.testRuntime(result)); + this.appendLine(this.outputFormatter.testRuntime(result)); } testConfiguration(result: TestConfiguration) { - this.appendLine(this.printer.testConfiguration(result)); + this.appendLine(this.outputFormatter.testConfiguration(result)); } testSuiteStarted(result: TestSuiteStarted): void { @@ -58,26 +84,26 @@ export class OutputChannelObserver implements TestRunnerObserver { return; } - this.appendLine(this.printer.testSuiteStarted(result)); + this.appendLine(this.outputFormatter.testSuiteStarted(result)); } testStarted(result: TestStarted): void { - this.appendLine(this.printer.testStarted(result)); + this.appendLine(this.outputFormatter.testStarted(result)); } testFinished(result: TestFinished): void { - this.appendLine(this.printer.testFinished(result)); + this.appendLine(this.outputFormatter.testFinished(result)); this.printedOutput(result); } testFailed(result: TestFailed): void { - this.appendLine(this.printer.testFinished(result)); + this.appendLine(this.outputFormatter.testFinished(result)); this.printedOutput(result); this.showOutputChannel(ShowOutputState.onFailure); } testIgnored(result: TestIgnored): void { - this.appendLine(this.printer.testFinished(result)); + this.appendLine(this.outputFormatter.testFinished(result)); this.printedOutput(result); this.showOutputChannel(ShowOutputState.onFailure); } @@ -88,27 +114,27 @@ export class OutputChannelObserver implements TestRunnerObserver { return; } - this.appendLine(this.printer.testSuiteFinished(result)); + this.appendLine(this.outputFormatter.testSuiteFinished(result)); } testResultSummary(result: TestResultSummary) { - this.appendLine(this.printer.end()); - this.append(this.printer.testResultSummary(result)); + this.appendLine(this.outputFormatter.end()); + this.append(this.outputFormatter.testResultSummary(result)); } testDuration(result: TestDuration) { - this.appendLine(this.printer.end()); - this.append(this.printer.timeAndMemory(result)); + this.appendLine(this.outputFormatter.end()); + this.append(this.outputFormatter.timeAndMemory(result)); } close() { - this.appendLine(this.printer.end()); + this.appendLine(this.outputFormatter.end()); this.printedOutput(); - this.printer.close(); + this.outputFormatter.close(); } private printedOutput(result: TestResult | undefined = undefined): void { - const output = this.printer.printedOutput(result); + const output = this.outputFormatter.printedOutput(result); if (output) { this.appendLine(output); this.outputChannel.show(false); diff --git a/src/Observers/Printers/CollisionPrinter.test.ts b/src/Observers/Printers/CollisionPrinter.test.ts index a865e2df..653835ba 100644 --- a/src/Observers/Printers/CollisionPrinter.test.ts +++ b/src/Observers/Printers/CollisionPrinter.test.ts @@ -1,7 +1,8 @@ -import { EOL, PHPUnitXML, TeamcityEvent } from '../../PHPUnit'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { EOL, PHPUnitXML, TeamcityEvent, type TestSuiteFinished } from '../../PHPUnit'; import { phpUnitProject } from '../../PHPUnit/__tests__/utils'; import { CollisionPrinter } from './CollisionPrinter'; -import { Printer } from './Printer'; +import { OutputFormatter } from './OutputFormatter'; describe('CollisionPrinter', () => { const phpUnitXML = new PHPUnitXML().setRoot(phpUnitProject('')); @@ -28,7 +29,7 @@ describe('CollisionPrinter', () => { event: TeamcityEvent.testSuiteFinished, id: 'Recca0120\\VSCode\\Tests\\AssertionsTest', flowId: 8024, - } as any); + } as unknown as TestSuiteFinished); expect(output).toEqual(''); }); @@ -72,7 +73,7 @@ describe('CollisionPrinter', () => { details: [ { file: phpUnitProject('tests/AssertionsTest.php'), - line: 22, + line: 27, }, ], duration: 0, @@ -80,26 +81,28 @@ describe('CollisionPrinter', () => { expect(output).toEqual([`❌ failed 0 ms`].join(EOL)); - expect(printer.end()).toEqual([ - ``, - `❌ FAILED Recca0120\\VSCode\\Tests\\AssertionsTest > failed`, - `Failed asserting that false is true.`, - ``, - `at ${Printer.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 22)}`, - ` 18 ▕ * @depends test_passed`, - ` 19 ▕ */`, - ` 20 ▕ public function test_failed()`, - ` 21 ▕ {`, - `➜ 22 ▕ $this->assertTrue(false);`, - ` 23 ▕ }`, - ` 24 ▕ `, - ` 25 ▕ public function test_is_not_same()`, - ` 26 ▕ {`, - ` 27 ▕ $this->assertSame(['a' => 'b', 'c' => 'd'], ['e' => 'f', 'g', 'h']);`, - ``, - `1. ${Printer.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 22)}`, - ``, - ].join(EOL)); + expect(printer.end()).toEqual( + [ + ``, + `❌ FAILED Recca0120\\VSCode\\Tests\\AssertionsTest > failed`, + `Failed asserting that false is true.`, + ``, + `at ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`, + ` 23 ▕ * @depends test_passed`, + ` 24 ▕ */`, + ` 25 ▕ public function test_failed()`, + ` 26 ▕ {`, + `➜ 27 ▕ $this->assertTrue(false);`, + ` 28 ▕ }`, + ` 29 ▕ `, + ` 30 ▕ public function test_is_not_same()`, + ` 31 ▕ {`, + ` 32 ▕ $this->assertSame(['a' => 'b', 'c' => 'd'], ['e' => 'f', 'g', 'h']);`, + ``, + `1. ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`, + ``, + ].join(EOL), + ); }); it('testFailed with actual and expect', () => { @@ -114,45 +117,47 @@ describe('CollisionPrinter', () => { details: [ { file: phpUnitProject('tests/AssertionsTest.php'), - line: 27, + line: 32, }, ], duration: 29, type: 'comparisonFailure', - actual: 'Array &0 [\n \'e\' => \'f\',\n 0 => \'g\',\n 1 => \'h\',\n]', - expected: 'Array &0 [\n \'a\' => \'b\',\n \'c\' => \'d\',\n]', + actual: "Array &0 [\n 'e' => 'f',\n 0 => 'g',\n 1 => 'h',\n]", + expected: "Array &0 [\n 'a' => 'b',\n 'c' => 'd',\n]", }); expect(output).toEqual([`❌ is_not_same 29 ms`].join(EOL)); - expect(printer.end()).toEqual([ - ``, - `❌ FAILED Recca0120\\VSCode\\Tests\\AssertionsTest > is_not_same`, - `Failed asserting that two arrays are identical.`, - ` Array &0 [`, - `- 'a' => 'b',`, - `- 'c' => 'd',`, - `+ 'e' => 'f',`, - `+ 0 => 'g',`, - `+ 1 => 'h',`, - ` ]`, - ``, - ``, - `at ${Printer.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`, - ` 23 ▕ }`, - ` 24 ▕ `, - ` 25 ▕ public function test_is_not_same()`, - ` 26 ▕ {`, - `➜ 27 ▕ $this->assertSame(['a' => 'b', 'c' => 'd'], ['e' => 'f', 'g', 'h']);`, - ` 28 ▕ }`, - ` 29 ▕ `, - ` 30 ▕ public function test_risky()`, - ` 31 ▕ {`, - ` 32 ▕ $a = 1;`, - ``, - `1. ${Printer.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`, - ``, - ].join(EOL)); + expect(printer.end()).toEqual( + [ + ``, + `❌ FAILED Recca0120\\VSCode\\Tests\\AssertionsTest > is_not_same`, + `Failed asserting that two arrays are identical.`, + ` Array &0 [`, + `- 'a' => 'b',`, + `- 'c' => 'd',`, + `+ 'e' => 'f',`, + `+ 0 => 'g',`, + `+ 1 => 'h',`, + ` ]`, + ``, + ``, + `at ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 32)}`, + ` 28 ▕ }`, + ` 29 ▕ `, + ` 30 ▕ public function test_is_not_same()`, + ` 31 ▕ {`, + `➜ 32 ▕ $this->assertSame(['a' => 'b', 'c' => 'd'], ['e' => 'f', 'g', 'h']);`, + ` 33 ▕ }`, + ` 34 ▕ `, + ` 35 ▕ public function test_risky()`, + ` 36 ▕ {`, + ` 37 ▕ $a = 1;`, + ``, + `1. ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 32)}`, + ``, + ].join(EOL), + ); }); it('testFailed and file not found', () => { @@ -175,14 +180,16 @@ describe('CollisionPrinter', () => { expect(output).toEqual([`❌ failed 0 ms`].join(EOL)); - expect(printer.end()).toEqual([ - ``, - `❌ FAILED Recca0120\\VSCode\\Tests\\NotFoundTest > failed`, - `Failed asserting that false is true.`, - ``, - `1. ${Printer.fileFormat(phpUnitProject('tests/NotFoundTest.php'), 22)}`, - ``, - ].join(EOL)); + expect(printer.end()).toEqual( + [ + ``, + `❌ FAILED Recca0120\\VSCode\\Tests\\NotFoundTest > failed`, + `Failed asserting that false is true.`, + ``, + `1. ${OutputFormatter.fileFormat(phpUnitProject('tests/NotFoundTest.php'), 22)}`, + ``, + ].join(EOL), + ); }); it('testIgnored', () => { @@ -197,6 +204,8 @@ describe('CollisionPrinter', () => { duration: 0, }); - expect(output).toEqual([`➖ skipped ➜ The MySQLi extension is not available. 0 ms`].join(EOL)); + expect(output).toEqual( + [`➖ skipped ➜ The MySQLi extension is not available. 0 ms`].join(EOL), + ); }); -}); \ No newline at end of file +}); diff --git a/src/Observers/Printers/CollisionPrinter.ts b/src/Observers/Printers/CollisionPrinter.ts index a8e1ebc5..55fef25a 100644 --- a/src/Observers/Printers/CollisionPrinter.ts +++ b/src/Observers/Printers/CollisionPrinter.ts @@ -1,8 +1,18 @@ -import { readFileSync } from 'node:fs'; -import { EOL, TeamcityEvent, TestFailed, TestFinished, TestIgnored, TestSuiteFinished } from '../../PHPUnit'; -import { Printer } from './Printer'; - -export class CollisionPrinter extends Printer { +import { injectable, injectFromBase } from 'inversify'; +import { + EOL, + TeamcityEvent, + type TestFailed, + type TestFinished, + type TestIgnored, + type TestSuiteFinished, +} from '../../PHPUnit'; +import { OutputFormatter } from './OutputFormatter'; +import { readSourceSnippet } from './SourceFileReader'; + +@injectable() +@injectFromBase() +export class CollisionPrinter extends OutputFormatter { private errors: TestFailed[] = []; start() { @@ -45,7 +55,9 @@ export class CollisionPrinter extends Printer { this.getFileContent(result), this.formatDetails(result), '', - ].filter((content) => content !== undefined).join(EOL); + ] + .filter((content) => content !== undefined) + .join(EOL); } private formatErrorTitle(result: TestFailed) { @@ -84,39 +96,26 @@ export class CollisionPrinter extends Printer { return undefined; } - try { - const data = readFileSync(this.phpUnitXML.path(detail.file), 'utf8'); - const position = Math.max(0, detail.line - 5); - const lines = data.split(/\r\n|\n/).splice(position, 10).map((line, index) => { - const currentPosition = position + index + 1; - const prefix = detail.line === currentPosition ? '➜ ' : ' '; - - return `${prefix}${String(currentPosition).padStart(2, ' ')} ▕ ${line}`; - }); - - return [ - '', - `at ${Printer.fileFormat(detail.file, detail.line)}`, - ...lines, - ].join(EOL); - } catch (e) { - return undefined; - } + return readSourceSnippet(this.phpUnitXML.path(detail.file), detail.line)?.join(EOL); } private formatDetails(result: TestFailed) { - return EOL + result.details - .map(({ file, line }) => Printer.fileFormat(file, line)) - .map((file, index) => `${index + 1}. ${file}`).join(EOL); + return ( + EOL + + result.details + .map(({ file, line }) => OutputFormatter.fileFormat(file, line)) + .map((file, index) => `${index + 1}. ${file}`) + .join(EOL) + ); } private formatExpected(expected: string, prefix: string) { return expected - .replace(/^Array\s+&0\s+[(\[]/, '') + .replace(/^Array\s+&0\s+[([]/, '') .replace(/[)\]]$/, '') .trim() .split(/\r\n|\n/) .map((text) => `${prefix} ${text.trim()}`) .join(EOL); } -} \ No newline at end of file +} diff --git a/src/Observers/Printers/OutputBuffer.ts b/src/Observers/Printers/OutputBuffer.ts new file mode 100644 index 00000000..96560836 --- /dev/null +++ b/src/Observers/Printers/OutputBuffer.ts @@ -0,0 +1,36 @@ +import { EOL } from '../../PHPUnit'; + +export class OutputBuffer { + private current?: string; + private store: Map = new Map(); + + setCurrent(current?: string) { + this.current = current; + } + + append(text: string) { + if (!this.current || text.match(/^##teamcity\[/)) { + return; + } + + const existing = this.store.get(this.current) || ''; + this.store.set(this.current, `${existing}${text}${EOL}`); + } + + get(name: string) { + const text = this.store.get(name); + if (text) { + this.store.delete(name); + } + this.setCurrent(undefined); + return text?.trim(); + } + + all() { + return Array.from(this.store.values()).join(EOL).trim(); + } + + clear() { + this.store.clear(); + } +} diff --git a/src/Observers/Printers/Printer.test.ts b/src/Observers/Printers/OutputFormatter.test.ts similarity index 83% rename from src/Observers/Printers/Printer.test.ts rename to src/Observers/Printers/OutputFormatter.test.ts index edea0c36..86f8191a 100644 --- a/src/Observers/Printers/Printer.test.ts +++ b/src/Observers/Printers/OutputFormatter.test.ts @@ -1,16 +1,17 @@ -import { EOL, PHPUnitXML, TeamcityEvent, TestFinished } from '../../PHPUnit'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { EOL, PHPUnitXML, TeamcityEvent, type TestFinished, type TestSuiteFinished } from '../../PHPUnit'; import { phpUnitProject } from '../../PHPUnit/__tests__/utils'; -import { Printer } from './Printer'; +import { OutputFormatter } from './OutputFormatter'; -class MyPrinter extends Printer { +class MyOutputFormatter extends OutputFormatter { testFinished(_result: TestFinished): string | undefined { return undefined; } } -describe('Printer', () => { +describe('OutputFormatter', () => { const phpUnitXML = new PHPUnitXML(); - const printer = new MyPrinter(phpUnitXML); + const printer = new MyOutputFormatter(phpUnitXML); beforeEach(() => printer.start()); afterEach(() => printer.close()); @@ -23,7 +24,9 @@ describe('Printer', () => { text: 'PHPUnit 11.5.0 by Sebastian Bergmann and contributors.', }); - expect(output).toEqual(`${EOL}🚀 PHPUnit 11.5.0 by Sebastian Bergmann and contributors.${EOL}`); + expect(output).toEqual( + `${EOL}🚀 PHPUnit 11.5.0 by Sebastian Bergmann and contributors.${EOL}`, + ); }); it('testRuntime', () => { @@ -61,7 +64,9 @@ describe('Printer', () => { risky: 2, }); - expect(output).toEqual('Tests: 33, Assertions: 30, Errors: 2, Failures: 6, Warnings: 1, PHPUnit Deprecations: 8, Skipped: 1, Incomplete: 1, Risky: 2.'); + expect(output).toEqual( + 'Tests: 33, Assertions: 30, Errors: 2, Failures: 6, Warnings: 1, PHPUnit Deprecations: 8, Skipped: 1, Incomplete: 1, Risky: 2.', + ); }); it('timeAndMemory', () => { @@ -112,8 +117,8 @@ describe('Printer', () => { event: TeamcityEvent.testSuiteFinished, id: 'Recca0120\\VSCode\\Tests\\AssertionsTest', flowId: 8024, - } as any); + } as unknown as TestSuiteFinished); expect(output).toBeUndefined(); }); -}); \ No newline at end of file +}); diff --git a/src/Observers/Printers/Printer.ts b/src/Observers/Printers/OutputFormatter.ts similarity index 69% rename from src/Observers/Printers/Printer.ts rename to src/Observers/Printers/OutputFormatter.ts index 2b814129..b68f9d8a 100644 --- a/src/Observers/Printers/Printer.ts +++ b/src/Observers/Printers/OutputFormatter.ts @@ -1,45 +1,26 @@ +import { inject, injectable } from 'inversify'; import { - EOL, PHPUnitXML, TeamcityEvent, TestConfiguration, TestDuration, TestFailed, TestFinished, TestProcesses, - TestResult, TestResultSummary, TestRuntime, TestStarted, TestSuiteFinished, TestSuiteStarted, TestVersion, + EOL, + PHPUnitXML, + TeamcityEvent, + type TestConfiguration, + type TestDuration, + type TestFailed, + type TestFinished, + type TestProcesses, + type TestResult, + type TestResultSummary, + type TestRuntime, + type TestStarted, + type TestSuiteFinished, + type TestSuiteStarted, + type TestVersion, } from '../../PHPUnit'; +import { OutputBuffer } from './OutputBuffer'; -class OutputBuffer { - private current?: string; - private store: Map = new Map(); - - setCurrent(current?: string) { - this.current = current; - } - - append(text: string) { - if (!this.current || text.match(/^##teamcity\[/)) { - return; - } - - const existing = this.store.get(this.current) || ''; - this.store.set(this.current, `${existing}${text}${EOL}`); - } - - get(name: string) { - const text = this.store.get(name); - if (text) { - this.store.delete(name); - } - this.setCurrent(undefined); - return text?.trim(); - } - - all() { - return Array.from(this.store.values()).join(EOL).trim(); - } - - clear() { - this.store.clear(); - } -} - -export abstract class Printer { - protected outputBuffer = new OutputBuffer; +@injectable() +export abstract class OutputFormatter { + protected outputBuffer = new OutputBuffer(); protected messages = new Map([ [TeamcityEvent.testVersion, ['🚀', 'STARTED']], [TeamcityEvent.testFinished, ['✅', 'PASSED']], @@ -47,7 +28,7 @@ export abstract class Printer { [TeamcityEvent.testIgnored, ['➖', 'IGNORED']], ]); - constructor(protected phpUnitXML: PHPUnitXML) {} + constructor(@inject(PHPUnitXML) protected phpUnitXML: PHPUnitXML) {} static fileFormat(file: string, line: number) { return `${file}:${line}`; @@ -55,7 +36,7 @@ export abstract class Printer { start() { this.outputBuffer.clear(); - }; + } error(text: string) { const [icon] = this.messages.get(TeamcityEvent.testFailed)!; @@ -113,8 +94,7 @@ export abstract class Printer { return undefined; } - close() { - } + close() {} printedOutput(result: TestResult | undefined = undefined) { const icon = '🟨'; @@ -132,7 +112,7 @@ export abstract class Printer { 'Test code or tested code printed unexpected output', ].join('|'); const matched = message.match(new RegExp(`(${pattern}):(?.*)`, 'i')); - const text = !matched ? this.outputBuffer.get(name) : matched?.groups!.output.trim(); + const text = !matched ? this.outputBuffer.get(name) : matched?.groups?.output.trim(); return text ? `${icon} ${text}` : undefined; } @@ -144,4 +124,4 @@ export abstract class Printer { private setCurrent(current?: string) { this.outputBuffer.setCurrent(current); } -} \ No newline at end of file +} diff --git a/src/Observers/Printers/PrettyPrinter.test.ts b/src/Observers/Printers/PrettyPrinter.test.ts index 0372a92b..968a17bd 100644 --- a/src/Observers/Printers/PrettyPrinter.test.ts +++ b/src/Observers/Printers/PrettyPrinter.test.ts @@ -1,7 +1,8 @@ +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { EOL, PHPUnitXML, TeamcityEvent } from '../../PHPUnit'; import { phpUnitProject } from '../../PHPUnit/__tests__/utils'; +import { OutputFormatter } from './OutputFormatter'; import { PrettyPrinter } from './PrettyPrinter'; -import { Printer } from './Printer'; describe('PrettyPrinter', () => { const phpUnitXML = new PHPUnitXML().setRoot(phpUnitProject('')); @@ -62,21 +63,23 @@ describe('PrettyPrinter', () => { details: [ { file: phpUnitProject('tests/AssertionsTest.php'), - line: 22, + line: 27, }, ], duration: 0, }); - expect(output).toEqual([ - ` ❌ failed 0 ms`, - ` ┐ `, - ` ├ Failed asserting that false is true.`, - ` │ `, - ` │ ${Printer.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 22)}`, - ` ┴ `, - ``, - ].join(EOL)); + expect(output).toEqual( + [ + ` ❌ failed 0 ms`, + ` ┐ `, + ` ├ Failed asserting that false is true.`, + ` │ `, + ` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`, + ` ┴ `, + ``, + ].join(EOL), + ); }); it('testFailed with actual and expect', () => { @@ -91,33 +94,35 @@ describe('PrettyPrinter', () => { details: [ { file: phpUnitProject('tests/AssertionsTest.php'), - line: 27, + line: 32, }, ], duration: 29, type: 'comparisonFailure', - actual: 'Array &0 [\n \'e\' => \'f\',\n 0 => \'g\',\n 1 => \'h\',\n]', - expected: 'Array &0 [\n \'a\' => \'b\',\n \'c\' => \'d\',\n]', + actual: "Array &0 [\n 'e' => 'f',\n 0 => 'g',\n 1 => 'h',\n]", + expected: "Array &0 [\n 'a' => 'b',\n 'c' => 'd',\n]", }); - expect(output).toEqual([ - ` ❌ is_not_same 29 ms`, - ` ┐ `, - ` ├ Failed asserting that two arrays are identical.`, - ` ┊ ---·Expected Array &0 [`, - ` ┊ 'a' => 'b',`, - ` ┊ 'c' => 'd',`, - ` ┊ ]`, - ` ┊ +++·Actual Array &0 [`, - ` ┊ 'e' => 'f',`, - ` ┊ 0 => 'g',`, - ` ┊ 1 => 'h',`, - ` ┊ ]`, - ` │ `, - ` │ ${Printer.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`, - ` ┴ `, - ``, - ].join(EOL)); + expect(output).toEqual( + [ + ` ❌ is_not_same 29 ms`, + ` ┐ `, + ` ├ Failed asserting that two arrays are identical.`, + ` ┊ ---·Expected Array &0 [`, + ` ┊ 'a' => 'b',`, + ` ┊ 'c' => 'd',`, + ` ┊ ]`, + ` ┊ +++·Actual Array &0 [`, + ` ┊ 'e' => 'f',`, + ` ┊ 0 => 'g',`, + ` ┊ 1 => 'h',`, + ` ┊ ]`, + ` │ `, + ` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 32)}`, + ` ┴ `, + ``, + ].join(EOL), + ); }); it('testIgnored', () => { @@ -134,4 +139,4 @@ describe('PrettyPrinter', () => { expect(output).toEqual([` ➖ skipped 0 ms`].join(EOL)); }); -}); \ No newline at end of file +}); diff --git a/src/Observers/Printers/PrettyPrinter.ts b/src/Observers/Printers/PrettyPrinter.ts index 383630d8..ef25b5aa 100644 --- a/src/Observers/Printers/PrettyPrinter.ts +++ b/src/Observers/Printers/PrettyPrinter.ts @@ -1,7 +1,13 @@ -import { EOL, TeamcityEvent, TestFailed, TestFinished, TestSuiteFinished } from '../../PHPUnit'; -import { Printer } from './Printer'; +import { + EOL, + TeamcityEvent, + type TestFailed, + type TestFinished, + type TestSuiteFinished, +} from '../../PHPUnit'; +import { OutputFormatter } from './OutputFormatter'; -export class PrettyPrinter extends Printer { +export class PrettyPrinter extends OutputFormatter { private decorated = { default: '│', start: '┐', @@ -40,8 +46,8 @@ export class PrettyPrinter extends Printer { private formatDetails(result: TestFailed) { return result.details - .map(({ file, line }) => Printer.fileFormat(file, line)) - .reduce((msg, file) => (msg + this.formatMessage(this.decorated.default, file)), ''); + .map(({ file, line }) => OutputFormatter.fileFormat(file, line)) + .reduce((msg, file) => msg + this.formatMessage(this.decorated.default, file), ''); } private formatDiff(result: TestFailed) { @@ -59,7 +65,7 @@ export class PrettyPrinter extends Printer { const indent = ' '; return message.split(/\r\n|\n/g).reduce((msg, line, index) => { - return (msg + `${indent}${decorated} ${index === 0 ? prefix : ''}${line}${EOL}`); + return `${msg}${indent}${decorated} ${index === 0 ? prefix : ''}${line}${EOL}`; }, ''); } -} \ No newline at end of file +} diff --git a/src/Observers/Printers/SourceFileReader.ts b/src/Observers/Printers/SourceFileReader.ts new file mode 100644 index 00000000..bbcc9746 --- /dev/null +++ b/src/Observers/Printers/SourceFileReader.ts @@ -0,0 +1,22 @@ +import { readFileSync } from 'node:fs'; +import { OutputFormatter } from './OutputFormatter'; + +export function readSourceSnippet(filePath: string, targetLine: number): string[] | undefined { + try { + const data = readFileSync(filePath, 'utf8'); + const position = Math.max(0, targetLine - 5); + const lines = data + .split(/\r\n|\n/) + .splice(position, 10) + .map((line, index) => { + const currentPosition = position + index + 1; + const prefix = targetLine === currentPosition ? '➜ ' : ' '; + + return `${prefix}${String(currentPosition).padStart(2, ' ')} ▕ ${line}`; + }); + + return ['', `at ${OutputFormatter.fileFormat(filePath, targetLine)}`, ...lines]; + } catch (_e) { + return undefined; + } +} diff --git a/src/Observers/Printers/index.ts b/src/Observers/Printers/index.ts index 718e12e3..aa719755 100644 --- a/src/Observers/Printers/index.ts +++ b/src/Observers/Printers/index.ts @@ -1,3 +1,5 @@ export * from './CollisionPrinter'; +export * from './OutputBuffer'; +export * from './OutputFormatter'; export * from './PrettyPrinter'; -export * from './Printer'; +export * from './SourceFileReader'; diff --git a/src/Observers/TestResultObserver.ts b/src/Observers/TestResultObserver.ts index 1b3a36c9..714883a2 100644 --- a/src/Observers/TestResultObserver.ts +++ b/src/Observers/TestResultObserver.ts @@ -1,13 +1,32 @@ -import { Location, Position, Range, TestItem, TestMessage, TestMessageStackFrame, TestRun } from 'vscode'; +import { + Location, + Position, + Range, + type TestItem, + TestMessage, + TestMessageStackFrame, + type TestRun, +} from 'vscode'; import { URI } from 'vscode-uri'; import { - EOL, PestV2Fixer, TestFailed, TestFinished, TestIgnored, TestResult, TestRunnerObserver, TestStarted, TestSuiteFinished, - TestSuiteStarted, + EOL, + PestV2Fixer, + type TestFailed, + type TestFinished, + type TestIgnored, + type TestResult, + type TestRunnerObserver, + type TestStarted, + type TestSuiteFinished, + type TestSuiteStarted, } from '../PHPUnit'; -import { TestCase } from '../TestCollection'; +import type { TestCase } from '../TestCollection'; export class TestResultObserver implements TestRunnerObserver { - constructor(private queue: Map, private testRun: TestRun) { } + constructor( + private queue: Map, + private testRun: TestRun, + ) {} line(line: string): void { this.testRun.appendOutput(`${line}${EOL}`); @@ -55,34 +74,48 @@ export class TestResultObserver implements TestRunnerObserver { const message = TestMessage.diff(result.message, result.expected!, result.actual!); const details = result.details; if (details.length > 0) { - const current = details.find(({ file }) => file.endsWith(result.file ?? ''))!; - const line = current ? current.line - 1 : test.range!.start.line; + const matchingDetail = details.find(({ file }) => file.endsWith(result.file ?? ''))!; + const line = matchingDetail ? matchingDetail.line - 1 : test.range!.start.line; - message.location = new Location(test.uri!, new Range(new Position(line, 0), new Position(line, 0))); + message.location = new Location( + test.uri!, + new Range(new Position(line, 0), new Position(line, 0)), + ); message.stackTrace = details - .filter(({ file, line }) => file.endsWith(result.file ?? '') && line !== current.line) - .map(({ file, line }) => new TestMessageStackFrame( - `${file}:${line}`, URI.file(file), new Position(line, 0), - )); + .filter( + ({ file, line }) => + file.endsWith(result.file ?? '') && line !== matchingDetail.line, + ) + .map( + ({ file, line }) => + new TestMessageStackFrame( + `${file}:${line}`, + URI.file(file), + new Position(line, 0), + ), + ); } return message; } - private doRun(result: TestResult, callback: (test: TestItem) => void) { - const test = this.find(result); - if (!test) { + private doRun(result: TestResult, updateTestRun: (testItem: TestItem) => void) { + const testItem = this.find(result); + if (!testItem) { return; } - callback(test); + updateTestRun(testItem); } private find(result: TestResult) { if ('id' in result) { for (const [_, testItem] of this.queue) { - if (result.id === testItem.id || PestV2Fixer.isEqualsPestV2DataSetId(result, testItem.id)) { + if ( + result.id === testItem.id || + PestV2Fixer.isEqualsPestV2DataSetId(result, testItem.id) + ) { return testItem; } } @@ -90,4 +123,4 @@ export class TestResultObserver implements TestRunnerObserver { return undefined; } -} \ No newline at end of file +} diff --git a/src/Observers/index.ts b/src/Observers/index.ts index 48508c1f..f0ddc430 100644 --- a/src/Observers/index.ts +++ b/src/Observers/index.ts @@ -1,3 +1,4 @@ -export * from './TestResultObserver'; +export * from './ErrorDialogObserver'; export * from './OutputChannelObserver'; -export * from './Printers'; \ No newline at end of file +export * from './Printers'; +export * from './TestResultObserver'; diff --git a/src/PHPUnit/CommandBuilder/index.ts b/src/PHPUnit/CommandBuilder/index.ts deleted file mode 100644 index d0c92f3d..00000000 --- a/src/PHPUnit/CommandBuilder/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Builder'; \ No newline at end of file diff --git a/src/PHPUnit/Configuration.test.ts b/src/PHPUnit/Configuration.test.ts index 8a00c1e3..8310cfd5 100644 --- a/src/PHPUnit/Configuration.test.ts +++ b/src/PHPUnit/Configuration.test.ts @@ -1,4 +1,5 @@ import { join } from 'node:path'; +import { describe, expect, it } from 'vitest'; import { phpUnitProject } from './__tests__/utils'; import { Configuration } from './Configuration'; diff --git a/src/PHPUnit/Configuration.ts b/src/PHPUnit/Configuration.ts index d6bb0fc2..8b7e7dfc 100644 --- a/src/PHPUnit/Configuration.ts +++ b/src/PHPUnit/Configuration.ts @@ -8,9 +8,9 @@ interface ConfigurationItem { export interface IConfiguration { get(key: string, defaultValue?: unknown): unknown | undefined; - has(key: string): any; + has(key: string): boolean; - update(key: string, value: any): Promise; + update(key: string, value: unknown): Promise; getArguments(input: string): string[]; @@ -20,9 +20,9 @@ export interface IConfiguration { export abstract class BaseConfiguration implements IConfiguration { abstract get(key: string, defaultValue?: unknown): unknown | undefined; - abstract has(key: string): any; + abstract has(key: string): boolean; - abstract update(key: string, value: any): Promise; + abstract update(key: string, value: unknown): Promise; getArguments(input: string = ''): string[] { const parameters = [input, ...(this.get('args', []) as string[])]; @@ -31,15 +31,22 @@ export abstract class BaseConfiguration implements IConfiguration { } async getConfigurationFile(root: string = ''): Promise { - let files = ['phpunit.xml', 'phpunit.xml.dist', 'phpunit.dist.xml'].map((file) => join(root, file)); + let files = ['phpunit.xml', 'phpunit.xml.dist', 'phpunit.dist.xml'].map((file) => + join(root, file), + ); - const configuration = this.getArguments().find((parameter: string) => parameter.startsWith('--configuration')); + const configuration = this.getArguments().find((parameter: string) => + parameter.startsWith('--configuration'), + ); if (configuration) { const configurationFile = configuration.replace('--configuration=', ''); files = [configurationFile, join(root, configurationFile), ...files]; } - return await findAsyncSequential(files, async (file) => await checkFileExists(file)); + return await findAsyncSequential( + files, + async (file) => await checkFileExists(file), + ); } } @@ -50,7 +57,7 @@ export class Configuration extends BaseConfiguration { super(); if (items instanceof Map) { this.items = items; - } else if (!!items) { + } else if (items) { for (const x in items) { this.items.set(x, items[x]); } @@ -65,7 +72,7 @@ export class Configuration extends BaseConfiguration { return this.items.has(key); } - async update(key: string, value: any) { + async update(key: string, value: unknown) { this.items.set(key, value); } } diff --git a/src/PHPUnit/CustomWeakMap.ts b/src/PHPUnit/CustomWeakMap.ts new file mode 100644 index 00000000..73dca8c7 --- /dev/null +++ b/src/PHPUnit/CustomWeakMap.ts @@ -0,0 +1,47 @@ +export class CustomWeakMap { + private weakMap: WeakMap; + private keys: Set; + + constructor() { + this.weakMap = new WeakMap(); + this.keys = new Set(); + } + + clear() { + this.weakMap = new WeakMap(); + this.keys = new Set(); + } + + delete(key: K) { + this.keys.delete(key); + + return this.weakMap.delete(key); + } + + get(key: K) { + return this.weakMap.get(key); + } + + has(key: K) { + return this.keys.has(key); + } + + set(key: K, value: V) { + this.keys.add(key); + this.weakMap.set(key, value); + + return this; + } + + forEach(callback: (value: V, key: K) => void) { + this.keys.forEach((key) => { + callback(this.weakMap.get(key)!, key); + }); + } + + *[Symbol.iterator](): Generator<[K, V]> { + for (const key of this.keys) { + yield [key, this.weakMap.get(key)!]; + } + } +} diff --git a/src/PHPUnit/Element.test.ts b/src/PHPUnit/Element.test.ts index 6bb35638..d9648b02 100644 --- a/src/PHPUnit/Element.test.ts +++ b/src/PHPUnit/Element.test.ts @@ -1,4 +1,5 @@ -import { Element } from './Element'; +import { describe, expect, it } from 'vitest'; +import { XmlElement } from './XmlElement'; describe('Element Test', () => { it('querySelectorAll should traverse arrays', () => { @@ -7,13 +8,13 @@ describe('Element Test', () => { project: { package: [ { file: { '@_name': 'file1.php' } }, - { file: { '@_name': 'file2.php' } } - ] - } - } + { file: { '@_name': 'file2.php' } }, + ], + }, + }, }; - const element = new Element(data); + const element = new XmlElement(data); const files = element.querySelectorAll('coverage project package file'); expect(files.length).toEqual(2); @@ -27,20 +28,16 @@ describe('Element Test', () => { project: [ { file: { '@_name': 'file.php' } }, { - package: [ - { file: { '@_name': 'file1.php' } }, - ] + package: [{ file: { '@_name': 'file1.php' } }], }, { - package: [ - { file: { '@_name': 'file2.php' } } - ] - } - ] - } + package: [{ file: { '@_name': 'file2.php' } }], + }, + ], + }, }; - const element = new Element(data); + const element = new XmlElement(data); const files1 = element.querySelectorAll('coverage project package file'); expect(files1.length).toEqual(2); @@ -54,7 +51,7 @@ describe('Element Test', () => { it('getAttribute should retrieve values', () => { const data = { '@_version': '1.0' }; - const element = new Element(data); + const element = new XmlElement(data); expect(element.getAttribute('version')).toEqual('1.0'); }); }); diff --git a/src/PHPUnit/PHPUnitXML.test.ts b/src/PHPUnit/PHPUnitXML.test.ts index 6f674c2a..c6a6341f 100644 --- a/src/PHPUnit/PHPUnitXML.test.ts +++ b/src/PHPUnit/PHPUnitXML.test.ts @@ -1,4 +1,5 @@ import { join } from 'node:path'; +import { afterEach, describe, expect, it } from 'vitest'; import { URI } from 'vscode-uri'; import { generateXML, phpUnitProject } from './__tests__/utils'; import { PHPUnitXML } from './PHPUnitXML'; @@ -156,7 +157,8 @@ describe('PHPUnit XML Test', () => { const { includes, excludes } = parsed.getPatterns(root); expect(includes.toGlobPattern()).toEqual({ uri: URI.file(phpUnitXML.root()), - pattern: '{tests/Unit/**/*.php,tests/Unit2/**/*.php,vendor/someone/tests/MyClassTest.php,vendor/someone/tests/MyClassTest2.php}', + pattern: + '{tests/Unit/**/*.php,tests/Unit2/**/*.php,vendor/someone/tests/MyClassTest.php,vendor/someone/tests/MyClassTest2.php}', }); expect(excludes.toGlobPattern()).toEqual({ uri: URI.file(phpUnitXML.root()), @@ -204,7 +206,13 @@ describe('PHPUnit XML Test', () => { const parsed = parse(xml); expect(parsed.getTestSuites()).toEqual([ - { tag: 'directory', name: 'Unit', prefix: undefined, suffix: '.phpt', value: 'tests/Unit' }, + { + tag: 'directory', + name: 'Unit', + prefix: undefined, + suffix: '.phpt', + value: 'tests/Unit', + }, ]); const { includes, excludes } = parsed.getPatterns(root); @@ -319,10 +327,22 @@ describe('PHPUnit XML Test', () => { expect(parse(xml).getSources()).toEqual([ { type: 'include', tag: 'directory', prefix: undefined, suffix: '.php', value: 'app' }, - { type: 'include', tag: 'directory', prefix: 'hello', suffix: undefined, value: 'app2' }, + { + type: 'include', + tag: 'directory', + prefix: 'hello', + suffix: undefined, + value: 'app2', + }, { type: 'include', tag: 'file', value: 'src/autoload.php' }, { type: 'include', tag: 'file', value: 'src/autoload2.php' }, - { type: 'exclude', tag: 'directory', prefix: undefined, suffix: '.php', value: 'src/generated' }, + { + type: 'exclude', + tag: 'directory', + prefix: undefined, + suffix: '.php', + value: 'src/generated', + }, { type: 'exclude', tag: 'file', value: 'src/autoload.php' }, ]); }); @@ -333,3 +353,99 @@ describe('PHPUnit XML Test', () => { expect(phpUnitXML.getTestSuites().length).not.toEqual(0); }); }); + +describe('PHPUnit XML in subdirectory (../tests)', () => { + const parentRoot = phpUnitProject(''); + const phpUnitXML = new PHPUnitXML(); + + it('should resolve root to parent when test directories use ../', () => { + const xml = ` + + + + ../tests + ../tests/Output + + +`; + + phpUnitXML.load(xml, phpUnitProject('v9/phpunit.xml')); + + expect(phpUnitXML.root()).toEqual(parentRoot); + }); + + it('should generate correct glob patterns for parent test directories', () => { + const xml = ` + + + + ../tests + ../tests/Output + + +`; + + phpUnitXML.load(xml, phpUnitProject('v9/phpunit.xml')); + + const { includes, excludes } = phpUnitXML.getPatterns(parentRoot); + expect(includes.toGlobPattern()).toEqual({ + uri: URI.file(join(parentRoot, 'tests')), + pattern: '{**/*.php}', + }); + expect(excludes.toGlobPattern()).toEqual({ + uri: URI.file(parentRoot), + pattern: '{**/.git/**,**/node_modules/**,tests/Output/**/*}', + }); + }); + + it('should resolve root to parent when test directories use deeply nested ../../../', () => { + const xml = ` + + + + ../../../tests + ../../../tests/Output + + +`; + + phpUnitXML.load(xml, phpUnitProject('a/b/c/phpunit.xml')); + + expect(phpUnitXML.root()).toEqual(parentRoot); + + const { includes, excludes } = phpUnitXML.getPatterns(parentRoot); + expect(includes.toGlobPattern()).toEqual({ + uri: URI.file(join(parentRoot, 'tests')), + pattern: '{**/*.php}', + }); + expect(excludes.toGlobPattern()).toEqual({ + uri: URI.file(parentRoot), + pattern: '{**/.git/**,**/node_modules/**,tests/Output/**/*}', + }); + }); + + it('should resolve bootstrap path relative to config directory', () => { + const xml = ` + + + + ../tests + + +`; + + phpUnitXML.load(xml, phpUnitProject('v9/phpunit.xml')); + + expect(phpUnitXML.path('vendor/autoload.php')).toEqual( + phpUnitProject('v9/vendor/autoload.php'), + ); + }); +}); diff --git a/src/PHPUnit/PHPUnitXML.ts b/src/PHPUnit/PHPUnitXML.ts index 46d68f9d..9a80a4fa 100644 --- a/src/PHPUnit/PHPUnitXML.ts +++ b/src/PHPUnit/PHPUnitXML.ts @@ -1,60 +1,23 @@ import { readFile } from 'node:fs/promises'; -import { dirname, isAbsolute, join, normalize, relative } from 'node:path'; -import { URI } from 'vscode-uri'; -import { Element } from './Element'; +import { dirname, isAbsolute, join, normalize, relative, resolve } from 'node:path'; +import { TestGlobPattern } from './TestGlobPattern'; +import { XmlElement } from './XmlElement'; -type Source = { tag: string; value: string; prefix?: string; suffix?: string; }; +export { TestGlobPattern }; -export type TestSuite = Source & { name: string }; - -export class Pattern { - private readonly relativePath: string; - - constructor(private root: string, private testPath: string, private items: string[] = []) { - this.relativePath = Pattern.normalizePath(relative(this.root, this.testPath)); - } - - private static normalizePath(...paths: string[]) { - return normalize(paths.join('/')).replace(/\\|\/+/g, '/'); - } - - push(item: TestSuite, extension: string = '') { - const args = [this.relativePath, item.value]; - if (item.tag !== 'file') { - args.push('**/*' + (item.suffix ?? extension)); - } - - this.items.push(Pattern.normalizePath(...args)); - } +type Source = { tag: string; value: string; prefix?: string; suffix?: string }; - toGlobPattern() { - const arrayUnique = (items: (string | undefined)[]) => Array.from(new Set(items)); - const dirs = arrayUnique(this.items.map((item) => { - return /^\*/.test(item) ? undefined : item.substring(0, item.indexOf('/')); - })); - - const legalDirs = dirs.filter(value => !!value); - const isSingle = dirs.length === 1 && legalDirs.length === 1; - if (!isSingle) { - return { uri: URI.file(this.root), pattern: `{${this.items}}` }; - } - - const dir = legalDirs[0]; - const items = this.items.map((item) => item.replace(new RegExp('^' + dir + '[\\/]?'), '')); - const pattern = `{${items}}`; - - return { uri: URI.file(join(this.root, dir!)), pattern }; - } -} +export type TestSuite = Source & { name: string }; export class PHPUnitXML { - private element?: Element; + private element?: XmlElement; private _file: string = ''; + private _configRoot: string = ''; private _root: string = ''; - private readonly cached: Map = new Map(); + private readonly cached: Map = new Map(); load(text: string | Buffer | Uint8Array, file: string) { - this.element = Element.load(text.toString()); + this.element = XmlElement.load(text.toString()); this._file = file; this.setRoot(dirname(file)); @@ -69,6 +32,7 @@ export class PHPUnitXML { setRoot(root: string) { this.cached.clear(); + this._configRoot = root; this._root = root; return this; @@ -79,40 +43,84 @@ export class PHPUnitXML { } root() { + if (this._root === this._configRoot && this.element) { + this._root = this.resolveProjectRoot(); + } + return this._root; } path(file: string): string { - const root = this.root(); + const configRoot = this._configRoot; + + return isAbsolute(file) || !configRoot ? file : join(configRoot, file); + } + + private resolveToRoot(root: string, value: string): string { + if (this._configRoot === root) { + return value; + } - return isAbsolute(file) || !root ? file : join(root, file); + return normalize(relative(root, resolve(this._configRoot, value))); + } + + private resolveProjectRoot(): string { + const configRoot = this._configRoot; + if (!this.element) { + return configRoot; + } + + for (const parent of this.element.querySelectorAll('phpunit testsuites testsuite')) { + for (const node of parent.querySelectorAll('directory')) { + const dir = node.getText(); + if (dir.startsWith('..')) { + const resolvedAbs = resolve(configRoot, dir); + const configRootAbs = resolve(configRoot); + + if (!resolvedAbs.startsWith(configRootAbs)) { + return normalize(resolve(configRoot, dir, '..')); + } + } + } + } + + return configRoot; } getTestSuites(): TestSuite[] { - const callback = (tag: string, node: Element, parent: Element) => { + const root = this.root(); + + const callback = (tag: string, node: XmlElement, parent: XmlElement) => { const name = parent.getAttribute('name') as string; const prefix = node.getAttribute('prefix'); const suffix = node.getAttribute('suffix'); - return { tag, name, value: node.getText(), prefix, suffix }; + return { tag, name, value: this.resolveToRoot(root, node.getText()), prefix, suffix }; }; const testSuites = this.getDirectoriesAndFiles('phpunit testsuites testsuite', { - directory: callback, file: callback, exclude: callback, + directory: callback, + file: callback, + exclude: callback, }); - return testSuites.length > 0 ? testSuites : [ - { tag: 'directory', name: 'default', value: '', suffix: '.php' }, - { tag: 'exclude', name: 'default', value: 'vendor' }, - ]; + return testSuites.length > 0 + ? testSuites + : [ + { tag: 'directory', name: 'default', value: '', suffix: '.php' }, + { tag: 'exclude', name: 'default', value: 'vendor' }, + ]; } getPatterns(root: string) { - const includes = new Pattern(root, this.root()); - const excludes = new Pattern(root, this.root(), ['**/.git/**', '**/node_modules/**']); + const includes = new TestGlobPattern(root, this.root()); + const excludes = new TestGlobPattern(root, this.root(), [ + '**/.git/**', + '**/node_modules/**', + ]); this.getTestSuites().forEach((item) => { - (item.tag !== 'exclude') ? includes.push(item, '.php') : excludes.push(item); + item.tag !== 'exclude' ? includes.push(item, '.php') : excludes.push(item); }); return { includes, excludes }; @@ -127,8 +135,7 @@ export class PHPUnitXML { } getSources() { - const appendType = (type: string, objs: Source[]) => - objs.map((obj) => ({ type, ...obj })); + const appendType = (type: string, objs: Source[]) => objs.map((obj) => ({ type, ...obj })); return [ ...appendType('include', this.getIncludes()), @@ -136,48 +143,51 @@ export class PHPUnitXML { ]; } - private fromCache(key: string, callback: () => T[]) { + private fromCache(key: string, callback: () => T[]): T[] { if (!this.cached.has(key)) { this.cached.set(key, callback() ?? []); } - return this.cached.get(key)!; + return this.cached.get(key) as T[]; } private getIncludesOrExcludes(key: string): Source[] { return this.getDirectoriesAndFiles(key, { - directory: (tag: string, node: Element) => { + directory: (tag: string, node: XmlElement) => { const prefix = node.getAttribute('prefix'); const suffix = node.getAttribute('suffix'); return { tag, value: node.getText(), prefix, suffix }; }, - file: (tag: string, node: Element) => ({ tag, value: node.getText() }), + file: (tag: string, node: XmlElement) => ({ tag, value: node.getText() }), }); } private getDirectoriesAndFiles( selector: string, - callbacks: { [key: string]: (tag: string, node: Element, parent: Element) => T; }, + callbacks: { [key: string]: (tag: string, node: XmlElement, parent: XmlElement) => T }, ) { if (!this.element) { return []; } return this.fromCache(selector, () => { - return this.element!.querySelectorAll(selector).reduce((results: T[], parent: Element) => { - for (const [type, callback] of Object.entries(callbacks)) { - const temp = parent - .querySelectorAll(type) - .map((node) => callback(type, node, parent)); - - if (temp) { - results.push(...temp); + return this.element!.querySelectorAll(selector).reduce( + (results: T[], parent: XmlElement) => { + for (const [type, callback] of Object.entries(callbacks)) { + const temp = parent + .querySelectorAll(type) + .map((node) => callback(type, node, parent)); + + if (temp) { + results.push(...temp); + } } - } - return results; - }, []); + return results; + }, + [], + ); }); } } diff --git a/src/PHPUnit/ProblemMatcher/PHPUnitProblemMatcher.test.ts b/src/PHPUnit/ProblemMatcher/PHPUnitProblemMatcher.test.ts index 3f98b8f2..23a5e085 100644 --- a/src/PHPUnit/ProblemMatcher/PHPUnitProblemMatcher.test.ts +++ b/src/PHPUnit/ProblemMatcher/PHPUnitProblemMatcher.test.ts @@ -1,11 +1,12 @@ -import { TeamcityEvent } from '.'; +import { describe, expect, it } from 'vitest'; import { phpUnitProject, phpUnitProjectWin } from '../__tests__/utils'; +import { TeamcityEvent } from '.'; import { ProblemMatcher } from './ProblemMatcher'; const problemMatcher = new ProblemMatcher(); describe('PHPUnit ProblemMatcher Text', () => { - const resultShouldBe = (content: string, expected: any) => { + const resultShouldBe = (content: string, expected: Record | undefined) => { const actual = problemMatcher.parse(content); if (expected === undefined) { @@ -57,111 +58,144 @@ describe('PHPUnit ProblemMatcher Text', () => { }); it('testSuiteStarted Recca0120\\VSCode\\Tests\\AssertionsTest', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Recca0120\\VSCode\\Tests\\AssertionsTest' locationHint='php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest' flowId='8024']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)', - flowId: 8024, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Recca0120\\VSCode\\Tests\\AssertionsTest' locationHint='php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest' flowId='8024']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)', + flowId: 8024, + }, + ); }); it('testStarted passed', () => { - resultShouldBe(`##teamcity[testStarted name='test_passed' locationHint='php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::test_passed' flowId='8024']`, { - event: TeamcityEvent.testStarted, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Passed', - flowId: 8024, - }); + resultShouldBe( + `##teamcity[testStarted name='test_passed' locationHint='php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::test_passed' flowId='8024']`, + { + event: TeamcityEvent.testStarted, + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Passed', + flowId: 8024, + }, + ); }); it('testFinished', () => { - resultShouldBe(`##teamcity[testFinished name='test_passed' duration='0' flowId='8024']`, { - event: TeamcityEvent.testFinished, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Passed', - flowId: 8024, - }); + resultShouldBe( + `##teamcity[testFinished name='test_passed' duration='0' flowId='8024']`, + { + event: TeamcityEvent.testFinished, + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Passed', + flowId: 8024, + }, + ); }); it('testStarted failed', () => { - resultShouldBe(`##teamcity[testStarted name='test_is_not_same' locationHint='php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::test_is_not_same' flowId='8024']`, { - event: TeamcityEvent.testStarted, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Is not same', - flowId: 8024, - }); + resultShouldBe( + `##teamcity[testStarted name='test_is_not_same' locationHint='php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::test_is_not_same' flowId='8024']`, + { + event: TeamcityEvent.testStarted, + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Is not same', + flowId: 8024, + }, + ); }); it('testFailed', () => { - resultShouldBe(`##teamcity[testFailed name='test_is_not_same' message='Failed asserting that two arrays are identical.' details=' ${phpUnitProjectWin('tests\\AssertionsTest.php')}:27|n ' duration='0' type='comparisonFailure' actual='Array &0 (|n |'e|' => |'f|'|n 0 => |'g|'|n 1 => |'h|'|n)' expected='Array &0 (|n |'a|' => |'b|'|n |'c|' => |'d|'|n)' flowId='8024']`, undefined); + resultShouldBe( + `##teamcity[testFailed name='test_is_not_same' message='Failed asserting that two arrays are identical.' details=' ${phpUnitProjectWin('tests\\AssertionsTest.php')}:32|n ' duration='0' type='comparisonFailure' actual='Array &0 (|n |'e|' => |'f|'|n 0 => |'g|'|n 1 => |'h|'|n)' expected='Array &0 (|n |'a|' => |'b|'|n |'c|' => |'d|'|n)' flowId='8024']`, + undefined, + ); }); it('testFinished failed', () => { - resultShouldBe(`##teamcity[testFinished name='test_is_not_same' duration='0' flowId='8024']`, { - event: TeamcityEvent.testFailed, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Is not same', - message: 'Failed asserting that two arrays are identical.', - details: [ - { - file: phpUnitProjectWin('tests/AssertionsTest.php'), - line: 27, - }, - ], - duration: 0, - type: 'comparisonFailure', - actual: `Array &0 (\n 'e' => 'f'\n 0 => 'g'\n 1 => 'h'\n)`, - expected: `Array &0 (\n 'a' => 'b'\n 'c' => 'd'\n)`, - flowId: 8024, - }); + resultShouldBe( + `##teamcity[testFinished name='test_is_not_same' duration='0' flowId='8024']`, + { + event: TeamcityEvent.testFailed, + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Is not same', + message: 'Failed asserting that two arrays are identical.', + details: [ + { + file: phpUnitProjectWin('tests/AssertionsTest.php'), + line: 32, + }, + ], + duration: 0, + type: 'comparisonFailure', + actual: `Array &0 (\n 'e' => 'f'\n 0 => 'g'\n 1 => 'h'\n)`, + expected: `Array &0 (\n 'a' => 'b'\n 'c' => 'd'\n)`, + flowId: 8024, + }, + ); }); it('testSuiteStarted addition_provider', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='addition_provider' locationHint='php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::addition_provider' flowId='8024']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', - file: phpUnitProjectWin('tests/AssertionsTest.php'), - locationHint: `php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::addition_provider`, - flowId: 8024, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='addition_provider' locationHint='php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::addition_provider' flowId='8024']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', + file: phpUnitProjectWin('tests/AssertionsTest.php'), + locationHint: `php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::addition_provider`, + flowId: 8024, + }, + ); }); it('testStarted addition_provider', () => { - resultShouldBe(`##teamcity[testStarted name='addition_provider with data set #2' locationHint='php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::addition_provider with data set #2' flowId='8024']`, { - event: TeamcityEvent.testStarted, - // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #2', - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', - file: phpUnitProjectWin('tests/AssertionsTest.php'), - locationHint: `php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::addition_provider with data set #2`, - flowId: 8024, - }); + resultShouldBe( + `##teamcity[testStarted name='addition_provider with data set #2' locationHint='php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::addition_provider with data set #2' flowId='8024']`, + { + event: TeamcityEvent.testStarted, + // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #2', + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', + file: phpUnitProjectWin('tests/AssertionsTest.php'), + locationHint: `php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::addition_provider with data set #2`, + flowId: 8024, + }, + ); }); it('testFailed addition_provider with failed', () => { - resultShouldBe(`##teamcity[testFailed name='addition_provider with data set #2' message='Failed asserting that 1 matches expected 2.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:60|n ' duration='0' type='comparisonFailure' actual='1' expected='2' flowId='8024']`, undefined); + resultShouldBe( + `##teamcity[testFailed name='addition_provider with data set #2' message='Failed asserting that 1 matches expected 2.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:66|n ' duration='0' type='comparisonFailure' actual='1' expected='2' flowId='8024']`, + undefined, + ); - resultShouldBe(`##teamcity[testFinished name='addition_provider with data set #2' duration='0' flowId='8024']`, { - event: TeamcityEvent.testFailed, - // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #2', - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', - file: phpUnitProjectWin('tests/AssertionsTest.php'), - locationHint: `php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::addition_provider with data set #2`, - message: 'Failed asserting that 1 matches expected 2.', - details: [ - { - file: phpUnitProjectWin('tests/AssertionsTest.php'), - line: 60, - }, - ], - type: 'comparisonFailure', - actual: '1', - expected: '2', - duration: 0, - flowId: 8024, - }); + resultShouldBe( + `##teamcity[testFinished name='addition_provider with data set #2' duration='0' flowId='8024']`, + { + event: TeamcityEvent.testFailed, + // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #2', + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', + file: phpUnitProjectWin('tests/AssertionsTest.php'), + locationHint: `php_qn://${phpUnitProjectWin('tests/AssertionsTest.php')}::\\Recca0120\\VSCode\\Tests\\AssertionsTest::addition_provider with data set #2`, + message: 'Failed asserting that 1 matches expected 2.', + details: [ + { + file: phpUnitProjectWin('tests/AssertionsTest.php'), + line: 66, + }, + ], + type: 'comparisonFailure', + actual: '1', + expected: '2', + duration: 0, + flowId: 8024, + }, + ); }); it('testSuiteFinished Recca0120\\VSCode\\Tests\\AssertionsTest', () => { - resultShouldBe(`##teamcity[testSuiteFinished name='Recca0120\\VSCode\\Tests\\AssertionsTest' flowId='8024']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)', - flowId: 8024, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='Recca0120\\VSCode\\Tests\\AssertionsTest' flowId='8024']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)', + flowId: 8024, + }, + ); }); it('testSuiteFinished default', () => { @@ -181,17 +215,20 @@ describe('PHPUnit ProblemMatcher Text', () => { }); it('TestSummary', () => { - resultShouldBe('Tests: 19, Assertions: 15, Errors: 2, Failures: 4, Skipped: 1, Incomplete: 1, Risky: 2.', { - event: TeamcityEvent.testResultSummary, - text: 'Tests: 19, Assertions: 15, Errors: 2, Failures: 4, Skipped: 1, Incomplete: 1, Risky: 2.', - tests: 19, - assertions: 15, - errors: 2, - failures: 4, - skipped: 1, - incomplete: 1, - risky: 2, - }); + resultShouldBe( + 'Tests: 19, Assertions: 15, Errors: 2, Failures: 4, Skipped: 1, Incomplete: 1, Risky: 2.', + { + event: TeamcityEvent.testResultSummary, + text: 'Tests: 19, Assertions: 15, Errors: 2, Failures: 4, Skipped: 1, Incomplete: 1, Risky: 2.', + tests: 19, + assertions: 15, + errors: 2, + failures: 4, + skipped: 1, + incomplete: 1, + risky: 2, + }, + ); }); it('empty line', () => { @@ -248,15 +285,19 @@ describe('PHPUnit ProblemMatcher Text', () => { expect.objectContaining({ event: TeamcityEvent.testFailed, name: 'testProductNeedUpdateReturnsFalseWhenPriceSyncNotEnabled', - locationHint: 'php_qn:///srv/app/tests/Ecommerce/Offer/Synchronizer/PriceSynchronizerTest.php::\\App\\Tests\\Ecommerce\\Offer\\Synchronizer\\PriceSynchronizerTest::testProductNeedUpdateReturnsFalseWhenPriceSyncNotEnabled', + locationHint: + 'php_qn:///srv/app/tests/Ecommerce/Offer/Synchronizer/PriceSynchronizerTest.php::\\App\\Tests\\Ecommerce\\Offer\\Synchronizer\\PriceSynchronizerTest::testProductNeedUpdateReturnsFalseWhenPriceSyncNotEnabled', flowId: 5161, id: 'Price Synchronizer (App\\Tests\\Ecommerce\\Offer\\Synchronizer\\PriceSynchronizer)::Product need update returns false when price sync not enabled', file: '/srv/app/tests/Ecommerce/Offer/Synchronizer/PriceSynchronizerTest.php', - message: 'Error: Class "App\\Ecommerce\\Offer\\Synchronizer\\PriceSynchronizer" not found', - details: [{ - file: '/srv/app/tests/Ecommerce/Offer/Synchronizer/PriceSynchronizerTest.php', - line: 28, - }], + message: + 'Error: Class "App\\Ecommerce\\Offer\\Synchronizer\\PriceSynchronizer" not found', + details: [ + { + file: '/srv/app/tests/Ecommerce/Offer/Synchronizer/PriceSynchronizerTest.php', + line: 28, + }, + ], duration: 0, }), ); @@ -277,7 +318,8 @@ describe('PHPUnit ProblemMatcher Text', () => { expect.objectContaining({ event: TeamcityEvent.testIgnored, name: 'test_permission', - locationHint: 'php_qn:///var/www/html/tests/Feature/ChatControllerTest.php::\\Tests\\Feature\\ChatControllerTest::test_permission', + locationHint: + 'php_qn:///var/www/html/tests/Feature/ChatControllerTest.php::\\Tests\\Feature\\ChatControllerTest::test_permission', flowId: 22946, id: 'Chat Controller (Tests\\Feature\\ChatController)::Permission', file: '/var/www/html/tests/Feature/ChatControllerTest.php', @@ -290,7 +332,8 @@ describe('PHPUnit ProblemMatcher Text', () => { expect.objectContaining({ event: TeamcityEvent.testIgnored, name: 'test_grant_chat_token', - locationHint: 'php_qn:///var/www/html/tests/Feature/ChatControllerTest.php::\\Tests\\Feature\\ChatControllerTest::test_grant_chat_token', + locationHint: + 'php_qn:///var/www/html/tests/Feature/ChatControllerTest.php::\\Tests\\Feature\\ChatControllerTest::test_grant_chat_token', flowId: 22946, id: 'Chat Controller (Tests\\Feature\\ChatController)::Grant chat token', file: '/var/www/html/tests/Feature/ChatControllerTest.php', diff --git a/src/PHPUnit/ProblemMatcher/PestProblemMatcher.test.ts b/src/PHPUnit/ProblemMatcher/PestProblemMatcher.test.ts index e19b8375..4d99db1f 100644 --- a/src/PHPUnit/ProblemMatcher/PestProblemMatcher.test.ts +++ b/src/PHPUnit/ProblemMatcher/PestProblemMatcher.test.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { pestProject } from '../__tests__/utils'; import { ProblemMatcher } from './ProblemMatcher'; import { TeamcityEvent } from './types'; @@ -5,7 +6,7 @@ import { TeamcityEvent } from './types'; const problemMatcher = new ProblemMatcher(); describe('Pest ProblemMatcher Text', () => { - const resultShouldBe = (content: string, expected: any) => { + const resultShouldBe = (content: string, expected: Record | undefined) => { const actual = problemMatcher.parse(content); if (expected === undefined) { @@ -17,12 +18,15 @@ describe('Pest ProblemMatcher Text', () => { describe('Teamcity Life Cycle', () => { it('testSuiteStarted phpunit.xml', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='${pestProject('phpunit.xml')}' locationHint='pest_qn://Example (Tests\\Feature\\Example)' flowId='68573']`, { - event: TeamcityEvent.testSuiteStarted, - id: pestProject('phpunit.xml'), - name: pestProject('phpunit.xml'), - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='${pestProject('phpunit.xml')}' locationHint='pest_qn://Example (Tests\\Feature\\Example)' flowId='68573']`, + { + event: TeamcityEvent.testSuiteStarted, + id: pestProject('phpunit.xml'), + name: pestProject('phpunit.xml'), + flowId: 68573, + }, + ); }); it('testCount', () => { @@ -34,30 +38,39 @@ describe('Pest ProblemMatcher Text', () => { }); it('testSuiteStarted Test Suite', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Test Suite' locationHint='pest_qn://Example (Tests\\Feature\\Example)' flowId='68573']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'Test Suite', - name: 'Test Suite', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Test Suite' locationHint='pest_qn://Example (Tests\\Feature\\Example)' flowId='68573']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'Test Suite', + name: 'Test Suite', + flowId: 68573, + }, + ); }); it('testSuiteStarted Tests\\Feature\\ExampleTest', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Tests\\Feature\\ExampleTest' locationHint='pest_qn://Example (Tests\\Feature\\Example)' flowId='68573']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'Tests\\Feature\\ExampleTest', - name: 'Tests\\Feature\\ExampleTest', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Tests\\Feature\\ExampleTest' locationHint='pest_qn://Example (Tests\\Feature\\Example)' flowId='68573']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'Tests\\Feature\\ExampleTest', + name: 'Tests\\Feature\\ExampleTest', + flowId: 68573, + }, + ); }); it('testStarted', () => { - resultShouldBe(`##teamcity[testStarted name='Example' locationHint='pest_qn://Example (Tests\\Feature\\Example)::Example' flowId='68573']`, { - event: TeamcityEvent.testStarted, - id: 'Example (Tests\\Feature\\Example)::Example', - name: 'Example', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testStarted name='Example' locationHint='pest_qn://Example (Tests\\Feature\\Example)::Example' flowId='68573']`, + { + event: TeamcityEvent.testStarted, + id: 'Example (Tests\\Feature\\Example)::Example', + name: 'Example', + flowId: 68573, + }, + ); }); it('testFinished', () => { @@ -70,36 +83,48 @@ describe('Pest ProblemMatcher Text', () => { }); it('testSuiteFinished Tests\\Feature\\ExampleTest', () => { - resultShouldBe(`##teamcity[testSuiteFinished name='Tests\\Feature\\ExampleTest' flowId='68573']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'Tests\\Feature\\ExampleTest', - name: 'Tests\\Feature\\ExampleTest', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='Tests\\Feature\\ExampleTest' flowId='68573']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'Tests\\Feature\\ExampleTest', + name: 'Tests\\Feature\\ExampleTest', + flowId: 68573, + }, + ); }); it('testSuiteStarted tests/Fixtures/CollisionTest.php', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Tests\\Fixtures\\CollisionTest' locationHint='pest_qn://tests/Fixtures/CollisionTest.php' flowId='68573']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'tests/Fixtures/CollisionTest.php', - name: 'Tests\\Fixtures\\CollisionTest', - file: 'tests/Fixtures/CollisionTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Tests\\Fixtures\\CollisionTest' locationHint='pest_qn://tests/Fixtures/CollisionTest.php' flowId='68573']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'tests/Fixtures/CollisionTest.php', + name: 'Tests\\Fixtures\\CollisionTest', + file: 'tests/Fixtures/CollisionTest.php', + flowId: 68573, + }, + ); }); it('testStarted tests/Fixtures/CollisionTest.php::error', () => { - resultShouldBe(`##teamcity[testStarted name='error' locationHint='pest_qn://tests/Fixtures/CollisionTest.php::error' flowId='68573']`, { - event: TeamcityEvent.testStarted, - id: 'tests/Fixtures/CollisionTest.php::error', - name: 'error', - file: 'tests/Fixtures/CollisionTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testStarted name='error' locationHint='pest_qn://tests/Fixtures/CollisionTest.php::error' flowId='68573']`, + { + event: TeamcityEvent.testStarted, + id: 'tests/Fixtures/CollisionTest.php::error', + name: 'error', + file: 'tests/Fixtures/CollisionTest.php', + flowId: 68573, + }, + ); }); it('testFinish tests/Fixtures/CollisionTest.php::error', () => { - resultShouldBe(`##teamcity[testFailed name='error' message='Exception: error' details='at tests/Fixtures/CollisionTest.php:4' flowId='68573']`, undefined); + resultShouldBe( + `##teamcity[testFailed name='error' message='Exception: error' details='at tests/Fixtures/CollisionTest.php:4' flowId='68573']`, + undefined, + ); resultShouldBe(`##teamcity[testFinished name='error' duration='3' flowId='68573']`, { event: TeamcityEvent.testFailed, @@ -118,13 +143,16 @@ describe('Pest ProblemMatcher Text', () => { }); it('testStarted tests/Fixtures/CollisionTest.php::success', () => { - resultShouldBe(`##teamcity[testStarted name='success' locationHint='pest_qn://tests/Fixtures/CollisionTest.php::success' flowId='68573']`, { - event: TeamcityEvent.testStarted, - id: 'tests/Fixtures/CollisionTest.php::success', - name: 'success', - file: 'tests/Fixtures/CollisionTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testStarted name='success' locationHint='pest_qn://tests/Fixtures/CollisionTest.php::success' flowId='68573']`, + { + event: TeamcityEvent.testStarted, + id: 'tests/Fixtures/CollisionTest.php::success', + name: 'success', + file: 'tests/Fixtures/CollisionTest.php', + flowId: 68573, + }, + ); }); it('testFinished tests/Fixtures/CollisionTest.php::success', () => { @@ -138,117 +166,153 @@ describe('Pest ProblemMatcher Text', () => { }); it('testSuiteFinished tests/Fixtures/CollisionTest.php', () => { - resultShouldBe(`##teamcity[testSuiteFinished name='Tests\\Fixtures\\CollisionTest' flowId='68573']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'tests/Fixtures/CollisionTest.php', - name: 'Tests\\Fixtures\\CollisionTest', - file: 'tests/Fixtures/CollisionTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='Tests\\Fixtures\\CollisionTest' flowId='68573']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'tests/Fixtures/CollisionTest.php', + name: 'Tests\\Fixtures\\CollisionTest', + file: 'tests/Fixtures/CollisionTest.php', + flowId: 68573, + }, + ); }); it('testSuiteStarted tests/Fixtures/DirectoryWithTests/ExampleTest.php', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Tests\\Fixtures\\DirectoryWithTests\\ExampleTest' locationHint='pest_qn://tests/Fixtures/DirectoryWithTests/ExampleTest.php' flowId='68573']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', - name: 'Tests\\Fixtures\\DirectoryWithTests\\ExampleTest', - file: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Tests\\Fixtures\\DirectoryWithTests\\ExampleTest' locationHint='pest_qn://tests/Fixtures/DirectoryWithTests/ExampleTest.php' flowId='68573']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', + name: 'Tests\\Fixtures\\DirectoryWithTests\\ExampleTest', + file: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', + flowId: 68573, + }, + ); }); it('testStarted tests/Fixtures/DirectoryWithTests/ExampleTest.php::it example 1', () => { - resultShouldBe(`##teamcity[testStarted name='it example 1' locationHint='pest_qn://tests/Fixtures/DirectoryWithTests/ExampleTest.php::it example 1' flowId='68573']`, { - event: TeamcityEvent.testStarted, - id: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php::it example 1', - name: 'it example 1', - file: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testStarted name='it example 1' locationHint='pest_qn://tests/Fixtures/DirectoryWithTests/ExampleTest.php::it example 1' flowId='68573']`, + { + event: TeamcityEvent.testStarted, + id: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php::it example 1', + name: 'it example 1', + file: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', + flowId: 68573, + }, + ); }); it('testFinished tests/Fixtures/DirectoryWithTests/ExampleTest.php::it example 1', () => { - resultShouldBe(`##teamcity[testFinished name='it example 1' duration='0' flowId='68573']`, { - event: TeamcityEvent.testFinished, - id: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php::it example 1', - name: 'it example 1', - file: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testFinished name='it example 1' duration='0' flowId='68573']`, + { + event: TeamcityEvent.testFinished, + id: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php::it example 1', + name: 'it example 1', + file: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', + flowId: 68573, + }, + ); }); it('testSuiteFinished tests/Fixtures/DirectoryWithTests/ExampleTest.php', () => { - resultShouldBe(`##teamcity[testSuiteFinished name='Tests\\Fixtures\\DirectoryWithTests\\ExampleTest' flowId='68573']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', - name: 'Tests\\Fixtures\\DirectoryWithTests\\ExampleTest', - file: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='Tests\\Fixtures\\DirectoryWithTests\\ExampleTest' flowId='68573']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', + name: 'Tests\\Fixtures\\DirectoryWithTests\\ExampleTest', + file: 'tests/Fixtures/DirectoryWithTests/ExampleTest.php', + flowId: 68573, + }, + ); }); it('testSuiteStarted tests/Fixtures/ExampleTest.php', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Tests\\Unit\\ExampleTest' locationHint='pest_qn://tests/Fixtures/ExampleTest.php' flowId='68573']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'tests/Fixtures/ExampleTest.php', - name: 'Tests\\Unit\\ExampleTest', - file: 'tests/Fixtures/ExampleTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Tests\\Unit\\ExampleTest' locationHint='pest_qn://tests/Fixtures/ExampleTest.php' flowId='68573']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'tests/Fixtures/ExampleTest.php', + name: 'Tests\\Unit\\ExampleTest', + file: 'tests/Fixtures/ExampleTest.php', + flowId: 68573, + }, + ); }); it('testStarted tests/Fixtures/ExampleTest.php::it example 2', () => { - resultShouldBe(`##teamcity[testStarted name='it example 2' locationHint='pest_qn://tests/Fixtures/ExampleTest.php::it example 2' flowId='68573']`, { - event: TeamcityEvent.testStarted, - id: 'tests/Fixtures/ExampleTest.php::it example 2', - name: 'it example 2', - file: 'tests/Fixtures/ExampleTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testStarted name='it example 2' locationHint='pest_qn://tests/Fixtures/ExampleTest.php::it example 2' flowId='68573']`, + { + event: TeamcityEvent.testStarted, + id: 'tests/Fixtures/ExampleTest.php::it example 2', + name: 'it example 2', + file: 'tests/Fixtures/ExampleTest.php', + flowId: 68573, + }, + ); }); it('testFinished tests/Fixtures/ExampleTest.php::it example 2', () => { - resultShouldBe(`##teamcity[testFinished name='it example 2' duration='0' flowId='68573']`, { - event: TeamcityEvent.testFinished, - id: 'tests/Fixtures/ExampleTest.php::it example 2', - name: 'it example 2', - file: 'tests/Fixtures/ExampleTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testFinished name='it example 2' duration='0' flowId='68573']`, + { + event: TeamcityEvent.testFinished, + id: 'tests/Fixtures/ExampleTest.php::it example 2', + name: 'it example 2', + file: 'tests/Fixtures/ExampleTest.php', + flowId: 68573, + }, + ); }); it('testSuiteFinished Tests\\Unit\\ExampleTest', () => { - resultShouldBe(`##teamcity[testSuiteFinished name='Tests\\Unit\\ExampleTest' flowId='68573']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'tests/Fixtures/ExampleTest.php', - name: 'Tests\\Unit\\ExampleTest', - file: 'tests/Fixtures/ExampleTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='Tests\\Unit\\ExampleTest' flowId='68573']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'tests/Fixtures/ExampleTest.php', + name: 'Tests\\Unit\\ExampleTest', + file: 'tests/Fixtures/ExampleTest.php', + flowId: 68573, + }, + ); }); it('testSuiteStarted Tests\\Fixtures\\Inheritance\\Base\\ExampleTest', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Tests\\Fixtures\\Inheritance\\Base\\ExampleTest' locationHint='pest_qn://Example (Tests\\Fixtures\\Inheritance\\Base\\Example)' flowId='68573']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'Tests\\Fixtures\\Inheritance\\Base\\ExampleTest', - name: 'Tests\\Fixtures\\Inheritance\\Base\\ExampleTest', - file: '', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Tests\\Fixtures\\Inheritance\\Base\\ExampleTest' locationHint='pest_qn://Example (Tests\\Fixtures\\Inheritance\\Base\\Example)' flowId='68573']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'Tests\\Fixtures\\Inheritance\\Base\\ExampleTest', + name: 'Tests\\Fixtures\\Inheritance\\Base\\ExampleTest', + file: '', + flowId: 68573, + }, + ); }); it('testStarted Example (Tests\\Fixtures\\Inheritance\\Base\\Example)::Example', () => { - resultShouldBe(`##teamcity[testStarted name='Example' locationHint='pest_qn://Example (Tests\\Fixtures\\Inheritance\\Base\\Example)::Example' flowId='68573']`, { - event: TeamcityEvent.testStarted, - id: 'Example (Tests\\Fixtures\\Inheritance\\Base\\Example)::Example', - name: 'Example', - file: '', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testStarted name='Example' locationHint='pest_qn://Example (Tests\\Fixtures\\Inheritance\\Base\\Example)::Example' flowId='68573']`, + { + event: TeamcityEvent.testStarted, + id: 'Example (Tests\\Fixtures\\Inheritance\\Base\\Example)::Example', + name: 'Example', + file: '', + flowId: 68573, + }, + ); }); it('testIgnored Example (Tests\\Fixtures\\Inheritance\\Base\\Example)::Example', () => { - resultShouldBe(`##teamcity[testIgnored name='Example' message='This test was ignored.' details='' flowId='68573']`, undefined); + resultShouldBe( + `##teamcity[testIgnored name='Example' message='This test was ignored.' details='' flowId='68573']`, + undefined, + ); resultShouldBe(`##teamcity[testFinished name='Example' duration='0' flowId='68573']`, { event: TeamcityEvent.testIgnored, @@ -260,33 +324,42 @@ describe('Pest ProblemMatcher Text', () => { }); it('testSuiteFinished Tests\\Fixtures\\Inheritance\\Base\\ExampleTest', () => { - resultShouldBe(`##teamcity[testSuiteFinished name='Tests\\Fixtures\\Inheritance\\Base\\ExampleTest' flowId='68573']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'Tests\\Fixtures\\Inheritance\\Base\\ExampleTest', - name: 'Tests\\Fixtures\\Inheritance\\Base\\ExampleTest', - file: '', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='Tests\\Fixtures\\Inheritance\\Base\\ExampleTest' flowId='68573']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'Tests\\Fixtures\\Inheritance\\Base\\ExampleTest', + name: 'Tests\\Fixtures\\Inheritance\\Base\\ExampleTest', + file: '', + flowId: 68573, + }, + ); }); it('testSuiteStarted Tests\\Fixtures\\Inheritance\\ExampleTest', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Tests\\Fixtures\\Inheritance\\ExampleTest' locationHint='pest_qn://Example (Tests\\Fixtures\\Inheritance\\Example)' flowId='68573']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'Tests\\Fixtures\\Inheritance\\ExampleTest', - name: 'Tests\\Fixtures\\Inheritance\\ExampleTest', - file: '', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Tests\\Fixtures\\Inheritance\\ExampleTest' locationHint='pest_qn://Example (Tests\\Fixtures\\Inheritance\\Example)' flowId='68573']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'Tests\\Fixtures\\Inheritance\\ExampleTest', + name: 'Tests\\Fixtures\\Inheritance\\ExampleTest', + file: '', + flowId: 68573, + }, + ); }); it('testStarted Example (Tests\\Fixtures\\Inheritance\\Example)::Example', () => { - resultShouldBe(`##teamcity[testStarted name='Example' locationHint='pest_qn://Example (Tests\\Fixtures\\Inheritance\\Example)::Example' flowId='68573']`, { - event: TeamcityEvent.testStarted, - id: 'Example (Tests\\Fixtures\\Inheritance\\Example)::Example', - name: 'Example', - file: '', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testStarted name='Example' locationHint='pest_qn://Example (Tests\\Fixtures\\Inheritance\\Example)::Example' flowId='68573']`, + { + event: TeamcityEvent.testStarted, + id: 'Example (Tests\\Fixtures\\Inheritance\\Example)::Example', + name: 'Example', + file: '', + flowId: 68573, + }, + ); }); it('testFinished Example (Tests\\Fixtures\\Inheritance\\Example)::Example', () => { @@ -300,13 +373,16 @@ describe('Pest ProblemMatcher Text', () => { }); it('testSuiteFinished Tests\\Fixtures\\Inheritance\\ExampleTest', () => { - resultShouldBe(`##teamcity[testSuiteFinished name='Tests\\Fixtures\\Inheritance\\ExampleTest' flowId='68573']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'Tests\\Fixtures\\Inheritance\\ExampleTest', - name: 'Tests\\Fixtures\\Inheritance\\ExampleTest', - file: '', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='Tests\\Fixtures\\Inheritance\\ExampleTest' flowId='68573']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'Tests\\Fixtures\\Inheritance\\ExampleTest', + name: 'Tests\\Fixtures\\Inheritance\\ExampleTest', + file: '', + flowId: 68573, + }, + ); }); it('testSuiteFinished Test Suite', () => { @@ -320,13 +396,16 @@ describe('Pest ProblemMatcher Text', () => { }); it('testSuiteFinished phpunit.xml', () => { - resultShouldBe(`##teamcity[testSuiteFinished name='${pestProject('phpunit.xml')}' flowId='68573']`, { - event: TeamcityEvent.testSuiteFinished, - id: pestProject('phpunit.xml'), - name: pestProject('phpunit.xml'), - file: '', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='${pestProject('phpunit.xml')}' flowId='68573']`, + { + event: TeamcityEvent.testSuiteFinished, + id: pestProject('phpunit.xml'), + name: pestProject('phpunit.xml'), + file: '', + flowId: 68573, + }, + ); }); it('TestSummary', () => { @@ -349,80 +428,113 @@ describe('Pest ProblemMatcher Text', () => { }); it('name has */', () => { - resultShouldBe(`##teamcity[testStarted name='test /** with comment {@*} should do' locationHint='pest_qn://tests/Unit/ExampleTest.php::test /** with comment {@*} should do' flowId='28391']`, { - event: TeamcityEvent.testStarted, - id: 'tests/Unit/ExampleTest.php::test /** with comment */ should do', - name: 'test /** with comment {@*} should do', - flowId: 28391, - }); - - resultShouldBe(`##teamcity[testFailed name='test /** with comment {@*} should do' message='Failed asserting that true is identical to false.' details='at tests/Unit/ExampleTest.php:196' flowId='28391']`, undefined); - - resultShouldBe(`##teamcity[testFinished name='test /** with comment {@*} should do' duration='0' flowId='28391']`, { - event: TeamcityEvent.testFailed, - id: 'tests/Unit/ExampleTest.php::test /** with comment */ should do', - name: 'test /** with comment {@*} should do', - flowId: 28391, - }); + resultShouldBe( + `##teamcity[testStarted name='test /** with comment {@*} should do' locationHint='pest_qn://tests/Unit/ExampleTest.php::test /** with comment {@*} should do' flowId='28391']`, + { + event: TeamcityEvent.testStarted, + id: 'tests/Unit/ExampleTest.php::test /** with comment */ should do', + name: 'test /** with comment {@*} should do', + flowId: 28391, + }, + ); + + resultShouldBe( + `##teamcity[testFailed name='test /** with comment {@*} should do' message='Failed asserting that true is identical to false.' details='at tests/Unit/ExampleTest.php:196' flowId='28391']`, + undefined, + ); + + resultShouldBe( + `##teamcity[testFinished name='test /** with comment {@*} should do' duration='0' flowId='28391']`, + { + event: TeamcityEvent.testFailed, + id: 'tests/Unit/ExampleTest.php::test /** with comment */ should do', + name: 'test /** with comment {@*} should do', + flowId: 28391, + }, + ); }); it('with dataset', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Addition provider' locationHint='pest_qn://Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider' flowId='53556']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', - name: 'Addition provider', - flowId: 53556, - }); - - resultShouldBe(`##teamcity[testStarted name='Addition provider with data set ""foo-bar_%$"' locationHint='pest_qn://Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set ""foo-bar_%$"' flowId='53556']`, { - event: TeamcityEvent.testStarted, - // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set ""foo-bar_%$"', - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', - name: 'Addition provider with data set ""foo-bar_%$"', - flowId: 53556, - }); - - resultShouldBe(`##teamcity[testFinished name='Addition provider with data set ""foo-bar_%$"' duration='0' flowId='53556']`, { - event: TeamcityEvent.testFinished, - // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set ""foo-bar_%$"', - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', - name: 'Addition provider with data set ""foo-bar_%$"', - flowId: 53556, - }); - - resultShouldBe(`##teamcity[testStarted name='Addition provider with data set #0' locationHint='pest_qn://Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #0' flowId='53556']`, { - event: TeamcityEvent.testStarted, - // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #0', - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', - name: 'Addition provider with data set #0', - flowId: 53556, - }); - - resultShouldBe(`##teamcity[testFinished name='Addition provider with data set #0' duration='0' flowId='53556']`, { - event: TeamcityEvent.testFinished, - // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #0', - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', - name: 'Addition provider with data set #0', - flowId: 53556, - }); - - resultShouldBe(`##teamcity[testStarted name='Addition provider with data set #1' locationHint='pest_qn://Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #1' flowId='53556']`, { - event: TeamcityEvent.testStarted, - // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #1', - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', - name: 'Addition provider with data set #1', - flowId: 53556, - }); - - resultShouldBe(`##teamcity[testFailed name='Addition provider with data set #1' message='Failed asserting that 1 matches expected 2.' details='at tests/AssertionsTest.php:62' type='comparisonFailure' actual='1' expected='2' flowId='53556']`, undefined); - - resultShouldBe(`##teamcity[testFinished name='Addition provider with data set #1' duration='0' flowId='53556']`, { - event: TeamcityEvent.testFailed, - // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #1', - id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', - name: 'Addition provider with data set #1', - flowId: 53556, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Addition provider' locationHint='pest_qn://Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider' flowId='53556']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', + name: 'Addition provider', + flowId: 53556, + }, + ); + + resultShouldBe( + `##teamcity[testStarted name='Addition provider with data set ""foo-bar_%$"' locationHint='pest_qn://Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set ""foo-bar_%$"' flowId='53556']`, + { + event: TeamcityEvent.testStarted, + // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set ""foo-bar_%$"', + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', + name: 'Addition provider with data set ""foo-bar_%$"', + flowId: 53556, + }, + ); + + resultShouldBe( + `##teamcity[testFinished name='Addition provider with data set ""foo-bar_%$"' duration='0' flowId='53556']`, + { + event: TeamcityEvent.testFinished, + // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set ""foo-bar_%$"', + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', + name: 'Addition provider with data set ""foo-bar_%$"', + flowId: 53556, + }, + ); + + resultShouldBe( + `##teamcity[testStarted name='Addition provider with data set #0' locationHint='pest_qn://Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #0' flowId='53556']`, + { + event: TeamcityEvent.testStarted, + // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #0', + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', + name: 'Addition provider with data set #0', + flowId: 53556, + }, + ); + + resultShouldBe( + `##teamcity[testFinished name='Addition provider with data set #0' duration='0' flowId='53556']`, + { + event: TeamcityEvent.testFinished, + // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #0', + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', + name: 'Addition provider with data set #0', + flowId: 53556, + }, + ); + + resultShouldBe( + `##teamcity[testStarted name='Addition provider with data set #1' locationHint='pest_qn://Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #1' flowId='53556']`, + { + event: TeamcityEvent.testStarted, + // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #1', + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', + name: 'Addition provider with data set #1', + flowId: 53556, + }, + ); + + resultShouldBe( + `##teamcity[testFailed name='Addition provider with data set #1' message='Failed asserting that 1 matches expected 2.' details='at tests/AssertionsTest.php:62' type='comparisonFailure' actual='1' expected='2' flowId='53556']`, + undefined, + ); + + resultShouldBe( + `##teamcity[testFinished name='Addition provider with data set #1' duration='0' flowId='53556']`, + { + event: TeamcityEvent.testFailed, + // id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider with data set #1', + id: 'Assertions (Recca0120\\VSCode\\Tests\\Assertions)::Addition provider', + name: 'Addition provider with data set #1', + flowId: 53556, + }, + ); resultShouldBe(`##teamcity[testSuiteFinished name='Addition provider' flowId='53556']`, { event: TeamcityEvent.testSuiteFinished, @@ -433,61 +545,82 @@ describe('Pest ProblemMatcher Text', () => { }); it('describe with dataset', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it ha' locationHint='pest_qn://tests/Unit/ExampleTest.php::\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it ha' flowId='11847']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it ha', - name: '`abc` → `def` → `ijk` → `lmn` → it ha', - flowId: 11847, - }); - - resultShouldBe(`##teamcity[testStarted name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'enunomaduro@gmail.com|')"' locationHint='pest_qn://tests/Unit/ExampleTest.php::\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'enunomaduro@gmail.com|')"' flowId='11847']`, { - event: TeamcityEvent.testStarted, - // id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'enunomaduro@gmail.com\')"', - id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails', - name: '`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'enunomaduro@gmail.com\')"', - flowId: 11847, - }); - - resultShouldBe(`##teamcity[testFinished name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'enunomaduro@gmail.com|')"' duration='9' flowId='11847']`, { - event: TeamcityEvent.testFinished, - // id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'enunomaduro@gmail.com\')"', - id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails', - name: '`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'enunomaduro@gmail.com\')"', - flowId: 11847, - }); - - resultShouldBe(`##teamcity[testStarted name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'other@example.com|')"' locationHint='pest_qn://tests/Unit/ExampleTest.php::\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'other@example.com|')"' flowId='11847']`, { - event: TeamcityEvent.testStarted, - // id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'other@example.com\')"', - id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails', - name: '`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'other@example.com\')"', - flowId: 11847, - }); - - resultShouldBe(`##teamcity[testFinished name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'other@example.com|')"' duration='0' flowId='11847']`, { - event: TeamcityEvent.testFinished, - // id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'other@example.com\')"', - id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails', - name: '`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'other@example.com\')"', - flowId: 11847, - }); - - resultShouldBe(`##teamcity[testSuiteFinished name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it ha' flowId='11847']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it ha', - name: '`abc` → `def` → `ijk` → `lmn` → it ha', - flowId: 11847, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it ha' locationHint='pest_qn://tests/Unit/ExampleTest.php::\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it ha' flowId='11847']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it ha', + name: '`abc` → `def` → `ijk` → `lmn` → it ha', + flowId: 11847, + }, + ); + + resultShouldBe( + `##teamcity[testStarted name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'enunomaduro@gmail.com|')"' locationHint='pest_qn://tests/Unit/ExampleTest.php::\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'enunomaduro@gmail.com|')"' flowId='11847']`, + { + event: TeamcityEvent.testStarted, + // id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'enunomaduro@gmail.com\')"', + id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails', + name: '`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'enunomaduro@gmail.com\')"', + flowId: 11847, + }, + ); + + resultShouldBe( + `##teamcity[testFinished name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'enunomaduro@gmail.com|')"' duration='9' flowId='11847']`, + { + event: TeamcityEvent.testFinished, + // id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'enunomaduro@gmail.com\')"', + id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails', + name: '`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'enunomaduro@gmail.com\')"', + flowId: 11847, + }, + ); + + resultShouldBe( + `##teamcity[testStarted name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'other@example.com|')"' locationHint='pest_qn://tests/Unit/ExampleTest.php::\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'other@example.com|')"' flowId='11847']`, + { + event: TeamcityEvent.testStarted, + // id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'other@example.com\')"', + id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails', + name: '`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'other@example.com\')"', + flowId: 11847, + }, + ); + + resultShouldBe( + `##teamcity[testFinished name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it has emails with data set "(|'other@example.com|')"' duration='0' flowId='11847']`, + { + event: TeamcityEvent.testFinished, + // id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'other@example.com\')"', + id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it has emails', + name: '`abc` → `def` → `ijk` → `lmn` → it has emails with data set "(\'other@example.com\')"', + flowId: 11847, + }, + ); + + resultShouldBe( + `##teamcity[testSuiteFinished name='\`abc\` → \`def\` → \`ijk\` → \`lmn\` → it ha' flowId='11847']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'tests/Unit/ExampleTest.php::`abc` → `def` → `ijk` → `lmn` → it ha', + name: '`abc` → `def` → `ijk` → `lmn` → it ha', + flowId: 11847, + }, + ); }); it('For Windows testStarted tests\\Fixtures\\ExampleTest.php::it example 2', () => { - resultShouldBe(`##teamcity[testStarted name='it example 2' locationHint='pest_qn://tests\\Fixtures\\ExampleTest.php::it example 2' flowId='68573']`, { - event: TeamcityEvent.testStarted, - id: 'tests/Fixtures/ExampleTest.php::it example 2', - name: 'it example 2', - file: 'tests/Fixtures/ExampleTest.php', - flowId: 68573, - }); + resultShouldBe( + `##teamcity[testStarted name='it example 2' locationHint='pest_qn://tests\\Fixtures\\ExampleTest.php::it example 2' flowId='68573']`, + { + event: TeamcityEvent.testStarted, + id: 'tests/Fixtures/ExampleTest.php::it example 2', + name: 'it example 2', + file: 'tests/Fixtures/ExampleTest.php', + flowId: 68573, + }, + ); }); it('For Windows testFinished tests/Fixtures/ExampleTest.php::it example 2', () => { @@ -502,39 +635,51 @@ describe('Pest ProblemMatcher Text', () => { describe('Pest v2', () => { it('testSuiteStarted phpunit.xml and locationHint prefix is file://', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='${pestProject('phpunit.xml')}' locationHint='file://Example (Tests\\Feature\\Example)' flowId='57317']`, { - event: TeamcityEvent.testSuiteStarted, - id: pestProject('phpunit.xml'), - name: pestProject('phpunit.xml'), - flowId: 57317, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='${pestProject('phpunit.xml')}' locationHint='file://Example (Tests\\Feature\\Example)' flowId='57317']`, + { + event: TeamcityEvent.testSuiteStarted, + id: pestProject('phpunit.xml'), + name: pestProject('phpunit.xml'), + flowId: 57317, + }, + ); }); it('testSuiteStarted Test Suite and locationHint prefix is file://', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Test Suite' locationHint='file://Example (Tests\\Feature\\Example)' flowId='57317']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'Test Suite', - name: 'Test Suite', - flowId: 57317, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Test Suite' locationHint='file://Example (Tests\\Feature\\Example)' flowId='57317']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'Test Suite', + name: 'Test Suite', + flowId: 57317, + }, + ); }); it('pest-v2 tests/Fixtures/CollisionTest.php', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Tests\\Fixtures\\CollisionTest' locationHint='file://tests/Fixtures/CollisionTest.php' flowId='57317']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'tests/Fixtures/CollisionTest.php', - name: 'Tests\\Fixtures\\CollisionTest', - file: 'tests/Fixtures/CollisionTest.php', - flowId: 57317, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Tests\\Fixtures\\CollisionTest' locationHint='file://tests/Fixtures/CollisionTest.php' flowId='57317']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'tests/Fixtures/CollisionTest.php', + name: 'Tests\\Fixtures\\CollisionTest', + file: 'tests/Fixtures/CollisionTest.php', + flowId: 57317, + }, + ); - resultShouldBe(`##teamcity[testStarted name='success' locationHint='pest_qn://tests/Fixtures/CollisionTest.php::success' flowId='57317']`, { - event: TeamcityEvent.testStarted, - id: 'tests/Fixtures/CollisionTest.php::success', - name: 'success', - file: 'tests/Fixtures/CollisionTest.php', - flowId: 57317, - }); + resultShouldBe( + `##teamcity[testStarted name='success' locationHint='pest_qn://tests/Fixtures/CollisionTest.php::success' flowId='57317']`, + { + event: TeamcityEvent.testStarted, + id: 'tests/Fixtures/CollisionTest.php::success', + name: 'success', + file: 'tests/Fixtures/CollisionTest.php', + flowId: 57317, + }, + ); resultShouldBe(`##teamcity[testFinished name='success' duration='0' flowId='57317']`, { event: TeamcityEvent.testFinished, @@ -544,67 +689,88 @@ describe('Pest ProblemMatcher Text', () => { flowId: 57317, }); - resultShouldBe(`##teamcity[testSuiteFinished name='Tests\\Fixtures\\CollisionTest' flowId='57317']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'tests/Fixtures/CollisionTest.php', - name: 'Tests\\Fixtures\\CollisionTest', - file: 'tests/Fixtures/CollisionTest.php', - flowId: 57317, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='Tests\\Fixtures\\CollisionTest' flowId='57317']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'tests/Fixtures/CollisionTest.php', + name: 'Tests\\Fixtures\\CollisionTest', + file: 'tests/Fixtures/CollisionTest.php', + flowId: 57317, + }, + ); }); it('pest-v2 data set', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails' locationHint='file://tests/Unit/ExampleTest.php' flowId='57317']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails', - name: 'Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails', - file: 'tests/Unit/ExampleTest.php', - flowId: 57317, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails' locationHint='file://tests/Unit/ExampleTest.php' flowId='57317']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails', + name: 'Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails', + file: 'tests/Unit/ExampleTest.php', + flowId: 57317, + }, + ); - resultShouldBe(`##teamcity[testStarted name='it has emails with data set "(|'enunomaduro@gmail.com|')"' locationHint='pest_qn://tests/Unit/ExampleTest.php::it has emails with data set "(|'enunomaduro@gmail.com|')"' flowId='57317']`, { - event: TeamcityEvent.testStarted, - // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'enunomaduro@gmail.com\')"', - id: 'tests/Unit/ExampleTest.php::it has emails', - name: 'it has emails with data set "(\'enunomaduro@gmail.com\')"', - file: 'tests/Unit/ExampleTest.php', - flowId: 57317, - }); + resultShouldBe( + `##teamcity[testStarted name='it has emails with data set "(|'enunomaduro@gmail.com|')"' locationHint='pest_qn://tests/Unit/ExampleTest.php::it has emails with data set "(|'enunomaduro@gmail.com|')"' flowId='57317']`, + { + event: TeamcityEvent.testStarted, + // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'enunomaduro@gmail.com\')"', + id: 'tests/Unit/ExampleTest.php::it has emails', + name: 'it has emails with data set "(\'enunomaduro@gmail.com\')"', + file: 'tests/Unit/ExampleTest.php', + flowId: 57317, + }, + ); - resultShouldBe(`##teamcity[testFinished name='it has emails with data set "(|'enunomaduro@gmail.com|')"' duration='1' flowId='57317']`, { - event: TeamcityEvent.testFinished, - // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'enunomaduro@gmail.com\')"', - id: 'tests/Unit/ExampleTest.php::it has emails', - name: 'it has emails with data set "(\'enunomaduro@gmail.com\')"', - file: 'tests/Unit/ExampleTest.php', - flowId: 57317, - }); + resultShouldBe( + `##teamcity[testFinished name='it has emails with data set "(|'enunomaduro@gmail.com|')"' duration='1' flowId='57317']`, + { + event: TeamcityEvent.testFinished, + // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'enunomaduro@gmail.com\')"', + id: 'tests/Unit/ExampleTest.php::it has emails', + name: 'it has emails with data set "(\'enunomaduro@gmail.com\')"', + file: 'tests/Unit/ExampleTest.php', + flowId: 57317, + }, + ); - resultShouldBe(`##teamcity[testStarted name='it has emails with data set "(|'other@example.com|')"' locationHint='pest_qn://tests/Unit/ExampleTest.php::it has emails with data set "(|'other@example.com|')"' flowId='57317']`, { - event: TeamcityEvent.testStarted, - // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'other@example.com\')"', - id: 'tests/Unit/ExampleTest.php::it has emails', - name: 'it has emails with data set "(\'other@example.com\')"', - file: 'tests/Unit/ExampleTest.php', - flowId: 57317, - }); + resultShouldBe( + `##teamcity[testStarted name='it has emails with data set "(|'other@example.com|')"' locationHint='pest_qn://tests/Unit/ExampleTest.php::it has emails with data set "(|'other@example.com|')"' flowId='57317']`, + { + event: TeamcityEvent.testStarted, + // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'other@example.com\')"', + id: 'tests/Unit/ExampleTest.php::it has emails', + name: 'it has emails with data set "(\'other@example.com\')"', + file: 'tests/Unit/ExampleTest.php', + flowId: 57317, + }, + ); - resultShouldBe(`##teamcity[testFinished name='it has emails with data set "(|'other@example.com|')"' duration='0' flowId='57317']`, { - event: TeamcityEvent.testFinished, - // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'other@example.com\')"', - id: 'tests/Unit/ExampleTest.php::it has emails', - name: 'it has emails with data set "(\'other@example.com\')"', - file: 'tests/Unit/ExampleTest.php', - flowId: 57317, - }); + resultShouldBe( + `##teamcity[testFinished name='it has emails with data set "(|'other@example.com|')"' duration='0' flowId='57317']`, + { + event: TeamcityEvent.testFinished, + // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'other@example.com\')"', + id: 'tests/Unit/ExampleTest.php::it has emails', + name: 'it has emails with data set "(\'other@example.com\')"', + file: 'tests/Unit/ExampleTest.php', + flowId: 57317, + }, + ); - resultShouldBe(`##teamcity[testSuiteFinished name='Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails' flowId='57317']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails', - name: 'Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails', - file: 'tests/Unit/ExampleTest.php', - flowId: 57317, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails' flowId='57317']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails', + name: 'Tests\\Unit\\ExampleTest::__pest_evaluable_it_has_emails', + file: 'tests/Unit/ExampleTest.php', + flowId: 57317, + }, + ); }); }); @@ -618,53 +784,74 @@ describe('Pest ProblemMatcher Text', () => { }); it('testStarted without flowId', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Tests\\Feature\\ExampleTest' locationHint='pest_qn://Tests\\Feature\\ExampleTest' flowId='58024']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'Tests/Feature/ExampleTest', - name: 'Tests\\Feature\\ExampleTest', - flowId: 58024, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Tests\\Feature\\ExampleTest' locationHint='pest_qn://Tests\\Feature\\ExampleTest' flowId='58024']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'Tests/Feature/ExampleTest', + name: 'Tests\\Feature\\ExampleTest', + flowId: 58024, + }, + ); - resultShouldBe(`##teamcity[testStarted name='test_example' locationHint='php_qn://${pestProject('tests/Feature/ExampleTest.php')}::\\Tests\\Feature\\ExampleTest::test_example']`, { - event: TeamcityEvent.testStarted, - id: 'Example (Tests\\Feature\\Example)::Example', - name: 'test_example', - flowId: 58024, - }); + resultShouldBe( + `##teamcity[testStarted name='test_example' locationHint='php_qn://${pestProject('tests/Feature/ExampleTest.php')}::\\Tests\\Feature\\ExampleTest::test_example']`, + { + event: TeamcityEvent.testStarted, + id: 'Example (Tests\\Feature\\Example)::Example', + name: 'test_example', + flowId: 58024, + }, + ); - resultShouldBe(`##teamcity[testFinished name='test_example' duration='1' flowId='58024']`, { - event: TeamcityEvent.testFinished, - id: 'Example (Tests\\Feature\\Example)::Example', - name: 'test_example', - flowId: 58024, - }); + resultShouldBe( + `##teamcity[testFinished name='test_example' duration='1' flowId='58024']`, + { + event: TeamcityEvent.testFinished, + id: 'Example (Tests\\Feature\\Example)::Example', + name: 'test_example', + flowId: 58024, + }, + ); - resultShouldBe(`##teamcity[testSuiteFinished name='Tests\\Feature\\ExampleTest' locationHint='pest_qn://Tests\\Feature\\ExampleTest' flowId='58024']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'Tests/Feature/ExampleTest', - name: 'Tests\\Feature\\ExampleTest', - flowId: 58024, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='Tests\\Feature\\ExampleTest' locationHint='pest_qn://Tests\\Feature\\ExampleTest' flowId='58024']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'Tests/Feature/ExampleTest', + name: 'Tests\\Feature\\ExampleTest', + flowId: 58024, + }, + ); }); it('pest-v1 tests/Fixtures/CollisionTest.php', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Tests\\Fixtures\\CollisionTest' locationHint='pest_qn://${pestProject('tests/Fixtures/CollisionTest.php')}' flowId='12667']`, { - event: TeamcityEvent.testSuiteStarted, - id: 'tests/Fixtures/CollisionTest.php', - name: 'Tests\\Fixtures\\CollisionTest', - // file: 'tests/Fixtures/CollisionTest.php', - flowId: 12667, - }); + resultShouldBe( + `##teamcity[testSuiteStarted name='Tests\\Fixtures\\CollisionTest' locationHint='pest_qn://${pestProject('tests/Fixtures/CollisionTest.php')}' flowId='12667']`, + { + event: TeamcityEvent.testSuiteStarted, + id: 'tests/Fixtures/CollisionTest.php', + name: 'Tests\\Fixtures\\CollisionTest', + // file: 'tests/Fixtures/CollisionTest.php', + flowId: 12667, + }, + ); - resultShouldBe(`##teamcity[testStarted name='error' locationHint='pest_qn://${pestProject('tests/Fixtures/CollisionTest.php')}::error' flowId='12667']`, { - event: TeamcityEvent.testStarted, - id: 'tests/Fixtures/CollisionTest.php::error', - name: 'error', - file: 'tests/Fixtures/CollisionTest.php', - flowId: 12667, - }); + resultShouldBe( + `##teamcity[testStarted name='error' locationHint='pest_qn://${pestProject('tests/Fixtures/CollisionTest.php')}::error' flowId='12667']`, + { + event: TeamcityEvent.testStarted, + id: 'tests/Fixtures/CollisionTest.php::error', + name: 'error', + file: 'tests/Fixtures/CollisionTest.php', + flowId: 12667, + }, + ); - resultShouldBe(`##teamcity[testIgnored name='error' message='' details=' /Users/recca0120/Desktop/vscode-phpunit/src/PHPUnit/__tests__/fixtures/pest-stub/tests/Fixtures/CollisionTest.php:5|n ' duration='6']`, undefined); + resultShouldBe( + `##teamcity[testIgnored name='error' message='' details=' /Users/recca0120/Desktop/vscode-phpunit/src/PHPUnit/__tests__/fixtures/pest-stub/tests/Fixtures/CollisionTest.php:5|n ' duration='6']`, + undefined, + ); resultShouldBe(`##teamcity[testFinished name='error' duration='6' flowId='12667']`, { event: TeamcityEvent.testIgnored, @@ -674,13 +861,16 @@ describe('Pest ProblemMatcher Text', () => { flowId: 12667, }); - resultShouldBe(`##teamcity[testStarted name='success' locationHint='pest_qn://${pestProject('tests/Fixtures/CollisionTest.php')}::success' flowId='12667']`, { - event: TeamcityEvent.testStarted, - id: 'tests/Fixtures/CollisionTest.php::success', - name: 'success', - file: 'tests/Fixtures/CollisionTest.php', - flowId: 12667, - }); + resultShouldBe( + `##teamcity[testStarted name='success' locationHint='pest_qn://${pestProject('tests/Fixtures/CollisionTest.php')}::success' flowId='12667']`, + { + event: TeamcityEvent.testStarted, + id: 'tests/Fixtures/CollisionTest.php::success', + name: 'success', + file: 'tests/Fixtures/CollisionTest.php', + flowId: 12667, + }, + ); resultShouldBe(`##teamcity[testFinished name='success' duration='0' flowId='12667']`, { event: TeamcityEvent.testFinished, @@ -690,82 +880,112 @@ describe('Pest ProblemMatcher Text', () => { flowId: 12667, }); - resultShouldBe(`##teamcity[testSuiteFinished name='Tests\\Fixtures\\CollisionTest' locationHint='pest_qn://${pestProject('tests/Fixtures/CollisionTest.php')}' flowId='12667']`, { - event: TeamcityEvent.testSuiteFinished, - id: 'tests/Fixtures/CollisionTest.php', - name: 'Tests\\Fixtures\\CollisionTest', - file: 'tests/Fixtures/CollisionTest.php', - flowId: 12667, - }); + resultShouldBe( + `##teamcity[testSuiteFinished name='Tests\\Fixtures\\CollisionTest' locationHint='pest_qn://${pestProject('tests/Fixtures/CollisionTest.php')}' flowId='12667']`, + { + event: TeamcityEvent.testSuiteFinished, + id: 'tests/Fixtures/CollisionTest.php', + name: 'Tests\\Fixtures\\CollisionTest', + file: 'tests/Fixtures/CollisionTest.php', + flowId: 12667, + }, + ); }); it('pest v1 data set', () => { - resultShouldBe(`##teamcity[testStarted name='it has emails with (|'enunomaduro@gmail.com|')' locationHint='pest_qn:///Users/recca0120/Desktop/vscode-phpunit/src/PHPUnit/__tests__/fixtures/pest-stub/tests/Unit/ExampleTest.php::it has emails with (|'enunomaduro@gmail.com|')' flowId='12667']`, { - event: TeamcityEvent.testStarted, - // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'enunomaduro@gmail.com\')"', - id: 'tests/Unit/ExampleTest.php::it has emails', - name: 'it has emails with (\'enunomaduro@gmail.com\')', - file: 'tests/Unit/ExampleTest.php', - flowId: 12667, - }); + resultShouldBe( + `##teamcity[testStarted name='it has emails with (|'enunomaduro@gmail.com|')' locationHint='pest_qn:///Users/recca0120/Desktop/vscode-phpunit/src/PHPUnit/__tests__/fixtures/pest-stub/tests/Unit/ExampleTest.php::it has emails with (|'enunomaduro@gmail.com|')' flowId='12667']`, + { + event: TeamcityEvent.testStarted, + // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'enunomaduro@gmail.com\')"', + id: 'tests/Unit/ExampleTest.php::it has emails', + name: "it has emails with ('enunomaduro@gmail.com')", + file: 'tests/Unit/ExampleTest.php', + flowId: 12667, + }, + ); - resultShouldBe(`##teamcity[testFinished name='it has emails with (|'enunomaduro@gmail.com|')' duration='1' flowId='12667']`, { - event: TeamcityEvent.testFinished, - // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'enunomaduro@gmail.com\')"', - id: 'tests/Unit/ExampleTest.php::it has emails', - name: 'it has emails with (\'enunomaduro@gmail.com\')', - file: 'tests/Unit/ExampleTest.php', - flowId: 12667, - }); + resultShouldBe( + `##teamcity[testFinished name='it has emails with (|'enunomaduro@gmail.com|')' duration='1' flowId='12667']`, + { + event: TeamcityEvent.testFinished, + // id: 'tests/Unit/ExampleTest.php::it has emails with data set "(\'enunomaduro@gmail.com\')"', + id: 'tests/Unit/ExampleTest.php::it has emails', + name: "it has emails with ('enunomaduro@gmail.com')", + file: 'tests/Unit/ExampleTest.php', + flowId: 12667, + }, + ); }); }); it('multi-word class names', () => { - resultShouldBe(`##teamcity[testStarted name='Login screen can be rendered' locationHint='pest_qn://Authentication Page (Tests\\Feature\\AuthenticationPage)::Login screen can be rendered' flowId='72545']`, { - event: TeamcityEvent.testStarted, - id: 'Authentication Page (Tests\\Feature\\AuthenticationPage)::Login screen can be rendered', - flowId: 72545, - }); - - resultShouldBe(`##teamcity[testFinished name='Login screen can be rendered' duration='1' flowId='72545']`, { - event: TeamcityEvent.testFinished, - id: 'Authentication Page (Tests\\Feature\\AuthenticationPage)::Login screen can be rendered', - flowId: 72545, - }); + resultShouldBe( + `##teamcity[testStarted name='Login screen can be rendered' locationHint='pest_qn://Authentication Page (Tests\\Feature\\AuthenticationPage)::Login screen can be rendered' flowId='72545']`, + { + event: TeamcityEvent.testStarted, + id: 'Authentication Page (Tests\\Feature\\AuthenticationPage)::Login screen can be rendered', + flowId: 72545, + }, + ); + + resultShouldBe( + `##teamcity[testFinished name='Login screen can be rendered' duration='1' flowId='72545']`, + { + event: TeamcityEvent.testFinished, + id: 'Authentication Page (Tests\\Feature\\AuthenticationPage)::Login screen can be rendered', + flowId: 72545, + }, + ); }); it('testFailed without TestStarted', () => { - resultShouldBe(`##teamcity[testFailed name='error' message='Exception: error' details='at tests/Fixtures/CollisionTest.php:4' flowId='68573']`, { - event: TeamcityEvent.testFailed, - id: 'tests/Fixtures/CollisionTest.php::error', - name: 'error', - message: 'Exception: error', - file: 'tests/Fixtures/CollisionTest.php', - flowId: 68573, - details: [ - { - file: 'tests/Fixtures/CollisionTest.php', - line: 4, - }, - ], - }); + resultShouldBe( + `##teamcity[testFailed name='error' message='Exception: error' details='at tests/Fixtures/CollisionTest.php:4' flowId='68573']`, + { + event: TeamcityEvent.testFailed, + id: 'tests/Fixtures/CollisionTest.php::error', + name: 'error', + message: 'Exception: error', + file: 'tests/Fixtures/CollisionTest.php', + flowId: 68573, + details: [ + { + file: 'tests/Fixtures/CollisionTest.php', + line: 4, + }, + ], + }, + ); }); it('testFinished without TestStarted', () => { - resultShouldBe('##teamcity[testFinished name=\'`before each` → example\' duration=\'12\' flowId=\'97972\']', undefined); + resultShouldBe( + "##teamcity[testFinished name='`before each` → example' duration='12' flowId='97972']", + undefined, + ); }); it('PHPUnit without TestStarted', () => { - resultShouldBe(`##teamcity[testSuiteStarted name='Tests\\Feature\\AuthenticationTest' locationHint='pest_qn://Authentication (Tests\\Feature\\Authentication)' flowId='6611']`, {}); + resultShouldBe( + `##teamcity[testSuiteStarted name='Tests\\Feature\\AuthenticationTest' locationHint='pest_qn://Authentication (Tests\\Feature\\Authentication)' flowId='6611']`, + {}, + ); resultShouldBe(`##teamcity[testCount count='1' flowId='6611']`, {}); - resultShouldBe(`##teamcity[testIgnored name='Login screen can be rendered' message='This test was ignored.' details='' flowId='6611']`, { - event: TeamcityEvent.testIgnored, - flowId: 6611, - id: 'Authentication (Tests\\Feature\\Authentication)::Login screen can be rendered', - name: 'Login screen can be rendered', - message: 'This test was ignored.', - duration: 0, - }); - resultShouldBe(`##teamcity[testSuiteFinished name='Tests\\Feature\\AuthenticationTest' flowId='6611']`, {}); + resultShouldBe( + `##teamcity[testIgnored name='Login screen can be rendered' message='This test was ignored.' details='' flowId='6611']`, + { + event: TeamcityEvent.testIgnored, + flowId: 6611, + id: 'Authentication (Tests\\Feature\\Authentication)::Login screen can be rendered', + name: 'Login screen can be rendered', + message: 'This test was ignored.', + duration: 0, + }, + ); + resultShouldBe( + `##teamcity[testSuiteFinished name='Tests\\Feature\\AuthenticationTest' flowId='6611']`, + {}, + ); }); }); diff --git a/src/PHPUnit/ProblemMatcher/ProblemMatcher.ts b/src/PHPUnit/ProblemMatcher/ProblemMatcher.ts index 7c06e06d..94623075 100644 --- a/src/PHPUnit/ProblemMatcher/ProblemMatcher.ts +++ b/src/PHPUnit/ProblemMatcher/ProblemMatcher.ts @@ -1,79 +1,96 @@ +import { PestFixer, PestV1Fixer, PHPUnitFixer } from '../Transformer'; import { - TeamcityEvent, TestFailed, TestFinished, TestIgnored, TestResult, TestResultParser, TestStarted, TestSuiteFinished, - TestSuiteStarted, + TeamcityEvent, + type TestFailed, + type TestFinished, + type TestIgnored, + type TestResult, + TestResultParser, + type TestStarted, + type TestSuiteFinished, + type TestSuiteStarted, } from '.'; -import { PestFixer, PestV1Fixer, PHPUnitFixer } from '../Transformer'; +import { TestResultCache } from './TestResultCache'; export class ProblemMatcher { - private cache = new Map(); - - private lookup: { [p: string]: (result: any) => TestResult | undefined } = { - [TeamcityEvent.testSuiteStarted]: this.handleStarted, - [TeamcityEvent.testStarted]: this.handleStarted, - [TeamcityEvent.testFinished]: this.handleFinished, - [TeamcityEvent.testFailed]: this.handleFault, - [TeamcityEvent.testIgnored]: this.handleFault, - [TeamcityEvent.testSuiteFinished]: this.handleFinished, - }; + private cache = new TestResultCache(); - constructor(private testResultParser: TestResultParser = new TestResultParser()) { } + constructor(private testResultParser: TestResultParser = new TestResultParser()) {} parse(input: string | Buffer): TestResult | undefined { let result = this.testResultParser.parse(input.toString()); - result = PestV1Fixer.fixFlowId(this.cache, result); + result = PestV1Fixer.fixFlowId(this.cache.asMap(), result); + + if (!this.isDispatchable(result)) { + return result; + } - return this.isResult(result) ? this.lookup[result!.event]?.call(this, result) : result; + return this.dispatch(result!); } - private isResult(result?: TestResult): boolean { + private isDispatchable(result?: TestResult): boolean { return !!result && 'event' in result && 'name' in result && 'flowId' in result; } + private dispatch(result: TestResult): TestResult | undefined { + switch (result.event) { + case TeamcityEvent.testSuiteStarted: + case TeamcityEvent.testStarted: + return this.handleStarted(result as TestSuiteStarted | TestStarted); + case TeamcityEvent.testFailed: + case TeamcityEvent.testIgnored: + return this.handleFault(result as TestFailed | TestIgnored); + case TeamcityEvent.testSuiteFinished: + case TeamcityEvent.testFinished: + return this.handleFinished(result as TestSuiteFinished | TestFinished); + default: + return undefined; + } + } + private handleStarted(testResult: TestSuiteStarted | TestStarted) { - const cacheId = this.cacheId(testResult); - this.cache.set(cacheId, testResult); + this.cache.set(testResult, testResult); - return this.cache.get(cacheId); + return this.cache.get(testResult); } private handleFault(testResult: TestFailed | TestIgnored): TestResult | undefined { - const cacheId = this.cacheId(testResult); - let prevTestResult = this.cache.get(cacheId) as (TestFailed | TestIgnored); + const prevTestResult = this.cache.get(testResult) as TestFailed | TestIgnored; if (!prevTestResult) { return PestFixer.fixNoTestStarted( - this.cache, - PHPUnitFixer.fixNoTestStarted(this.cache, testResult), + this.cache.asMap(), + PHPUnitFixer.fixNoTestStarted(this.cache.asMap(), testResult), ); } if (prevTestResult.event === TeamcityEvent.testStarted) { - this.cache.set(cacheId, { ...(prevTestResult ?? {}), ...testResult }); - - return; - } - - if (testResult.message) { - prevTestResult.message += '\n\n' + testResult.message; + this.cache.set(testResult, { ...prevTestResult, ...testResult }); + return undefined; } - prevTestResult.details.push(...testResult.details); - this.cache.set(cacheId, prevTestResult); + this.mergeFaultDetails(prevTestResult, testResult); + this.cache.set(testResult, prevTestResult); return undefined; } - private handleFinished(testResult: TestSuiteFinished | TestFinished) { - const cacheId = this.cacheId(testResult); + private mergeFaultDetails(target: TestFailed | TestIgnored, source: TestFailed | TestIgnored) { + if (source.message) { + target.message += `\n\n${source.message}`; + } + target.details.push(...source.details); + } - if (!this.cache.has(cacheId)) { + private handleFinished(testResult: TestSuiteFinished | TestFinished) { + if (!this.cache.has(testResult)) { return; } - const prevTestResult = this.cache.get(cacheId)!; + const prevTestResult = this.cache.get(testResult)!; const event = this.isFault(prevTestResult) ? prevTestResult.event : testResult.event; const result = { ...prevTestResult, ...testResult, event }; - this.cache.delete(cacheId); + this.cache.delete(testResult); return result; } @@ -81,8 +98,4 @@ export class ProblemMatcher { private isFault(testResult: TestResult) { return [TeamcityEvent.testFailed, TeamcityEvent.testIgnored].includes(testResult.event); } - - private cacheId(testResult: TestSuiteStarted | TestStarted | TestFailed | TestIgnored | TestSuiteFinished | TestFinished) { - return `${testResult.name}-${testResult.flowId}`; - } } diff --git a/src/PHPUnit/ProblemMatcher/TestConfigurationParser.ts b/src/PHPUnit/ProblemMatcher/TestConfigurationParser.ts index 60ab5728..58912842 100644 --- a/src/PHPUnit/ProblemMatcher/TestConfigurationParser.ts +++ b/src/PHPUnit/ProblemMatcher/TestConfigurationParser.ts @@ -1,4 +1,4 @@ -import { TeamcityEvent, TestConfiguration } from './types'; +import { TeamcityEvent, type TestConfiguration } from './types'; import { ValueParser } from './ValueParser'; export class TestConfigurationParser extends ValueParser { diff --git a/src/PHPUnit/ProblemMatcher/TestDurationParser.ts b/src/PHPUnit/ProblemMatcher/TestDurationParser.ts index f5adf142..1674da21 100644 --- a/src/PHPUnit/ProblemMatcher/TestDurationParser.ts +++ b/src/PHPUnit/ProblemMatcher/TestDurationParser.ts @@ -1,17 +1,16 @@ -import { TeamcityEvent, TestDuration } from './types'; -import { IParser } from './ValueParser'; +import { TeamcityEvent, type TestDuration } from './types'; +import type { IParser } from './ValueParser'; export class TestDurationParser implements IParser { - private readonly pattern = new RegExp( - '(Time|Duration):\\s+(? - `, - ); + `); const files = [ URI.file(phpUnitProject('tests/AssertionsTest.php')), @@ -98,8 +104,7 @@ describe('TestCollection', () => { tests tests/Unit/ExampleTest.php - `, - ); + `); const files = [ URI.file(phpUnitProject('tests/AssertionsTest.php')), @@ -126,8 +131,7 @@ describe('TestCollection', () => { tests/Unit/ExampleTest.php tests/Feature/ExampleTest.php - `, - ); + `); const files = [ URI.file(phpUnitProject('tests/AssertionsTest.php')), @@ -140,9 +144,7 @@ describe('TestCollection', () => { await shouldBe(collection, { default: [files[0]], - // eslint-disable-next-line @typescript-eslint/naming-convention Unit: [files[1]], - // eslint-disable-next-line @typescript-eslint/naming-convention Feature: [files[2]], }); }); @@ -153,8 +155,7 @@ describe('TestCollection', () => { tests/*/SubFolder - `, - ); + `); const files = [ URI.file(phpUnitProject('tests/Unit/ExampleTest.php')), URI.file(phpUnitProject('tests/Unit/SubFolder/ExampleTest.php')), @@ -173,12 +174,9 @@ describe('TestCollection', () => { tests/unit - `, - ); + `); - const files = [ - URI.file(phpUnitProject('tests/Unit/ExampleTest.php')), - ]; + const files = [URI.file(phpUnitProject('tests/Unit/ExampleTest.php'))]; for (const file of files) { await collection.add(file); } @@ -194,8 +192,7 @@ describe('TestCollection', () => { tests - `, - ); + `); const files = [ URI.file(phpUnitProject('tests/AbstractTest.php')), @@ -215,8 +212,7 @@ describe('TestCollection', () => { tests - `, - ); + `); const files = [ URI.file(phpUnitProject('tests/Unit/ExampleTest.php')), @@ -235,9 +231,7 @@ describe('TestCollection', () => { tests - `, - ); - + `); const files = [URI.file(phpUnitProject('tests/Unit/ExampleTest.php'))]; for (const file of files) { @@ -259,8 +253,7 @@ describe('TestCollection', () => { tests/Feature - `, - ); + `); const files = [ URI.file(phpUnitProject('tests/Unit/ExampleTest.php')), @@ -274,4 +267,4 @@ describe('TestCollection', () => { collection.reset(); expect(collection.size).toEqual(0); }); -}); \ No newline at end of file +}); diff --git a/src/PHPUnit/TestCollection/TestCollection.ts b/src/PHPUnit/TestCollection/TestCollection.ts index 6b3fb943..41233f7c 100644 --- a/src/PHPUnit/TestCollection/TestCollection.ts +++ b/src/PHPUnit/TestCollection/TestCollection.ts @@ -1,8 +1,8 @@ -import { Minimatch } from 'minimatch'; import { extname, join } from 'node:path'; +import { Minimatch } from 'minimatch'; import { URI } from 'vscode-uri'; -import { PHPUnitXML, TestDefinition, TestParser, TestSuite } from '../index'; -import { TestDefinitionBuilder } from './TestDefinitionBuilder'; +import { type PHPUnitXML, type TestDefinition, TestParser, type TestSuite } from '../index'; +import { TestDefinitionCollector } from './TestDefinitionCollector'; export interface File { testsuite: string; @@ -10,73 +10,13 @@ export interface File { tests: T[]; } -abstract class Base implements Iterable<[K, V]> { - protected _items: Map = new Map(); - - get size() { - return this._items.size; - } - - items() { - return this._items; - } - - set(key: K, value: V) { - return this._items.set(key, value); - } - - get(key: K) { - return this._items.get(key); - } - - has(key: K) { - return this._items.has(key); - } - - delete(key: K) { - return this._items.delete(key); - } - - keys() { - return Array.from(this._items.entries()).map(([key]) => key); - } - - forEach(callback: (tests: V, key: K, map: Map) => void, thisArg?: any) { - this._items.forEach(callback, thisArg); - } - - toJSON() { - return this._items; - } - - * [Symbol.iterator](): Generator<[K, V], void, unknown> { - for (const item of this._items.entries()) { - yield item; - } - } -} - -export class TestDefinitions extends Base { - protected _items = new Map(); -} - -export class Files extends Base> { - protected _items = new Map>(); -} - -export class Workspace extends Base> { - protected _items = new Map>(); -} - export class TestCollection { - private readonly _workspaces: Workspace; + private suites = new Map>>(); - constructor(private phpUnitXML: PHPUnitXML) { - this._workspaces = new Workspace; - } + constructor(private phpUnitXML: PHPUnitXML) {} get size() { - return this._workspaces.size; + return this.suites.size; } getWorkspace() { @@ -85,13 +25,17 @@ export class TestCollection { items() { const workspace = this.getWorkspace(); - if (!this._workspaces.has(workspace.fsPath)) { - const files = new Files; - this.phpUnitXML.getTestSuites().forEach((suite) => files.set(suite.name, new TestDefinitions())); - this._workspaces.set(workspace.fsPath, files); + if (!this.suites.has(workspace.fsPath)) { + const testsuites = new Map>(); + this.phpUnitXML + .getTestSuites() + .forEach((suite) => + testsuites.set(suite.name, new Map()), + ); + this.suites.set(workspace.fsPath, testsuites); } - return this._workspaces.get(workspace.fsPath)!; + return this.suites.get(workspace.fsPath)!; } async add(uri: URI) { @@ -109,7 +53,7 @@ export class TestCollection { if (testDefinitions.length === 0) { this.delete(uri); } - files.get(testsuite)!.set(uri, testDefinitions); + files.get(testsuite)?.set(uri.toString(), testDefinitions); return this; } @@ -132,7 +76,7 @@ export class TestCollection { for (const file of this.gatherFiles()) { this.deleteFile(file); } - this._workspaces.delete(this.getWorkspace().fsPath); + this.suites.delete(this.getWorkspace().fsPath); return this; } @@ -156,26 +100,26 @@ export class TestCollection { protected createTestParser() { const testParser = new TestParser(this.phpUnitXML); - const testDefinitionBuilder = new TestDefinitionBuilder(testParser); + const testDefinitionBuilder = new TestDefinitionCollector(testParser); return { testParser, testDefinitionBuilder }; } protected deleteFile(file: File) { - return this.items().get(file.testsuite)?.delete(file.uri); + return this.items().get(file.testsuite)?.delete(file.uri.toString()); } - private* gatherFiles() { + private *gatherFiles() { for (const [testsuite, files] of this.items()) { - for (const [uri, tests] of files) { - yield { testsuite, uri, tests }; + for (const [uriStr, tests] of files) { + yield { testsuite, uri: URI.parse(uriStr), tests }; } } } private parseTestsuite(uri: URI) { const testSuites = this.phpUnitXML.getTestSuites(); - const testsuite = testSuites.find(item => { + const testsuite = testSuites.find((item) => { return ['directory', 'file'].includes(item.tag) && this.match(item, uri); }); @@ -196,7 +140,8 @@ export class TestCollection { private match(testSuite: TestSuite, uri: URI) { const workspace = this.getWorkspace(); - const isFile = testSuite.tag === 'file' || (testSuite.tag === 'exclude' && extname(testSuite.value)); + const isFile = + testSuite.tag === 'file' || (testSuite.tag === 'exclude' && extname(testSuite.value)); if (isFile) { return join(workspace.fsPath, testSuite.value) === uri.fsPath; @@ -212,4 +157,3 @@ export class TestCollection { return minimatch.match(uri.toString(true)); } } - diff --git a/src/PHPUnit/TestCollection/TestDefinitionBuilder.ts b/src/PHPUnit/TestCollection/TestDefinitionBuilder.ts deleted file mode 100644 index 611816c6..00000000 --- a/src/PHPUnit/TestCollection/TestDefinitionBuilder.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { TestParser } from '../TestParser'; -import { TestDefinition, TestType } from '../types'; - -export class TestDefinitionBuilder { - private readonly testDefinitions: TestDefinition[] = []; - - constructor(private testParser: TestParser) { - this.onInit(); - } - - onInit() { - this.testParser.on(TestType.method, (testDefinition) => this.testDefinitions.push(testDefinition)); - this.testParser.on(TestType.describe, (testDefinition) => this.testDefinitions.push(testDefinition)); - this.testParser.on(TestType.class, (testDefinition) => this.testDefinitions.push(testDefinition)); - this.testParser.on(TestType.namespace, (testDefinition) => this.testDefinitions.push(testDefinition)); - } - - get() { - return this.testDefinitions; - } -} \ No newline at end of file diff --git a/src/PHPUnit/TestCollection/TestDefinitionCollector.ts b/src/PHPUnit/TestCollection/TestDefinitionCollector.ts new file mode 100644 index 00000000..eebdb70d --- /dev/null +++ b/src/PHPUnit/TestCollection/TestDefinitionCollector.ts @@ -0,0 +1,29 @@ +import type { TestParser } from '../TestParser'; +import { type TestDefinition, TestType } from '../types'; + +export class TestDefinitionCollector { + private readonly testDefinitions: TestDefinition[] = []; + + constructor(private testParser: TestParser) { + this.onInit(); + } + + onInit() { + this.testParser.on(TestType.method, (testDefinition) => + this.testDefinitions.push(testDefinition), + ); + this.testParser.on(TestType.describe, (testDefinition) => + this.testDefinitions.push(testDefinition), + ); + this.testParser.on(TestType.class, (testDefinition) => + this.testDefinitions.push(testDefinition), + ); + this.testParser.on(TestType.namespace, (testDefinition) => + this.testDefinitions.push(testDefinition), + ); + } + + get() { + return this.testDefinitions; + } +} diff --git a/src/PHPUnit/TestCollection/index.ts b/src/PHPUnit/TestCollection/index.ts index 540e4bef..f6043ba4 100644 --- a/src/PHPUnit/TestCollection/index.ts +++ b/src/PHPUnit/TestCollection/index.ts @@ -1,2 +1,2 @@ export * from './TestCollection'; -export * from './TestDefinitionBuilder'; \ No newline at end of file +export * from './TestDefinitionCollector'; diff --git a/src/PHPUnit/TestGlobPattern.ts b/src/PHPUnit/TestGlobPattern.ts new file mode 100644 index 00000000..b8c11309 --- /dev/null +++ b/src/PHPUnit/TestGlobPattern.ts @@ -0,0 +1,49 @@ +import { join, normalize, relative } from 'node:path'; +import { URI } from 'vscode-uri'; +import type { TestSuite } from './PHPUnitXML'; + +export class TestGlobPattern { + private readonly relativePath: string; + + constructor( + private root: string, + private testPath: string, + private items: string[] = [], + ) { + this.relativePath = TestGlobPattern.normalizePath(relative(this.root, this.testPath)); + } + + private static normalizePath(...paths: string[]) { + return normalize(paths.join('/')).replace(/\\|\/+/g, '/'); + } + + push(item: TestSuite, extension: string = '') { + const args = [this.relativePath, item.value]; + if (item.tag !== 'file') { + args.push(`**/*${item.suffix ?? extension}`); + } + + this.items.push(TestGlobPattern.normalizePath(...args)); + } + + toGlobPattern() { + const arrayUnique = (items: (string | undefined)[]) => Array.from(new Set(items)); + const dirs = arrayUnique( + this.items.map((item) => { + return /^\*/.test(item) ? undefined : item.substring(0, item.indexOf('/')); + }), + ); + + const legalDirs = dirs.filter((value) => !!value); + const isSingle = dirs.length === 1 && legalDirs.length === 1; + if (!isSingle) { + return { uri: URI.file(this.root), pattern: `{${this.items}}` }; + } + + const dir = legalDirs[0]; + const items = this.items.map((item) => item.replace(new RegExp(`^${dir}[\\/]?`), '')); + const pattern = `{${items}}`; + + return { uri: URI.file(join(this.root, dir!)), pattern }; + } +} diff --git a/src/PHPUnit/TestParser/AnnotationParser.ts b/src/PHPUnit/TestParser/AnnotationParser.ts index ff3103f9..a9a012f4 100644 --- a/src/PHPUnit/TestParser/AnnotationParser.ts +++ b/src/PHPUnit/TestParser/AnnotationParser.ts @@ -1,50 +1,8 @@ -import { Declaration, Method } from 'php-parser'; -import { Annotations } from '../types'; +import type { Declaration, Method } from 'php-parser'; +import type { Annotations } from '../types'; +import { lookup } from './AttributeParser'; -const lookup = ['depends', 'dataProvider', 'testdox', 'group']; - -export class AttributeParser { - public parse(declaration: Declaration) { - const attributes = this.parseAttributes(declaration); - const annotations = {} as Annotations; - - for (const property of lookup) { - const values = attributes - .filter((attribute: any) => new RegExp(property, 'i').test(attribute.name)) - .map((attribute: any) => attribute.args[0]); - - if (values.length > 0) { - annotations[property] = values; - } - } - - return annotations; - } - - public isTest(method: Method) { - return !method.attrGroups - ? false - : this.parseAttributes(method).some((attribute: any) => attribute.name === 'Test'); - } - - private parseAttributes(declaration: any): any[] { - if (!declaration.hasOwnProperty('attrGroups')) { - return []; - } - - return declaration.attrGroups.reduce((attributes: any[], group: any) => { - return [ - ...attributes, - ...group.attrs.map((attr: any) => { - return { - name: attr.name, - args: attr.args.map((arg: any) => arg.value), - }; - }), - ]; - }, []); - } -} +export { AttributeParser } from './AttributeParser'; export class AnnotationParser { public parse(declaration: Declaration): Annotations { @@ -54,9 +12,7 @@ export class AnnotationParser { public isTest(method: Method) { return !method.leadingComments ? false - : new RegExp('@test').test( - method.leadingComments.map((comment) => comment.value).join('\n'), - ); + : /@test/.test(method.leadingComments.map((comment) => comment.value).join('\n')); } private readonly template = (annotation: string) => @@ -75,13 +31,16 @@ export class AnnotationParser { .reduce((result, matches) => this.append(result, matches), {} as Annotations); } - private append(annotations: Annotations | any, matches: IterableIterator) { - for (let match of matches) { - const groups = match!.groups; + private append(annotations: Annotations, matches: IterableIterator) { + for (const match of matches) { + const groups = match?.groups; for (const property in groups) { const value = groups[property]; if (value) { - annotations[property] = [...(annotations[property] ?? []), value.trim()]; + annotations[property] = [ + ...((annotations[property] as unknown[] | undefined) ?? []), + value.replace(/\s*\*\/\s*$/, '').trim(), + ]; } } } @@ -89,5 +48,3 @@ export class AnnotationParser { return annotations; } } - - diff --git a/src/PHPUnit/TestParser/AttributeParser.ts b/src/PHPUnit/TestParser/AttributeParser.ts new file mode 100644 index 00000000..fd2d1715 --- /dev/null +++ b/src/PHPUnit/TestParser/AttributeParser.ts @@ -0,0 +1,59 @@ +import type { AttrGroup, Attribute, Declaration, Method } from 'php-parser'; +import type { Annotations } from '../types'; + +export const lookup = ['depends', 'dataProvider', 'testdox', 'group']; + +interface ParsedAttribute { + name: string; + args: unknown[]; +} + +export class AttributeParser { + public parse(declaration: Declaration) { + const attributes = this.parseAttributes(declaration); + const annotations = {} as Annotations; + + for (const property of lookup) { + const values = attributes + .filter((attribute: ParsedAttribute) => + new RegExp(property, 'i').test(attribute.name), + ) + .map((attribute: ParsedAttribute) => attribute.args[0]); + + if (values.length > 0) { + annotations[property] = values; + } + } + + return annotations; + } + + public isTest(method: Method) { + return !method.attrGroups + ? false + : this.parseAttributes(method).some( + (attribute: ParsedAttribute) => attribute.name === 'Test', + ); + } + + private parseAttributes(declaration: Declaration): ParsedAttribute[] { + if (!('attrGroups' in declaration)) { + return []; + } + + return (declaration.attrGroups as AttrGroup[]).reduce( + (attributes: ParsedAttribute[], group: AttrGroup) => { + return [ + ...attributes, + ...group.attrs.map((attr: Attribute) => { + return { + name: attr.name, + args: attr.args.map((arg: { value?: unknown }) => arg.value), + }; + }), + ]; + }, + [], + ); + } +} diff --git a/src/PHPUnit/TestParser/PHPDefinition.ts b/src/PHPUnit/TestParser/PHPDefinition.ts deleted file mode 100644 index 9ab4fa92..00000000 --- a/src/PHPUnit/TestParser/PHPDefinition.ts +++ /dev/null @@ -1,443 +0,0 @@ -import { basename, dirname, join, relative } from 'node:path'; -import { Declaration, Identifier, Name, Namespace, Node, PropertyLookup } from 'php-parser'; -import { PHPUnitXML } from '../PHPUnitXML'; -import { Transformer, TransformerFactory } from '../Transformer'; -import { TestDefinition, TestType } from '../types'; -import { capitalize } from '../utils'; -import { AnnotationParser, AttributeParser } from './AnnotationParser'; - -type AST = Node & { - name?: Identifier | string, - visibility?: string, - isAbstract?: boolean, - body?: Node[], - children?: Node[], - expression?: AST - what?: (Name | PropertyLookup) & { offset?: Identifier }, - arguments?: AST[], - value?: string; -} - -export const annotationParser = new AnnotationParser(); -export const attributeParser = new AttributeParser(); - -abstract class TestDefinitionBuilder { - constructor(protected definition: PHPDefinition) { - } - - abstract build(): TestDefinition; - - protected generate(testDefinition: Partial) { - testDefinition = { - type: this.definition.type, - classFQN: this.definition.classFQN, - children: [], - annotations: this.definition.annotations, - file: this.definition.file, - ...this.definition.position, - ...testDefinition, - }; - const transformer = this.getTransformer(testDefinition); - testDefinition.id = transformer.uniqueId(testDefinition as TestDefinition); - testDefinition.label = transformer.generateLabel(testDefinition as TestDefinition); - - return testDefinition as TestDefinition; - } - - private getTransformer(testDefinition: Pick): Transformer { - return TransformerFactory.factory(testDefinition.classFQN!); - } -} - -class NamespaceDefinitionBuilder extends TestDefinitionBuilder { - build() { - const type = TestType.namespace; - const depth = 0; - - const classFQN = this.definition.classFQN; - if (this.definition.kind === 'program') { - const partsFQN = classFQN!.split('\\'); - const namespace = partsFQN.slice(0, -1).join('\\'); - - return this.generate({ type, depth, namespace, classFQN: namespace }); - } - - if (this.definition.kind === 'class') { - const partsFQN = classFQN!.split('\\'); - const className = partsFQN.pop()!; - const namespace = partsFQN.join('\\'); - - return this.generate({ type, depth, namespace, classFQN: namespace, className }); - } - - return this.generate({ type, depth, namespace: classFQN, classFQN }); - } -} - -class TestSuiteDefinitionBuilder extends TestDefinitionBuilder { - build() { - return this.generate({ - namespace: this.definition.parent?.name, - className: this.definition.name, - depth: 1, - }); - } -} - -class TestCaseDefinitionBuilder extends TestDefinitionBuilder { - build() { - return this.generate({ - namespace: this.definition.parent!.parent?.name, - className: this.definition.parent!.name, - methodName: this.definition.name, - depth: 2, - }); - } -} - -class PestTestDefinitionBuilder extends TestDefinitionBuilder { - build() { - if (this.definition.kind === 'program') { - const classFQN = this.definition.classFQN!; - const partsFQN = classFQN.split('\\'); - const className = partsFQN.pop()!; - - return this.generate({ namespace: partsFQN.join('\\'), className, depth: 1 }); - } - - let depth = 2; - - let { methodName, label } = this.parseMethodNameAndLabel(); - - if (this.definition.type === TestType.describe) { - methodName = '`' + methodName + '`'; - } - - let parent = this.definition.parent; - while (parent && parent.kind === 'call' && parent.type !== TestType.describe) { - parent = parent.parent; - } - - if (parent?.type === TestType.describe) { - const describeNames: string[] = []; - while (parent && parent.type === TestType.describe) { - describeNames.push('`' + parent.arguments[0].name + '`'); - parent = parent.parent; - depth++; - } - methodName = describeNames.reverse().concat(methodName).join(' → '); - } - - const { classFQN, namespace, className } = parent!.toTestDefinition(); - - return this.generate({ classFQN, namespace, className, methodName, label, depth }); - } - - private parseMethodNameAndLabel() { - const args = this.definition.arguments; - - if (this.definition.name !== 'arch') { - let methodName = args[0].name; - - if (this.definition.name === 'it') { - methodName = 'it ' + methodName; - } - - return { methodName, label: methodName }; - } - - if (args.length > 0) { - const methodName = args[0].name; - - return { methodName, label: methodName }; - } - - const names = [] as string[]; - let parent = this.definition.parent; - while (parent && parent.kind === 'call') { - names.push(parent.name); - parent = parent.parent; - } - - const methodName = names - .map((name: string) => name === 'preset' ? `${name} ` : ` ${name} `) - .join('→'); - - const label = names.join(' → '); - - return { methodName, label }; - } -} - -export class PHPDefinition { - constructor(private readonly ast: AST, private options: { - phpUnitXML: PHPUnitXML, - file: string, - namespace?: PHPDefinition, - parent?: PHPDefinition, - }) { - } - - get kind() { - return this.ast.kind; - } - - get file() { - return this.options.file; - } - - get root() { - return this.options.phpUnitXML.root(); - } - - get type() { - if (this.kind === 'namespace') { - return TestType.namespace; - } - - if (['program', 'class'].includes(this.kind)) { - return TestType.class; - } - - if (this.kind === 'method') { - return TestType.method; - } - - if (this.kind === 'call') { - return this.name === 'describe' ? TestType.describe : TestType.method; - } - - return undefined; - } - - get classFQN(): string | undefined { - if (this.kind === 'program') { - let relativePath = relative(this.root, this.file); - let baseName = basename(this.file, '.php'); - const dotPos = baseName.lastIndexOf('.'); - if (dotPos !== -1) { - baseName = baseName.substring(0, dotPos); - } - relativePath = join(capitalize(dirname(relativePath)), baseName).replace(/\//g, '\\'); - relativePath = relativePath.replace(/%[a-fA-F0-9][a-fA-F0-9]/g, ''); - relativePath = relativePath.replace(/\\'|\\"/g, ''); - relativePath = relativePath.replace(/[^A-Za-z0-9\\]/, ''); - - return 'P\\' + relativePath; - } - - if (this.kind === 'namespace') { - return this.name; - } - - if (this.kind === 'class') { - return [this.parent?.name, this.name].filter((name) => !!name).join('\\'); - } - - return this.parent?.classFQN; - } - - get parent() { - return this.options.parent!; - } - - get children() { - if (this.kind === 'namespace') { - return this.getClasses(); - } - - if (this.kind === 'class') { - return this.getMethods(); - } - - return undefined; - } - - get arguments() { - return this.ast.arguments?.map((ast: AST) => { - return new PHPDefinition(ast, { ...this.options, parent: this }); - }) ?? []; - } - - get name(): string { - if (this.ast.kind === 'namedargument') { - if ((this.ast.value as any).kind === 'string') { - return (this.ast.value as any).value; - } - } - - if (typeof this.ast.name === 'string') { - return this.ast.name; - } - - if (this.ast.name?.name) { - return this.ast.name?.name; - } - - - if (this.ast.what) { - if (this.ast.what.offset && this.ast.what.offset.kind === 'identifier') { - return this.ast.what.offset.name; - } - - return (this.ast.what as Name).name; - } - - if (this.ast.kind === 'string') { - return this.ast.value!; - } - - return ''; - } - - get annotations() { - return { - ...annotationParser.parse(this.ast as Declaration), - ...attributeParser.parse(this.ast as Declaration), - }; - } - - get position() { - const loc = this.ast.loc!; - const start = { line: loc.start.line, character: loc.start.column }; - const end = { line: loc.end.line, character: loc.end.column }; - - return { start, end }; - } - - getClasses() { - const definitions: PHPDefinition[] = this.kind !== 'program' - ? [] - : this.getNamespaces().reduce((definitions, definition: PHPDefinition) => { - return definitions.concat(definition.getClasses()); - }, [] as PHPDefinition[]); - - const options = { ...this.options }; - if (this.kind === 'namespace') { - options.parent = this; - } - - return definitions.concat((this.ast.children ?? []) - .map((node: Node) => new PHPDefinition(node, options)) - .filter((definition: PHPDefinition) => definition.kind === 'class')); - } - - getFunctions(): PHPDefinition[] { - const args = this.arguments; - - if (this.type === TestType.describe) { - return args[1].getFunctions(); - } - - if (args.length > 1 && args[1].kind === 'namedargument') { - return args[1].getFunctions(); - } - - if (args.length > 1 && args[1].kind === 'arrowfunc') { - return [new PHPDefinition(this.ast, this.options)]; - } - - if (['closure', 'arrowfunc'].includes(this.kind) && this.ast.body) { - return new PHPDefinition(this.ast.body as any, this.options).getFunctions(); - } - - if (this.kind === 'namedargument') { - return new PHPDefinition((this.ast.value as any).body, this.options).getFunctions(); - } - - return (this.ast.children ?? []) - .reduce((children: AST[], node) => { - return children.concat(node.kind === 'namespace' ? (node as Namespace).children : [node]); - }, []) - .reduce((definitions, node: AST) => { - if (!(node.kind === 'expressionstatement' && (node.expression as any).kind !== 'include')) { - return definitions; - } - - const parent = ['block'].includes(this.kind) ? this.parent : this; - let options = { ...this.options, parent }; - - let ast = node.expression as AST; - while (ast.what) { - if (ast.what.kind === 'name') { - break; - } - if (ast.kind === 'call') { - options.parent = new PHPDefinition(ast, { ...options }); - } - ast = ast.what as AST; - } - - return definitions.concat(new PHPDefinition(ast, options)); - }, [] as PHPDefinition[]); - } - - isTest() { - if (this.ast.isAbstract) { - return false; - } - - if (this.kind === 'class') { - return this.name.endsWith('Test') && this.children!.some((definition): boolean => definition.isTest()); - } - - if (this.kind === 'method' && this.acceptModifier()) { - return this.name.startsWith('test') || - annotationParser.isTest(this.ast as any) || - attributeParser.isTest(this.ast as any); - } - - if (this.kind === 'call') { - return ['it', 'test', 'describe', 'arch'].includes(this.name); - } - - return false; - } - - toTestDefinition(): TestDefinition { - if (this.kind === 'class') { - return new TestSuiteDefinitionBuilder(this).build(); - } - - if (this.kind === 'method') { - return new TestCaseDefinitionBuilder(this).build(); - } - - return new PestTestDefinitionBuilder(this).build(); - } - - createNamespaceTestDefinition(): TestDefinition { - return new NamespaceDefinitionBuilder(this).build(); - } - - private getMethods(): PHPDefinition[] { - if (['program', 'namespace'].includes(this.ast.kind)) { - return this.getClasses().reduce((definitions: PHPDefinition[], definition: PHPDefinition) => { - return definitions.concat(definition.getMethods()); - }, []); - } - - const options = { ...this.options }; - if (this.kind === 'class') { - options.parent = this; - } - - return (this.ast.body ?? []) - .map((node: Node) => new PHPDefinition(node, options)) - .filter((definition: PHPDefinition) => definition.kind === 'method'); - } - - private getNamespaces() { - if (this.kind !== 'program') { - return []; - } - - return (this.ast.children ?? []) - .map((node: Node) => new PHPDefinition(node, this.options)) - .filter((definition: PHPDefinition) => definition.kind === 'namespace'); - } - - private acceptModifier() { - return ['', 'public'].includes(this.ast.visibility!); - } -} \ No newline at end of file diff --git a/src/PHPUnit/TestParser/PHPUnitParser.test.ts b/src/PHPUnit/TestParser/PHPUnitParser.test.ts index 46ff0655..8fd07ad7 100644 --- a/src/PHPUnit/TestParser/PHPUnitParser.test.ts +++ b/src/PHPUnit/TestParser/PHPUnitParser.test.ts @@ -1,41 +1,12 @@ -import { readFile } from 'fs/promises'; -import { phpUnitProject } from '../__tests__/utils'; -import { PHPUnitXML } from '../PHPUnitXML'; -import { TestDefinition, TestType } from '../types'; -import { TestParser } from './TestParser'; - -export const parse = (buffer: Buffer | string, file: string) => { - const tests: TestDefinition[] = []; - const phpUnitXML = new PHPUnitXML(); - phpUnitXML.setRoot(phpUnitProject('')); - const testParser = new TestParser(phpUnitXML); - testParser.on(TestType.namespace, (testDefinition: TestDefinition) => tests.push(testDefinition)); - testParser.on(TestType.class, (testDefinition: TestDefinition) => tests.push(testDefinition)); - testParser.on(TestType.method, (testDefinition: TestDefinition) => tests.push(testDefinition)); - testParser.parse(buffer, file); - - return tests; -}; +import { readFile } from 'node:fs/promises'; +import { beforeAll, describe, expect, it } from 'vitest'; +import { findTest, parseTestFile, phpUnitProject } from '../__tests__/utils'; +import { type TestDefinition, TestType } from '../types'; -describe('PHPUnitParser Test', () => { - const findTest = (tests: TestDefinition[], id: string) => { - const lookup = { - [TestType.method]: (test: TestDefinition) => test.methodName === id, - [TestType.class]: (test: TestDefinition) => test.className === id && !test.methodName, - [TestType.namespace]: (test: TestDefinition) => test.classFQN === id && !test.className && !test.methodName, - } as { [key: string]: Function }; - - for (const [, fn] of Object.entries(lookup)) { - const test = tests.find((test: TestDefinition) => fn(test)); - - if (test) { - return test; - } - } - - return undefined; - }; +export const parse = (buffer: Buffer | string, file: string) => + parseTestFile(buffer, file, phpUnitProject('')); +describe('PHPUnitParser Test', () => { const givenTest = (file: string, content: string, id: string) => { return findTest(parse(content, file), id); }; @@ -43,176 +14,200 @@ describe('PHPUnitParser Test', () => { describe('AssertionsTest', () => { const file = phpUnitProject('tests/AssertionsTest.php'); let content: string; - beforeAll(async () => content = (await readFile(file)).toString()); + beforeAll(async () => (content = (await readFile(file)).toString())); it('parse namespace', () => { - expect(givenTest(file, content, 'Tests')).toEqual(expect.objectContaining({ - type: TestType.namespace, - // file, - id: 'namespace:Tests', - classFQN: 'Tests', - namespace: 'Tests', - depth: 0, - })); + expect(givenTest(file, content, 'Tests')).toEqual( + expect.objectContaining({ + type: TestType.namespace, + // file, + id: 'namespace:Tests', + classFQN: 'Tests', + namespace: 'Tests', + depth: 0, + }), + ); }); it('parse class', () => { - expect(givenTest(file, content, 'AssertionsTest')).toEqual(expect.objectContaining({ - type: TestType.class, - file, - id: 'Assertions (Tests\\Assertions)', - classFQN: 'Tests\\AssertionsTest', - namespace: 'Tests', - className: 'AssertionsTest', - start: { line: 8, character: 0 }, - end: { line: 83, character: 1 }, - depth: 1, - })); + expect(givenTest(file, content, 'AssertionsTest')).toEqual( + expect.objectContaining({ + type: TestType.class, + file, + id: 'Assertions (Tests\\Assertions)', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', + className: 'AssertionsTest', + start: { line: 9, character: 0 }, + end: { line: 89, character: 1 }, + depth: 1, + }), + ); }); it('it should parse test_passed', () => { - expect(givenTest(file, content, 'test_passed')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Assertions (Tests\\Assertions)::Passed', - classFQN: 'Tests\\AssertionsTest', - namespace: 'Tests', - className: 'AssertionsTest', - methodName: 'test_passed', - start: { line: 12, character: 4 }, - end: { line: 15, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'test_passed')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Assertions (Tests\\Assertions)::Passed', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', + className: 'AssertionsTest', + methodName: 'test_passed', + annotations: { group: ['integration'] }, + start: { line: 16, character: 4 }, + end: { line: 19, character: 5 }, + depth: 2, + }), + ); }); it('it should parse test_failed', () => { - expect(givenTest(file, content, 'test_failed')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Assertions (Tests\\Assertions)::Failed', - classFQN: 'Tests\\AssertionsTest', - namespace: 'Tests', - className: 'AssertionsTest', - methodName: 'test_failed', - annotations: { depends: ['test_passed'] }, - start: { line: 20, character: 4 }, - end: { line: 23, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'test_failed')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Assertions (Tests\\Assertions)::Failed', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', + className: 'AssertionsTest', + methodName: 'test_failed', + annotations: { depends: ['test_passed'], group: ['integration'] }, + start: { line: 25, character: 4 }, + end: { line: 28, character: 5 }, + depth: 2, + }), + ); }); it('it should parse test_is_not_same', () => { - expect(givenTest(file, content, 'test_is_not_same')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Assertions (Tests\\Assertions)::Is not same', - classFQN: 'Tests\\AssertionsTest', - namespace: 'Tests', - className: 'AssertionsTest', - methodName: 'test_is_not_same', - start: { line: 25, character: 4 }, - end: { line: 28, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'test_is_not_same')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Assertions (Tests\\Assertions)::Is not same', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', + className: 'AssertionsTest', + methodName: 'test_is_not_same', + start: { line: 30, character: 4 }, + end: { line: 33, character: 5 }, + depth: 2, + }), + ); }); it('it should parse test_risky', () => { - expect(givenTest(file, content, 'test_risky')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Assertions (Tests\\Assertions)::Risky', - classFQN: 'Tests\\AssertionsTest', - namespace: 'Tests', - className: 'AssertionsTest', - methodName: 'test_risky', - start: { line: 30, character: 4 }, - end: { line: 33, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'test_risky')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Assertions (Tests\\Assertions)::Risky', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', + className: 'AssertionsTest', + methodName: 'test_risky', + start: { line: 35, character: 4 }, + end: { line: 38, character: 5 }, + depth: 2, + }), + ); }); it('it should parse annotation_test', () => { - expect(givenTest(file, content, 'annotation_test')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Assertions (Tests\\Assertions)::Annotation test', - classFQN: 'Tests\\AssertionsTest', - namespace: 'Tests', - className: 'AssertionsTest', - methodName: 'annotation_test', - start: { line: 38, character: 4 }, - end: { line: 41, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'annotation_test')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Assertions (Tests\\Assertions)::Annotation test', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', + className: 'AssertionsTest', + methodName: 'annotation_test', + annotations: { group: ['integration'] }, + start: { line: 44, character: 4 }, + end: { line: 47, character: 5 }, + depth: 2, + }), + ); }); it('it should parse test_skipped', () => { - expect(givenTest(file, content, 'test_skipped')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Assertions (Tests\\Assertions)::Skipped', - classFQN: 'Tests\\AssertionsTest', - namespace: 'Tests', - className: 'AssertionsTest', - methodName: 'test_skipped', - start: { line: 43, character: 4 }, - end: { line: 46, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'test_skipped')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Assertions (Tests\\Assertions)::Skipped', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', + className: 'AssertionsTest', + methodName: 'test_skipped', + start: { line: 49, character: 4 }, + end: { line: 52, character: 5 }, + depth: 2, + }), + ); }); it('it should parse test_incomplete', () => { - expect(givenTest(file, content, 'test_incomplete')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Assertions (Tests\\Assertions)::Incomplete', - classFQN: 'Tests\\AssertionsTest', - namespace: 'Tests', - className: 'AssertionsTest', - methodName: 'test_incomplete', - start: { line: 48, character: 4 }, - end: { line: 51, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'test_incomplete')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Assertions (Tests\\Assertions)::Incomplete', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', + className: 'AssertionsTest', + methodName: 'test_incomplete', + start: { line: 54, character: 4 }, + end: { line: 57, character: 5 }, + depth: 2, + }), + ); }); it('it should parse addition_provider', () => { - expect(givenTest(file, content, 'addition_provider')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Assertions (Tests\\Assertions)::Addition provider', - classFQN: 'Tests\\AssertionsTest', - namespace: 'Tests', - className: 'AssertionsTest', - methodName: 'addition_provider', - annotations: { dataProvider: ['additionProvider'], depends: ['test_passed'] }, - start: { line: 60, character: 4 }, - end: { line: 63, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'addition_provider')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Assertions (Tests\\Assertions)::Addition provider', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', + className: 'AssertionsTest', + methodName: 'addition_provider', + annotations: { dataProvider: ['additionProvider'], depends: ['test_passed'] }, + start: { line: 66, character: 4 }, + end: { line: 69, character: 5 }, + depth: 2, + }), + ); }); it('it should parse testdox annotation', () => { - expect(givenTest(file, content, 'balanceIsInitiallyZero')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Assertions (Tests\\Assertions)::Balance is initially zero', - classFQN: 'Tests\\AssertionsTest', - namespace: 'Tests', - className: 'AssertionsTest', - methodName: 'balanceIsInitiallyZero', - annotations: { testdox: ['has an initial balance of zero'] }, - start: { line: 79, character: 4 }, - end: { line: 82, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'balanceIsInitiallyZero')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Assertions (Tests\\Assertions)::Balance is initially zero', + classFQN: 'Tests\\AssertionsTest', + namespace: 'Tests', + className: 'AssertionsTest', + methodName: 'balanceIsInitiallyZero', + annotations: { testdox: ['has an initial balance of zero'] }, + start: { line: 85, character: 4 }, + end: { line: 88, character: 5 }, + depth: 2, + }), + ); }); }); describe('parse AbstractTest', () => { const file = phpUnitProject('tests/AbstractTest.php'); let content: string; - beforeAll(async () => content = (await readFile(file)).toString()); + beforeAll(async () => (content = (await readFile(file)).toString())); it('it should not parse abstract class', () => { expect(parse(content, file)).toHaveLength(0); @@ -222,182 +217,217 @@ describe('PHPUnitParser Test', () => { describe('parse StaticMethodTest', () => { const file = phpUnitProject('tests/StaticMethodTest.php'); let content: string; - beforeAll(async () => content = (await readFile(file)).toString()); + beforeAll(async () => (content = (await readFile(file)).toString())); it('StaticMethodTest should has 3 tests', () => { expect(parse(content, file)).toHaveLength(3); }); it('it should parse test_static_public_fail', () => { - expect(givenTest(file, content, 'test_static_public_fail')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Static Method (Tests\\StaticMethod)::Static public fail', - classFQN: 'Tests\\StaticMethodTest', - namespace: 'Tests', - className: 'StaticMethodTest', - methodName: 'test_static_public_fail', - start: { line: 9, character: 4 }, - end: { line: 11, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'test_static_public_fail')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Static Method (Tests\\StaticMethod)::Static public fail', + classFQN: 'Tests\\StaticMethodTest', + namespace: 'Tests', + className: 'StaticMethodTest', + methodName: 'test_static_public_fail', + start: { line: 9, character: 4 }, + end: { line: 11, character: 5 }, + depth: 2, + }), + ); }); }); describe('parse HasPropertyTest', () => { const file = phpUnitProject('tests/SubFolder/HasPropertyTest.php'); let content: string; - beforeAll(async () => content = (await readFile(file)).toString()); + beforeAll(async () => (content = (await readFile(file)).toString())); it('HasPropertyTest should has 3 tests', () => { expect(parse(content, file)).toHaveLength(3); }); it('it should parse property', () => { - expect(givenTest(file, content, 'property')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Has Property (Tests\\SubFolder\\HasProperty)::Property', - classFQN: 'Tests\\SubFolder\\HasPropertyTest', - namespace: 'Tests\\SubFolder', - className: 'HasPropertyTest', - methodName: 'property', - start: { line: 17, character: 4 }, - end: { line: 20, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'property')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Has Property (Tests\\SubFolder\\HasProperty)::Property', + classFQN: 'Tests\\SubFolder\\HasPropertyTest', + namespace: 'Tests\\SubFolder', + className: 'HasPropertyTest', + methodName: 'property', + start: { line: 17, character: 4 }, + end: { line: 20, character: 5 }, + depth: 2, + }), + ); }); }); describe('parse LeadingCommentsTest', () => { const file = phpUnitProject('tests/SubFolder/LeadingCommentsTest.php'); let content: string; - beforeAll(async () => content = (await readFile(file)).toString()); + beforeAll(async () => (content = (await readFile(file)).toString())); it('it should parse firstLeadingComments', () => { - expect(givenTest(file, content, 'firstLeadingComments')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Leading Comments (Tests\\SubFolder\\LeadingComments)::First leading comments', - classFQN: 'Tests\\SubFolder\\LeadingCommentsTest', - namespace: 'Tests\\SubFolder', - className: 'LeadingCommentsTest', - methodName: 'firstLeadingComments', - start: { line: 10, character: 4 }, - end: { line: 13, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'firstLeadingComments')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Leading Comments (Tests\\SubFolder\\LeadingComments)::First leading comments', + classFQN: 'Tests\\SubFolder\\LeadingCommentsTest', + namespace: 'Tests\\SubFolder', + className: 'LeadingCommentsTest', + methodName: 'firstLeadingComments', + start: { line: 10, character: 4 }, + end: { line: 13, character: 5 }, + depth: 2, + }), + ); }); }); describe('parse UseTraitTest', () => { const file = phpUnitProject('tests/SubFolder/UseTraitTest.php'); let content: string; - beforeAll(async () => content = (await readFile(file)).toString()); + beforeAll(async () => (content = (await readFile(file)).toString())); it('it should parse use_trait', () => { - expect(givenTest(file, content, 'use_trait')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Use Trait (Tests\\SubFolder\\UseTrait)::Use trait', - classFQN: 'Tests\\SubFolder\\UseTraitTest', - namespace: 'Tests\\SubFolder', - className: 'UseTraitTest', - methodName: 'use_trait', - start: { line: 12, character: 4 }, - end: { line: 15, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'use_trait')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Use Trait (Tests\\SubFolder\\UseTrait)::Use trait', + classFQN: 'Tests\\SubFolder\\UseTraitTest', + namespace: 'Tests\\SubFolder', + className: 'UseTraitTest', + methodName: 'use_trait', + start: { line: 12, character: 4 }, + end: { line: 15, character: 5 }, + depth: 2, + }), + ); }); }); describe('parse AttributeTest', () => { const file = phpUnitProject('tests/AttributeTest.php'); let content: string; - beforeAll(async () => content = (await readFile(file)).toString()); + beforeAll(async () => (content = (await readFile(file)).toString())); + + it('parse class with Group attribute', () => { + expect(givenTest(file, content, 'AttributeTest')).toEqual( + expect.objectContaining({ + type: TestType.class, + file, + id: 'Attribute (Tests\\Attribute)', + classFQN: 'Tests\\AttributeTest', + namespace: 'Tests', + className: 'AttributeTest', + annotations: { group: ['integration'] }, + start: { line: 13, character: 0 }, + end: { line: 61, character: 1 }, + depth: 1, + }), + ); + }); it('parse Test Attribute', () => { - expect(givenTest(file, content, 'hi')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Attribute (Tests\\Attribute)::Hi', - classFQN: 'Tests\\AttributeTest', - namespace: 'Tests', - className: 'AttributeTest', - methodName: 'hi', - start: { line: 14, character: 4 }, - end: { line: 17, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'hi')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Attribute (Tests\\Attribute)::Hi', + classFQN: 'Tests\\AttributeTest', + namespace: 'Tests', + className: 'AttributeTest', + methodName: 'hi', + start: { line: 16, character: 4 }, + end: { line: 19, character: 5 }, + depth: 2, + }), + ); }); it('parse DataProvider Attribute', () => { - expect(givenTest(file, content, 'testAdd')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Attribute (Tests\\Attribute)::Add', - classFQN: 'Tests\\AttributeTest', - namespace: 'Tests', - className: 'AttributeTest', - methodName: 'testAdd', - annotations: { dataProvider: ['additionProvider'] }, - start: { line: 20, character: 4 }, - end: { line: 23, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'testAdd')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Attribute (Tests\\Attribute)::Add', + classFQN: 'Tests\\AttributeTest', + namespace: 'Tests', + className: 'AttributeTest', + methodName: 'testAdd', + annotations: { dataProvider: ['additionProvider'] }, + start: { line: 22, character: 4 }, + end: { line: 25, character: 5 }, + depth: 2, + }), + ); }); it('parse Depends Attribute', () => { - expect(givenTest(file, content, 'testPush')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Attribute (Tests\\Attribute)::Push', - classFQN: 'Tests\\AttributeTest', - namespace: 'Tests', - className: 'AttributeTest', - methodName: 'testPush', - annotations: { depends: ['testEmpty'] }, - start: { line: 44, character: 4 }, - end: { line: 51, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'testPush')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Attribute (Tests\\Attribute)::Push', + classFQN: 'Tests\\AttributeTest', + namespace: 'Tests', + className: 'AttributeTest', + methodName: 'testPush', + annotations: { depends: ['testEmpty'] }, + start: { line: 46, character: 4 }, + end: { line: 53, character: 5 }, + depth: 2, + }), + ); }); it('parse TestDox Attribute', () => { - expect(givenTest(file, content, 'balanceIsInitiallyZero')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Attribute (Tests\\Attribute)::Balance is initially zero', - classFQN: 'Tests\\AttributeTest', - namespace: 'Tests', - className: 'AttributeTest', - methodName: 'balanceIsInitiallyZero', - annotations: { testdox: ['has an initial balance of zero'] }, - start: { line: 55, character: 4 }, - end: { line: 58, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'balanceIsInitiallyZero')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Attribute (Tests\\Attribute)::Balance is initially zero', + classFQN: 'Tests\\AttributeTest', + namespace: 'Tests', + className: 'AttributeTest', + methodName: 'balanceIsInitiallyZero', + annotations: { testdox: ['has an initial balance of zero'] }, + start: { line: 57, character: 4 }, + end: { line: 60, character: 5 }, + depth: 2, + }), + ); }); }); describe('parse NoNamespaceTest', () => { const file = phpUnitProject('tests/NoNamespaceTest.php'); let content: string; - beforeAll(async () => content = (await readFile(file)).toString()); + beforeAll(async () => (content = (await readFile(file)).toString())); it('parse NoNamespaceTest', () => { - expect(givenTest(file, content, 'test_no_namespace')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'No Namespace::No namespace', - classFQN: 'NoNamespaceTest', - className: 'NoNamespaceTest', - methodName: 'test_no_namespace', - label: 'test_no_namespace', - start: { line: 7, character: 4 }, - end: { line: 10, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'test_no_namespace')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'No Namespace::No namespace', + classFQN: 'NoNamespaceTest', + className: 'NoNamespaceTest', + methodName: 'test_no_namespace', + label: 'test_no_namespace', + start: { line: 7, character: 4 }, + end: { line: 10, character: 5 }, + depth: 2, + }), + ); }); }); @@ -412,17 +442,19 @@ final class PDF_testerTest extends TestCase { } } `; - expect(givenTest(file, content, 'test_hello')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'PDF Tester::Hello', - classFQN: 'PDF_testerTest', - className: 'PDF_testerTest', - methodName: 'test_hello', - start: { line: 5, character: 4 }, - end: { line: 7, character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'test_hello')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'PDF Tester::Hello', + classFQN: 'PDF_testerTest', + className: 'PDF_testerTest', + methodName: 'test_hello', + start: { line: 5, character: 4 }, + end: { line: 7, character: 5 }, + depth: 2, + }), + ); }); it('fix const array problem', () => { @@ -444,17 +476,19 @@ final class ArrayConstTest extends TestCase { } } `; - expect(givenTest(file, content, 'test_hello')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Array Const::Hello', - classFQN: 'ArrayConstTest', - className: 'ArrayConstTest', - methodName: 'test_hello', - start: { line: expect.any(Number), character: 4 }, - end: { line: expect.any(Number), character: 5 }, - depth: 2, - })); + expect(givenTest(file, content, 'test_hello')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Array Const::Hello', + classFQN: 'ArrayConstTest', + className: 'ArrayConstTest', + methodName: 'test_hello', + start: { line: expect.any(Number), character: 4 }, + end: { line: expect.any(Number), character: 5 }, + depth: 2, + }), + ); }); it('ignore annotation string case', () => { @@ -475,19 +509,21 @@ final class TestDoxTest extends TestCase { } } `; - expect(givenTest(file, content, 'testAtTestWith')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Test Dox::At test with', - classFQN: 'TestDoxTest', - className: 'TestDoxTest', - methodName: 'testAtTestWith', - label: 'Do a test', - annotations: { 'testdox': ['Do a test'] }, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 2, - })); + expect(givenTest(file, content, 'testAtTestWith')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Test Dox::At test with', + classFQN: 'TestDoxTest', + className: 'TestDoxTest', + methodName: 'testAtTestWith', + label: 'Do a test', + annotations: { testdox: ['Do a test'] }, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 2, + }), + ); }); it('parse @group annotation', () => { @@ -506,16 +542,18 @@ final class GroupTest extends TestCase { } } `; - expect(givenTest(file, content, 'test_with_groups')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Group::With groups', - classFQN: 'GroupTest', - className: 'GroupTest', - methodName: 'test_with_groups', - annotations: { group: ['integration', 'slow'] }, - depth: 2, - })); + expect(givenTest(file, content, 'test_with_groups')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Group::With groups', + classFQN: 'GroupTest', + className: 'GroupTest', + methodName: 'test_with_groups', + annotations: { group: ['integration', 'slow'] }, + depth: 2, + }), + ); }); it('parse #[Group] attribute', () => { @@ -533,16 +571,18 @@ final class GroupAttributeTest extends TestCase { } } `; - expect(givenTest(file, content, 'test_with_group_attributes')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - id: 'Group Attribute::With group attributes', - classFQN: 'GroupAttributeTest', - className: 'GroupAttributeTest', - methodName: 'test_with_group_attributes', - annotations: { group: ['plaid', 'api'] }, - depth: 2, - })); + expect(givenTest(file, content, 'test_with_group_attributes')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + id: 'Group Attribute::With group attributes', + classFQN: 'GroupAttributeTest', + className: 'GroupAttributeTest', + methodName: 'test_with_group_attributes', + annotations: { group: ['plaid', 'api'] }, + depth: 2, + }), + ); }); it('parse single @group annotation', () => { @@ -560,11 +600,13 @@ final class SingleGroupTest extends TestCase { } } `; - expect(givenTest(file, content, 'test_unit')).toEqual(expect.objectContaining({ - type: TestType.method, - file, - methodName: 'test_unit', - annotations: { group: ['unit'] }, - })); + expect(givenTest(file, content, 'test_unit')).toEqual( + expect.objectContaining({ + type: TestType.method, + file, + methodName: 'test_unit', + annotations: { group: ['unit'] }, + }), + ); }); }); diff --git a/src/PHPUnit/TestParser/PHPUnitParser.ts b/src/PHPUnit/TestParser/PHPUnitParser.ts index 6e7eab23..881c167c 100644 --- a/src/PHPUnit/TestParser/PHPUnitParser.ts +++ b/src/PHPUnit/TestParser/PHPUnitParser.ts @@ -1,11 +1,11 @@ -import { TestDefinition } from '../types'; -import { Parser } from './Parser'; -import { PHPDefinition } from './PHPDefinition'; +import type { TestDefinition } from '../types'; +import type { Parser } from './Parser'; +import type { PhpAstNodeWrapper } from './PhpAstNodeWrapper'; export class PHPUnitParser implements Parser { - parse(definition: PHPDefinition): TestDefinition[] | undefined { + parse(definition: PhpAstNodeWrapper): TestDefinition[] | undefined { const testDefinitions: TestDefinition[] = []; - const getParent = (definition: PHPDefinition) => { + const getParent = (definition: PhpAstNodeWrapper) => { const testDefinition = definition.toTestDefinition(); if (!definition.parent) { testDefinitions.push(testDefinition); @@ -13,7 +13,9 @@ export class PHPUnitParser implements Parser { return testDefinition; } - let namespace = testDefinitions.find((item: TestDefinition) => item.namespace === definition.parent?.name); + let namespace = testDefinitions.find( + (item: TestDefinition) => item.namespace === definition.parent?.name, + ); if (!namespace) { namespace = definition.parent.createNamespaceTestDefinition(); testDefinitions.push(namespace); @@ -23,14 +25,15 @@ export class PHPUnitParser implements Parser { return testDefinition; }; - definition.getClasses() - .filter(definition => definition.isTest()) - .forEach(definition => { + definition + .getClasses() + .filter((definition) => definition.isTest()) + .forEach((definition) => { getParent(definition).children = (definition.children ?? []) - .filter(definition => definition.isTest()) - .map(definition => definition.toTestDefinition()); + .filter((definition) => definition.isTest()) + .map((definition) => definition.toTestDefinition()); }); return testDefinitions.length === 0 ? undefined : testDefinitions; } -} \ No newline at end of file +} diff --git a/src/PHPUnit/TestParser/Parser.ts b/src/PHPUnit/TestParser/Parser.ts index 70026695..d2540d13 100644 --- a/src/PHPUnit/TestParser/Parser.ts +++ b/src/PHPUnit/TestParser/Parser.ts @@ -1,6 +1,6 @@ -import { TestDefinition } from '../types'; -import { PHPDefinition } from './PHPDefinition'; +import type { TestDefinition } from '../types'; +import type { PhpAstNodeWrapper } from './PhpAstNodeWrapper'; export interface Parser { - parse(definition: PHPDefinition): TestDefinition[] | undefined; -} \ No newline at end of file + parse(definition: PhpAstNodeWrapper): TestDefinition[] | undefined; +} diff --git a/src/PHPUnit/TestParser/PestClassFQNGenerator.ts b/src/PHPUnit/TestParser/PestClassFQNGenerator.ts new file mode 100644 index 00000000..6ffc891f --- /dev/null +++ b/src/PHPUnit/TestParser/PestClassFQNGenerator.ts @@ -0,0 +1,17 @@ +import { basename, dirname, join, relative } from 'node:path'; +import { capitalize } from '../utils'; + +export function generatePestClassFQN(root: string, file: string): string { + let relativePath = relative(root, file); + let baseName = basename(file, '.php'); + const dotPos = baseName.lastIndexOf('.'); + if (dotPos !== -1) { + baseName = baseName.substring(0, dotPos); + } + relativePath = join(capitalize(dirname(relativePath)), baseName).replace(/\//g, '\\'); + relativePath = relativePath.replace(/%[a-fA-F0-9][a-fA-F0-9]/g, ''); + relativePath = relativePath.replace(/\\'|\\"/g, ''); + relativePath = relativePath.replace(/[^A-Za-z0-9\\]/, ''); + + return `P\\${relativePath}`; +} diff --git a/src/PHPUnit/TestParser/PestParser.test.ts b/src/PHPUnit/TestParser/PestParser.test.ts index b2c2b5eb..67e7da6f 100644 --- a/src/PHPUnit/TestParser/PestParser.test.ts +++ b/src/PHPUnit/TestParser/PestParser.test.ts @@ -1,44 +1,11 @@ -import { expect } from '@jest/globals'; -import { pestProject } from '../__tests__/utils'; -import { PHPUnitXML } from '../PHPUnitXML'; -import { TestDefinition, TestType } from '../types'; -import { TestParser } from './TestParser'; - -export const parse = (buffer: Buffer | string, file: string) => { - const tests: TestDefinition[] = []; - const phpUnitXML = new PHPUnitXML(); - phpUnitXML.setRoot(pestProject('')); - const testParser = new TestParser(phpUnitXML); - - testParser.on(TestType.namespace, (testDefinition: TestDefinition) => tests.push(testDefinition)); - testParser.on(TestType.class, (testDefinition: TestDefinition) => tests.push(testDefinition)); - testParser.on(TestType.describe, (testDefinition: TestDefinition) => tests.push(testDefinition)); - testParser.on(TestType.method, (testDefinition: TestDefinition) => tests.push(testDefinition)); - testParser.parse(buffer, file); - - return tests; -}; +import { describe, expect, it } from 'vitest'; +import { findTest, parseTestFile, pestProject } from '../__tests__/utils'; +import { type TestDefinition, TestType } from '../types'; -describe('PestParser', () => { - const findTest = (tests: TestDefinition[], id: string) => { - const lookup = { - [TestType.method]: (test: TestDefinition) => test.methodName === id, - [TestType.describe]: (test: TestDefinition) => test.methodName === id, - [TestType.class]: (test: TestDefinition) => test.className === id && !test.methodName, - [TestType.namespace]: (test: TestDefinition) => test.classFQN === id && !test.className && !test.methodName, - } as { [key: string]: Function }; - - for (const [, fn] of Object.entries(lookup)) { - const test = tests.find((test: TestDefinition) => fn(test)); - - if (test) { - return test; - } - } - - return undefined; - }; +export const parse = (buffer: Buffer | string, file: string) => + parseTestFile(buffer, file, pestProject('')); +describe('PestParser', () => { const givenTest = (file: string, content: string, id: string) => { return findTest(parse(content, file), id); }; @@ -53,14 +20,16 @@ test('example', function () { }); `; - expect(givenTest(file, content, 'P\\Tests\\Fixtures')).toEqual(expect.objectContaining({ - type: TestType.namespace, - id: 'namespace:Tests\\Fixtures', - classFQN: 'P\\Tests\\Fixtures', - namespace: 'P\\Tests\\Fixtures', - label: 'Tests\\Fixtures', - depth: 0, - })); + expect(givenTest(file, content, 'P\\Tests\\Fixtures')).toEqual( + expect.objectContaining({ + type: TestType.namespace, + id: 'namespace:Tests\\Fixtures', + classFQN: 'P\\Tests\\Fixtures', + namespace: 'P\\Tests\\Fixtures', + label: 'Tests\\Fixtures', + depth: 0, + }), + ); }); it('ExampleTest', async () => { @@ -70,18 +39,20 @@ test('example', function () { expect(true)->toBeTrue(); }) `; - expect(givenTest(file, content, 'ExampleTest')).toEqual(expect.objectContaining({ - type: TestType.class, - id: 'Tests\\Fixtures\\ExampleTest', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - label: 'ExampleTest', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 1, - })); + expect(givenTest(file, content, 'ExampleTest')).toEqual( + expect.objectContaining({ + type: TestType.class, + id: 'Tests\\Fixtures\\ExampleTest', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + label: 'ExampleTest', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 1, + }), + ); }); it('example', async () => { @@ -92,19 +63,21 @@ test('example', function () { }); `; - expect(givenTest(file, content, 'example')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::example', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: 'example', - label: 'example', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 2, - })); + expect(givenTest(file, content, 'example')).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::example', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: 'example', + label: 'example', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 2, + }), + ); }); it('it test example', async () => { @@ -115,19 +88,21 @@ it('test example', function () { }); `; - expect(givenTest(file, content, 'it test example')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::it test example', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: 'it test example', - label: 'it test example', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 2, - })); + expect(givenTest(file, content, 'it test example')).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::it test example', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: 'it test example', + label: 'it test example', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 2, + }), + ); }); it('`something` → example', async () => { @@ -140,33 +115,37 @@ describe('something', function () { }); `; - expect(givenTest(file, content, '`something`')).toEqual(expect.objectContaining({ - type: TestType.describe, - id: 'tests/Fixtures/ExampleTest.php::`something`', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: '`something`', - label: 'something', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 2, - })); - - expect(givenTest(file, content, '`something` → example')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::`something` → example', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: '`something` → example', - label: 'example', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 3, - })); + expect(givenTest(file, content, '`something`')).toEqual( + expect.objectContaining({ + type: TestType.describe, + id: 'tests/Fixtures/ExampleTest.php::`something`', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: '`something`', + label: 'something', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 2, + }), + ); + + expect(givenTest(file, content, '`something` → example')).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::`something` → example', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: '`something` → example', + label: 'example', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 3, + }), + ); }); it('arrow function `something` → it example', async () => { @@ -176,19 +155,21 @@ describe('something', fn () => it('example', fn() => expect(true)->toBeTrue())); `; - expect(givenTest(file, content, '`something` → it example')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::`something` → it example', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: '`something` → it example', - label: 'it example', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 3, - })); + expect(givenTest(file, content, '`something` → it example')).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::`something` → it example', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: '`something` → it example', + label: 'it example', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 3, + }), + ); }); it('`something` → `something else` → it test example', async () => { @@ -203,33 +184,39 @@ describe('something', function () { }); `; - expect(givenTest(file, content, '`something` → `something else`')).toEqual(expect.objectContaining({ - type: TestType.describe, - id: 'tests/Fixtures/ExampleTest.php::`something` → `something else`', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: '`something` → `something else`', - label: 'something else', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 3, - })); - - expect(givenTest(file, content, '`something` → `something else` → it test example')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::`something` → `something else` → it test example', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: '`something` → `something else` → it test example', - label: 'it test example', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 4, - })); + expect(givenTest(file, content, '`something` → `something else`')).toEqual( + expect.objectContaining({ + type: TestType.describe, + id: 'tests/Fixtures/ExampleTest.php::`something` → `something else`', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: '`something` → `something else`', + label: 'something else', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 3, + }), + ); + + expect( + givenTest(file, content, '`something` → `something else` → it test example'), + ).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::`something` → `something else` → it test example', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: '`something` → `something else` → it test example', + label: 'it test example', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 4, + }), + ); }); it('it example 2', () => { @@ -238,19 +225,21 @@ describe('something', function () { it('example 2')->assertTrue(true); `; - expect(givenTest(file, content, 'it example 2')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::it example 2', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: 'it example 2', - label: 'it example 2', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 2, - })); + expect(givenTest(file, content, 'it example 2')).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::it example 2', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: 'it example 2', + label: 'it example 2', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 2, + }), + ); }); it('not it or test', async () => { @@ -276,19 +265,21 @@ it('asserts true is true', function () { }); `; - expect(givenTest(file, content, 'it asserts true is true')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::it asserts true is true', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: 'it asserts true is true', - label: 'it asserts true is true', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 2, - })); + expect(givenTest(file, content, 'it asserts true is true')).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::it asserts true is true', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: 'it asserts true is true', + label: 'it asserts true is true', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 2, + }), + ); }); it('test with namedargument', async () => { @@ -301,19 +292,21 @@ describe(description: 'something', test: function () { }); `; - expect(givenTest(file, content, '`something` → it asserts true is true')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::`something` → it asserts true is true', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: '`something` → it asserts true is true', - label: 'it asserts true is true', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 3, - })); + expect(givenTest(file, content, '`something` → it asserts true is true')).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::`something` → it asserts true is true', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: '`something` → it asserts true is true', + label: 'it asserts true is true', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 3, + }), + ); }); it('parse arch', async () => { @@ -325,47 +318,53 @@ arch()->preset()->security(); `; - expect(givenTest(file, content, 'preset → php ')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::preset → php ', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: 'preset → php ', - label: 'preset → php', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 2, - })); - - expect(givenTest(file, content, 'preset → strict ')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::preset → strict ', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: 'preset → strict ', - label: 'preset → strict', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 2, - })); - - expect(givenTest(file, content, 'preset → security ')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::preset → security ', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: 'preset → security ', - label: 'preset → security', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 2, - })); + expect(givenTest(file, content, 'preset → php ')).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::preset → php ', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: 'preset → php ', + label: 'preset → php', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 2, + }), + ); + + expect(givenTest(file, content, 'preset → strict ')).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::preset → strict ', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: 'preset → strict ', + label: 'preset → strict', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 2, + }), + ); + + expect(givenTest(file, content, 'preset → security ')).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::preset → security ', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: 'preset → security ', + label: 'preset → security', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 2, + }), + ); }); it('parse arch with name', async () => { @@ -375,19 +374,21 @@ arch('Then should pass the PHP preset')->preset()->php(); `; - expect(givenTest(file, content, 'Then should pass the PHP preset')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::Then should pass the PHP preset', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: 'Then should pass the PHP preset', - label: 'Then should pass the PHP preset', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 2, - })); + expect(givenTest(file, content, 'Then should pass the PHP preset')).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::Then should pass the PHP preset', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: 'Then should pass the PHP preset', + label: 'Then should pass the PHP preset', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 2, + }), + ); }); it('parse describe arch', () => { @@ -401,18 +402,27 @@ describe('Given a project', function () { `; - expect(givenTest(file, content, '`Given a project` → `When the architecture is tested` → Then should pass the PHP preset')).toEqual(expect.objectContaining({ - type: TestType.method, - id: 'tests/Fixtures/ExampleTest.php::`Given a project` → `When the architecture is tested` → Then should pass the PHP preset', - classFQN: 'P\\Tests\\Fixtures\\ExampleTest', - namespace: 'P\\Tests\\Fixtures', - className: 'ExampleTest', - methodName: '`Given a project` → `When the architecture is tested` → Then should pass the PHP preset', - label: 'Then should pass the PHP preset', - file, - start: { line: expect.any(Number), character: expect.any(Number) }, - end: { line: expect.any(Number), character: expect.any(Number) }, - depth: 4, - })); + expect( + givenTest( + file, + content, + '`Given a project` → `When the architecture is tested` → Then should pass the PHP preset', + ), + ).toEqual( + expect.objectContaining({ + type: TestType.method, + id: 'tests/Fixtures/ExampleTest.php::`Given a project` → `When the architecture is tested` → Then should pass the PHP preset', + classFQN: 'P\\Tests\\Fixtures\\ExampleTest', + namespace: 'P\\Tests\\Fixtures', + className: 'ExampleTest', + methodName: + '`Given a project` → `When the architecture is tested` → Then should pass the PHP preset', + label: 'Then should pass the PHP preset', + file, + start: { line: expect.any(Number), character: expect.any(Number) }, + end: { line: expect.any(Number), character: expect.any(Number) }, + depth: 4, + }), + ); }); -}); \ No newline at end of file +}); diff --git a/src/PHPUnit/TestParser/PestParser.ts b/src/PHPUnit/TestParser/PestParser.ts index 8093e804..06ee90bd 100644 --- a/src/PHPUnit/TestParser/PestParser.ts +++ b/src/PHPUnit/TestParser/PestParser.ts @@ -1,13 +1,14 @@ -import { TestDefinition, TestType } from '../types'; -import { Parser } from './Parser'; -import { PHPDefinition } from './PHPDefinition'; +import { type TestDefinition, TestType } from '../types'; +import type { Parser } from './Parser'; +import type { PhpAstNodeWrapper } from './PhpAstNodeWrapper'; export class PestParser implements Parser { - parse(definition: PHPDefinition): TestDefinition[] | undefined { - const getFunctions = (definition: PHPDefinition) => { - return definition.getFunctions() - .filter((definition: PHPDefinition) => definition.isTest()) - .map((definition: PHPDefinition) => { + parse(definition: PhpAstNodeWrapper): TestDefinition[] | undefined { + const getFunctions = (definition: PhpAstNodeWrapper) => { + return definition + .getFunctions() + .filter((definition: PhpAstNodeWrapper) => definition.isTest()) + .map((definition: PhpAstNodeWrapper) => { const testDefinition = definition.toTestDefinition(); if (definition.type === TestType.describe) { @@ -30,4 +31,4 @@ export class PestParser implements Parser { return [parent]; } -} \ No newline at end of file +} diff --git a/src/PHPUnit/TestParser/PhpAstNodeWrapper.ts b/src/PHPUnit/TestParser/PhpAstNodeWrapper.ts new file mode 100644 index 00000000..eda809d9 --- /dev/null +++ b/src/PHPUnit/TestParser/PhpAstNodeWrapper.ts @@ -0,0 +1,336 @@ +import type { + Declaration, + Identifier, + Method, + Name, + Namespace, + Node, + PropertyLookup, +} from 'php-parser'; +import type { PHPUnitXML } from '../PHPUnitXML'; +import { type TestDefinition, TestType } from '../types'; +import { AnnotationParser, AttributeParser } from './AnnotationParser'; +import { generatePestClassFQN } from './PestClassFQNGenerator'; +import { + NamespaceDefinitionBuilder, + PestTestDefinitionBuilder, + TestCaseDefinitionBuilder, + TestSuiteDefinitionBuilder, +} from './TestDefinitionBuilder'; + +type AST = Node & { + name?: Identifier | string; + visibility?: string; + isAbstract?: boolean; + body?: Node[]; + children?: Node[]; + expression?: AST; + what?: (Name | PropertyLookup) & { offset?: Identifier }; + arguments?: AST[]; + value?: string; +}; + +export const annotationParser = new AnnotationParser(); +export const attributeParser = new AttributeParser(); + +export class PhpAstNodeWrapper { + constructor( + private readonly ast: AST, + private options: { + phpUnitXML: PHPUnitXML; + file: string; + namespace?: PhpAstNodeWrapper; + parent?: PhpAstNodeWrapper; + }, + ) {} + + get kind() { + return this.ast.kind; + } + + get file() { + return this.options.file; + } + + get root() { + return this.options.phpUnitXML.root(); + } + + get type() { + if (this.kind === 'namespace') { + return TestType.namespace; + } + + if (['program', 'class'].includes(this.kind)) { + return TestType.class; + } + + if (this.kind === 'method') { + return TestType.method; + } + + if (this.kind === 'call') { + return this.name === 'describe' ? TestType.describe : TestType.method; + } + + return undefined; + } + + get classFQN(): string | undefined { + if (this.kind === 'program') { + return generatePestClassFQN(this.root, this.file); + } + + if (this.kind === 'namespace') { + return this.name; + } + + if (this.kind === 'class') { + return [this.parent?.name, this.name].filter((name) => !!name).join('\\'); + } + + return this.parent?.classFQN; + } + + get parent() { + return this.options.parent!; + } + + get children() { + if (this.kind === 'namespace') { + return this.getClasses(); + } + + if (this.kind === 'class') { + return this.getMethods(); + } + + return undefined; + } + + get arguments() { + return ( + this.ast.arguments?.map((ast: AST) => { + return new PhpAstNodeWrapper(ast, { ...this.options, parent: this }); + }) ?? [] + ); + } + + get name(): string { + if (this.ast.kind === 'namedargument') { + if ((this.ast.value as unknown as AST).kind === 'string') { + return (this.ast.value as unknown as AST).value!; + } + } + + if (typeof this.ast.name === 'string') { + return this.ast.name; + } + + if (this.ast.name?.name) { + return this.ast.name?.name; + } + + if (this.ast.what) { + if (this.ast.what.offset && this.ast.what.offset.kind === 'identifier') { + return this.ast.what.offset.name; + } + + return (this.ast.what as Name).name; + } + + if (this.ast.kind === 'string') { + return this.ast.value!; + } + + return ''; + } + + get annotations() { + return { + ...annotationParser.parse(this.ast as Declaration), + ...attributeParser.parse(this.ast as Declaration), + }; + } + + get position() { + const loc = this.ast.loc!; + const start = { line: loc.start.line, character: loc.start.column }; + const end = { line: loc.end.line, character: loc.end.column }; + + return { start, end }; + } + + getClasses() { + const definitions: PhpAstNodeWrapper[] = + this.kind !== 'program' + ? [] + : this.getNamespaces().reduce((definitions, definition: PhpAstNodeWrapper) => { + return definitions.concat(definition.getClasses()); + }, [] as PhpAstNodeWrapper[]); + + const options = { ...this.options }; + if (this.kind === 'namespace') { + options.parent = this; + } + + return definitions.concat( + (this.ast.children ?? []) + .map((node: Node) => new PhpAstNodeWrapper(node, options)) + .filter((definition: PhpAstNodeWrapper) => definition.kind === 'class'), + ); + } + + getFunctions(): PhpAstNodeWrapper[] { + const args = this.arguments; + + if (this.type === TestType.describe) { + return args[1].getFunctions(); + } + + if (args.length > 1 && args[1].kind === 'namedargument') { + return args[1].getFunctions(); + } + + if (args.length > 1 && args[1].kind === 'arrowfunc') { + return [new PhpAstNodeWrapper(this.ast, this.options)]; + } + + if (['closure', 'arrowfunc'].includes(this.kind) && this.ast.body) { + return new PhpAstNodeWrapper( + this.ast.body as unknown as AST, + this.options, + ).getFunctions(); + } + + if (this.kind === 'namedargument') { + return new PhpAstNodeWrapper( + (this.ast.value as unknown as AST).body as unknown as AST, + this.options, + ).getFunctions(); + } + + return collectPestFunctions(this.ast.children ?? [], this.options, this); + } + + isTest() { + if (this.ast.isAbstract) { + return false; + } + + if (this.kind === 'class') { + return ( + this.name.endsWith('Test') && + this.children!.some((definition): boolean => definition.isTest()) + ); + } + + if (this.kind === 'method' && this.acceptModifier()) { + return ( + this.name.startsWith('test') || + annotationParser.isTest(this.ast as unknown as Method) || + attributeParser.isTest(this.ast as unknown as Method) + ); + } + + if (this.kind === 'call') { + return ['it', 'test', 'describe', 'arch'].includes(this.name); + } + + return false; + } + + toTestDefinition(): TestDefinition { + if (this.kind === 'class') { + return new TestSuiteDefinitionBuilder(this).build(); + } + + if (this.kind === 'method') { + return new TestCaseDefinitionBuilder(this).build(); + } + + return new PestTestDefinitionBuilder(this).build(); + } + + createNamespaceTestDefinition(): TestDefinition { + return new NamespaceDefinitionBuilder(this).build(); + } + + private getMethods(): PhpAstNodeWrapper[] { + if (['program', 'namespace'].includes(this.ast.kind)) { + return this.getClasses().reduce( + (definitions: PhpAstNodeWrapper[], definition: PhpAstNodeWrapper) => { + return definitions.concat(definition.getMethods()); + }, + [], + ); + } + + const options = { ...this.options }; + if (this.kind === 'class') { + options.parent = this; + } + + return (this.ast.body ?? []) + .map((node: Node) => new PhpAstNodeWrapper(node, options)) + .filter((definition: PhpAstNodeWrapper) => definition.kind === 'method'); + } + + private getNamespaces() { + if (this.kind !== 'program') { + return []; + } + + return (this.ast.children ?? []) + .map((node: Node) => new PhpAstNodeWrapper(node, this.options)) + .filter((definition: PhpAstNodeWrapper) => definition.kind === 'namespace'); + } + + private acceptModifier() { + return ['', 'public'].includes(this.ast.visibility!); + } +} + +function collectPestFunctions( + children: Node[], + options: { + phpUnitXML: PHPUnitXML; + file: string; + namespace?: PhpAstNodeWrapper; + parent?: PhpAstNodeWrapper; + }, + parentNode: PhpAstNodeWrapper, +): PhpAstNodeWrapper[] { + return children + .reduce((flatChildren: AST[], node) => { + return flatChildren.concat( + node.kind === 'namespace' ? (node as Namespace).children : [node], + ); + }, []) + .reduce((definitions, node: AST) => { + if ( + !( + node.kind === 'expressionstatement' && + (node.expression as AST).kind !== 'include' + ) + ) { + return definitions; + } + + const parent = ['block'].includes(parentNode.kind) ? parentNode.parent : parentNode; + const opts = { ...options, parent }; + + let ast = node.expression as AST; + while (ast.what) { + if (ast.what.kind === 'name') { + break; + } + if (ast.kind === 'call') { + opts.parent = new PhpAstNodeWrapper(ast, { ...opts }); + } + ast = ast.what as AST; + } + + return definitions.concat(new PhpAstNodeWrapper(ast, opts)); + }, [] as PhpAstNodeWrapper[]); +} diff --git a/src/PHPUnit/TestParser/TestDefinitionBuilder.ts b/src/PHPUnit/TestParser/TestDefinitionBuilder.ts new file mode 100644 index 00000000..49788d07 --- /dev/null +++ b/src/PHPUnit/TestParser/TestDefinitionBuilder.ts @@ -0,0 +1,150 @@ +import { type Transformer, TransformerFactory } from '../Transformer'; +import { type TestDefinition, TestType } from '../types'; +import type { PhpAstNodeWrapper } from './PhpAstNodeWrapper'; + +abstract class TestDefinitionBuilder { + constructor(protected definition: PhpAstNodeWrapper) {} + + abstract build(): TestDefinition; + + protected generate(testDefinition: Partial) { + testDefinition = { + type: this.definition.type, + classFQN: this.definition.classFQN, + children: [], + annotations: this.definition.annotations, + file: this.definition.file, + ...this.definition.position, + ...testDefinition, + }; + const transformer = this.getTransformer(testDefinition); + testDefinition.id = transformer.uniqueId(testDefinition as TestDefinition); + testDefinition.label = transformer.generateLabel(testDefinition as TestDefinition); + + return testDefinition as TestDefinition; + } + + private getTransformer(testDefinition: Pick): Transformer { + return TransformerFactory.create(testDefinition.classFQN!); + } +} + +export class NamespaceDefinitionBuilder extends TestDefinitionBuilder { + build() { + const type = TestType.namespace; + const depth = 0; + + const classFQN = this.definition.classFQN; + if (this.definition.kind === 'program') { + const partsFQN = classFQN!.split('\\'); + const namespace = partsFQN.slice(0, -1).join('\\'); + + return this.generate({ type, depth, namespace, classFQN: namespace }); + } + + if (this.definition.kind === 'class') { + const partsFQN = classFQN!.split('\\'); + const className = partsFQN.pop()!; + const namespace = partsFQN.join('\\'); + + return this.generate({ type, depth, namespace, classFQN: namespace, className }); + } + + return this.generate({ type, depth, namespace: classFQN, classFQN }); + } +} + +export class TestSuiteDefinitionBuilder extends TestDefinitionBuilder { + build() { + return this.generate({ + namespace: this.definition.parent?.name, + className: this.definition.name, + depth: 1, + }); + } +} + +export class TestCaseDefinitionBuilder extends TestDefinitionBuilder { + build() { + return this.generate({ + namespace: this.definition.parent?.parent?.name, + className: this.definition.parent?.name, + methodName: this.definition.name, + depth: 2, + }); + } +} + +export class PestTestDefinitionBuilder extends TestDefinitionBuilder { + build() { + if (this.definition.kind === 'program') { + const classFQN = this.definition.classFQN!; + const partsFQN = classFQN.split('\\'); + const className = partsFQN.pop()!; + + return this.generate({ namespace: partsFQN.join('\\'), className, depth: 1 }); + } + + let depth = 2; + + let { methodName, label } = this.parseMethodNameAndLabel(); + + if (this.definition.type === TestType.describe) { + methodName = `\`${methodName}\``; + } + + let parent = this.definition.parent; + while (parent && parent.kind === 'call' && parent.type !== TestType.describe) { + parent = parent.parent; + } + + if (parent?.type === TestType.describe) { + const describeNames: string[] = []; + while (parent && parent.type === TestType.describe) { + describeNames.push(`\`${parent.arguments[0].name}\``); + parent = parent.parent; + depth++; + } + methodName = describeNames.reverse().concat(methodName).join(' → '); + } + + const { classFQN, namespace, className } = parent?.toTestDefinition(); + + return this.generate({ classFQN, namespace, className, methodName, label, depth }); + } + + private parseMethodNameAndLabel() { + const args = this.definition.arguments; + + if (this.definition.name !== 'arch') { + let methodName = args[0].name; + + if (this.definition.name === 'it') { + methodName = `it ${methodName}`; + } + + return { methodName, label: methodName }; + } + + if (args.length > 0) { + const methodName = args[0].name; + + return { methodName, label: methodName }; + } + + const names = [] as string[]; + let parent = this.definition.parent; + while (parent && parent.kind === 'call') { + names.push(parent.name); + parent = parent.parent; + } + + const methodName = names + .map((name: string) => (name === 'preset' ? `${name} ` : ` ${name} `)) + .join('→'); + + const label = names.join(' → '); + + return { methodName, label }; + } +} diff --git a/src/PHPUnit/TestParser/TestParser.ts b/src/PHPUnit/TestParser/TestParser.ts index 779d8c6d..99b5146c 100644 --- a/src/PHPUnit/TestParser/TestParser.ts +++ b/src/PHPUnit/TestParser/TestParser.ts @@ -1,22 +1,21 @@ import { EventEmitter } from 'node:events'; import { readFile } from 'node:fs/promises'; -import { Declaration, Node } from 'php-parser'; -import { PHPUnitXML } from '../PHPUnitXML'; -import { TestDefinition, TestType } from '../types'; +import type { Comment, Declaration, Node } from 'php-parser'; +import type { PHPUnitXML } from '../PHPUnitXML'; +import type { TestDefinition, TestType } from '../types'; import { engine } from '../utils'; -import { Parser } from './Parser'; +import type { Parser } from './Parser'; import { PestParser } from './PestParser'; -import { PHPDefinition } from './PHPDefinition'; import { PHPUnitParser } from './PHPUnitParser'; +import { PhpAstNodeWrapper } from './PhpAstNodeWrapper'; const textDecoder = new TextDecoder('utf-8'); export class TestParser { private parsers: Parser[] = [new PestParser(), new PHPUnitParser()]; - private eventEmitter = new EventEmitter; + private eventEmitter = new EventEmitter(); - constructor(private phpUnitXML: PHPUnitXML) { - } + constructor(private phpUnitXML: PHPUnitXML) {} on(eventName: TestType, callback: (testDefinition: TestDefinition, index?: number) => void) { this.eventEmitter.on(`${eventName}`, callback); @@ -27,27 +26,12 @@ export class TestParser { } parse(text: Buffer | string, file: string, testsuite?: string) { - text = text.toString(); - - // Todo https://github.com/glayzzle/php-parser/issues/170 - text = text.replace(/\?>\r?\n<\?/g, '?>\n___PSEUDO_INLINE_PLACEHOLDER___ { - if (comment.value[comment.value.length - 1] === '\r') { - comment.value = comment.value.slice(0, -1); - comment.loc!.end.offset = comment.loc!.end.offset - 1; - } - if (comment.value[comment.value.length - 1] === '\n') { - comment.value = comment.value.slice(0, -1); - comment.loc!.end.offset = comment.loc!.end.offset - 1; - } - }); + const preprocessed = applyInlinePlaceholderWorkaround(text.toString()); + const ast = engine.parseCode(preprocessed, file); + if (ast.comments) { + normalizeCommentLineBreaks(ast.comments); + } return this.parseAst(ast, file, testsuite); } catch (e) { @@ -57,12 +41,19 @@ export class TestParser { } } - private parseAst(declaration: Declaration | Node, file: string, testsuite?: string): TestDefinition[] | undefined { - const definition = new PHPDefinition(declaration, { phpUnitXML: this.phpUnitXML, file }); + private parseAst( + declaration: Declaration | Node, + file: string, + testsuite?: string, + ): TestDefinition[] | undefined { + const definition = new PhpAstNodeWrapper(declaration, { + phpUnitXML: this.phpUnitXML, + file, + }); for (const parser of this.parsers) { const tests = parser.parse(definition); - tests?.forEach((testDefinition) => testDefinition.testsuite = testsuite); + tests?.forEach((testDefinition) => (testDefinition.testsuite = testsuite)); if (tests) { return this.emit(tests); } @@ -72,7 +63,7 @@ export class TestParser { } private emit(tests: TestDefinition[]) { - tests.forEach(test => { + tests.forEach((test) => { this.eventEmitter.emit(`${test.type}`, test); if (test.children && test.children.length > 0) { this.emit(test.children); @@ -81,4 +72,25 @@ export class TestParser { return tests; } -} \ No newline at end of file +} + +/** Workaround for https://github.com/glayzzle/php-parser/issues/170 */ +function applyInlinePlaceholderWorkaround(text: string): string { + return text.replace(/\?>\r?\n<\?/g, '?>\n___PSEUDO_INLINE_PLACEHOLDER___ { + if (comment.value[comment.value.length - 1] === '\r') { + comment.value = comment.value.slice(0, -1); + // biome-ignore lint/style/noNonNullAssertion: loc is always present when withPositions is true + comment.loc!.end.offset = comment.loc!.end.offset - 1; + } + if (comment.value[comment.value.length - 1] === '\n') { + comment.value = comment.value.slice(0, -1); + // biome-ignore lint/style/noNonNullAssertion: loc is always present when withPositions is true + comment.loc!.end.offset = comment.loc!.end.offset - 1; + } + }); +} diff --git a/src/PHPUnit/TestParser/index.ts b/src/PHPUnit/TestParser/index.ts index 9668977c..65de47c7 100644 --- a/src/PHPUnit/TestParser/index.ts +++ b/src/PHPUnit/TestParser/index.ts @@ -1,4 +1,5 @@ -export * from './TestParser'; -export * from './PHPUnitParser'; +export * from './PestClassFQNGenerator'; export * from './PestParser'; -export * from './PHPDefinition'; +export * from './PHPUnitParser'; +export * from './PhpAstNodeWrapper'; +export * from './TestParser'; diff --git a/src/PHPUnit/TestRunner.test.ts b/src/PHPUnit/TestRunner.test.ts index 060def31..e0650c83 100644 --- a/src/PHPUnit/TestRunner.test.ts +++ b/src/PHPUnit/TestRunner.test.ts @@ -1,9 +1,10 @@ -import { spawn } from 'child_process'; +import { spawn } from 'node:child_process'; import * as semver from 'semver'; +import { beforeEach, describe, expect, it, type Mock, vi } from 'vitest'; import { getPhpUnitVersion, phpUnitProject, phpUnitProjectWin } from './__tests__/utils'; -import { Builder } from './CommandBuilder'; import { Configuration } from './Configuration'; import { TeamcityEvent } from './ProblemMatcher'; +import { ProcessBuilder } from './ProcessBuilder'; import { TestRunner } from './TestRunner'; import { TestRunnerEvent } from './TestRunnerObserver'; import { TransformerFactory } from './Transformer'; @@ -11,40 +12,43 @@ import { TestType } from './types'; const PHPUNIT_VERSION: string = getPhpUnitVersion(); -jest.mock('child_process'); +vi.mock('child_process', async () => { + const actual = await vi.importActual('child_process'); + return { ...actual, spawn: vi.fn(actual.spawn) }; +}); -const onTestRunnerEvents = new Map([ - [TestRunnerEvent.run, jest.fn()], - [TestRunnerEvent.line, jest.fn()], - [TestRunnerEvent.result, jest.fn()], - [TestRunnerEvent.close, jest.fn()], - [TestRunnerEvent.error, jest.fn()], +const onTestRunnerEvents = new Map([ + [TestRunnerEvent.run, vi.fn()], + [TestRunnerEvent.line, vi.fn()], + [TestRunnerEvent.result, vi.fn()], + [TestRunnerEvent.close, vi.fn()], + [TestRunnerEvent.error, vi.fn()], ]); -const onTestResultEvents = new Map([ - [TeamcityEvent.testVersion, jest.fn()], - [TeamcityEvent.testRuntime, jest.fn()], - [TeamcityEvent.testConfiguration, jest.fn()], - [TeamcityEvent.testCount, jest.fn()], - [TeamcityEvent.testDuration, jest.fn()], - [TeamcityEvent.testResultSummary, jest.fn()], - [TeamcityEvent.testSuiteStarted, jest.fn()], - [TeamcityEvent.testSuiteFinished, jest.fn()], - [TeamcityEvent.testStarted, jest.fn()], - [TeamcityEvent.testFailed, jest.fn()], - [TeamcityEvent.testIgnored, jest.fn()], - [TeamcityEvent.testFinished, jest.fn()], +const onTestResultEvents = new Map([ + [TeamcityEvent.testVersion, vi.fn()], + [TeamcityEvent.testRuntime, vi.fn()], + [TeamcityEvent.testConfiguration, vi.fn()], + [TeamcityEvent.testCount, vi.fn()], + [TeamcityEvent.testDuration, vi.fn()], + [TeamcityEvent.testResultSummary, vi.fn()], + [TeamcityEvent.testSuiteStarted, vi.fn()], + [TeamcityEvent.testSuiteFinished, vi.fn()], + [TeamcityEvent.testStarted, vi.fn()], + [TeamcityEvent.testFailed, vi.fn()], + [TeamcityEvent.testIgnored, vi.fn()], + [TeamcityEvent.testFinished, vi.fn()], ]); const fakeSpawn = (contents: string[]) => { - const stdout = jest.fn().mockImplementation((_event, fn: (data: string) => void) => { - contents.forEach((line) => fn(line + '\n')); + const stdout = vi.fn().mockImplementation((_event, fn: (data: string) => void) => { + contents.forEach((line) => fn(`${line}\n`)); }); - (spawn as jest.Mock).mockReturnValue({ + (spawn as Mock).mockReturnValue({ stdout: { on: stdout }, - stderr: { on: jest.fn() }, - on: jest.fn().mockImplementation((_event, callback: (data: number) => void) => { + stderr: { on: vi.fn() }, + on: vi.fn().mockImplementation((_event, callback: (data: number) => void) => { if (_event === 'close') { callback(2); } @@ -56,52 +60,59 @@ const hasFile = ( testResult: { details: { file: string; line: number }[] }[], pattern: string, l: number, -) => (testResult[0].details).some(({ file, line }) => { - return !!file.match(new RegExp(pattern)) && line === l; -}); +) => + testResult[0].details.some(({ file, line }) => { + return !!file.match(new RegExp(pattern)) && line === l; + }); -function expectedTestResult(expected: any, projectPath: (path: string) => string): void { - const [classFQN, methodName] = expected.id.split('::'); - const locationHint = `php_qn://${expected.file}::\\${expected.id}`; +const resolveTestId = (rawId: string) => { + const [classFQN, methodName] = rawId.split('::'); const type = !methodName ? TestType.class : TestType.method; - const converter = TransformerFactory.factory(classFQN); - expected.id = converter.uniqueId({ type, classFQN, methodName }); + return TransformerFactory.create(classFQN).uniqueId({ type, classFQN, methodName }); +}; - const actual = onTestRunnerEvents.get(TestRunnerEvent.result)!.mock.calls.find((call: any) => { - return call[0].id === expected.id && call[0].event === expected.event; - }); +const findResultCall = (id: string, event: TeamcityEvent) => + onTestRunnerEvents.get(TestRunnerEvent.result)!.mock.calls.find( + // biome-ignore lint/suspicious/noExplicitAny: vitest mock calls have dynamic shape + (call: any) => call[0].id === id && call[0].event === event, + ); + +const adjustFailedDetails = ( + // biome-ignore lint/suspicious/noExplicitAny: test result with dynamic detail entries + actual: any, + details: { file: string; line: number }[], + projectPath: (path: string) => string, +) => { + if (hasFile(actual, 'AssertionsTest', 6)) { + details = [{ file: projectPath('tests/AssertionsTest.php'), line: 6 }, ...details]; + } + if (hasFile(actual, 'phpunit', 60)) { + details = [...details, { file: projectPath('vendor/phpunit/phpunit/phpunit'), line: 60 }]; + } + return details; +}; + +// biome-ignore lint/suspicious/noExplicitAny: test helper with dynamic property access +function expectedTestResult(expected: any, projectPath: (path: string) => string): void { + const locationHint = `php_qn://${expected.file}::\\${expected.id}`; + expected.id = resolveTestId(expected.id); + const actual = findResultCall(expected.id, expected.event); expect(actual).not.toBeUndefined(); if (expected.event === TeamcityEvent.testFailed) { - if (hasFile(actual, 'AssertionsTest', 5)) { - expected.details = [{ - file: projectPath('tests/AssertionsTest.php'), - line: 5, - }, ...expected.details]; - } - - if (hasFile(actual, 'phpunit', 60)) { - expected.details = [...expected.details, { - file: projectPath('vendor/phpunit/phpunit/phpunit'), - line: 60, - }]; - } - expect(actual[0].details).toEqual(expected.details); + expected.details = adjustFailedDetails(actual!, expected.details, projectPath); + expect(actual![0].details).toEqual(expected.details); } - - expect(actual[0]).toEqual( - expect.objectContaining({ ...expected, locationHint }), - ); + const expectedWithHint = { ...expected, locationHint }; + expect(actual![0]).toEqual(expect.objectContaining(expectedWithHint)); expect(onTestResultEvents.get(expected.event)).toHaveBeenCalledWith( - expect.objectContaining({ ...expected, locationHint }), + expect.objectContaining(expectedWithHint), ); if (semver.lt(PHPUNIT_VERSION, '10.0.0')) { expect(onTestResultEvents.get(TeamcityEvent.testVersion)).toHaveBeenCalled(); - // expect(onTestResultEvents.get(TestResultEvent.testRuntime)).toHaveBeenCalled(); - // expect(onTestResultEvents.get(TestResultEvent.testConfiguration)).toHaveBeenCalled(); expect(onTestResultEvents.get(TeamcityEvent.testCount)).toHaveBeenCalled(); expect(onTestResultEvents.get(TeamcityEvent.testDuration)).toHaveBeenCalled(); expect(onTestResultEvents.get(TeamcityEvent.testResultSummary)).toHaveBeenCalled(); @@ -111,154 +122,93 @@ function expectedTestResult(expected: any, projectPath: (path: string) => string expect(onTestRunnerEvents.get(TestRunnerEvent.close)).toHaveBeenCalled(); } +const teamcityOutput = ( + appPath: (path: string) => string, + events: string[], + summary = 'OK (1 test, 1 assertion)', +) => [ + 'PHPUnit 9.5.26 by Sebastian Bergmann and contributors.', + 'Runtime: PHP 8.1.12', + `Configuration: '${appPath('phpunit.xml')}`, + "##teamcity[testCount count='1' flowId='8024']", + ...events, + 'Time: 00:00.049, Memory: 6.00 MB', + summary, +]; + const generateTestResult = ( - testResult: { event: TeamcityEvent; name?: string; file: string; id: string; phpVfsComposer?: boolean }, + testResult: { + event: TeamcityEvent; + name?: string; + file: string; + id: string; + phpVfsComposer?: boolean; + }, appPath: (path: string) => string, phpVfsComposer: boolean = false, ) => { - let { event, name, file, id } = testResult; + const { event, name, file, id } = testResult; const locationHint = `php_qn://${file}::\\${id}`; - const phpUnitXml = appPath('phpunit.xml'); if ([TeamcityEvent.testSuiteStarted, TeamcityEvent.testSuiteFinished].includes(event)) { - fakeSpawn([ - 'PHPUnit 9.5.26 by Sebastian Bergmann and contributors.', - 'Runtime: PHP 8.1.12', - `Configuration: '${phpUnitXml}`, - '##teamcity[testCount count=\'1\' flowId=\'8024\']', - `##teamcity[testSuiteStarted name='${id}' locationHint='${locationHint}' flowId='8024']`, - `##teamcity[testSuiteFinished name='${id}' flowId='8024']`, - 'Time: 00:00.049, Memory: 6.00 MB', - 'OK (1 test, 1 assertion)', - ]); + fakeSpawn( + teamcityOutput(appPath, [ + `##teamcity[testSuiteStarted name='${id}' locationHint='${locationHint}' flowId='8024']`, + `##teamcity[testSuiteFinished name='${id}' flowId='8024']`, + ]), + ); } if ([TeamcityEvent.testStarted, TeamcityEvent.testFinished].includes(event)) { - fakeSpawn([ - 'PHPUnit 9.5.26 by Sebastian Bergmann and contributors.', - 'Runtime: PHP 8.1.12', - `Configuration: '${phpUnitXml}`, - '##teamcity[testCount count=\'1\' flowId=\'8024\']', - `##teamcity[testStarted name='${name}' locationHint='${locationHint}::${name}' flowId='8024']`, - `##teamcity[testFinished name='${name}' duration='0' flowId='8024']`, - 'Time: 00:00.049, Memory: 6.00 MB', - 'Tests: 1, Assertions: 1, Failures: 1', - ]); + fakeSpawn( + teamcityOutput( + appPath, + [ + `##teamcity[testStarted name='${name}' locationHint='${locationHint}::${name}' flowId='8024']`, + `##teamcity[testFinished name='${name}' duration='0' flowId='8024']`, + ], + 'Tests: 1, Assertions: 1, Failures: 1', + ), + ); } if ([TeamcityEvent.testFailed].includes(event)) { - let details = `${file}:22|n`; + let details = `${file}:26|n`; if (phpVfsComposer) { details += ` phpvfscomposer://${appPath('vendor/phpunit/phpunit/phpunit')}:60`; } - fakeSpawn([ - 'PHPUnit 9.5.26 by Sebastian Bergmann and contributors.', - 'Runtime: PHP 8.1.12', - `Configuration: '${phpUnitXml}`, - '##teamcity[testCount count=\'1\' flowId=\'8024\']', - `##teamcity[testStarted name='${name}' locationHint='${locationHint}::test_failed' flowId='8024']`, - `##teamcity[testFailed name='${name}' message='Failed asserting that false is true.|n|n${file}:5|n' details=' ${details} ' duration='0' flowId='8024']`, - `##teamcity[testFinished name='${name}' duration='0' flowId='8024']`, - 'Time: 00:00.049, Memory: 6.00 MB', - 'Tests: 1, Assertions: 1, Failures: 1', - ]); + fakeSpawn( + teamcityOutput( + appPath, + [ + `##teamcity[testStarted name='${name}' locationHint='${locationHint}::test_failed' flowId='8024']`, + `##teamcity[testFailed name='${name}' message='Failed asserting that false is true.|n|n${file}:6|n' details=' ${details} ' duration='0' flowId='8024']`, + `##teamcity[testFinished name='${name}' duration='0' flowId='8024']`, + ], + 'Tests: 1, Assertions: 1, Failures: 1', + ), + ); } }; -const expectedCommand = async (builder: Builder, expected: string[]) => { +const expectedCommand = async (builder: ProcessBuilder, expected: string[]) => { const testRunner = new TestRunner(); - onTestResultEvents.forEach((fn, eventName) => testRunner.on(eventName, (test: any) => fn(test))); - onTestRunnerEvents.forEach((fn, eventName) => testRunner.on(eventName, (test: any) => fn(test))); + onTestResultEvents.forEach((fn, eventName) => + testRunner.on(eventName, (test: unknown) => fn(test)), + ); + onTestRunnerEvents.forEach((fn, eventName) => + testRunner.on(eventName, (test: unknown) => fn(test)), + ); await testRunner.run(builder).run(); - const call = (spawn as jest.Mock).mock.calls[0]; + const call = (spawn as Mock).mock.calls[0]; expect([call[0], ...call[1]]).toEqual(expected); }; -const shouldRunTest = async ( - expected: string[], - builder: Builder, - projectPath: (path: string) => string, - appPath: (path: string) => string, - start: { event: TeamcityEvent, name?: string, file: string, id: string, phpVfsComposer?: boolean, }, - finished: any, -) => { - generateTestResult(start, appPath, start.phpVfsComposer); - - await expectedCommand(builder, expected); - - expectedTestResult(finished, projectPath); -}; - -const shouldRunAllTest = async (expected: string[], builder: Builder, projectPath: (path: string) => string, appPath: (path: string) => string) => { - await shouldRunTest(expected, builder, projectPath, appPath, { - event: TeamcityEvent.testStarted, - name: 'test_passed', - file: appPath('tests/AssertionsTest.php'), - id: 'Tests\\AssertionsTest', - }, { - event: TeamcityEvent.testFinished, - name: 'test_passed', - flowId: expect.any(Number), - id: 'Tests\\AssertionsTest::test_passed', - file: projectPath('tests/AssertionsTest.php'), - }); -}; - -const shouldRunTestSuite = async (expected: string[], builder: Builder, projectPath: (uri: string) => string, appPath: (path: string) => string) => { - builder.setArguments(projectPath('tests/AssertionsTest.php')); - - await shouldRunTest(expected, builder, projectPath, appPath, { - event: TeamcityEvent.testSuiteStarted, - file: appPath('tests/AssertionsTest.php'), - id: 'Tests\\AssertionsTest', - }, { - event: TeamcityEvent.testSuiteFinished, - flowId: expect.any(Number), - id: 'Tests\\AssertionsTest', - file: projectPath('tests/AssertionsTest.php'), - }); -}; - -const shouldRunTestPassed = async (expected: string[], builder: Builder, projectPath: (path: string) => string, appPath: (path: string) => string) => { - const filter = `^.*::(test_passed)( with data set .*)?$`; - builder.setArguments(`${projectPath('tests/AssertionsTest.php')} --filter "${filter}"`); - - await shouldRunTest(expected, builder, projectPath, appPath, { - event: TeamcityEvent.testStarted, - name: 'test_passed', - file: appPath('tests/AssertionsTest.php'), - id: 'Tests\\AssertionsTest', - }, { - event: TeamcityEvent.testFinished, - flowId: expect.any(Number), - id: 'Tests\\AssertionsTest::test_passed', - file: projectPath('tests/AssertionsTest.php'), - }); -}; - -const shouldRunTestFailed = async (expected: string[], builder: Builder, projectPath: (uri: string) => string, appPath: (path: string) => string, phpVfsComposer: boolean = false) => { - const filter = `^.*::(test_passed|test_failed)( with data set .*)?$`; - builder.setArguments(`${projectPath('tests/AssertionsTest.php')} --filter "${filter}"`); - - await shouldRunTest(expected, builder, projectPath, appPath, { - event: TeamcityEvent.testFailed, - name: 'test_failed', - file: appPath('tests/AssertionsTest.php'), - id: 'Tests\\AssertionsTest', - phpVfsComposer, - }, { - event: TeamcityEvent.testFailed, - flowId: expect.any(Number), - id: 'Tests\\AssertionsTest::test_failed', - file: projectPath('tests/AssertionsTest.php'), - message: 'Failed asserting that false is true.', - details: [{ file: projectPath('tests/AssertionsTest.php'), line: 22 }], - }); -}; +const TEST_CLASS = 'Tests\\AssertionsTest'; describe('TestRunner Test', () => { - beforeEach(() => jest.restoreAllMocks()); + beforeEach(() => vi.restoreAllMocks()); it('run error command', async () => { const cwd = phpUnitProject(''); @@ -269,7 +219,7 @@ describe('TestRunner Test', () => { args: ['-c', '${PWD}/phpunit.xml'], }); - const builder = new Builder(configuration, { cwd }); + const builder = new ProcessBuilder(configuration, { cwd }); const expected = [ 'foo', 'vendor/bin/phpunit', @@ -283,464 +233,211 @@ describe('TestRunner Test', () => { expect(onTestRunnerEvents.get(TestRunnerEvent.close)!).toHaveBeenCalledTimes(1); }); - describe('local', () => { - const projectPath = phpUnitProject; - const appPath = phpUnitProject; - const cwd = projectPath(''); - const configuration = new Configuration({ - php: 'php', - phpunit: '${workspaceFolder}/vendor/bin/phpunit', - args: ['-c', '${workspaceFolder}/phpunit.xml'], - }); - const builder = new Builder(configuration, { cwd }); - - it('should run all tests', async () => { - const expected = [ - 'php', - appPath('vendor/bin/phpunit'), - `--configuration=${appPath('phpunit.xml')}`, - '--colors=never', - '--teamcity', - ]; - - await shouldRunAllTest(expected, builder, projectPath, appPath); - }); - - it('should run test suite', async () => { - const expected = [ - 'php', - appPath('vendor/bin/phpunit'), - `--configuration=${appPath('phpunit.xml')}`, - appPath('tests/AssertionsTest.php'), - '--colors=never', - '--teamcity', - ]; - - await shouldRunTestSuite(expected, builder, projectPath, appPath); - }); - - it('should run test passed', async () => { - const expected = [ - 'php', - appPath('vendor/bin/phpunit'), - `--configuration=${appPath('phpunit.xml')}`, - `--filter=^.*::(test_passed)( with data set .*)?$`, - appPath('tests/AssertionsTest.php'), - '--colors=never', - '--teamcity', - ]; - - await shouldRunTestPassed(expected, builder, projectPath, appPath); - }); - - it('should run test failed', async () => { - const expected = [ - 'php', - appPath('vendor/bin/phpunit'), - `--configuration=${appPath('phpunit.xml')}`, - `--filter=^.*::(test_passed|test_failed)( with data set .*)?$`, - appPath('tests/AssertionsTest.php'), - '--colors=never', - '--teamcity', - ]; - - await shouldRunTestFailed(expected, builder, projectPath, appPath); - }); - }); - - describe('SSH', () => { - const projectPath = phpUnitProject; - const appPath = (path?: string) => path ? `/app/${path}` : '/app'; - const cwd = projectPath(''); - const configuration = new Configuration({ - command: 'ssh -i dockerfiles/sshd/id_rsa -p 2222 root@localhost -o StrictHostKeyChecking=no cd /app;', - php: 'php', - phpunit: 'vendor/bin/phpunit', - args: ['-c', '/app/phpunit.xml'], - // eslint-disable-next-line @typescript-eslint/naming-convention - paths: { '${PWD}': appPath('') }, - }); - const builder = new Builder(configuration, { cwd }); - - it('should run all tests for SSH', async () => { - const expected = [ - 'ssh', - '-i', - 'dockerfiles/sshd/id_rsa', - '-p', - '2222', - 'root@localhost', - '-o', - 'StrictHostKeyChecking=no', - 'cd', - '/app;', - [ - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - `--colors=never`, - `--teamcity`, - ].join(' '), - ]; - - await shouldRunAllTest(expected, builder, projectPath, appPath); - }); - - it('should run test suite for SSH', async () => { - const expected = [ - 'ssh', - '-i', - 'dockerfiles/sshd/id_rsa', - '-p', - '2222', - 'root@localhost', - '-o', - 'StrictHostKeyChecking=no', - 'cd', - '/app;', - [ - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - appPath('tests/AssertionsTest.php'), - `--colors=never`, - `--teamcity`, - ].join(' '), - ]; - - await shouldRunTestSuite(expected, builder, projectPath, appPath); - }); - - it('should run test passed for SSH', async () => { - const expected = [ - 'ssh', - '-i', - 'dockerfiles/sshd/id_rsa', - '-p', - '2222', - 'root@localhost', - '-o', - 'StrictHostKeyChecking=no', - 'cd', - '/app;', - [ - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - `'--filter=^.*::(test_passed)( with data set .*)?$'`, - appPath('tests/AssertionsTest.php'), - `--colors=never`, - `--teamcity`, - ].join(' '), - ]; - - await shouldRunTestPassed(expected, builder, projectPath, appPath); + const testEnvironment = ( + name: string, + projectPath: (path: string) => string, + appPath: (path: string) => string, + configuration: Configuration, + buildCommand: (...middle: string[]) => string[], + options?: { skipPhpVfsComposer?: boolean }, + ) => { + const passedPattern = `^.*::(test_passed)( with data set .*)?$`; + const failedPattern = `^.*::(test_passed|test_failed)( with data set .*)?$`; + const filterPassed = `--filter=${passedPattern}`; + const filterFailed = `--filter=${failedPattern}`; + const testFile = appPath('tests/AssertionsTest.php'); + const localFile = projectPath('tests/AssertionsTest.php'); + + const startEvent = ( + event: TeamcityEvent, + opts?: { name?: string; phpVfsComposer?: boolean }, + ) => ({ event, file: testFile, id: TEST_CLASS, ...opts }); + + // biome-ignore lint/suspicious/noExplicitAny: test helper with dynamic property access + const finishedEvent = (event: TeamcityEvent, id: string, opts?: Record) => ({ + event, + flowId: expect.any(Number), + id, + file: localFile, + ...opts, }); - it('should run test failed for SSH', async () => { - const expected = [ - 'ssh', - '-i', - 'dockerfiles/sshd/id_rsa', - '-p', - '2222', - 'root@localhost', - '-o', - 'StrictHostKeyChecking=no', - 'cd', - '/app;', - [ - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - `'--filter=^.*::(test_passed|test_failed)( with data set .*)?$'`, - appPath('tests/AssertionsTest.php'), - `--colors=never`, - `--teamcity`, - ].join(' '), - ]; - - await shouldRunTestFailed(expected, builder, projectPath, appPath); + describe(name, () => { + const builder = new ProcessBuilder(configuration, { cwd: projectPath('') }); + + const runTest = async ( + expected: string[], + start: { + event: TeamcityEvent; + name?: string; + file: string; + id: string; + phpVfsComposer?: boolean; + }, + // biome-ignore lint/suspicious/noExplicitAny: test helper with dynamic property access + finished: any, + ) => { + generateTestResult(start, appPath, start.phpVfsComposer); + await expectedCommand(builder, expected); + expectedTestResult(finished, projectPath); + }; + + it('should run all tests', async () => { + await runTest( + buildCommand(), + startEvent(TeamcityEvent.testStarted, { name: 'test_passed' }), + finishedEvent(TeamcityEvent.testFinished, `${TEST_CLASS}::test_passed`, { + name: 'test_passed', + }), + ); + }); + + it('should run test suite', async () => { + builder.setArguments(localFile); + await runTest( + buildCommand(testFile), + startEvent(TeamcityEvent.testSuiteStarted), + finishedEvent(TeamcityEvent.testSuiteFinished, TEST_CLASS), + ); + }); + + it('should run test passed', async () => { + builder.setArguments(`${localFile} --filter "${passedPattern}"`); + await runTest( + buildCommand(filterPassed, testFile), + startEvent(TeamcityEvent.testStarted, { name: 'test_passed' }), + finishedEvent(TeamcityEvent.testFinished, `${TEST_CLASS}::test_passed`), + ); + }); + + it('should run test failed', async () => { + builder.setArguments(`${localFile} --filter "${failedPattern}"`); + await runTest( + buildCommand(filterFailed, testFile), + startEvent(TeamcityEvent.testFailed, { name: 'test_failed' }), + finishedEvent(TeamcityEvent.testFailed, `${TEST_CLASS}::test_failed`, { + message: 'Failed asserting that false is true.', + details: [{ file: localFile, line: 26 }], + }), + ); + }); + + if (!options?.skipPhpVfsComposer) { + it('should run test failed with phpvfscomposer', async () => { + builder.setArguments(`${localFile} --filter "${failedPattern}"`); + await runTest( + buildCommand(filterFailed, testFile), + startEvent(TeamcityEvent.testFailed, { + name: 'test_failed', + phpVfsComposer: true, + }), + finishedEvent(TeamcityEvent.testFailed, `${TEST_CLASS}::test_failed`, { + message: 'Failed asserting that false is true.', + details: [{ file: localFile, line: 26 }], + }), + ); + }); + } }); + }; - it('should run test failed with phpvfscomposer for Docker', async () => { - const expected = [ - 'ssh', - '-i', - 'dockerfiles/sshd/id_rsa', - '-p', - '2222', - 'root@localhost', - '-o', - 'StrictHostKeyChecking=no', - 'cd', - '/app;', - [ - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - `'--filter=^.*::(test_passed|test_failed)( with data set .*)?$'`, - appPath('tests/AssertionsTest.php'), - `--colors=never`, - `--teamcity`, - ].join(' '), - ]; - - await shouldRunTestFailed(expected, builder, projectPath, appPath, true); - }); - }); + const remoteAppPath = (path: string) => (path ? `/app/${path}` : '/app'); + // biome-ignore lint/suspicious/noControlCharactersInRegex: original test behavior preserved + const winAppPath = (path: string) => (path ? `./${path}` : '.').replace(/\/g/, '\\'); - describe('Docker', () => { - const projectPath = phpUnitProject; - const appPath = (path?: string) => path ? `/app/${path}` : '/app'; - const cwd = projectPath(''); - const configuration = new Configuration({ - command: 'docker run -i --rm -v ${workspaceFolder}:/app -w /app phpunit-stub', + testEnvironment( + 'local', + phpUnitProject, + phpUnitProject, + new Configuration({ php: 'php', - phpunit: 'vendor/bin/phpunit', - args: ['-c', '${PWD}/phpunit.xml'], - // eslint-disable-next-line @typescript-eslint/naming-convention - paths: { '${PWD}': appPath('') }, - }); - - const builder = new Builder(configuration, { cwd }); - - it('should run all tests for Docker', async () => { - const expected = [ - 'docker', - 'run', - '-i', - '--rm', - '-v', - `${projectPath('')}:/app`, - '-w', - '/app', - 'phpunit-stub', - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - '--colors=never', - '--teamcity', - ]; - - await shouldRunAllTest(expected, builder, projectPath, appPath); - }); - - it('should run test suite for Docker', async () => { - const expected = [ - 'docker', - 'run', - '-i', - '--rm', - '-v', - `${projectPath('')}:/app`, - '-w', - '/app', - 'phpunit-stub', - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - appPath('tests/AssertionsTest.php'), - '--colors=never', - '--teamcity', - ]; - - await shouldRunTestSuite(expected, builder, projectPath, appPath); - }); - - it('should run test passed for Docker', async () => { - const expected = [ - 'docker', - 'run', - '-i', - '--rm', - '-v', - `${projectPath('')}:/app`, - '-w', - '/app', - 'phpunit-stub', - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - `--filter=^.*::(test_passed)( with data set .*)?$`, - appPath('tests/AssertionsTest.php'), - '--colors=never', - '--teamcity', - ]; - - await shouldRunTestPassed(expected, builder, projectPath, appPath); - }); - - it('should run test failed for Docker', async () => { - const expected = [ - 'docker', - 'run', - '-i', - '--rm', - '-v', - `${projectPath('')}:/app`, - '-w', - '/app', - 'phpunit-stub', - 'php', 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - `--filter=^.*::(test_passed|test_failed)( with data set .*)?$`, - appPath('tests/AssertionsTest.php'), - '--colors=never', - '--teamcity', - ]; - - await shouldRunTestFailed(expected, builder, projectPath, appPath); - }); - - it('should run test failed with phpvfscomposer for Docker', async () => { - const expected = [ - 'docker', - 'run', - '-i', - '--rm', - '-v', - `${projectPath('')}:/app`, - '-w', - '/app', - 'phpunit-stub', - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - `--filter=^.*::(test_passed|test_failed)( with data set .*)?$`, - appPath('tests/AssertionsTest.php'), - '--colors=never', - '--teamcity', - ]; - - await shouldRunTestFailed(expected, builder, projectPath, appPath, true); - }); - }); + phpunit: '${workspaceFolder}/vendor/bin/phpunit', + args: ['-c', '${workspaceFolder}/phpunit.xml'], + }), + (...middle) => [ + 'php', + phpUnitProject('vendor/bin/phpunit'), + `--configuration=${phpUnitProject('phpunit.xml')}`, + ...middle, + '--colors=never', + '--teamcity', + ], + { skipPhpVfsComposer: true }, + ); - describe('Windows Docker', () => { - const projectPath = phpUnitProjectWin; - const appPath = (path?: string) => (path ? `./${path}` : '.').replace(/\/g/, '\\'); - const cwd = projectPath(''); - const configuration = new Configuration({ - command: 'docker run -i --rm -v ${workspaceFolder}:/app -w /app phpunit-stub', + const sshPrefix = [ + 'ssh', + '-i', + 'dockerfiles/sshd/id_rsa', + '-p', + '2222', + 'root@localhost', + '-o', + 'StrictHostKeyChecking=no', + 'cd', + '/app;', + ]; + testEnvironment( + 'SSH', + phpUnitProject, + remoteAppPath, + new Configuration({ + command: + 'ssh -i dockerfiles/sshd/id_rsa -p 2222 root@localhost -o StrictHostKeyChecking=no cd /app;', php: 'php', phpunit: 'vendor/bin/phpunit', - args: ['-c', '${PWD}/phpunit.xml'], - // eslint-disable-next-line @typescript-eslint/naming-convention - paths: { '${PWD}': appPath('') }, - }); - const builder = new Builder(configuration, { cwd }); - - it('should run all tests for Windows Docker', async () => { - const expected = [ - 'docker', - 'run', - '-i', - '--rm', - '-v', - `${projectPath('')}:/app`, - '-w', - '/app', - 'phpunit-stub', - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - '--colors=never', - '--teamcity', - ]; - - await shouldRunAllTest(expected, builder, projectPath, appPath); - }); - - it('should run test suite for Windows Docker', async () => { - const expected = [ - 'docker', - 'run', - '-i', - '--rm', - '-v', - `${projectPath('')}:/app`, - '-w', - '/app', - 'phpunit-stub', - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - appPath('tests/AssertionsTest.php'), - '--colors=never', - '--teamcity', - ]; - - await shouldRunTestSuite(expected, builder, projectPath, appPath); - }); - - it('should run test passed for Windows Docker', async () => { - const expected = [ - 'docker', - 'run', - '-i', - '--rm', - '-v', - `${projectPath('')}:/app`, - '-w', - '/app', - 'phpunit-stub', - 'php', - 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - `--filter=^.*::(test_passed)( with data set .*)?$`, - appPath('tests/AssertionsTest.php'), - '--colors=never', - '--teamcity', - ]; - - await shouldRunTestPassed(expected, builder, projectPath, appPath); - }); - - it('should run test failed for Windows Docker', async () => { - const expected = [ - 'docker', - 'run', - '-i', - '--rm', - '-v', - `${projectPath('')}:/app`, - '-w', - '/app', - 'phpunit-stub', + args: ['-c', '/app/phpunit.xml'], + paths: { '${PWD}': remoteAppPath('') }, + }), + (...middle) => [ + ...sshPrefix, + [ 'php', 'vendor/bin/phpunit', - `--configuration=${appPath('phpunit.xml')}`, - `--filter=^.*::(test_passed|test_failed)( with data set .*)?$`, - appPath('tests/AssertionsTest.php'), + `--configuration=${remoteAppPath('phpunit.xml')}`, + ...middle.map((a) => (a.startsWith('--filter') ? `'${a}'` : a)), '--colors=never', '--teamcity', - ]; - - await shouldRunTestFailed(expected, builder, projectPath, appPath); - }); + ].join(' '), + ], + ); - it('should run test failed with phpvfscomposer for Windows Docker', async () => { - const expected = [ - 'docker', - 'run', - '-i', - '--rm', - '-v', - `${projectPath('')}:/app`, - '-w', - '/app', - 'phpunit-stub', + const dockerPrefix = (projectPath: (p: string) => string) => [ + 'docker', + 'run', + '-i', + '--rm', + '-v', + `${projectPath('')}:/app`, + '-w', + '/app', + 'phpunit-stub', + ]; + + for (const [name, projectPath, appPath] of [ + ['Docker', phpUnitProject, remoteAppPath], + ['Windows Docker', phpUnitProjectWin, winAppPath], + ] as const) { + testEnvironment( + name, + projectPath, + appPath, + new Configuration({ + command: 'docker run -i --rm -v ${workspaceFolder}:/app -w /app phpunit-stub', + php: 'php', + phpunit: 'vendor/bin/phpunit', + args: ['-c', '${PWD}/phpunit.xml'], + paths: { '${PWD}': appPath('') }, + }), + (...middle) => [ + ...dockerPrefix(projectPath), 'php', 'vendor/bin/phpunit', `--configuration=${appPath('phpunit.xml')}`, - `--filter=^.*::(test_passed|test_failed)( with data set .*)?$`, - appPath('tests/AssertionsTest.php'), + ...middle, '--colors=never', '--teamcity', - ]; - - await shouldRunTestFailed(expected, builder, projectPath, appPath, true); - }); - }); -}); \ No newline at end of file + ], + ); + } +}); diff --git a/src/PHPUnit/TestRunner.ts b/src/PHPUnit/TestRunner.ts index 6f3d5c81..a0b6334d 100644 --- a/src/PHPUnit/TestRunner.ts +++ b/src/PHPUnit/TestRunner.ts @@ -1,90 +1,17 @@ -import { spawn } from 'child_process'; -import { ChildProcess } from 'node:child_process'; -import { EventEmitter } from 'node:events'; -import { Builder } from './CommandBuilder'; -import { ProblemMatcher, TeamcityEvent, TestResult } from './ProblemMatcher'; -import { EventResultMap, TestRunnerEvent, TestRunnerEventProxy, TestRunnerObserver } from './TestRunnerObserver'; - -export class TestRunnerProcess { - private child?: ChildProcess; - private emitter = new EventEmitter(); - private output = ''; - private temp = ''; - private abortController: AbortController; - - constructor(private builder: Builder) { - this.abortController = new AbortController(); - } - - on(eventName: string, callback: (...args: any[]) => void) { - this.emitter.on(eventName, callback); - - return this; - } - - emit(eventName: string, ...args: any[]) { - this.emitter.emit(eventName, ...args); - } - - run() { - return new Promise((resolve) => { - this.execute(); - this.child?.on('error', () => resolve(true)); - this.child?.on('close', () => resolve(true)); - }); - } - - getCloverFile() { - return this.builder.getXdebug()?.getCloverFile(); - } - - abort() { - this.abortController.abort(); - - const killed = this.child?.killed; - if (killed) { - this.emitter.emit('abort'); - } - - return killed; - } - - private execute() { - this.output = ''; - this.temp = ''; - - this.emitter.emit('start', this.builder); - const { runtime, args, options } = this.builder.build(); - this.child = spawn(runtime, args, { ...options, signal: this.abortController.signal }); - this.child.stdout!.on('data', (data) => this.appendOutput(data)); - this.child.stderr!.on('data', (data) => this.appendOutput(data)); - this.child.stdout!.on('end', () => this.emitLines(this.temp)); - this.child.on('error', (err: Error) => this.emitter.emit('error', err)); - this.child.on('close', (code) => this.emitter.emit('close', code, this.output)); - } - - private appendOutput(data: string) { - const out = data.toString(); - this.output += out; - this.temp += out; - const lines = this.emitLines(this.temp, 1); - this.temp = lines.shift()!; - }; - - private emitLines(temp: string, limit = 0) { - const lines = temp.split(/\r\n|\n/); - while (lines.length > limit) { - this.emitter.emit('line', lines.shift()!); - } - - return lines; - } -} +import { ProblemMatcher, type TestResult } from './ProblemMatcher'; +import type { ProcessBuilder } from './ProcessBuilder'; +import { + type EventResultMap, + TestRunnerEvent, + TestRunnerEventProxy, + type TestRunnerObserver, +} from './TestRunnerObserver'; +import { TestRunnerProcess } from './TestRunnerProcess'; export class TestRunner { private readonly defaultObserver: TestRunnerEventProxy; private readonly problemMatcher = new ProblemMatcher(); - private readonly teamcityPattern = new RegExp('##teamcity\\[', 'i'); + private readonly teamcityPattern = /##teamcity\[/i; private observers: TestRunnerObserver[] = []; constructor() { @@ -96,46 +23,57 @@ export class TestRunner { this.observers.push(observer); } - on(eventName: K, callback: (result: EventResultMap[K]) => void): this { + on( + eventName: K, + callback: (result: EventResultMap[K]) => void, + ): this { this.defaultObserver.on(eventName, callback); return this; } - run(builder: Builder) { + run(builder: ProcessBuilder) { const process = new TestRunnerProcess(builder); - process.on('start', (builder: Builder) => this.emit(TestRunnerEvent.run, builder)); + + process.on('start', (builder: ProcessBuilder) => this.emit(TestRunnerEvent.run, builder)); process.on('line', (line: string) => this.processLine(line, builder)); - process.on('error', (err: Error) => { - const error = err.stack ?? err.message; - this.emit(TestRunnerEvent.error, error); - this.emit(TestRunnerEvent.close, 2); - }); - process.on('close', (code: number | null, output: string) => { - const eventName = this.isTestRunning(output) ? TestRunnerEvent.output : TestRunnerEvent.error; - this.emit(eventName, output); - this.emit(TestRunnerEvent.close, code); - }); + process.on('error', (err: Error) => this.handleProcessError(err)); + process.on('close', (code: number | null, output: string) => + this.handleProcessClose(code, output), + ); return process; } - emit(eventName: TestRunnerEvent | TeamcityEvent, result: TestResult | any) { - this.observers - .filter((observer) => observer[eventName]) - .forEach((observer) => (observer[eventName] as Function)(result)); + emit(eventName: K, result: EventResultMap[K]) { + for (const observer of this.observers) { + const handler = observer[eventName] as + | ((result: EventResultMap[K]) => void) + | undefined; + handler?.call(observer, result); + } + } + + private handleProcessError(err: Error) { + const error = err.stack ?? err.message; + this.emit(TestRunnerEvent.error, error); + this.emit(TestRunnerEvent.close, 2); } - private isTestRunning(output: string) { - return this.teamcityPattern.test(output); + private handleProcessClose(code: number | null, output: string) { + const eventName = this.teamcityPattern.test(output) + ? TestRunnerEvent.output + : TestRunnerEvent.error; + this.emit(eventName, output); + this.emit(TestRunnerEvent.close, code); } - private processLine(line: string, builder: Builder) { - this.emitResult(builder, this.problemMatcher.parse(line)); + private processLine(line: string, builder: ProcessBuilder) { + this.emitTestResult(builder, this.problemMatcher.parse(line)); this.emit(TestRunnerEvent.line, line); } - private emitResult(builder: Builder, result: TestResult | undefined) { + private emitTestResult(builder: ProcessBuilder, result: TestResult | undefined) { if (!result) { return; } diff --git a/src/PHPUnit/TestRunnerObserver.test.ts b/src/PHPUnit/TestRunnerObserver.test.ts new file mode 100644 index 00000000..cba21d7b --- /dev/null +++ b/src/PHPUnit/TestRunnerObserver.test.ts @@ -0,0 +1,144 @@ +import { describe, expect, it, vi } from 'vitest'; +import { TeamcityEvent } from './ProblemMatcher'; +import { + TestRunnerEvent, + TestRunnerEventProxy, + type TestRunnerObserver, +} from './TestRunnerObserver'; + +describe('TestRunnerObserver', () => { + describe('TestRunnerObserver type covers all events', () => { + it('should allow implementing all TestRunnerEvent handlers', () => { + const observer: TestRunnerObserver = { + start: () => {}, + run: () => {}, + line: () => {}, + result: () => {}, + output: () => {}, + error: () => {}, + close: () => {}, + abort: () => {}, + done: () => {}, + }; + + expect(observer.start).toBeDefined(); + expect(observer.run).toBeDefined(); + expect(observer.line).toBeDefined(); + expect(observer.result).toBeDefined(); + expect(observer.output).toBeDefined(); + expect(observer.error).toBeDefined(); + expect(observer.close).toBeDefined(); + expect(observer.abort).toBeDefined(); + expect(observer.done).toBeDefined(); + }); + + it('should allow implementing all TeamcityEvent handlers', () => { + const observer: TestRunnerObserver = { + testVersion: () => {}, + testProcesses: () => {}, + testRuntime: () => {}, + testConfiguration: () => {}, + testSuiteStarted: () => {}, + testCount: () => {}, + testStarted: () => {}, + testFinished: () => {}, + testFailed: () => {}, + testIgnored: () => {}, + testSuiteFinished: () => {}, + testDuration: () => {}, + testResultSummary: () => {}, + }; + + expect(observer.testVersion).toBeDefined(); + expect(observer.testProcesses).toBeDefined(); + expect(observer.testRuntime).toBeDefined(); + expect(observer.testConfiguration).toBeDefined(); + expect(observer.testSuiteStarted).toBeDefined(); + expect(observer.testCount).toBeDefined(); + expect(observer.testStarted).toBeDefined(); + expect(observer.testFinished).toBeDefined(); + expect(observer.testFailed).toBeDefined(); + expect(observer.testIgnored).toBeDefined(); + expect(observer.testSuiteFinished).toBeDefined(); + expect(observer.testDuration).toBeDefined(); + expect(observer.testResultSummary).toBeDefined(); + }); + + it('should allow partial implementation (only some handlers)', () => { + const observer: TestRunnerObserver = { + testFailed: () => {}, + error: () => {}, + }; + + expect(observer.testFailed).toBeDefined(); + expect(observer.error).toBeDefined(); + expect(observer.testFinished).toBeUndefined(); + }); + }); + + describe('EventResultMap covers all events', () => { + it('should have keys for every TestRunnerEvent', () => { + const allRunnerEvents = Object.values(TestRunnerEvent); + const mapKeys = new Set(); + + // EventResultMap keys are verified by TypeScript at compile time, + // but we verify at runtime that the proxy registers all events + const proxy = new TestRunnerEventProxy(); + for (const event of allRunnerEvents) { + expect(typeof proxy[event]).toBe('function'); + mapKeys.add(event); + } + + expect(mapKeys.size).toBe(allRunnerEvents.length); + }); + + it('should have keys for every TeamcityEvent', () => { + const allTeamcityEvents = Object.values(TeamcityEvent); + const proxy = new TestRunnerEventProxy(); + + for (const event of allTeamcityEvents) { + expect(typeof proxy[event]).toBe('function'); + } + }); + }); + + describe('TestRunnerEventProxy', () => { + it('should notify listeners when event is emitted', () => { + const proxy = new TestRunnerEventProxy(); + const callback = vi.fn(); + + proxy.on(TestRunnerEvent.line, callback); + proxy[TestRunnerEvent.line]('test line'); + + expect(callback).toHaveBeenCalledWith('test line'); + }); + + it('should notify listeners for teamcity events', () => { + const proxy = new TestRunnerEventProxy(); + const callback = vi.fn(); + + proxy.on(TeamcityEvent.testFailed, callback); + const fakeResult = { + event: TeamcityEvent.testFailed, + name: 'test', + flowId: 1, + } as unknown as import('./ProblemMatcher').TestFailed; + proxy[TeamcityEvent.testFailed](fakeResult); + + expect(callback).toHaveBeenCalledWith(fakeResult); + }); + + it('should support multiple listeners for the same event', () => { + const proxy = new TestRunnerEventProxy(); + const callback1 = vi.fn(); + const callback2 = vi.fn(); + + proxy.on(TestRunnerEvent.error, callback1); + proxy.on(TestRunnerEvent.error, callback2); + proxy[TestRunnerEvent.error]('some error'); + + expect(callback1).toHaveBeenCalledWith('some error'); + expect(callback2).toHaveBeenCalledWith('some error'); + }); + }); +}); diff --git a/src/PHPUnit/TestRunnerObserver.ts b/src/PHPUnit/TestRunnerObserver.ts index 0c487cde..77d2b85d 100644 --- a/src/PHPUnit/TestRunnerObserver.ts +++ b/src/PHPUnit/TestRunnerObserver.ts @@ -1,8 +1,20 @@ -import { Builder } from './CommandBuilder'; -import { - TeamcityEvent, TestConfiguration, TestCount, TestDuration, TestFailed, TestFinished, TestIgnored, TestProcesses, - TestResult, TestResultSummary, TestRuntime, TestStarted, TestSuiteFinished, TestSuiteStarted, TestVersion, +import type { + TestConfiguration, + TestCount, + TestDuration, + TestFailed, + TestFinished, + TestIgnored, + TestProcesses, + TestResultSummary, + TestRuntime, + TestStarted, + TestSuiteFinished, + TestSuiteStarted, + TestVersion, } from './ProblemMatcher'; +import { TeamcityEvent, type TestResult } from './ProblemMatcher'; +import type { ProcessBuilder } from './ProcessBuilder'; export enum TestRunnerEvent { start = 'start', @@ -18,7 +30,7 @@ export enum TestRunnerEvent { export type EventResultMap = { [TestRunnerEvent.start]: undefined; - [TestRunnerEvent.run]: Builder; + [TestRunnerEvent.run]: ProcessBuilder; [TestRunnerEvent.line]: string; [TestRunnerEvent.result]: TestResult; [TestRunnerEvent.output]: string; @@ -43,100 +55,85 @@ export type EventResultMap = { export type TestRunnerObserver = Partial<{ [K in keyof EventResultMap]: (result: EventResultMap[K]) => void; -} & { [p in TeamcityEvent]: (result: EventResultMap[p]) => void }> +}>; export class TestRunnerEventProxy implements TestRunnerObserver { - private listeners: { [K in keyof EventResultMap]?: Array<(result: EventResultMap[K]) => void> } = {}; + private listeners: { + [K in keyof EventResultMap]?: Array<(result: EventResultMap[K]) => void>; + } = {}; start(): void { - this.emit(TestRunnerEvent.start, undefined); + this.notify(TestRunnerEvent.start, undefined); } - - run(builder: Builder): void { - this.emit(TestRunnerEvent.run, builder); + run(builder: ProcessBuilder): void { + this.notify(TestRunnerEvent.run, builder); } - line(line: string): void { - this.emit(TestRunnerEvent.line, line); + this.notify(TestRunnerEvent.line, line); + } + result(result: TestResult): void { + this.notify(TestRunnerEvent.result, result); } - output(output: string): void { - this.emit(TestRunnerEvent.output, output); + this.notify(TestRunnerEvent.output, output); } - error(error: string): void { - this.emit(TestRunnerEvent.error, error); + this.notify(TestRunnerEvent.error, error); } - close(code: number | null): void { - this.emit(TestRunnerEvent.close, code); + this.notify(TestRunnerEvent.close, code); } - abort(): void { - this.emit(TestRunnerEvent.abort, undefined); + this.notify(TestRunnerEvent.abort, undefined); } - done(): void { - this.emit(TestRunnerEvent.done, undefined); - } - - result(result: TestResult): void { - this.emit(TestRunnerEvent.result, result); + this.notify(TestRunnerEvent.done, undefined); } testVersion(result: TestVersion): void { - this.emit(TeamcityEvent.testVersion, result); + this.notify(TeamcityEvent.testVersion, result); } - testProcesses(result: TestProcesses): void { - this.emit(TeamcityEvent.testProcesses, result); + this.notify(TeamcityEvent.testProcesses, result); } - testRuntime(result: TestRuntime): void { - this.emit(TeamcityEvent.testRuntime, result); + this.notify(TeamcityEvent.testRuntime, result); } - testConfiguration(result: TestConfiguration): void { - this.emit(TeamcityEvent.testConfiguration, result); + this.notify(TeamcityEvent.testConfiguration, result); } - testSuiteStarted(result: TestSuiteStarted): void { - this.emit(TeamcityEvent.testSuiteStarted, result); + this.notify(TeamcityEvent.testSuiteStarted, result); } - testCount(result: TestCount): void { - this.emit(TeamcityEvent.testCount, result); + this.notify(TeamcityEvent.testCount, result); } - testStarted(result: TestStarted): void { - this.emit(TeamcityEvent.testStarted, result); + this.notify(TeamcityEvent.testStarted, result); } - testFinished(result: TestFinished): void { - this.emit(TeamcityEvent.testFinished, result); + this.notify(TeamcityEvent.testFinished, result); } - testFailed(result: TestFailed): void { - this.emit(TeamcityEvent.testFailed, result); + this.notify(TeamcityEvent.testFailed, result); } - testIgnored(result: TestIgnored): void { - this.emit(TeamcityEvent.testIgnored, result); + this.notify(TeamcityEvent.testIgnored, result); } - testSuiteFinished(result: TestSuiteFinished): void { - this.emit(TeamcityEvent.testSuiteFinished, result); + this.notify(TeamcityEvent.testSuiteFinished, result); } - testDuration(result: TestDuration): void { - this.emit(TeamcityEvent.testDuration, result); + this.notify(TeamcityEvent.testDuration, result); } - testResultSummary(result: TestResultSummary): void { - this.emit(TeamcityEvent.testResultSummary, result); + this.notify(TeamcityEvent.testResultSummary, result); } - on(eventName: K, fn: (result: EventResultMap[K]) => void): this { + on( + eventName: K, + fn: (result: EventResultMap[K]) => void, + ): this { if (!this.listeners[eventName]) { this.listeners[eventName] = []; } @@ -145,7 +142,7 @@ export class TestRunnerEventProxy implements TestRunnerObserver { return this; } - private emit(eventName: K, result: EventResultMap[K]): void { - this.listeners[eventName]?.forEach(callback => callback(result)); + private notify(eventName: K, result: EventResultMap[K]): void { + this.listeners[eventName]?.forEach((callback) => callback(result)); } } diff --git a/src/PHPUnit/TestRunnerProcess.ts b/src/PHPUnit/TestRunnerProcess.ts new file mode 100644 index 00000000..df616dea --- /dev/null +++ b/src/PHPUnit/TestRunnerProcess.ts @@ -0,0 +1,82 @@ +import type { ChildProcess } from 'node:child_process'; +import { spawn } from 'node:child_process'; +import { EventEmitter } from 'node:events'; +import type { ProcessBuilder } from './ProcessBuilder'; + +export class TestRunnerProcess { + private child?: ChildProcess; + private emitter = new EventEmitter(); + private output = ''; + private incompleteLineBuffer = ''; + private abortController: AbortController; + + constructor(private builder: ProcessBuilder) { + this.abortController = new AbortController(); + } + + // biome-ignore lint/suspicious/noExplicitAny: EventEmitter callback signature requires any[] + on(eventName: string, callback: (...args: any[]) => void) { + this.emitter.on(eventName, callback); + + return this; + } + + // biome-ignore lint/suspicious/noExplicitAny: EventEmitter emit signature requires any[] + emit(eventName: string, ...args: any[]) { + this.emitter.emit(eventName, ...args); + } + + run() { + return new Promise((resolve) => { + this.execute(); + this.child?.on('error', () => resolve(true)); + this.child?.on('close', () => resolve(true)); + }); + } + + getCloverFile() { + return this.builder.getXdebug()?.getCloverFile(); + } + + abort() { + this.abortController.abort(); + + const killed = this.child?.killed; + if (killed) { + this.emitter.emit('abort'); + } + + return killed; + } + + private execute() { + this.output = ''; + this.incompleteLineBuffer = ''; + + this.emitter.emit('start', this.builder); + const { runtime, args, options } = this.builder.build(); + this.child = spawn(runtime, args, { ...options, signal: this.abortController.signal }); + this.child.stdout?.on('data', (data) => this.processOutput(data)); + this.child.stderr?.on('data', (data) => this.processOutput(data)); + this.child.stdout?.on('end', () => this.flushCompleteLines(this.incompleteLineBuffer)); + this.child.on('error', (err: Error) => this.emitter.emit('error', err)); + this.child.on('close', (code) => this.emitter.emit('close', code, this.output)); + } + + private processOutput(data: string) { + const out = data.toString(); + this.output += out; + this.incompleteLineBuffer += out; + const lines = this.flushCompleteLines(this.incompleteLineBuffer, 1); + this.incompleteLineBuffer = lines.shift()!; + } + + private flushCompleteLines(buffer: string, limit = 0) { + const lines = buffer.split(/\r\n|\n/); + while (lines.length > limit) { + this.emitter.emit('line', lines.shift()!); + } + + return lines; + } +} diff --git a/src/PHPUnit/Transformer/PHPUnitFixer.ts b/src/PHPUnit/Transformer/PHPUnitFixer.ts index 8f6f3cba..d9021de2 100644 --- a/src/PHPUnit/Transformer/PHPUnitFixer.ts +++ b/src/PHPUnit/Transformer/PHPUnitFixer.ts @@ -1,4 +1,4 @@ -import { TestFailed, TestIgnored, TestResult } from '../ProblemMatcher'; +import type { TestFailed, TestIgnored, TestResult } from '../ProblemMatcher'; import { TransformerFactory } from './TransformerFactory'; import { getPrevTestResult } from './utils'; @@ -8,7 +8,7 @@ export class PHPUnitFixer { return testResult; } - const prevTestResult = getPrevTestResult(new RegExp('^(php_qn):\/\/'), cache, testResult); + const prevTestResult = getPrevTestResult(/^(php_qn):\/\//, cache, testResult); if (!prevTestResult) { return testResult; } @@ -17,11 +17,11 @@ export class PHPUnitFixer { const parts = prevTestResult.locationHint?.split('::') ?? []; const locationHint = parts.slice(0, Math.max(2, parts.length - 1)).join('::'); testResult.locationHint = [locationHint, testResult.name] - .filter(value => !!value) + .filter((value) => !!value) .join('::'); } - const transformer = TransformerFactory.factory(testResult.locationHint); + const transformer = TransformerFactory.create(testResult.locationHint); const { id, file } = transformer.fromLocationHit(testResult.locationHint, testResult.name); testResult.id = id; testResult.file = file; diff --git a/src/PHPUnit/Transformer/PHPUnitTransformer.ts b/src/PHPUnit/Transformer/PHPUnitTransformer.ts index 5646175a..0a96727d 100644 --- a/src/PHPUnit/Transformer/PHPUnitTransformer.ts +++ b/src/PHPUnit/Transformer/PHPUnitTransformer.ts @@ -1,9 +1,11 @@ -import { TestDefinition, TestType } from '../types'; +import { type TestDefinition, TestType } from '../types'; import { capitalize, snakeCase, titleCase } from '../utils'; import { Transformer } from './Transformer'; export class PHPUnitTransformer extends Transformer { - uniqueId(testDefinition: Pick): string { + uniqueId( + testDefinition: Pick, + ): string { let { type, classFQN } = testDefinition; classFQN = classFQN!.replace(/Test$/i, ''); const partsFQN = classFQN.replace(/Test$/i, '').split('\\'); @@ -19,10 +21,13 @@ export class PHPUnitTransformer extends Transformer { } return [classFQN, this.getMethodName({ methodName: testDefinition.methodName })].join('::'); - }; + } fromLocationHit(locationHint: string, _name: string) { - const partsLocation = locationHint.replace(/^php_qn:\/\//, '').replace(/::\\/g, '::').split('::'); + const partsLocation = locationHint + .replace(/^php_qn:\/\//, '') + .replace(/::\\/g, '::') + .split('::'); const file = partsLocation.shift(); const [classFQN, methodName] = partsLocation; @@ -33,8 +38,8 @@ export class PHPUnitTransformer extends Transformer { } protected normalizeMethodName(methodName: string) { - return capitalize(snakeCase( - methodName.replace(/^test/i, '').replace(/_/g, ' ').trim(), - )).replace(/_/g, ' '); + return capitalize( + snakeCase(methodName.replace(/^test/i, '').replace(/_/g, ' ').trim()), + ).replace(/_/g, ' '); } -} \ No newline at end of file +} diff --git a/src/PHPUnit/Transformer/PestFixer.ts b/src/PHPUnit/Transformer/PestFixer.ts index 8fc52bd8..c174f065 100644 --- a/src/PHPUnit/Transformer/PestFixer.ts +++ b/src/PHPUnit/Transformer/PestFixer.ts @@ -1,14 +1,8 @@ -import { TeamcityEvent, TestFailed, TestIgnored, TestResult } from '../ProblemMatcher'; -import { capitalize } from '../utils'; +import type { TestFailed, TestIgnored, TestResult } from '../ProblemMatcher'; import { getPrevTestResult } from './utils'; -class Str { - static prefix = '__pest_evaluable_'; - - static evaluable(code: string) { - return this.prefix + code.replace(/_/g, '__').replace(/\s/g, '_').replace(/[^a-zA-Z0-9_\u0080-\uFFFF]/g, '_'); - } -} +export { PestV1Fixer } from './PestV1Fixer'; +export { PestV2Fixer } from './PestV2Fixer'; export class PestFixer { static fixNoTestStarted(cache: Map, testResult: TestFailed | TestIgnored) { @@ -28,89 +22,16 @@ export class PestFixer { return testResult; } - const pattern = new RegExp('^(pest_qn|file):\/\/'); + const pattern = /^(pest_qn|file):\/\//; const prevTestResult = getPrevTestResult(pattern, cache, testResult); if (prevTestResult) { - testResult.id = [ - prevTestResult.locationHint?.replace(pattern, ''), - testResult.name, - ].filter(v => !!v).join('::'); - - return testResult; - } - - return testResult; - } -} - -export class PestV1Fixer { - static fixLocationHint(locationHint: string) { - return this.fixDataSet(/^tests\//.test(locationHint) ? locationHint : locationHint.substring(locationHint.lastIndexOf('tests/'))); - } + testResult.id = [prevTestResult.locationHint?.replace(pattern, ''), testResult.name] + .filter((v) => !!v) + .join('::'); - static fixFlowId(cache: Map, testResult?: TestResult) { - if (!testResult) { return testResult; } - const events = [TeamcityEvent.testStarted, TeamcityEvent.testFailed, TeamcityEvent.testIgnored]; - if ('event' in testResult && !events.includes(testResult.event) || (testResult as any).flowId) { - return testResult; - } - - const result = Array.from(cache.values()).reverse().find((result: TestResult) => { - if (testResult.event !== TeamcityEvent.testStarted) { - return result.event === TeamcityEvent.testStarted && (result as any).name === (testResult as any).name; - } - - const matched = (testResult as any).id?.match(/\((?.+)\)/); - - return matched && (result as any).id === matched.groups?.id.replace(/\\/g, '/') + 'Test'; - }); - - (testResult as any).flowId = (result as any)?.flowId; - return testResult; } - - private static fixDataSet(locationHint: string) { - const matched = locationHint.match(/(?.+)\swith\s\('(?.+)'\)/); - - return matched && matched.groups?.description - ? `${matched.groups.description} with data set "(\'${matched.groups.data}\')"` - : locationHint; - } -} - -export class PestV2Fixer { - static fixId(location: string, name: string) { - return this.hasPrefix(name) ? name : location; - } - - static isEqualsPestV2DataSetId(result: TestResult, testItemId: string) { - if (!('id' in result) || !this.hasPrefix(result.id)) { - return false; - } - - let [classFQN, method] = testItemId.split('::'); - classFQN = capitalize(classFQN.replace(/\//g, '\\').replace(/\.php$/, '')); - - return [classFQN, this.methodName(method)].join('::') === result.id; - } - - private static hasPrefix(id?: string) { - return id && new RegExp(Str.prefix).test(id); - } - - static methodName(methodName: string) { - methodName = methodName.replace(/\{@\*}/g, '*/'); - const matched = methodName.match(/(?.*)\swith\sdata\sset\s(?.+)/); - let dataset = ''; - if (matched) { - methodName = matched.groups!.method; - dataset = matched.groups!.dataset.replace(/\|'/g, '\''); - } - - return Str.evaluable(methodName) + dataset; - } } diff --git a/src/PHPUnit/Transformer/PestTransFormer.test.ts b/src/PHPUnit/Transformer/PestTransFormer.test.ts index d0d2d4b4..af53b6da 100644 --- a/src/PHPUnit/Transformer/PestTransFormer.test.ts +++ b/src/PHPUnit/Transformer/PestTransFormer.test.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { TestType } from '../types'; import { PestV2Fixer } from './PestFixer'; import { PestTransformer } from './PestTransformer'; @@ -19,10 +20,12 @@ describe('PestTransformer', () => { it('ensures the given closures reports the correct class name and suggests the [pest()] function', () => { const type = TestType.method; const className = 'P\\Tests\\Unit\\ExampleTest'; - const methodName = 'ensures the given closures reports the correct class name and suggests the [pest()] function'; + const methodName = + 'ensures the given closures reports the correct class name and suggests the [pest()] function'; const classFQN = className; - const expected = 'tests/Unit/ExampleTest.php::ensures the given closures reports the correct class name and suggests the [pest()] function'; + const expected = + 'tests/Unit/ExampleTest.php::ensures the given closures reports the correct class name and suggests the [pest()] function'; expect(transformer.uniqueId({ type, classFQN, methodName })).toEqual(expected); }); }); @@ -31,339 +34,90 @@ describe('PestTransformer', () => { it('test /** with comment */ should do', () => { const input = 'test /** with comment */ should do'; const expected = 'test /\\*\\* with comment \\*/ should do'; - expect(input.replace(/([\[\]()*])/g, '\\$1')).toEqual(expected); + expect(input.replace(/([[\]()*])/g, '\\$1')).toEqual(expected); }); it('ensures the given closures reports the correct class name and suggests the [pest()] function', () => { - const input = 'ensures the given closures reports the correct class name and suggests the [pest()] function'; - const expected = 'ensures the given closures reports the correct class name and suggests the \\[pest\\(\\)\\] function'; - expect(input.replace(/([\[\]()*])/g, '\\$1')).toEqual(expected); + const input = + 'ensures the given closures reports the correct class name and suggests the [pest()] function'; + const expected = + 'ensures the given closures reports the correct class name and suggests the \\[pest\\(\\)\\] function'; + expect(input.replace(/([[\]()*])/g, '\\$1')).toEqual(expected); }); }); describe('pest id', () => { - it('test description', () => { - const actual = PestV2Fixer.methodName('test description'); - - expect(actual).toEqual('__pest_evaluable_test_description'); - }); - - it('test_description', () => { - const actual = PestV2Fixer.methodName('test_description'); - - expect(actual).toEqual('__pest_evaluable_test__description'); - }); - - it('ふ+が+', () => { - const actual = PestV2Fixer.methodName('ふ+が+'); - - expect(actual).toEqual('__pest_evaluable_ふ_が_'); - }); - - it('ほげ', () => { - const actual = PestV2Fixer.methodName('ほげ'); - - expect(actual).toEqual('__pest_evaluable_ほげ'); - }); - - it('卜竹弓一十山', () => { - const actual = PestV2Fixer.methodName('卜竹弓一十山'); - - expect(actual).toEqual('__pest_evaluable_卜竹弓一十山'); - }); - - it('アゴデヸ', () => { - const actual = PestV2Fixer.methodName('アゴデヸ'); - - expect(actual).toEqual('__pest_evaluable_アゴデヸ'); - }); - - it('!p8VrB', () => { - const actual = PestV2Fixer.methodName('!p8VrB'); - - expect(actual).toEqual('__pest_evaluable__p8VrB'); - }); - - it('&xe6VeKWF#n4', () => { - const actual = PestV2Fixer.methodName('&xe6VeKWF#n4'); - - expect(actual).toEqual('__pest_evaluable__amp_xe6VeKWF_n4'); - }); - - it('%%HurHUnw7zM!', () => { - const actual = PestV2Fixer.methodName('%%HurHUnw7zM!'); - - expect(actual).toEqual('__pest_evaluable___HurHUnw7zM_'); - }); - - it('rundeliekend', () => { - const actual = PestV2Fixer.methodName('rundeliekend'); - - expect(actual).toEqual('__pest_evaluable_rundeliekend'); - }); - - it('g%%c!Jt9$fy#Kf', () => { - const actual = PestV2Fixer.methodName('g%%c!Jt9$fy#Kf'); - - expect(actual).toEqual('__pest_evaluable_g__c_Jt9_fy_Kf'); - }); - - it('NRs*Gz2@hmB$W$BPD%%b2U%3P%z%apnwSX', () => { - const actual = PestV2Fixer.methodName('NRs*Gz2@hmB$W$BPD%%b2U%3P%z%apnwSX'); - - expect(actual).toEqual('__pest_evaluable_NRs_Gz2_hmB_W_BPD__b2U_3P_z_apnwSX'); - }); - - it('ÀĤ{¼÷', () => { - const actual = PestV2Fixer.methodName('ÀĤ{¼÷'); - - expect(actual).toEqual('__pest_evaluable_ÀĤ_¼÷'); - }); - - it('ìèéàòç', () => { - const actual = PestV2Fixer.methodName('ìèéàòç'); - - expect(actual).toEqual('__pest_evaluable_ìèéàòç'); - }); - - it('زهراء المعادي', () => { - const actual = PestV2Fixer.methodName('زهراء المعادي'); - - expect(actual).toEqual('__pest_evaluable_زهراء_المعادي'); - }); - - it('الجبيهه', () => { - const actual = PestV2Fixer.methodName('الجبيهه'); - - expect(actual).toEqual('__pest_evaluable_الجبيهه'); - }); - - it('الظهران', () => { - const actual = PestV2Fixer.methodName('الظهران'); - - expect(actual).toEqual('__pest_evaluable_الظهران'); - }); - - it('Каролин', () => { - const actual = PestV2Fixer.methodName('Каролин'); - - expect(actual).toEqual('__pest_evaluable_Каролин'); - }); - - it('অ্যান্টার্কটিকা', () => { - const actual = PestV2Fixer.methodName('অ্যান্টার্কটিকা'); - - expect(actual).toEqual('__pest_evaluable_অ্যান্টার্কটিকা'); - }); - - it('Frýdek-Místek"', () => { - const actual = PestV2Fixer.methodName('Frýdek-Místek"'); - - expect(actual).toEqual('__pest_evaluable_Frýdek_Místek_'); - }); - - it('Allingåbro&', () => { - const actual = PestV2Fixer.methodName('Allingåbro&'); - - expect(actual).toEqual('__pest_evaluable_Allingåbro_amp_'); - }); - - it('Κεντροαφρικανική Δημοκρατία', () => { - const actual = PestV2Fixer.methodName('Κεντροαφρικανική Δημοκρατία'); - - expect(actual).toEqual('__pest_evaluable_Κεντροαφρικανική_Δημοκρατία'); - }); - - it('آذربایجان غربی', () => { - const actual = PestV2Fixer.methodName('آذربایجان غربی'); - - expect(actual).toEqual('__pest_evaluable_آذربایجان_غربی'); - }); - - it('זימבבואה', () => { - const actual = PestV2Fixer.methodName('זימבבואה'); - - expect(actual).toEqual('__pest_evaluable_זימבבואה'); - }); - - it('Belišće', () => { - const actual = PestV2Fixer.methodName('Belišće'); - - expect(actual).toEqual('__pest_evaluable_Belišće'); - }); - - it('Գվատեմալա', () => { - const actual = PestV2Fixer.methodName('Գվատեմալա'); - - expect(actual).toEqual('__pest_evaluable_Գվատեմալա'); - }); - - it('パプアニューギニア', () => { - const actual = PestV2Fixer.methodName('パプアニューギニア'); - - expect(actual).toEqual('__pest_evaluable_パプアニューギニア'); - }); - - it('富山県', () => { - const actual = PestV2Fixer.methodName('富山県'); - - expect(actual).toEqual('__pest_evaluable_富山県'); - }); - - it('Қарағанды', () => { - const actual = PestV2Fixer.methodName('Қарағанды'); - - expect(actual).toEqual('__pest_evaluable_Қарағанды'); - }); - - it('Қостанай', () => { - const actual = PestV2Fixer.methodName('Қостанай'); - - expect(actual).toEqual('__pest_evaluable_Қостанай'); - }); - - it('안양시 동안구', () => { - const actual = PestV2Fixer.methodName('안양시 동안구'); - - expect(actual).toEqual('__pest_evaluable_안양시_동안구'); - }); - - it('Itālija', () => { - const actual = PestV2Fixer.methodName('Itālija'); - - expect(actual).toEqual('__pest_evaluable_Itālija'); - }); - - it('Honningsvåg', () => { - const actual = PestV2Fixer.methodName('Honningsvåg'); - - expect(actual).toEqual('__pest_evaluable_Honningsvåg'); - }); - - it('Águeda', () => { - const actual = PestV2Fixer.methodName('Águeda'); - - expect(actual).toEqual('__pest_evaluable_Águeda'); - }); - - it('Râșcani', () => { - const actual = PestV2Fixer.methodName('Râșcani'); - - expect(actual).toEqual('__pest_evaluable_Râșcani'); - }); - - it('Năsăud', () => { - const actual = PestV2Fixer.methodName('Năsăud'); - - expect(actual).toEqual('__pest_evaluable_Năsăud'); - }); - - it('Орехово-Зуево', () => { - const actual = PestV2Fixer.methodName('Орехово-Зуево'); - - expect(actual).toEqual('__pest_evaluable_Орехово_Зуево'); - }); - - it('Čereňany', () => { - const actual = PestV2Fixer.methodName('Čereňany'); - - expect(actual).toEqual('__pest_evaluable_Čereňany'); - }); - - it('Moravče', () => { - const actual = PestV2Fixer.methodName('Moravče'); - - expect(actual).toEqual('__pest_evaluable_Moravče'); - }); - - it('Šentjernej', () => { - const actual = PestV2Fixer.methodName('Šentjernej'); - - expect(actual).toEqual('__pest_evaluable_Šentjernej'); - }); - - it('Врање', () => { - const actual = PestV2Fixer.methodName('Врање'); - - expect(actual).toEqual('__pest_evaluable_Врање'); - }); - - it('Крушевац', () => { - const actual = PestV2Fixer.methodName('Крушевац'); - - expect(actual).toEqual('__pest_evaluable_Крушевац'); - }); - - it('Åkersberga', () => { - const actual = PestV2Fixer.methodName('Åkersberga'); - - expect(actual).toEqual('__pest_evaluable_Åkersberga'); - }); - - it('บอสเนียและเฮอร์เซโกวีนา', () => { - const actual = PestV2Fixer.methodName('บอสเนียและเฮอร์เซโกวีนา'); - - expect(actual).toEqual('__pest_evaluable_บอสเนียและเฮอร์เซโกวีนา'); - }); - - it('Birleşik Arap Emirlikleri', () => { - const actual = PestV2Fixer.methodName('Birleşik Arap Emirlikleri'); - - expect(actual).toEqual('__pest_evaluable_Birleşik_Arap_Emirlikleri'); - }); - - it('Німеччина', () => { - const actual = PestV2Fixer.methodName('Німеччина'); - - expect(actual).toEqual('__pest_evaluable_Німеччина'); - }); - - it('Nam Định', () => { - const actual = PestV2Fixer.methodName('Nam Định'); - - expect(actual).toEqual('__pest_evaluable_Nam_Định'); - }); - - it('呼和浩特', () => { - const actual = PestV2Fixer.methodName('呼和浩特'); - - expect(actual).toEqual('__pest_evaluable_呼和浩特'); - }); - - it('test /** with comment */ should do', () => { - const actual = PestV2Fixer.methodName('test /** with comment */ should do'); - - expect(actual).toEqual('__pest_evaluable_test_____with_comment____should_do'); - }); - - it('test /** with comment */ should do', () => { - const actual = PestV2Fixer.methodName('test /** with comment */ should do'); - - expect(actual).toEqual('__pest_evaluable_test_____with_comment____should_do'); - }); - - it('ensures the given closures reports the correct class name and suggests the [pest()] function', () => { - const actual = PestV2Fixer.methodName('ensures the given closures reports the correct class name and suggests the [pest()] function'); - - expect(actual).toEqual('__pest_evaluable_ensures_the_given_closures_reports_the_correct_class_name_and_suggests_the__pest____function'); - }); - - it('adds coverage if --min exist', () => { - const actual = PestV2Fixer.methodName('adds coverage if --min exist'); - - expect(actual).toEqual('__pest_evaluable_adds_coverage_if___min_exist'); - }); - - it('has_emails with dataset', () => { - const actual = PestV2Fixer.methodName(`it has emails with data set "(|'enunomaduro@gmail.com|')"`); - - expect(actual).toEqual('__pest_evaluable_it_has_emails"(\'enunomaduro@gmail.com\')"'); - }); - - it('test /** with comment {@*} should do', () => { - const actual = PestV2Fixer.methodName('test /** with comment {@*} should do'); - - expect(actual).toEqual('__pest_evaluable_test_____with_comment____should_do'); + it.each([ + ['test description', '__pest_evaluable_test_description'], + ['test_description', '__pest_evaluable_test__description'], + ['ふ+が+', '__pest_evaluable_ふ_が_'], + ['ほげ', '__pest_evaluable_ほげ'], + ['卜竹弓一十山', '__pest_evaluable_卜竹弓一十山'], + ['アゴデヸ', '__pest_evaluable_アゴデヸ'], + ['!p8VrB', '__pest_evaluable__p8VrB'], + ['&xe6VeKWF#n4', '__pest_evaluable__amp_xe6VeKWF_n4'], + ['%%HurHUnw7zM!', '__pest_evaluable___HurHUnw7zM_'], + ['rundeliekend', '__pest_evaluable_rundeliekend'], + ['g%%c!Jt9$fy#Kf', '__pest_evaluable_g__c_Jt9_fy_Kf'], + [ + 'NRs*Gz2@hmB$W$BPD%%b2U%3P%z%apnwSX', + '__pest_evaluable_NRs_Gz2_hmB_W_BPD__b2U_3P_z_apnwSX', + ], + ['ÀĤ{¼÷', '__pest_evaluable_ÀĤ_¼÷'], + ['ìèéàòç', '__pest_evaluable_ìèéàòç'], + ['زهراء المعادي', '__pest_evaluable_زهراء_المعادي'], + ['الجبيهه', '__pest_evaluable_الجبيهه'], + ['الظهران', '__pest_evaluable_الظهران'], + ['Каролин', '__pest_evaluable_Каролин'], + ['অ্যান্টার্কটিকা', '__pest_evaluable_অ্যান্টার্কটিকা'], + ['Frýdek-Místek"', '__pest_evaluable_Frýdek_Místek_'], + ['Allingåbro&', '__pest_evaluable_Allingåbro_amp_'], + ['Κεντροαφρικανική Δημοκρατία', '__pest_evaluable_Κεντροαφρικανική_Δημοκρατία'], + ['آذربایجان غربی', '__pest_evaluable_آذربایجان_غربی'], + ['זימבבואה', '__pest_evaluable_זימבבואה'], + ['Belišće', '__pest_evaluable_Belišće'], + ['Գվատեմալա', '__pest_evaluable_Գվատեմալա'], + ['パプアニューギニア', '__pest_evaluable_パプアニューギニア'], + ['富山県', '__pest_evaluable_富山県'], + ['Қарағанды', '__pest_evaluable_Қарағанды'], + ['Қостанай', '__pest_evaluable_Қостанай'], + ['안양시 동안구', '__pest_evaluable_안양시_동안구'], + ['Itālija', '__pest_evaluable_Itālija'], + ['Honningsvåg', '__pest_evaluable_Honningsvåg'], + ['Águeda', '__pest_evaluable_Águeda'], + ['Râșcani', '__pest_evaluable_Râșcani'], + ['Năsăud', '__pest_evaluable_Năsăud'], + ['Орехово-Зуево', '__pest_evaluable_Орехово_Зуево'], + ['Čereňany', '__pest_evaluable_Čereňany'], + ['Moravče', '__pest_evaluable_Moravče'], + ['Šentjernej', '__pest_evaluable_Šentjernej'], + ['Врање', '__pest_evaluable_Врање'], + ['Крушевац', '__pest_evaluable_Крушевац'], + ['Åkersberga', '__pest_evaluable_Åkersberga'], + ['บอสเนียและเฮอร์เซโกวีนา', '__pest_evaluable_บอสเนียและเฮอร์เซโกวีนา'], + ['Birleşik Arap Emirlikleri', '__pest_evaluable_Birleşik_Arap_Emirlikleri'], + ['Німеччина', '__pest_evaluable_Німеччина'], + ['Nam Định', '__pest_evaluable_Nam_Định'], + ['呼和浩特', '__pest_evaluable_呼和浩特'], + [ + 'test /** with comment */ should do', + '__pest_evaluable_test_____with_comment____should_do', + ], + [ + 'ensures the given closures reports the correct class name and suggests the [pest()] function', + '__pest_evaluable_ensures_the_given_closures_reports_the_correct_class_name_and_suggests_the__pest____function', + ], + ['adds coverage if --min exist', '__pest_evaluable_adds_coverage_if___min_exist'], + [ + `it has emails with data set "(|'enunomaduro@gmail.com|')"`, + '__pest_evaluable_it_has_emails"(\'enunomaduro@gmail.com\')"', + ], + [ + 'test /** with comment {@*} should do', + '__pest_evaluable_test_____with_comment____should_do', + ], + ])('PestV2Fixer.methodName(%j) → %s', (input, expected) => { + expect(PestV2Fixer.methodName(input)).toEqual(expected); }); }); -}); \ No newline at end of file +}); diff --git a/src/PHPUnit/Transformer/PestTransformer.ts b/src/PHPUnit/Transformer/PestTransformer.ts index 80ad5f04..98345140 100644 --- a/src/PHPUnit/Transformer/PestTransformer.ts +++ b/src/PHPUnit/Transformer/PestTransformer.ts @@ -1,11 +1,13 @@ -import { TestDefinition, TestType } from '../types'; +import { type TestDefinition, TestType } from '../types'; import { uncapitalize } from '../utils'; import { PestV1Fixer, PestV2Fixer } from './PestFixer'; import { PHPUnitTransformer } from './PHPUnitTransformer'; import { TransformerFactory } from './TransformerFactory'; export class PestTransformer extends PHPUnitTransformer { - uniqueId(testDefinition: Pick): string { + uniqueId( + testDefinition: Pick, + ): string { if (!TransformerFactory.isPest(testDefinition.classFQN!)) { return super.uniqueId(testDefinition); } @@ -21,14 +23,23 @@ export class PestTransformer extends PHPUnitTransformer { return classFQN; } - return [uncapitalize(classFQN).replace(/\\/g, '/') + '.php', this.getMethodName(testDefinition)].join('::'); - }; + return [ + `${uncapitalize(classFQN).replace(/\\/g, '/')}.php`, + this.getMethodName(testDefinition), + ].join('::'); + } fromLocationHit(locationHint: string, name: string) { - const matched = locationHint.match(/(pest_qn|file):\/\/(?(?[\w\s]+)\((?[\w\\]+)\)(::(?.+))?)/); + const matched = locationHint.match( + /(pest_qn|file):\/\/(?(?[\w\s]+)\((?[\w\\]+)\)(::(?.+))?)/, + ); if (!matched) { - const location = PestV1Fixer.fixLocationHint(locationHint.replace(/(pest_qn|file):\/\//, '').replace(/\\/g, '/')); - const id = this.removeDataset(this.normalizeMethodName(PestV2Fixer.fixId(location, name))); + const location = PestV1Fixer.fixLocationHint( + locationHint.replace(/(pest_qn|file):\/\//, '').replace(/\\/g, '/'), + ); + const id = this.removeDataset( + this.normalizeMethodName(PestV2Fixer.fixId(location, name)), + ); const file = location.split('::')[0]; return { id, file }; @@ -49,4 +60,4 @@ export class PestTransformer extends PHPUnitTransformer { protected normalizeMethodName(methodName: string) { return methodName.replace(/\{@\*}/g, '*/'); } -} \ No newline at end of file +} diff --git a/src/PHPUnit/Transformer/PestV1Fixer.ts b/src/PHPUnit/Transformer/PestV1Fixer.ts new file mode 100644 index 00000000..2c1cdf09 --- /dev/null +++ b/src/PHPUnit/Transformer/PestV1Fixer.ts @@ -0,0 +1,52 @@ +import { TeamcityEvent, type TestResult } from '../ProblemMatcher'; + +export class PestV1Fixer { + static fixLocationHint(locationHint: string) { + return PestV1Fixer.fixDataSet( + /^tests\//.test(locationHint) + ? locationHint + : locationHint.substring(locationHint.lastIndexOf('tests/')), + ); + } + + static fixFlowId(cache: Map, testResult?: TestResult) { + if (!testResult) { + return testResult; + } + + const events = [ + TeamcityEvent.testStarted, + TeamcityEvent.testFailed, + TeamcityEvent.testIgnored, + ]; + const tr = testResult as TestResult & { flowId?: number; name?: string; id?: string }; + if (('event' in testResult && !events.includes(testResult.event)) || tr.flowId) { + return testResult; + } + + const result = Array.from(cache.values()) + .reverse() + .find((result: TestResult) => { + const r = result as TestResult & { name?: string; id?: string }; + if (testResult.event !== TeamcityEvent.testStarted) { + return result.event === TeamcityEvent.testStarted && r.name === tr.name; + } + + const matched = tr.id?.match(/\((?.+)\)/); + + return matched && r.id === `${matched.groups?.id.replace(/\\/g, '/')}Test`; + }); + + tr.flowId = (result as (TestResult & { flowId?: number }) | undefined)?.flowId; + + return testResult; + } + + private static fixDataSet(locationHint: string) { + const matched = locationHint.match(/(?.+)\swith\s\('(?.+)'\)/); + + return matched?.groups?.description + ? `${matched.groups.description} with data set "('${matched.groups.data}')"` + : locationHint; + } +} diff --git a/src/PHPUnit/Transformer/PestV2Fixer.ts b/src/PHPUnit/Transformer/PestV2Fixer.ts new file mode 100644 index 00000000..e6b8d27b --- /dev/null +++ b/src/PHPUnit/Transformer/PestV2Fixer.ts @@ -0,0 +1,49 @@ +import type { TestResult } from '../ProblemMatcher'; +import { capitalize } from '../utils'; + +class Str { + static prefix = '__pest_evaluable_'; + + static evaluable(code: string) { + return ( + Str.prefix + + code + .replace(/_/g, '__') + .replace(/\s/g, '_') + .replace(/[^a-zA-Z0-9_\u0080-\uFFFF]/g, '_') + ); + } +} + +export class PestV2Fixer { + static fixId(location: string, name: string) { + return PestV2Fixer.hasPrefix(name) ? name : location; + } + + static isEqualsPestV2DataSetId(result: TestResult, testItemId: string) { + if (!('id' in result) || !PestV2Fixer.hasPrefix(result.id)) { + return false; + } + + let [classFQN, method] = testItemId.split('::'); + classFQN = capitalize(classFQN.replace(/\//g, '\\').replace(/\.php$/, '')); + + return [classFQN, PestV2Fixer.methodName(method)].join('::') === result.id; + } + + private static hasPrefix(id?: string) { + return id && new RegExp(Str.prefix).test(id); + } + + static methodName(methodName: string) { + methodName = methodName.replace(/\{@\*}/g, '*/'); + const matched = methodName.match(/(?.*)\swith\sdata\sset\s(?.+)/); + let dataset = ''; + if (matched) { + methodName = matched.groups!.method; + dataset = matched.groups!.dataset.replace(/\|'/g, "'"); + } + + return Str.evaluable(methodName) + dataset; + } +} diff --git a/src/PHPUnit/Transformer/Transformer.ts b/src/PHPUnit/Transformer/Transformer.ts index 57cefacb..3cc411b4 100644 --- a/src/PHPUnit/Transformer/Transformer.ts +++ b/src/PHPUnit/Transformer/Transformer.ts @@ -1,14 +1,19 @@ -import { TestResultIdentify } from '../ProblemMatcher'; -import { TestDefinition, TestType } from '../types'; +import type { TestResultIdentify } from '../ProblemMatcher'; +import { type TestDefinition, TestType } from '../types'; export abstract class Transformer { static generateSearchText(input: string) { - return input.replace(/([\[\]()*+$!\\])/g, '\\$1').replace(/@/g, '[\\W]'); + return input.replace(/([[\]()*+$!\\])/g, '\\$1').replace(/@/g, '[\\W]'); } - generateLabel(testDefinition: Pick & { - label?: string - }): string { + generateLabel( + testDefinition: Pick< + TestDefinition, + 'type' | 'classFQN' | 'className' | 'methodName' | 'annotations' + > & { + label?: string; + }, + ): string { const { type, classFQN, className, methodName, annotations, label } = testDefinition; if (annotations?.testdox && annotations.testdox.length > 0) { @@ -30,19 +35,23 @@ export abstract class Transformer { return methodName!.replace(/`/g, ''); } - abstract uniqueId(testDefinition: Pick): string ; + abstract uniqueId( + testDefinition: Pick, + ): string; - abstract fromLocationHit(locationHint: string, name: string): TestResultIdentify + abstract fromLocationHit(locationHint: string, name: string): TestResultIdentify; - protected abstract normalizeMethodName(methodName: string): string + protected abstract normalizeMethodName(methodName: string): string; protected getMethodName(testDefinition: Pick) { let { methodName, annotations } = testDefinition; let dataset = ''; - const matched = methodName!.match(/(?.*)(?\swith\sdata\sset\s[#"].+$)/); - if (matched && matched.groups) { - methodName = matched.groups['methodName']; - dataset = matched.groups['dataset']; + const matched = methodName?.match( + /(?.*)(?\swith\sdata\sset\s[#"].+$)/, + ); + if (matched?.groups) { + methodName = matched.groups.methodName; + dataset = matched.groups.dataset; } if (annotations?.testdox && annotations.testdox.length > 0) { @@ -57,4 +66,4 @@ export abstract class Transformer { protected removeDataset(id: string) { return id.replace(/\swith\sdata\sset\s[#"].+$/, ''); } -} \ No newline at end of file +} diff --git a/src/PHPUnit/Transformer/TransformerFactory.ts b/src/PHPUnit/Transformer/TransformerFactory.ts index 61ce0d1c..a69655bd 100644 --- a/src/PHPUnit/Transformer/TransformerFactory.ts +++ b/src/PHPUnit/Transformer/TransformerFactory.ts @@ -3,17 +3,10 @@ import { PHPUnitTransformer } from './PHPUnitTransformer'; export abstract class TransformerFactory { static isPest(text: string) { - return new RegExp([ - '^pest', - '^P\\\\', - '^pest_qn:\/\/', - '^file:\/\/', - ].join('|'), 'i').test(text); + return new RegExp(['^pest', '^P\\\\', '^pest_qn://', '^file://'].join('|'), 'i').test(text); } - static factory(text: string) { - return this.isPest(text) ? new PestTransformer() : new PHPUnitTransformer(); + static create(text: string) { + return TransformerFactory.isPest(text) ? new PestTransformer() : new PHPUnitTransformer(); } } - - diff --git a/src/PHPUnit/Transformer/index.ts b/src/PHPUnit/Transformer/index.ts index db1fbda3..51082b73 100644 --- a/src/PHPUnit/Transformer/index.ts +++ b/src/PHPUnit/Transformer/index.ts @@ -1,7 +1,9 @@ -export * from './Transformer'; -export * from './TransformerFactory'; -export * from './PHPUnitFixer'; -export * from './PHPUnitTransformer'; export * from './PestFixer'; export * from './PestTransformer'; -export { getPrevTestResult } from './utils'; \ No newline at end of file +export * from './PestV1Fixer'; +export * from './PestV2Fixer'; +export * from './PHPUnitFixer'; +export * from './PHPUnitTransformer'; +export * from './Transformer'; +export * from './TransformerFactory'; +export { getPrevTestResult } from './utils'; diff --git a/src/PHPUnit/Transformer/utils.ts b/src/PHPUnit/Transformer/utils.ts index 19ef7b74..72421542 100644 --- a/src/PHPUnit/Transformer/utils.ts +++ b/src/PHPUnit/Transformer/utils.ts @@ -1,6 +1,17 @@ -import { TeamcityEvent, TestFailed, TestIgnored, TestResult, TestStarted, TestSuiteStarted } from '../ProblemMatcher'; +import { + TeamcityEvent, + type TestFailed, + type TestIgnored, + type TestResult, + type TestStarted, + type TestSuiteStarted, +} from '../ProblemMatcher'; -export const getPrevTestResult = (pattern: RegExp, cache: Map, testResult: TestFailed | TestIgnored) => { +export const getPrevTestResult = ( + pattern: RegExp, + cache: Map, + testResult: TestFailed | TestIgnored, +) => { for (const prevTestResult of Array.from(cache.values()).reverse()) { if (isTestStarted(pattern, prevTestResult)) { return prevTestResult as TestStarted | TestSuiteStarted; @@ -19,6 +30,8 @@ export const getPrevTestResult = (pattern: RegExp, cache: Map { - return [TeamcityEvent.testStarted, TeamcityEvent.testSuiteStarted].includes(testResult.event) - && pattern.test(testResult.locationHint ?? ''); -}; \ No newline at end of file + return ( + [TeamcityEvent.testStarted, TeamcityEvent.testSuiteStarted].includes(testResult.event) && + pattern.test(testResult.locationHint ?? '') + ); +}; diff --git a/src/PHPUnit/Element.ts b/src/PHPUnit/XmlElement.ts similarity index 50% rename from src/PHPUnit/Element.ts rename to src/PHPUnit/XmlElement.ts index 4d039a5b..074e4ab9 100644 --- a/src/PHPUnit/Element.ts +++ b/src/PHPUnit/XmlElement.ts @@ -1,29 +1,29 @@ -import { XMLParser } from 'fast-xml-parser'; import { readFile } from 'node:fs/promises'; +import { XMLParser } from 'fast-xml-parser'; const parser = new XMLParser({ ignoreAttributes: false, trimValues: true }); -export class Element { - constructor(private readonly node: any) {} +export class XmlElement { + constructor(private readonly node: Record) {} static async loadFile(file: string) { - return Element.load(await readFile(file)); + return XmlElement.load(await readFile(file)); } static load(buffer: string | Buffer | Uint8Array) { - return new Element(parser.parse(buffer.toString())); + return new XmlElement(parser.parse(buffer.toString())); } - getAttribute(key: string) { - return this.node[`@_${key}`] ?? undefined; + getAttribute(key: string): string | undefined { + return (this.node[`@_${key}`] as string) ?? undefined; } - getText() { + getText(): string { if (typeof this.node === 'string') { return this.node; } - return this.node['#text']; + return this.node['#text'] as string; } querySelector(selector: string) { @@ -32,13 +32,15 @@ export class Element { querySelectorAll(selector: string) { const segments = selector.split(' '); - let current = this.node; + let current: unknown = this.node; while (segments.length > 0) { const segment = segments.shift()!; if (Array.isArray(current)) { - current = current.flatMap((node) => node[segment] ?? undefined).filter((node) => node !== undefined); + current = current + .flatMap((node: Record) => node[segment] ?? undefined) + .filter((node: unknown) => node !== undefined); } else { - current = current[segment] ?? undefined; + current = (current as Record)[segment] ?? undefined; } if (current === undefined) { @@ -46,10 +48,12 @@ export class Element { } } - return this.ensureArray(current).map((node) => new Element(node)); + return this.ensureArray(current).map( + (node: Record) => new XmlElement(node), + ); } - private ensureArray(obj: any) { + private ensureArray(obj: unknown) { return Array.isArray(obj) ? obj : [obj]; } -} \ No newline at end of file +} diff --git a/src/PHPUnit/__mocks__/child_process.ts b/src/PHPUnit/__mocks__/child_process.ts index 48ef1b03..7e11b94c 100644 --- a/src/PHPUnit/__mocks__/child_process.ts +++ b/src/PHPUnit/__mocks__/child_process.ts @@ -1,5 +1,6 @@ // eslint-disable-next-line @typescript-eslint/naming-convention -const child_process = jest.requireActual('child_process'); -const spawn = jest.spyOn(child_process, 'spawn'); +const child_process = await vi.importActual('child_process'); +const spawn = vi.spyOn(child_process, 'spawn'); -module.exports = { ...child_process, spawn }; +export { spawn }; +export const { exec, execSync, execFile, execFileSync, fork, spawnSync } = child_process; diff --git a/src/PHPUnit/__tests__/fixtures/.gitignore b/src/PHPUnit/__tests__/fixtures/.gitignore new file mode 100644 index 00000000..16402302 --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/.gitignore @@ -0,0 +1,9 @@ +.vendor-cache/ +.phpunit.cache/ +.phpunit.result.cache +phpunit-stub/.vscode/ +pest-stub/.vscode/ +phpunit-stub/v*/vendor/ +phpunit-stub/v*/composer.lock +pest-stub/v*/vendor/ +pest-stub/v*/composer.lock diff --git a/src/PHPUnit/__tests__/fixtures/pest-stub/composer.json b/src/PHPUnit/__tests__/fixtures/pest-stub/composer.json index 14e18a16..5148a76c 100644 --- a/src/PHPUnit/__tests__/fixtures/pest-stub/composer.json +++ b/src/PHPUnit/__tests__/fixtures/pest-stub/composer.json @@ -1,30 +1,30 @@ { - "name": "recca0120/vscode-phpunit", - "type": "project", - "require-dev": { - "mockery/mockery": "^1.5 || 1.3", - "pestphp/pest": "^1.23.1 || ^2.36 || ^3.6" - }, - "license": "MIT", - "autoload": { - "psr-4": { - "App\\": "src/" + "name": "recca0120/vscode-phpunit", + "type": "project", + "require-dev": { + "mockery/mockery": "^1.5 || 1.3", + "pestphp/pest": "^1.23.1 || ^2.36 || ^3.6" + }, + "license": "MIT", + "autoload": { + "psr-4": { + "App\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "authors": [ + { + "name": "recca0120", + "email": "recca0120@gmail.com" + } + ], + "config": { + "allow-plugins": { + "pestphp/pest-plugin": true + } } - }, - "autoload-dev": { - "psr-4": { - "Tests\\": "tests/" - } - }, - "authors": [ - { - "name": "recca0120", - "email": "recca0120@gmail.com" - } - ], - "config": { - "allow-plugins": { - "pestphp/pest-plugin": true - } - } } diff --git a/src/PHPUnit/__tests__/fixtures/pest-stub/v2/composer.json b/src/PHPUnit/__tests__/fixtures/pest-stub/v2/composer.json new file mode 100644 index 00000000..4767da44 --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/pest-stub/v2/composer.json @@ -0,0 +1,30 @@ +{ + "name": "recca0120/vscode-phpunit", + "type": "project", + "require-dev": { + "mockery/mockery": "^1.5 || 1.3", + "pestphp/pest": "^2.0" + }, + "license": "MIT", + "autoload": { + "psr-4": { + "App\\": "../src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "../tests/" + } + }, + "authors": [ + { + "name": "recca0120", + "email": "recca0120@gmail.com" + } + ], + "config": { + "allow-plugins": { + "pestphp/pest-plugin": true + } + } +} diff --git a/src/PHPUnit/__tests__/fixtures/pest-stub/v2/phpunit.xml b/src/PHPUnit/__tests__/fixtures/pest-stub/v2/phpunit.xml new file mode 100644 index 00000000..ae97e749 --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/pest-stub/v2/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ../tests + + + + + ../app + ../src + + + diff --git a/src/PHPUnit/__tests__/fixtures/pest-stub/v3/composer.json b/src/PHPUnit/__tests__/fixtures/pest-stub/v3/composer.json new file mode 100644 index 00000000..d5368177 --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/pest-stub/v3/composer.json @@ -0,0 +1,30 @@ +{ + "name": "recca0120/vscode-phpunit", + "type": "project", + "require-dev": { + "mockery/mockery": "^1.5 || 1.3", + "pestphp/pest": "^3.6" + }, + "license": "MIT", + "autoload": { + "psr-4": { + "App\\": "../src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "../tests/" + } + }, + "authors": [ + { + "name": "recca0120", + "email": "recca0120@gmail.com" + } + ], + "config": { + "allow-plugins": { + "pestphp/pest-plugin": true + } + } +} diff --git a/src/PHPUnit/__tests__/fixtures/pest-stub/v3/phpunit.xml b/src/PHPUnit/__tests__/fixtures/pest-stub/v3/phpunit.xml new file mode 100644 index 00000000..c60fe822 --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/pest-stub/v3/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ../tests + + + + + ../app + ../src + + + diff --git a/src/PHPUnit/__tests__/fixtures/pest-stub/v4/composer.json b/src/PHPUnit/__tests__/fixtures/pest-stub/v4/composer.json new file mode 100644 index 00000000..b5c253ee --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/pest-stub/v4/composer.json @@ -0,0 +1,30 @@ +{ + "name": "recca0120/vscode-phpunit", + "type": "project", + "require-dev": { + "mockery/mockery": "^1.5 || 1.3", + "pestphp/pest": "^4.0" + }, + "license": "MIT", + "autoload": { + "psr-4": { + "App\\": "../src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "../tests/" + } + }, + "authors": [ + { + "name": "recca0120", + "email": "recca0120@gmail.com" + } + ], + "config": { + "allow-plugins": { + "pestphp/pest-plugin": true + } + } +} diff --git a/src/PHPUnit/__tests__/fixtures/pest-stub/v4/phpunit.xml b/src/PHPUnit/__tests__/fixtures/pest-stub/v4/phpunit.xml new file mode 100644 index 00000000..c60fe822 --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/pest-stub/v4/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ../tests + + + + + ../app + ../src + + + diff --git a/src/PHPUnit/__tests__/fixtures/phpunit-stub/composer.json b/src/PHPUnit/__tests__/fixtures/phpunit-stub/composer.json index 3d02d814..c8f4447b 100644 --- a/src/PHPUnit/__tests__/fixtures/phpunit-stub/composer.json +++ b/src/PHPUnit/__tests__/fixtures/phpunit-stub/composer.json @@ -1,26 +1,26 @@ { - "name": "recca0120/vscode-phpunit", - "type": "project", - "require-dev": { - "phpunit/phpunit": "^12.0 || ^11.0 || ^10.0 || ^9.5 || ^7.5", - "mockery/mockery": "^1.5 || 1.3", - "brianium/paratest": "^7.0 || ^6.6 || ^4.0" - }, - "license": "MIT", - "autoload": { - "psr-4": { - "App\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "Tests\\": "tests/" - } - }, - "authors": [ - { - "name": "recca0120", - "email": "recca0120@gmail.com" - } - ] + "name": "recca0120/vscode-phpunit", + "type": "project", + "require-dev": { + "phpunit/phpunit": "^12.0 || ^11.0 || ^10.0 || ^9.5 || ^7.5", + "mockery/mockery": "^1.5 || 1.3", + "brianium/paratest": "^7.0 || ^6.6 || ^4.0" + }, + "license": "MIT", + "autoload": { + "psr-4": { + "App\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "authors": [ + { + "name": "recca0120", + "email": "recca0120@gmail.com" + } + ] } diff --git a/src/PHPUnit/__tests__/fixtures/phpunit-stub/tests/AssertionsTest.php b/src/PHPUnit/__tests__/fixtures/phpunit-stub/tests/AssertionsTest.php index 592623ad..d276a9b2 100644 --- a/src/PHPUnit/__tests__/fixtures/phpunit-stub/tests/AssertionsTest.php +++ b/src/PHPUnit/__tests__/fixtures/phpunit-stub/tests/AssertionsTest.php @@ -3,17 +3,22 @@ namespace Tests; use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; +use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; class AssertionsTest extends TestCase { use MockeryPHPUnitIntegration; + /** + * @group integration + */ public function test_passed() { $this->assertTrue(true); } + #[Group('integration')] /** * @depends test_passed */ @@ -32,6 +37,7 @@ public function test_risky() $a = 1; } + #[\PHPUnit\Framework\Attributes\Group('integration')] /** * @test */ diff --git a/src/PHPUnit/__tests__/fixtures/phpunit-stub/tests/AttributeTest.php b/src/PHPUnit/__tests__/fixtures/phpunit-stub/tests/AttributeTest.php index a5590185..ccde3aa3 100644 --- a/src/PHPUnit/__tests__/fixtures/phpunit-stub/tests/AttributeTest.php +++ b/src/PHPUnit/__tests__/fixtures/phpunit-stub/tests/AttributeTest.php @@ -4,10 +4,12 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\TestDox; use PHPUnit\Framework\TestCase; +#[Group('integration')] class AttributeTest extends TestCase { #[Test] diff --git a/src/PHPUnit/__tests__/fixtures/phpunit-stub/v10/composer.json b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v10/composer.json new file mode 100644 index 00000000..d1000d43 --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v10/composer.json @@ -0,0 +1,26 @@ +{ + "name": "recca0120/vscode-phpunit", + "type": "project", + "require-dev": { + "phpunit/phpunit": "^10.0", + "mockery/mockery": "^1.5 || 1.3", + "brianium/paratest": "^7.0 || ^6.6 || ^4.0" + }, + "license": "MIT", + "autoload": { + "psr-4": { + "App\\": "../src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "../tests/" + } + }, + "authors": [ + { + "name": "recca0120", + "email": "recca0120@gmail.com" + } + ] +} diff --git a/src/PHPUnit/__tests__/fixtures/phpunit-stub/v10/phpunit.xml b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v10/phpunit.xml new file mode 100644 index 00000000..96d0013f --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v10/phpunit.xml @@ -0,0 +1,22 @@ + + + + + ../tests + ../tests/Output + + + + + ../src + + + diff --git a/src/PHPUnit/__tests__/fixtures/phpunit-stub/v11/composer.json b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v11/composer.json new file mode 100644 index 00000000..ebb8b802 --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v11/composer.json @@ -0,0 +1,26 @@ +{ + "name": "recca0120/vscode-phpunit", + "type": "project", + "require-dev": { + "phpunit/phpunit": "^11.0", + "mockery/mockery": "^1.5 || 1.3", + "brianium/paratest": "^7.0 || ^6.6 || ^4.0" + }, + "license": "MIT", + "autoload": { + "psr-4": { + "App\\": "../src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "../tests/" + } + }, + "authors": [ + { + "name": "recca0120", + "email": "recca0120@gmail.com" + } + ] +} diff --git a/src/PHPUnit/__tests__/fixtures/phpunit-stub/v11/phpunit.xml b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v11/phpunit.xml new file mode 100644 index 00000000..96d0013f --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v11/phpunit.xml @@ -0,0 +1,22 @@ + + + + + ../tests + ../tests/Output + + + + + ../src + + + diff --git a/src/PHPUnit/__tests__/fixtures/phpunit-stub/v12/composer.json b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v12/composer.json new file mode 100644 index 00000000..d75def8b --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v12/composer.json @@ -0,0 +1,26 @@ +{ + "name": "recca0120/vscode-phpunit", + "type": "project", + "require-dev": { + "phpunit/phpunit": "^12.0", + "mockery/mockery": "^1.5 || 1.3", + "brianium/paratest": "^7.0 || ^6.6 || ^4.0" + }, + "license": "MIT", + "autoload": { + "psr-4": { + "App\\": "../src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "../tests/" + } + }, + "authors": [ + { + "name": "recca0120", + "email": "recca0120@gmail.com" + } + ] +} diff --git a/src/PHPUnit/__tests__/fixtures/phpunit-stub/v12/phpunit.xml b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v12/phpunit.xml new file mode 100644 index 00000000..96d0013f --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v12/phpunit.xml @@ -0,0 +1,22 @@ + + + + + ../tests + ../tests/Output + + + + + ../src + + + diff --git a/src/PHPUnit/__tests__/fixtures/phpunit-stub/v9/composer.json b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v9/composer.json new file mode 100644 index 00000000..e255e24a --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v9/composer.json @@ -0,0 +1,26 @@ +{ + "name": "recca0120/vscode-phpunit", + "type": "project", + "require-dev": { + "phpunit/phpunit": "^9.6", + "mockery/mockery": "^1.5 || 1.3", + "brianium/paratest": "^7.0 || ^6.6 || ^4.0" + }, + "license": "MIT", + "autoload": { + "psr-4": { + "App\\": "../src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "../tests/" + } + }, + "authors": [ + { + "name": "recca0120", + "email": "recca0120@gmail.com" + } + ] +} diff --git a/src/PHPUnit/__tests__/fixtures/phpunit-stub/v9/phpunit.xml b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v9/phpunit.xml new file mode 100644 index 00000000..e10737dc --- /dev/null +++ b/src/PHPUnit/__tests__/fixtures/phpunit-stub/v9/phpunit.xml @@ -0,0 +1,23 @@ + + + + + ../tests + ../tests/Output + + + + + ../src + + + diff --git a/src/PHPUnit/__tests__/utils.ts b/src/PHPUnit/__tests__/utils.ts index 034cba74..b55389c0 100644 --- a/src/PHPUnit/__tests__/utils.ts +++ b/src/PHPUnit/__tests__/utils.ts @@ -1,24 +1,158 @@ import { execSync } from 'node:child_process'; import { join } from 'node:path'; +import { PHPUnitXML } from '../PHPUnitXML'; +import { TestParser } from '../TestParser/TestParser'; +import { type TestDefinition, TestType } from '../types'; export const fixturePath = (uri: string) => join(__dirname, 'fixtures', uri); export const phpUnitProject = (uri: string) => fixturePath(join('phpunit-stub', uri)); -export const phpUnitProjectWin = (path: string) => `C:\\vscode\\${path}`.replace(/\//g, '\\').replace(/\\$/g, ''); +export const phpUnitProjectWin = (path: string) => + `C:\\vscode\\${path}`.replace(/\//g, '\\').replace(/\\$/g, ''); export const pestProject = (uri: string) => fixturePath(join('pest-stub', uri)); -export const normalPath = (path: string) => path.replace(/^\w:/, (matched) => matched.toLowerCase()); +export const normalPath = (path: string) => + path.replace(/^\w:/, (matched) => matched.toLowerCase()); export const getPhpUnitVersion = (): string => { - const output = execSync('php vendor/bin/phpunit --version', { cwd: phpUnitProject('') }).toString(); + const stubs = detectPhpUnitStubs(); + if (stubs.length === 0) { + throw new Error('No PHPUnit stubs found'); + } + return stubs[0].phpUnitVersion; +}; + +export const parseTestFile = (buffer: Buffer | string, file: string, root: string) => { + const tests: TestDefinition[] = []; + const phpUnitXML = new PHPUnitXML(); + phpUnitXML.setRoot(root); + const testParser = new TestParser(phpUnitXML); + for (const type of Object.values(TestType).filter((v) => typeof v === 'number') as TestType[]) { + testParser.on(type, (testDefinition: TestDefinition) => tests.push(testDefinition)); + } + testParser.parse(buffer, file); - return output.match(/PHPUnit\s([\d.]+)/)![1]; + return tests; }; -export const getPhpVersion = (phpBinary = 'php'): string => { - const output = execSync(`${phpBinary} --version`, { cwd: phpUnitProject('') }).toString(); +export const findTest = (tests: TestDefinition[], id: string) => { + const lookup: Record boolean> = { + [TestType.method]: (test) => test.methodName === id, + [TestType.describe]: (test) => test.methodName === id, + [TestType.class]: (test) => test.className === id && !test.methodName, + [TestType.namespace]: (test) => test.classFQN === id && !test.className && !test.methodName, + }; - return output.match(/PHP\s([\d.]+)/)![1]; + for (const fn of Object.values(lookup)) { + const test = tests.find(fn); + if (test) { + return test; + } + } + + return undefined; }; +export interface PhpUnitStub { + name: string; + root: string; + phpUnitVersion: string; + binary: string; + args: string[]; +} + +export function detectPhpUnitStubs(): PhpUnitStub[] { + const versions = [9, 10, 11, 12]; + const root = phpUnitProject(''); + + return versions.flatMap((v) => { + const binary = `v${v}/vendor/bin/phpunit`; + try { + const output = execSync(`php ${binary} --version`, { + cwd: root, + timeout: 10000, + }).toString(); + const phpUnitVersion = output.match(/PHPUnit\s([\d.]+)/)![1]; + return [ + { + name: `phpunit-v${v}`, + root, + phpUnitVersion, + binary, + args: ['-c', join(root, `v${v}/phpunit.xml`)], + }, + ]; + } catch { + return []; + } + }); +} + +export interface ParatestStub { + name: string; + root: string; + binary: string; + args: string[]; +} + +export function detectParatestStubs(): ParatestStub[] { + const versions = [9, 10, 11, 12]; + const root = phpUnitProject(''); + + return versions.flatMap((v) => { + const binary = `v${v}/vendor/bin/paratest`; + try { + execSync(`php ${binary} --version`, { + cwd: root, + timeout: 10000, + }); + return [ + { + name: `paratest-v${v}`, + root, + binary, + args: ['-c', join(root, `v${v}/phpunit.xml`)], + }, + ]; + } catch { + return []; + } + }); +} + +export interface PestStub { + name: string; + root: string; + pestVersion: string; + binary: string; + args: string[]; +} + +export function detectPestStubs(): PestStub[] { + const versions = [2, 3, 4]; + const root = pestProject(''); + + return versions.flatMap((v) => { + const binary = `v${v}/vendor/bin/pest`; + try { + const output = execSync(`php ${binary} --version --test-directory=../tests`, { + cwd: root, + timeout: 10000, + }).toString(); + const pestVersion = output.match(/(\d+\.\d+\.\d+)/)![1]; + return [ + { + name: `pest-v${v}`, + root, + pestVersion, + binary, + args: ['-c', join(root, `v${v}/phpunit.xml`), '--test-directory=../tests'], + }, + ]; + } catch { + return []; + } + }); +} + export const generateXML = (text: string) => { return ` { > ${text.trim()} `; -}; \ No newline at end of file +}; diff --git a/src/PHPUnit/index.ts b/src/PHPUnit/index.ts index eae4564e..901ec99a 100644 --- a/src/PHPUnit/index.ts +++ b/src/PHPUnit/index.ts @@ -1,12 +1,14 @@ export * from './Configuration'; -export * from './CommandBuilder'; -export * from './Element'; -export * from './TestRunnerObserver'; -export * from './TestRunner'; -export * from './TestParser'; -export * from './ProblemMatcher'; +export * from './CustomWeakMap'; export * from './PHPUnitXML'; +export * from './ProblemMatcher'; +export * from './ProcessBuilder'; export * from './TestCollection'; +export * from './TestParser'; +export * from './TestRunner'; +export * from './TestRunnerObserver'; +export * from './TestRunnerProcess'; export * from './Transformer'; +export * from './types'; export * from './utils'; -export * from './types'; \ No newline at end of file +export * from './XmlElement'; diff --git a/src/PHPUnit/types.ts b/src/PHPUnit/types.ts index 93868206..8e459d85 100644 --- a/src/PHPUnit/types.ts +++ b/src/PHPUnit/types.ts @@ -26,7 +26,7 @@ export type TestDefinition = { className?: string; methodName?: string; parent?: TestDefinition; - children?: TestDefinition[] + children?: TestDefinition[]; depth: number; file?: string; start?: Position; @@ -42,4 +42,4 @@ export interface Teamcity { locationHint: string; message: string; details: string; -} \ No newline at end of file +} diff --git a/src/PHPUnit/utils.test.ts b/src/PHPUnit/utils.test.ts index fd48dc44..ca360803 100644 --- a/src/PHPUnit/utils.test.ts +++ b/src/PHPUnit/utils.test.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { titleCase } from './utils'; describe('utils', () => { @@ -50,4 +51,4 @@ describe('utils', () => { expect(titleCase('This is an HTML element')).toEqual('This Is An HTML Element'); }); }); -}); \ No newline at end of file +}); diff --git a/src/PHPUnit/utils.ts b/src/PHPUnit/utils.ts index e5e65c3b..65eb0147 100644 --- a/src/PHPUnit/utils.ts +++ b/src/PHPUnit/utils.ts @@ -1,67 +1,9 @@ import { stat } from 'node:fs/promises'; import { Engine } from 'php-parser'; -import * as yargsParser from 'yargs-parser'; -import { Teamcity } from './types'; +import yargsParser from 'yargs-parser'; -class EscapeValue { - private values = { - escape: ['||', '|\'', '|n', '|r', '|]', '|['], - unescape: ['|', '\'', '\n', '\r', ']', '['], - }; - - private patterns: { unescape: RegExp[]; escape: RegExp[] }; - - constructor() { - this.patterns = { - escape: this.toRegExp(this.values.escape), - unescape: this.toRegExp(this.values.unescape), - }; - } - - public escape(value: string | number | object) { - return this.change(value, this.patterns.unescape, this.values.escape); - } - - public unescape(value: string | number | object) { - return this.change(value, this.patterns.escape, this.values.unescape); - } - - public escapeSingleQuote(value: string | number | object) { - return this.change(value, [new RegExp('\\|\'', 'g')], ['%%%SINGLE_QUOTE%%%']); - } - - public unescapeSingleQuote(value: string | number | object) { - return this.change(value, [new RegExp('%%%SINGLE_QUOTE%%%', 'g')], ['\'']); - } - - private change(value: string | number | any, from: RegExp[], to: string[]) { - if (typeof value === 'object') { - for (const x in value) { - value[x] = this.change(value[x], from, to); - } - - return value; - } - - if (typeof value !== 'string') { - return value; - } - - for (const x in from) { - value = value.replace(from[x], to[x]); - } - - return value; - } - - private toRegExp(values: string[]) { - return values.map((str) => { - str = str.replace(/([|\]\[])/g, (m) => `\\${m}`); - - return new RegExp(str, 'g'); - }); - } -} +export { CustomWeakMap } from './CustomWeakMap'; +export { escapeValue, parseTeamcity } from './ProblemMatcher/parseTeamcity'; export const EOL = '\r\n'; @@ -69,18 +11,17 @@ export const engine = new Engine({ ast: { withPositions: true, withSource: true }, parser: { extractDoc: true, suppressErrors: false }, lexer: { - // eslint-disable-next-line @typescript-eslint/naming-convention all_tokens: true, - // eslint-disable-next-line @typescript-eslint/naming-convention short_tags: true, }, }); -export const escapeValue = new EscapeValue(); - -export const parseValue = (key: any, value: any): string[] => { +export const parseValue = (key: string, value: string | boolean | string[]): string[] => { if (Array.isArray(value)) { - return value.reduce((acc: string[], item: any) => acc.concat(parseValue(key, item)), []); + return value.reduce( + (acc: string[], item: string | boolean | string[]) => acc.concat(parseValue(key, item)), + [], + ); } const dash = key.length === 1 ? '-' : '--'; const operator = key.length === 1 ? ' ' : '='; @@ -88,53 +29,13 @@ export const parseValue = (key: any, value: any): string[] => { return [value === true ? `${dash}${key}` : `${dash}${key}${operator}${value}`]; }; -export const groupBy = (items: T[], key: string): { [key: string]: T[]; } => { - if (!items) { - return {}; - } - - return items.reduce((acc, item: T) => { - const itemKey = item[key] as string; - - if (!acc[itemKey]) { - acc[itemKey] = []; - } - - acc[itemKey].push(item); - - return acc; - }, {} as { [key: string]: T[] }); -}; - -export const parseTeamcity = (text: string): Teamcity => { - text = text.trim().replace(new RegExp('^.*#+teamcity'), '').replace(/^\[|]$/g, ''); - text = escapeValue.escapeSingleQuote(text) as string; - text = escapeValue.unescape(text) as string; - - const [eventName, ...args] = yargsParser(text)._; - const command = [ - `--event='${eventName}'`, - ...args.map((parameter) => `--${parameter}`), - ]; - - const { _, $0, ...argv } = yargsParser(command.join(' '), { - string: ['actual', 'expected'], - }); - - return escapeValue.unescapeSingleQuote(argv); -}; - export const parseArguments = (parameters: string[], excludes: string[]) => { const { _, ...argv } = yargsParser(parameters.join(' ').trim(), { alias: { configuration: ['c'] }, configuration: { - // eslint-disable-next-line @typescript-eslint/naming-convention 'camel-case-expansion': false, - // eslint-disable-next-line @typescript-eslint/naming-convention 'boolean-negation': false, - // eslint-disable-next-line @typescript-eslint/naming-convention 'short-option-groups': true, - // eslint-disable-next-line @typescript-eslint/naming-convention 'dot-notation': false, }, }); @@ -142,9 +43,14 @@ export const parseArguments = (parameters: string[], excludes: string[]) => { return Object.entries(argv) .filter(([key]) => !excludes.includes(key)) .reduce( - (parameters: any, [key, value]) => [...parseValue(key, value), ...parameters], - _.map((parameter) => (typeof parameter === 'number' ? parameter : decodeURIComponent(parameter))), - ) as string[]; + (parameters: string[], [key, value]) => [ + ...parseValue(key, value as string | boolean | string[]), + ...parameters, + ], + _.map((parameter) => + typeof parameter === 'number' ? String(parameter) : decodeURIComponent(parameter), + ), + ); }; export async function checkFileExists(filePath: string): Promise { @@ -152,8 +58,12 @@ export async function checkFileExists(filePath: string): Promise { await stat(filePath); return true; - } catch (error: any) { - if (error.code === 'ENOENT') { + } catch (error: unknown) { + if ( + error instanceof Error && + 'code' in error && + (error as NodeJS.ErrnoException).code === 'ENOENT' + ) { return false; } else { throw error; @@ -173,65 +83,28 @@ export async function findAsyncSequential( return undefined; } -export class CustomWeakMap { - private weakMap: WeakMap; - private keys: Set; - - constructor() { - this.weakMap = new WeakMap(); - this.keys = new Set(); - } - - clear() { - this.weakMap = new WeakMap(); - this.keys = new Set(); - } - - delete(key: K) { - this.keys.delete(key); - - return this.weakMap.delete(key); - } - - get(key: K) { - return this.weakMap.get(key); - } - - has(key: K) { - return this.keys.has(key); - } - - set(key: K, value: V) { - this.keys.add(key); - this.weakMap.set(key, value); - - return this; - } - - forEach(callback: (value: V, key: K) => void) { - this.keys.forEach((key) => { - callback(this.weakMap.get(key)!, key); - }); - } - - * [Symbol.iterator](): Generator<[K, V]> { - for (const key of this.keys) { - yield [key, this.weakMap.get(key)!]; - } - } -} - export const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1); export const uncapitalize = (str: string) => str.charAt(0).toLowerCase() + str.slice(1); -export const snakeCase = (str: string) => str.replace(/([a-z])([A-Z])/g, '$1_$2').replace(/[\s\-]+/g, '_').toLowerCase(); -export const camelCase = (str: string) => str.toLowerCase().replace(/([-_ \s]+[a-z])/g, (group) => group.toUpperCase().replace(/[-_ \s]/g, '')); -export const titleCase = (str: string) => capitalize(str.replace(/([A-Z]+|[_\-\s]+([A-Z]+|[a-z]))/g, (_: string, matched: string) => { - return ' ' + matched.trim().replace(/[_\-]/, '').toUpperCase(); -}).trim()); +export const snakeCase = (str: string) => + str + .replace(/([a-z])([A-Z])/g, '$1_$2') + .replace(/[\s-]+/g, '_') + .toLowerCase(); +export const camelCase = (str: string) => + str + .toLowerCase() + .replace(/([-_ \s]+[a-z])/g, (group) => group.toUpperCase().replace(/[-_ \s]/g, '')); +export const titleCase = (str: string) => + capitalize( + str + .replace(/([A-Z]+|[_\-\s]+([A-Z]+|[a-z]))/g, (_: string, matched: string) => { + return ` ${matched.trim().replace(/[_-]/, '').toUpperCase()}`; + }) + .trim(), + ); export const cloneInstance = (obj: T): T => { const clone = Object.create(Object.getPrototypeOf(obj)); return Object.assign(clone, obj); }; - diff --git a/src/TestCollection/TestCase.ts b/src/TestCollection/TestCase.ts index 98ca14c2..b77b55b2 100644 --- a/src/TestCollection/TestCase.ts +++ b/src/TestCollection/TestCase.ts @@ -1,22 +1,23 @@ -import { Position, TestItem } from 'vscode'; -import { Builder, TestDefinition, TestType } from '../PHPUnit'; -import { FilterStrategyFactory } from '../PHPUnit/CommandBuilder/FilterStrategy'; +import type { Position, TestItem } from 'vscode'; +import { + FilterStrategyFactory, + type ProcessBuilder, + type TestDefinition, + TestType, +} from '../PHPUnit'; export class TestCase { - constructor(private testDefinition: TestDefinition) { } + constructor(private testDefinition: TestDefinition) {} get type() { return this.testDefinition.type; } - get groups(): string[] { - return (this.testDefinition.annotations?.group as string[]) ?? []; - } - - update(builder: Builder, index: number) { - return builder.clone() + configureProcessBuilder(builder: ProcessBuilder, index: number) { + return builder + .clone() .setXdebug(builder.getXdebug()?.clone().setIndex(index)) - .setArguments(FilterStrategyFactory.getStrategy(this.testDefinition).getFilter()); + .setArguments(FilterStrategyFactory.create(this.testDefinition).getFilter()); } inRange = (test: TestItem, position: Position) => { @@ -26,4 +27,4 @@ export class TestCase { return position.line >= test.range!.start.line && position.line <= test.range!.end.line; }; -} \ No newline at end of file +} diff --git a/src/TestCollection/TestCollection.test.ts b/src/TestCollection/TestCollection.test.ts index 7e796380..8a526338 100644 --- a/src/TestCollection/TestCollection.test.ts +++ b/src/TestCollection/TestCollection.test.ts @@ -1,7 +1,7 @@ -import { expect } from '@jest/globals'; -import { RelativePattern, TestController, tests, Uri, workspace } from 'vscode'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { RelativePattern, type TestController, tests, Uri, workspace } from 'vscode'; import { URI } from 'vscode-uri'; -import { Files, PHPUnitXML, TestDefinition, TestDefinitions, TestParser } from '../PHPUnit'; +import { PHPUnitXML, type TestDefinition } from '../PHPUnit'; import { generateXML, phpUnitProject } from '../PHPUnit/__tests__/utils'; import { TestCollection } from './TestCollection'; @@ -17,9 +17,9 @@ describe('Extension TestCollection', () => { return new TestCollection(ctrl, phpUnitXML); }; - const toTree = (items: any) => { - const results = [] as any[]; - items.forEach((item: any) => { + const toTree = (items: import('vscode').TestItemCollection) => { + const results: { id: string; label: string; children: ReturnType }[] = []; + items.forEach((item: import('vscode').TestItem) => { results.push({ id: item.id, label: item.label, @@ -30,25 +30,20 @@ describe('Extension TestCollection', () => { return results; }; - const shouldBe = async (_collection: TestCollection, testsuites: any) => { - const phpUnitXML = new PHPUnitXML(); - phpUnitXML.setRoot(phpUnitProject('')); - const testParser = new TestParser(phpUnitXML); - const expected = new Files; - for (const [name, files] of Object.entries(testsuites)) { - const tests = new TestDefinitions(); - for (const uri of (files as URI[])) { - tests.set(uri, await testParser.parseFile(uri.fsPath) ?? []); + const collectTestItemFiles = (items: import('vscode').TestItemCollection): string[] => { + const files: string[] = []; + items.forEach((item: import('vscode').TestItem) => { + if (item.uri) { + files.push(item.uri.fsPath); } - expected.set(name, tests); - } - - // expect(_collection.items()).toEqual(expected); + files.push(...collectTestItemFiles(item.children)); + }); + return [...new Set(files)]; }; beforeEach(() => { ctrl = tests.createTestController('phpUnitTestController', 'PHPUnit'); - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('without namespace', async () => { @@ -57,20 +52,23 @@ describe('Extension TestCollection', () => { tests - `, - ); + `); await collection.add(URI.file(phpUnitProject('tests/NoNamespaceTest.php'))); - expect(toTree(ctrl.items)).toEqual([{ - id: 'No Namespace', - label: '$(symbol-class) NoNamespaceTest', - children: [{ - id: 'No Namespace::No namespace', - label: '$(symbol-method) test_no_namespace', - children: [], - }], - }]); + expect(toTree(ctrl.items)).toEqual([ + { + id: 'No Namespace', + label: '$(symbol-class) NoNamespaceTest', + children: [ + { + id: 'No Namespace::No namespace', + label: '$(symbol-method) test_no_namespace', + children: [], + }, + ], + }, + ]); }); it('with namespace', async () => { @@ -79,29 +77,26 @@ describe('Extension TestCollection', () => { tests - `, - ); + `); await collection.add(URI.file(phpUnitProject('tests/AssertionsTest.php'))); await collection.add(URI.file(phpUnitProject('tests/AttributeTest.php'))); expect(toTree(ctrl.items)).toEqual([ - expect.objectContaining( - { - id: 'namespace:Tests', - label: '$(symbol-namespace) Tests', - children: [ - expect.objectContaining({ - id: 'Assertions (Tests\\Assertions)', - label: '$(symbol-class) AssertionsTest', - }), - expect.objectContaining({ - id: 'Attribute (Tests\\Attribute)', - label: '$(symbol-class) AttributeTest', - }), - ], - }, - ), + expect.objectContaining({ + id: 'namespace:Tests', + label: '$(symbol-namespace) Tests', + children: [ + expect.objectContaining({ + id: 'Assertions (Tests\\Assertions)', + label: '$(symbol-class) AssertionsTest', + }), + expect.objectContaining({ + id: 'Attribute (Tests\\Attribute)', + label: '$(symbol-class) AttributeTest', + }), + ], + }), ]); }); @@ -114,8 +109,7 @@ describe('Extension TestCollection', () => { tests/Feature - `, - ); + `); await collection.add(URI.file(phpUnitProject('tests/Unit/ExampleTest.php'))); await collection.add(URI.file(phpUnitProject('tests/Feature/ExampleTest.php'))); @@ -156,8 +150,7 @@ describe('Extension TestCollection', () => { tests - `, - ); + `); const includes: string[] = ['**/*.php']; const excludes: string[] = ['**/.git/**', '**/node_modules/**', '**/vendor/**']; @@ -169,16 +162,14 @@ describe('Extension TestCollection', () => { await collection.add(file); } - const skips = [ - 'phpunit-stub/src/', - 'phpunit-stub\\src\\', - 'AbstractTest.php', - ]; + const skips = ['phpunit-stub/src/', 'phpunit-stub\\src\\', 'AbstractTest.php']; + const expectedFiles = files + .filter((file) => !skips.some((skip) => file.fsPath.includes(skip))) + .map((file) => file.fsPath) + .sort(); - await shouldBe(collection, { - default: files.filter((file) => !skips.find((skip) => { - return file.fsPath.indexOf(skip) !== -1; - })), - }); + const actualFiles = collectTestItemFiles(ctrl.items).sort(); + + expect(actualFiles).toEqual(expectedFiles); }); -}); \ No newline at end of file +}); diff --git a/src/TestCollection/TestCollection.ts b/src/TestCollection/TestCollection.ts index dc8de4ec..0a2b91ee 100644 --- a/src/TestCollection/TestCollection.ts +++ b/src/TestCollection/TestCollection.ts @@ -1,34 +1,39 @@ -import { Position, TestController, TestItem, TestRunRequest } from 'vscode'; -import { URI } from 'vscode-uri'; +import { inject, injectable } from 'inversify'; +import type { Position, TestController, TestItem, TestRunRequest } from 'vscode'; +import type { URI } from 'vscode-uri'; import { - CustomWeakMap, File, PHPUnitXML, TestCollection as BaseTestCollection, TestDefinition, TestType, + TestCollection as BaseTestCollection, + CustomWeakMap, + type File, + PHPUnitXML, + type TestDefinition, + TestType, } from '../PHPUnit'; -import { TestCase } from './TestCase'; +import { TYPES } from '../types'; +import type { TestCase } from './TestCase'; import { TestHierarchyBuilder } from './TestHierarchyBuilder'; +@injectable() export class TestCollection extends BaseTestCollection { private testItems = new Map>>(); + private testCaseIndex = new Map(); - constructor(private ctrl: TestController, phpUnitXML: PHPUnitXML) { + constructor( + @inject(TYPES.TestController) private ctrl: TestController, + @inject(PHPUnitXML) phpUnitXML: PHPUnitXML, + ) { super(phpUnitXML); } getTestCase(testItem: TestItem): TestCase | undefined { - for (const [, testData] of this.getTestData()) { - const testCase = testData.get(testItem); - if (testCase) { - return testCase; - } - } - - return; + return this.testCaseIndex.get(testItem.id); } findTestsByFile(uri: URI): TestItem[] { - const tests = [] as TestItem[]; - for (const [test, testCase] of this.getTestCases(uri)) { + const tests: TestItem[] = []; + for (const [testItem, testCase] of this.getTestCases(uri)) { if (testCase.type === TestType.class) { - tests.push(test); + tests.push(testItem); } } @@ -41,21 +46,18 @@ export class TestCollection extends BaseTestCollection { return items.length > 0 ? [items[0]] : this.findTestsByFile(uri); } - findTestsByRequest(request?: TestRunRequest) { if (!request || !request.include) { return undefined; } - const include = request.include; + const includeIds = new Set(request.include.map((item) => item.id)); const tests: TestItem[] = []; for (const [, testData] of this.getTestData()) { testData.forEach((_, testItem: TestItem) => { - include.forEach((test) => { - if (test.id === testItem.id) { - tests.push(testItem); - } - }); + if (includeIds.has(testItem.id)) { + tests.push(testItem); + } }); } @@ -65,9 +67,12 @@ export class TestCollection extends BaseTestCollection { reset() { for (const [, testData] of this.getTestData()) { for (const [testItem] of testData) { - testItem.parent ? testItem.parent.children.delete(testItem.id) : this.ctrl.items.delete(testItem.id); + testItem.parent + ? testItem.parent.children.delete(testItem.id) + : this.ctrl.items.delete(testItem.id); } } + this.testCaseIndex.clear(); return super.reset(); } @@ -82,6 +87,7 @@ export class TestCollection extends BaseTestCollection { testData.clear(); for (const [testItem, testCase] of testHierarchyBuilder.get()) { testData.set(testItem, testCase); + this.testCaseIndex.set(testItem.id, testCase); } return testDefinitionBuilder.get(); @@ -105,7 +111,10 @@ export class TestCollection extends BaseTestCollection { private getTestData() { const workspace = this.getWorkspace(); if (!this.testItems.has(workspace.fsPath)) { - this.testItems.set(workspace.fsPath, new Map>()); + this.testItems.set( + workspace.fsPath, + new Map>(), + ); } return this.testItems.get(workspace.fsPath)!; @@ -113,9 +122,9 @@ export class TestCollection extends BaseTestCollection { private inRangeTestItems(uri: URI, position: Position) { const items: TestItem[] = []; - for (const [test, testCase] of this.getTestCases(uri)) { - if (testCase.inRange(test, position)) { - items.push(test); + for (const [testItem, testCase] of this.getTestCases(uri)) { + if (testCase.inRange(testItem, position)) { + items.push(testItem); } } items.sort((a, b) => this.compareFn(b, position) - this.compareFn(a, position)); @@ -135,20 +144,20 @@ export class TestCollection extends BaseTestCollection { return; } - let item = testItem; - while (item.parent) { - const parent = item.parent; + let current = testItem; + while (current.parent) { + const parent = current.parent; const children = parent.children; - children.delete(item.id); + children.delete(current.id); if (children.size !== 0) { break; } - item = parent; - if (!item.parent) { - this.ctrl.items.delete(item.id); + current = parent; + if (!current.parent) { + this.ctrl.items.delete(current.id); } } }); } -} \ No newline at end of file +} diff --git a/src/TestCollection/TestHierarchyBuilder.test.ts b/src/TestCollection/TestHierarchyBuilder.test.ts index 88a8c6b7..b2f95650 100644 --- a/src/TestCollection/TestHierarchyBuilder.test.ts +++ b/src/TestCollection/TestHierarchyBuilder.test.ts @@ -1,14 +1,14 @@ -import { expect } from '@jest/globals'; -import { TestController, tests } from 'vscode'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { type TestController, tests } from 'vscode'; import { PHPUnitXML, TestParser } from '../PHPUnit'; import { pestProject, phpUnitProject } from '../PHPUnit/__tests__/utils'; import { TestHierarchyBuilder } from './TestHierarchyBuilder'; type CODE = { - testsuite: { name: string, path: string }, - file: string, - code: string -} + testsuite: { name: string; path: string }; + file: string; + code: string; +}; export const generateXML = (text: string) => { return ` @@ -26,20 +26,24 @@ ${namespace}; class ${className} extends TestCase { -${methods.map((name) => ` +${methods + .map( + (name) => ` public function ${name}() { $this->assertTrue(true); } -`).join('')} +`, + ) + .join('')} }`; describe('TestHierarchyBuilder', () => { let ctrl: TestController; let configurationFile: string; - const toTree = (items: any) => { - const results = [] as any[]; - items.forEach((item: any) => { + const toTree = (items: import('vscode').TestItemCollection) => { + const results: { id: string; label: string; children: ReturnType }[] = []; + items.forEach((item: import('vscode').TestItem) => { results.push({ id: item.id, label: item.label, children: toTree(item.children) }); }); @@ -47,25 +51,30 @@ describe('TestHierarchyBuilder', () => { }; const givenCodes = (codes: CODE[]) => { - const testsuites = Object.entries(codes - .map(({ testsuite }) => testsuite) - .reduce((items, item) => { - if (!(item.name in items)) { - items[item.name] = []; - } - items[item.name].push(item.path); + const testsuites = Object.entries( + codes + .map(({ testsuite }) => testsuite) + .reduce( + (items, item) => { + if (!(item.name in items)) { + items[item.name] = []; + } + items[item.name].push(item.path); - return items; - }, {} as { [index: string]: string[] })) - .map(([name, paths]) => { - const directories = paths.map(path => `${path}`).join(''); + return items; + }, + {} as { [index: string]: string[] }, + ), + ).map(([name, paths]) => { + const directories = paths.map((path) => `${path}`).join(''); - return `${directories}`; - }); + return `${directories}`; + }); - const phpUnitXml = (new PHPUnitXML()).load(generateXML( - `${testsuites.join('')}`, - ), configurationFile); + const phpUnitXml = new PHPUnitXML().load( + generateXML(`${testsuites.join('')}`), + configurationFile, + ); const testParser = new TestParser(phpUnitXml); const builder = new TestHierarchyBuilder(ctrl, testParser); @@ -80,14 +89,16 @@ describe('TestHierarchyBuilder', () => { }); describe('PHPUnit', () => { - beforeEach(() => configurationFile = phpUnitProject('phpunit.xml')); + beforeEach(() => (configurationFile = phpUnitProject('phpunit.xml'))); it('no namespace', () => { - givenCodes([{ - testsuite: { name: 'default', path: 'tests' }, - file: phpUnitProject('tests/AssertionsTest.php'), - code: givenPhp('', 'AssertionsTest', ['test_passed', 'test_failed']), - }]); + givenCodes([ + { + testsuite: { name: 'default', path: 'tests' }, + file: phpUnitProject('tests/AssertionsTest.php'), + code: givenPhp('', 'AssertionsTest', ['test_passed', 'test_failed']), + }, + ]); expect(toTree(ctrl.items)).toEqual([ { @@ -110,11 +121,13 @@ describe('TestHierarchyBuilder', () => { }); it('nested namespace', () => { - givenCodes([{ - testsuite: { name: 'default', path: 'tests' }, - file: phpUnitProject('tests/AssertionsTest.php'), - code: givenPhp('namespace Tests', 'AssertionsTest', ['test_passed']), - }]); + givenCodes([ + { + testsuite: { name: 'default', path: 'tests' }, + file: phpUnitProject('tests/AssertionsTest.php'), + code: givenPhp('namespace Tests', 'AssertionsTest', ['test_passed']), + }, + ]); expect(toTree(ctrl.items)).toEqual([ { @@ -138,15 +151,18 @@ describe('TestHierarchyBuilder', () => { }); it('sibling namespace', () => { - givenCodes([{ - testsuite: { name: 'default', path: 'tests' }, - file: phpUnitProject('tests/AssertionsTest.php'), - code: givenPhp('namespace Tests', 'AssertionsTest', ['test_passed']), - }, { - testsuite: { name: 'default', path: 'tests' }, - file: phpUnitProject('tests/Assertions2Test.php'), - code: givenPhp('namespace Tests', 'Assertions2Test', ['test_passed']), - }]); + givenCodes([ + { + testsuite: { name: 'default', path: 'tests' }, + file: phpUnitProject('tests/AssertionsTest.php'), + code: givenPhp('namespace Tests', 'AssertionsTest', ['test_passed']), + }, + { + testsuite: { name: 'default', path: 'tests' }, + file: phpUnitProject('tests/Assertions2Test.php'), + code: givenPhp('namespace Tests', 'Assertions2Test', ['test_passed']), + }, + ]); expect(toTree(ctrl.items)).toEqual([ { @@ -181,22 +197,23 @@ describe('TestHierarchyBuilder', () => { }); it('two testsuites', () => { - givenCodes([{ - testsuite: { name: 'Unit', path: 'tests/Unit' }, - file: phpUnitProject('tests/Feature/ExampleTest.php'), - code: givenPhp('namespace Tests\\Unit', 'ExampleTest', ['test_passed']), - }, { - testsuite: { name: 'Feature', path: 'tests/Feature' }, - file: phpUnitProject('tests/Feature/ExampleTest.php'), - code: givenPhp('namespace Tests\\Feature', 'ExampleTest', ['test_passed']), - }]); - - // console.log(toTree(ctrl.items)); + givenCodes([ + { + testsuite: { name: 'Unit', path: 'tests/Unit' }, + file: phpUnitProject('tests/Feature/ExampleTest.php'), + code: givenPhp('namespace Tests\\Unit', 'ExampleTest', ['test_passed']), + }, + { + testsuite: { name: 'Feature', path: 'tests/Feature' }, + file: phpUnitProject('tests/Feature/ExampleTest.php'), + code: givenPhp('namespace Tests\\Feature', 'ExampleTest', ['test_passed']), + }, + ]); }); }); describe('PEST', () => { - beforeEach(() => configurationFile = pestProject('phpunit.xml')); + beforeEach(() => (configurationFile = pestProject('phpunit.xml'))); it('nested describe', () => { const code = `toBe(false); }); `; - givenCodes([{ - testsuite: { name: 'default', path: 'tests' }, - file: pestProject('tests/ExampleTest.php'), - code: code, - }]); + givenCodes([ + { + testsuite: { name: 'default', path: 'tests' }, + file: pestProject('tests/ExampleTest.php'), + code: code, + }, + ]); - expect(toTree(ctrl.items)).toEqual([{ - id: 'namespace:Tests', - label: '$(symbol-namespace) Tests', - children: [{ - id: 'Tests\\ExampleTest', - label: '$(symbol-class) ExampleTest', + expect(toTree(ctrl.items)).toEqual([ + { + id: 'namespace:Tests', + label: '$(symbol-namespace) Tests', children: [ - expect.objectContaining({ - id: 'tests/ExampleTest.php::`Given something ...`', - label: '$(symbol-class) Given something ...', - }), { - id: 'tests/ExampleTest.php::Test1', - label: '$(symbol-method) Test1', - children: [], - }, - { - id: 'tests/ExampleTest.php::`Given something else...`', - label: '$(symbol-class) Given something else...', + id: 'Tests\\ExampleTest', + label: '$(symbol-class) ExampleTest', children: [ expect.objectContaining({ - id: 'tests/ExampleTest.php::`Given something else...` → `When...`', - label: '$(symbol-class) When...', + id: 'tests/ExampleTest.php::`Given something ...`', + label: '$(symbol-class) Given something ...', }), { - id: 'tests/ExampleTest.php::`Given something else...` → Test2', - label: '$(symbol-method) Test2', + id: 'tests/ExampleTest.php::Test1', + label: '$(symbol-method) Test1', + children: [], + }, + { + id: 'tests/ExampleTest.php::`Given something else...`', + label: '$(symbol-class) Given something else...', + children: [ + expect.objectContaining({ + id: 'tests/ExampleTest.php::`Given something else...` → `When...`', + label: '$(symbol-class) When...', + }), + { + id: 'tests/ExampleTest.php::`Given something else...` → Test2', + label: '$(symbol-method) Test2', + children: [], + }, + expect.objectContaining({ + id: 'tests/ExampleTest.php::`Given something else...` → `When also...`', + label: '$(symbol-class) When also...', + }), + ], + }, + { + id: 'tests/ExampleTest.php::Test3', + label: '$(symbol-method) Test3', children: [], }, - expect.objectContaining({ - id: 'tests/ExampleTest.php::`Given something else...` → `When also...`', - label: '$(symbol-class) When also...', - }), ], }, - { - id: 'tests/ExampleTest.php::Test3', - label: '$(symbol-method) Test3', - children: [], - }, ], - }], - }]); + }, + ]); }); }); -}); \ No newline at end of file +}); diff --git a/src/TestCollection/TestHierarchyBuilder.ts b/src/TestCollection/TestHierarchyBuilder.ts index bafff6a8..3793d191 100644 --- a/src/TestCollection/TestHierarchyBuilder.ts +++ b/src/TestCollection/TestHierarchyBuilder.ts @@ -1,35 +1,13 @@ -import { Position, Range, TestController, TestItem, TestTag, Uri } from 'vscode'; -import { CustomWeakMap, TestDefinition, TestParser, TestType, TransformerFactory } from '../PHPUnit'; +import { Position, Range, type TestController, type TestItem, TestTag, Uri } from 'vscode'; +import { + CustomWeakMap, + type TestDefinition, + type TestParser, + TestType, + TransformerFactory, +} from '../PHPUnit'; import { TestCase } from './TestCase'; -export class GroupRegistry { - private static instance: GroupRegistry; - private groups = new Set(); - - static getInstance(): GroupRegistry { - if (!GroupRegistry.instance) { - GroupRegistry.instance = new GroupRegistry(); - } - return GroupRegistry.instance; - } - - add(group: string) { - this.groups.add(group); - } - - addAll(groups: string[]) { - groups.forEach(g => this.groups.add(g)); - } - - getAll(): string[] { - return Array.from(this.groups).sort(); - } - - clear() { - this.groups.clear(); - } -} - export class TestHierarchyBuilder { private icons = { [TestType.namespace]: '$(symbol-namespace)', @@ -37,27 +15,30 @@ export class TestHierarchyBuilder { [TestType.method]: '$(symbol-method)', [TestType.describe]: '$(symbol-class)', }; - private length = 1; - private readonly ancestors: [{ item: TestItem, type: TestType, children: TestItem[] }] = [ - { item: this.createProxyTestController(), type: TestType.namespace, children: [] }, + private ancestorDepth = 1; + private readonly ancestors: [{ item: TestItem; type: TestType; children: TestItem[] }] = [ + { item: this.createRootItem(), type: TestType.namespace, children: [] }, ]; private testData = new CustomWeakMap(); - constructor(private ctrl: TestController, private testParser: TestParser) { + constructor( + private ctrl: TestController, + private testParser: TestParser, + ) { this.onInit(); } onInit() { this.testParser.on(TestType.method, (testDefinition, index) => { - this.ascend(this.length + testDefinition.depth); + this.ascend(this.ancestorDepth + testDefinition.depth); this.addTestItem(testDefinition, `${index}`); }); this.testParser.on(TestType.describe, (testDefinition) => { - this.ascend(this.length + testDefinition.depth); + this.ascend(this.ancestorDepth + testDefinition.depth); this.addTestItem(testDefinition, testDefinition.id); }); this.testParser.on(TestType.class, (testDefinition) => { - this.ascend(this.length + testDefinition.depth); + this.ascend(this.ancestorDepth + testDefinition.depth); this.addTestItem(testDefinition, testDefinition.id); }); this.testParser.on(TestType.namespace, (testDefinition) => { @@ -73,12 +54,12 @@ export class TestHierarchyBuilder { } private addNamespaceTestItems(testDefinition: TestDefinition) { - const transformer = TransformerFactory.factory(testDefinition.classFQN!); + const transformer = TransformerFactory.create(testDefinition.classFQN!); let children = this.ctrl.items; let testItem: TestItem | undefined; let parts = testDefinition.label?.split('\\') ?? []; - parts = parts.filter(value => !!value); + parts = parts.filter((value) => !!value); parts.forEach((part, index, parts) => { const type = TestType.namespace; @@ -86,15 +67,24 @@ export class TestHierarchyBuilder { const classFQN = parts.slice(0, index + 1).join('\\'); const id = transformer.uniqueId({ type, classFQN }); const label = transformer.generateLabel({ type, classFQN: part }); - const testDefinition = { type, id, namespace: classFQN, label, depth: index + 1 } as TestDefinition; - - testItem = children.get(testDefinition.id); + const namespaceDefinition = { + type, + id, + namespace: classFQN, + label, + depth: index + 1, + } as TestDefinition; + + testItem = children.get(namespaceDefinition.id); if (!testItem) { - testItem = this.ctrl.createTestItem(testDefinition.id, this.parseLabelWithIcon(testDefinition)); + testItem = this.ctrl.createTestItem( + namespaceDefinition.id, + this.parseLabelWithIcon(namespaceDefinition), + ); testItem.canResolveChildren = true; - testItem.sortText = testDefinition.id; + testItem.sortText = namespaceDefinition.id; children.add(testItem); - this.testData.set(testItem, new TestCase(testDefinition)); + this.testData.set(testItem, new TestCase(namespaceDefinition)); } const parent = this.ancestors[this.ancestors.length - 1]; @@ -103,7 +93,7 @@ export class TestHierarchyBuilder { children = testItem.children; }); - this.length = this.ancestors.length - 1; + this.ancestorDepth = this.ancestors.length - 1; } private addTestItem(testDefinition: TestDefinition, sortText: string) { @@ -113,12 +103,12 @@ export class TestHierarchyBuilder { // Inherit group tags from parent class to methods for proper filter inheritance if (testDefinition.type === TestType.method && parent.type === TestType.class) { - const parentTags = (parent.item.tags ?? []).filter(t => t.id.startsWith('group:')); + const parentTags = (parent.item.tags ?? []).filter((t) => t.id.startsWith('group:')); if (parentTags.length > 0) { const ownTags = testItem.tags ?? []; testItem.tags = [ ...ownTags, - ...parentTags.filter(pt => !ownTags.some(ot => ot.id === pt.id)), + ...parentTags.filter((pt) => !ownTags.some((ot) => ot.id === pt.id)), ]; } } @@ -131,15 +121,18 @@ export class TestHierarchyBuilder { } private createTestItem(testDefinition: TestDefinition, sortText: string) { - const testItem = this.ctrl.createTestItem(testDefinition.id, this.parseLabelWithIcon(testDefinition), Uri.file(testDefinition.file!)); + const testItem = this.ctrl.createTestItem( + testDefinition.id, + this.parseLabelWithIcon(testDefinition), + Uri.file(testDefinition.file!), + ); testItem.canResolveChildren = testDefinition.type === TestType.class; testItem.sortText = sortText; testItem.range = this.createRange(testDefinition); const groups = (testDefinition.annotations?.group as string[]) ?? []; if (groups.length > 0) { - GroupRegistry.getInstance().addAll(groups); - testItem.tags = groups.map(g => new TestTag(`group:${g}`)); + testItem.tags = groups.map((g) => new TestTag(`group:${g}`)); } return testItem; @@ -147,17 +140,17 @@ export class TestHierarchyBuilder { private ascend(depth: number) { while (this.ancestors.length > depth) { - const finished = this.ancestors.pop()!; - if (finished.type === TestType.method) { - finished.item.children.replace(finished.children); + const completedAncestor = this.ancestors.pop()!; + if (completedAncestor.type === TestType.method) { + completedAncestor.item.children.replace(completedAncestor.children); continue; } - for (const child of finished.children) { - finished.item.children.add(child); + for (const child of completedAncestor.children) { + completedAncestor.item.children.add(child); } } - }; + } private createRange(testDefinition: TestDefinition) { return new Range( @@ -166,12 +159,8 @@ export class TestHierarchyBuilder { ); } - private createProxyTestController() { - return new Proxy(this.ctrl, { - get(target: any, prop) { - return prop === 'children' ? target.items : target[prop]; - }, - }) as TestItem; + private createRootItem(): TestItem { + return { children: this.ctrl.items } as TestItem; } private parseLabelWithIcon(testDefinition: TestDefinition) { @@ -179,4 +168,4 @@ export class TestHierarchyBuilder { return icon ? `${icon} ${testDefinition.label}` : testDefinition.label; } -} \ No newline at end of file +} diff --git a/src/TestCollection/index.ts b/src/TestCollection/index.ts index 5854e221..cb3f2be3 100644 --- a/src/TestCollection/index.ts +++ b/src/TestCollection/index.ts @@ -1,3 +1,3 @@ +export * from './TestCase'; export * from './TestCollection'; export * from './TestHierarchyBuilder'; -export * from './TestCase'; \ No newline at end of file diff --git a/src/TestDiscovery/TestFileDiscovery.ts b/src/TestDiscovery/TestFileDiscovery.ts new file mode 100644 index 00000000..53e981c8 --- /dev/null +++ b/src/TestDiscovery/TestFileDiscovery.ts @@ -0,0 +1,75 @@ +import { inject, injectable } from 'inversify'; +import { type GlobPattern, RelativePattern, Uri, type WorkspaceFolder, workspace } from 'vscode'; +import { Configuration } from '../Configuration'; +import { PHPUnitXML, type TestGlobPattern } from '../PHPUnit'; +import { TestCollection } from '../TestCollection'; + +export type WorkspaceTestPattern = { + workspaceFolder: WorkspaceFolder; + pattern: RelativePattern; + exclude: RelativePattern; +}; + +@injectable() +export class TestFileDiscovery { + constructor( + @inject(Configuration) private configuration: Configuration, + @inject(PHPUnitXML) private phpUnitXML: PHPUnitXML, + @inject(TestCollection) private testCollection: TestCollection, + ) {} + + async loadWorkspaceConfiguration(): Promise { + const configurationFile = await this.configuration.getConfigurationFile( + workspace.workspaceFolders?.[0].uri.fsPath, + ); + if (configurationFile) { + this.testCollection.reset(); + await this.phpUnitXML.loadFile(configurationFile); + } + } + + async getWorkspaceTestPatterns(): Promise { + if (!workspace.workspaceFolders) { + return []; + } + + return Promise.all( + workspace.workspaceFolders.map(async (workspaceFolder: WorkspaceFolder) => { + const configurationFile = await this.configuration.getConfigurationFile( + workspaceFolder.uri.fsPath, + ); + configurationFile + ? await this.phpUnitXML.loadFile(Uri.file(configurationFile).fsPath) + : this.phpUnitXML.setRoot(workspaceFolder.uri.fsPath); + const { includes, excludes } = this.phpUnitXML.getPatterns( + workspaceFolder.uri.fsPath, + ); + + const toRelativePattern = (pattern: TestGlobPattern) => { + const { uri, pattern: glob } = pattern.toGlobPattern(); + return new RelativePattern(uri, glob); + }; + + return { + workspaceFolder, + pattern: toRelativePattern(includes), + exclude: toRelativePattern(excludes), + }; + }), + ); + } + + async reloadAll(): Promise { + await Promise.all( + (await this.getWorkspaceTestPatterns()).map(({ pattern, exclude }) => + this.discoverTestFiles(pattern, exclude), + ), + ); + } + + async discoverTestFiles(pattern: GlobPattern, exclude: GlobPattern): Promise { + this.testCollection.reset(); + const files = await workspace.findFiles(pattern, exclude); + await Promise.all(files.map((file) => this.testCollection.add(file))); + } +} diff --git a/src/TestDiscovery/TestFileWatcher.ts b/src/TestDiscovery/TestFileWatcher.ts new file mode 100644 index 00000000..c99ad196 --- /dev/null +++ b/src/TestDiscovery/TestFileWatcher.ts @@ -0,0 +1,55 @@ +import { inject, injectable } from 'inversify'; +import { + type Disposable, + type EventEmitter, + type ExtensionContext, + type Uri, + workspace, +} from 'vscode'; +import { TestCollection } from '../TestCollection'; +import { TYPES } from '../types'; +import { TestFileDiscovery } from './TestFileDiscovery'; + +@injectable() +export class TestFileWatcher { + constructor( + @inject(TestFileDiscovery) private testFileDiscovery: TestFileDiscovery, + @inject(TestCollection) private testCollection: TestCollection, + @inject(TYPES.FileChangedEmitter) private fileChangedEmitter: EventEmitter, + ) {} + + registerDocumentListeners(context: ExtensionContext): void { + context.subscriptions.push( + workspace.onDidOpenTextDocument((document) => this.testCollection.add(document.uri)), + workspace.onDidChangeTextDocument((e) => this.testCollection.change(e.document.uri)), + ); + } + + async startWatching(): Promise { + return Promise.all( + (await this.testFileDiscovery.getWorkspaceTestPatterns()).map( + async ({ pattern, exclude }) => { + const watcher = workspace.createFileSystemWatcher(pattern); + + watcher.onDidCreate((uri) => { + this.testCollection.add(uri); + this.fileChangedEmitter.fire(uri); + }); + + watcher.onDidChange((uri) => { + this.testCollection.change(uri); + this.fileChangedEmitter.fire(uri); + }); + + watcher.onDidDelete((uri) => { + this.testCollection.delete(uri); + }); + + await this.testFileDiscovery.discoverTestFiles(pattern, exclude); + + return watcher; + }, + ), + ); + } +} diff --git a/src/TestDiscovery/TestWatchManager.ts b/src/TestDiscovery/TestWatchManager.ts new file mode 100644 index 00000000..77553e8f --- /dev/null +++ b/src/TestDiscovery/TestWatchManager.ts @@ -0,0 +1,71 @@ +import { inject, injectable } from 'inversify'; +import { + type CancellationToken, + type EventEmitter, + type TestItem, + type TestRunProfile, + TestRunRequest, + type Uri, +} from 'vscode'; +import { TestCollection } from '../TestCollection'; +import { TestRunHandler } from '../TestExecution'; +import { TYPES } from '../types'; + +@injectable() +export class TestWatchManager { + private watchingTests = new Map(); + + constructor( + @inject(TestRunHandler) private handler: TestRunHandler, + @inject(TestCollection) private testCollection: TestCollection, + @inject(TYPES.FileChangedEmitter) private fileChangedEmitter: EventEmitter, + ) {} + + createRunHandler(): ( + request: TestRunRequest, + cancellation: CancellationToken, + ) => Promise { + return async (request: TestRunRequest, cancellation: CancellationToken) => { + if (!request.continuous) { + return this.handler.startTestRun(request, cancellation); + } + + if (request.include === undefined) { + this.watchingTests.set('ALL', request.profile); + cancellation.onCancellationRequested(() => this.watchingTests.delete('ALL')); + } else { + request.include.forEach((testItem) => + this.watchingTests.set(testItem, request.profile), + ); + cancellation.onCancellationRequested(() => + request.include?.forEach((testItem) => this.watchingTests.delete(testItem)), + ); + } + }; + } + + setupFileChangeListener(): void { + this.fileChangedEmitter.event((uri) => { + if (this.watchingTests.has('ALL')) { + this.handler.startTestRun( + new TestRunRequest(undefined, undefined, this.watchingTests.get('ALL'), true), + ); + return; + } + + const include: TestItem[] = []; + let profile: TestRunProfile | undefined; + for (const [testItem, thisProfile] of this.watchingTests) { + const cast = testItem as TestItem; + if (cast.uri?.toString() === uri.toString()) { + include.push(...this.testCollection.findTestsByFile(cast.uri!)); + profile = thisProfile; + } + } + + if (include.length) { + this.handler.startTestRun(new TestRunRequest(include, undefined, profile, true)); + } + }); + } +} diff --git a/src/TestDiscovery/index.ts b/src/TestDiscovery/index.ts new file mode 100644 index 00000000..62642f0a --- /dev/null +++ b/src/TestDiscovery/index.ts @@ -0,0 +1,3 @@ +export * from './TestFileDiscovery'; +export * from './TestFileWatcher'; +export * from './TestWatchManager'; diff --git a/src/TestExecution/TestQueueBuilder.test.ts b/src/TestExecution/TestQueueBuilder.test.ts new file mode 100644 index 00000000..e2b4fc3f --- /dev/null +++ b/src/TestExecution/TestQueueBuilder.test.ts @@ -0,0 +1,69 @@ +import { beforeEach, describe, expect, it, type Mock, vi } from 'vitest'; +import type { TestItem, TestItemCollection, TestRunRequest } from 'vscode'; +import { TestType } from '../PHPUnit'; +import type { TestCase, TestCollection } from '../TestCollection'; +import { TestQueueBuilder } from './TestQueueBuilder'; + +const createTestItem = (id: string, children: TestItem[] = []): TestItem => { + const childCollection = { + forEach: (cb: (item: TestItem) => void) => children.forEach(cb), + } as TestItemCollection; + + return { id, children: childCollection } as TestItem; +}; + +describe('TestQueueBuilder', () => { + let testCollection: TestCollection; + let queueBuilder: TestQueueBuilder; + + beforeEach(() => { + testCollection = { getTestCase: vi.fn() } as unknown as TestCollection; + queueBuilder = new TestQueueBuilder(testCollection); + }); + + it('should discover method test items', async () => { + const testItem = createTestItem('test1'); + const testCase = { type: TestType.method } as TestCase; + (testCollection.getTestCase as Mock).mockReturnValue(testCase); + + const request = {} as TestRunRequest; + const queue = await queueBuilder.build([testItem], request); + + expect(queue.size).toBe(1); + expect(queue.get(testCase)).toBe(testItem); + }); + + it('should recurse into non-method items', async () => { + const childItem = createTestItem('child'); + const parentItem = createTestItem('parent', [childItem]); + + const childCase = { type: TestType.method } as TestCase; + (testCollection.getTestCase as Mock) + .mockReturnValueOnce({ type: TestType.class }) + .mockReturnValueOnce(childCase); + + const request = {} as TestRunRequest; + const queue = await queueBuilder.build([parentItem], request); + + expect(queue.size).toBe(1); + expect(queue.get(childCase)).toBe(childItem); + }); + + it('should skip excluded items', async () => { + const testItem = createTestItem('excluded'); + const request = { exclude: [testItem] } as unknown as TestRunRequest; + + const queue = await queueBuilder.build([testItem], request); + + expect(queue.size).toBe(0); + }); + + it('should gather test items from a collection', () => { + const items = [createTestItem('a'), createTestItem('b')]; + const collection = { + forEach: (cb: (item: TestItem) => void) => items.forEach(cb), + } as TestItemCollection; + + expect(queueBuilder.collectItems(collection)).toEqual(items); + }); +}); diff --git a/src/TestExecution/TestQueueBuilder.ts b/src/TestExecution/TestQueueBuilder.ts new file mode 100644 index 00000000..5cacdb4a --- /dev/null +++ b/src/TestExecution/TestQueueBuilder.ts @@ -0,0 +1,37 @@ +import { inject, injectable } from 'inversify'; +import type { TestItem, TestItemCollection, TestRunRequest } from 'vscode'; +import { TestType } from '../PHPUnit'; +import { type TestCase, TestCollection } from '../TestCollection'; + +@injectable() +export class TestQueueBuilder { + constructor(@inject(TestCollection) private testCollection: TestCollection) {} + + async build( + tests: Iterable, + request: TestRunRequest, + queue = new Map(), + ): Promise> { + for (const testItem of tests) { + if (request.exclude?.includes(testItem)) { + continue; + } + + const testCase = this.testCollection.getTestCase(testItem); + if (testCase?.type === TestType.method) { + queue.set(testCase, testItem); + } else { + await this.build(this.collectItems(testItem.children), request, queue); + } + } + + return queue; + } + + collectItems(collection: TestItemCollection): TestItem[] { + const testItems: TestItem[] = []; + collection.forEach((testItem) => testItems.push(testItem)); + + return testItems; + } +} diff --git a/src/TestExecution/TestRunHandler.ts b/src/TestExecution/TestRunHandler.ts new file mode 100644 index 00000000..7a34315c --- /dev/null +++ b/src/TestExecution/TestRunHandler.ts @@ -0,0 +1,114 @@ +import { inject, injectable } from 'inversify'; +import { + type CancellationToken, + debug, + type TestController, + type TestRun, + type TestRunRequest, + workspace, +} from 'vscode'; +import { Configuration } from '../Configuration'; +import { CoverageCollector } from '../Coverage'; +import { + Mode, + PHPUnitXML, + ProcessBuilder, + type TestRunner, + TestRunnerEvent, + Xdebug, +} from '../PHPUnit'; +import { TestCollection } from '../TestCollection'; +import { TYPES } from '../types'; +import { TestQueueBuilder } from './TestQueueBuilder'; +import { TestRunnerBuilder } from './TestRunnerBuilder'; + +@injectable() +export class TestRunHandler { + private previousRequest: TestRunRequest | undefined; + + constructor( + @inject(TYPES.TestController) private ctrl: TestController, + @inject(PHPUnitXML) private phpUnitXML: PHPUnitXML, + @inject(Configuration) private configuration: Configuration, + @inject(TestCollection) private testCollection: TestCollection, + @inject(TestRunnerBuilder) private testRunnerBuilder: TestRunnerBuilder, + @inject(CoverageCollector) private coverageCollector: CoverageCollector, + @inject(TestQueueBuilder) private testQueueBuilder: TestQueueBuilder, + ) {} + + getPreviousRequest() { + return this.previousRequest; + } + + async startTestRun(request: TestRunRequest, cancellation?: CancellationToken) { + const builder = await this.createProcessBuilder(request); + const xdebug = builder.getXdebug()!; + + await this.manageDebugSession(xdebug, async () => { + const testRun = this.ctrl.createTestRun(request); + await this.runTestQueue(builder, testRun, request, cancellation); + }); + + this.previousRequest = request; + } + + private async createProcessBuilder(request: TestRunRequest): Promise { + const builder = new ProcessBuilder(this.configuration, { cwd: this.phpUnitXML.root() }); + const xdebug = new Xdebug(this.configuration); + builder.setXdebug(xdebug); + await xdebug.setMode(request.profile?.kind); + + return builder; + } + + private async manageDebugSession(xdebug: Xdebug, fn: () => Promise): Promise { + if (xdebug.mode === Mode.debug) { + const wsf = workspace.getWorkspaceFolder(this.testCollection.getWorkspace()); + // TODO: perhaps wait for the debug session + await debug.startDebugging(wsf, xdebug.name ?? (await xdebug.getDebugConfiguration())); + } + + await fn(); + + if (xdebug.mode === Mode.debug && debug.activeDebugSession?.type === 'php') { + debug.stopDebugging(debug.activeDebugSession); + } + } + + private async runTestQueue( + builder: ProcessBuilder, + testRun: TestRun, + request: TestRunRequest, + cancellation?: CancellationToken, + ) { + const queue = await this.testQueueBuilder.build( + request.include ?? this.testQueueBuilder.collectItems(this.ctrl.items), + request, + ); + queue.forEach((testItem) => testRun.enqueued(testItem)); + + const runner = this.testRunnerBuilder.build(queue, testRun, request); + runner.emit(TestRunnerEvent.start, undefined); + + const processes = this.createProcesses(runner, builder, request); + cancellation?.onCancellationRequested(() => + processes.forEach((process) => process.abort()), + ); + + await Promise.all(processes.map((process) => process.run())); + await this.coverageCollector.collect(processes, testRun); + + runner.emit(TestRunnerEvent.done, undefined); + } + + private createProcesses(runner: TestRunner, builder: ProcessBuilder, request: TestRunRequest) { + if (!request.include) { + return [runner.run(builder)]; + } + + return request.include + .map((testItem) => this.testCollection.getTestCase(testItem)!) + .map((testCase, index) => testCase.configureProcessBuilder(builder, index)) + .map((builder) => runner.run(builder)); + } +} diff --git a/src/TestExecution/TestRunnerBuilder.test.ts b/src/TestExecution/TestRunnerBuilder.test.ts new file mode 100644 index 00000000..462d0247 --- /dev/null +++ b/src/TestExecution/TestRunnerBuilder.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it, vi } from 'vitest'; +import type { TestItem, TestRun, TestRunRequest } from 'vscode'; +import type { ErrorDialogObserver, OutputChannelObserver } from '../Observers'; +import { TestRunner } from '../PHPUnit'; +import type { TestCase } from '../TestCollection'; +import { TestRunnerBuilder } from './TestRunnerBuilder'; + +describe('TestRunnerBuilder', () => { + it('should build a TestRunner with observers', () => { + const outputChannelObserver = { setRequest: vi.fn() } as unknown as OutputChannelObserver; + const errorDialogObserver = {} as ErrorDialogObserver; + const builder = new TestRunnerBuilder(outputChannelObserver, errorDialogObserver); + + const queue = new Map(); + const testRun = { enqueued: vi.fn() } as unknown as TestRun; + const request = {} as TestRunRequest; + + const runner = builder.build(queue, testRun, request); + + expect(runner).toBeInstanceOf(TestRunner); + expect(outputChannelObserver.setRequest).toHaveBeenCalledWith(request); + }); +}); diff --git a/src/TestExecution/TestRunnerBuilder.ts b/src/TestExecution/TestRunnerBuilder.ts new file mode 100644 index 00000000..06f94369 --- /dev/null +++ b/src/TestExecution/TestRunnerBuilder.ts @@ -0,0 +1,24 @@ +import { inject, injectable } from 'inversify'; +import type { TestItem, TestRun, TestRunRequest } from 'vscode'; +import { ErrorDialogObserver, OutputChannelObserver, TestResultObserver } from '../Observers'; +import { TestRunner } from '../PHPUnit'; +import type { TestCase } from '../TestCollection'; + +@injectable() +export class TestRunnerBuilder { + constructor( + @inject(OutputChannelObserver) private outputChannelObserver: OutputChannelObserver, + @inject(ErrorDialogObserver) private errorDialogObserver: ErrorDialogObserver, + ) {} + + build(queue: Map, testRun: TestRun, request: TestRunRequest): TestRunner { + this.outputChannelObserver.setRequest(request); + + const runner = new TestRunner(); + runner.observe(new TestResultObserver(queue, testRun)); + runner.observe(this.outputChannelObserver); + runner.observe(this.errorDialogObserver); + + return runner; + } +} diff --git a/src/TestExecution/index.ts b/src/TestExecution/index.ts new file mode 100644 index 00000000..4cbf9395 --- /dev/null +++ b/src/TestExecution/index.ts @@ -0,0 +1,3 @@ +export * from './TestQueueBuilder'; +export * from './TestRunHandler'; +export * from './TestRunnerBuilder'; diff --git a/src/container.ts b/src/container.ts new file mode 100644 index 00000000..c682c1e6 --- /dev/null +++ b/src/container.ts @@ -0,0 +1,50 @@ +import { Container } from 'inversify'; +import { EventEmitter, type OutputChannel, type TestController, type Uri, workspace } from 'vscode'; +import { PHPUnitLinkProvider, TestCommandRegistry } from './Commands'; +import { Configuration } from './Configuration'; +import { CoverageCollector } from './Coverage'; +import { CollisionPrinter, ErrorDialogObserver, OutputChannelObserver } from './Observers'; +import { OutputFormatter } from './Observers/Printers'; +import { PHPUnitXML } from './PHPUnit'; +import { TestCollection } from './TestCollection'; +import { TestFileDiscovery, TestFileWatcher, TestWatchManager } from './TestDiscovery'; +import { TestQueueBuilder, TestRunHandler, TestRunnerBuilder } from './TestExecution'; +import { TYPES } from './types'; + +export function createContainer(ctrl: TestController, outputChannel: OutputChannel): Container { + const container = new Container(); + + // VS Code external objects (use Symbols) + container.bind(TYPES.TestController).toConstantValue(ctrl); + container.bind(TYPES.OutputChannel).toConstantValue(outputChannel); + container.bind(TYPES.FileChangedEmitter).toConstantValue(new EventEmitter()); + + // PHPUnit layer (no decorators, use toDynamicValue) + container + .bind(PHPUnitXML) + .toDynamicValue(() => new PHPUnitXML()) + .inSingletonScope(); + container + .bind(Configuration) + .toDynamicValue(() => new Configuration(workspace.getConfiguration('phpunit'))) + .inSingletonScope(); + + // Abstract → Concrete + container.bind(OutputFormatter).to(CollisionPrinter).inSingletonScope(); + + // src/ layer classes (auto-resolve constructors) + container.bind(CoverageCollector).toSelf().inSingletonScope(); + container.bind(ErrorDialogObserver).toSelf().inSingletonScope(); + container.bind(OutputChannelObserver).toSelf().inSingletonScope(); + container.bind(TestCollection).toSelf().inSingletonScope(); + container.bind(TestRunnerBuilder).toSelf().inSingletonScope(); + container.bind(TestQueueBuilder).toSelf().inSingletonScope(); + container.bind(TestRunHandler).toSelf().inSingletonScope(); + container.bind(TestFileDiscovery).toSelf().inSingletonScope(); + container.bind(TestFileWatcher).toSelf().inSingletonScope(); + container.bind(TestWatchManager).toSelf().inSingletonScope(); + container.bind(TestCommandRegistry).toSelf().inSingletonScope(); + container.bind(PHPUnitLinkProvider).toSelf().inSingletonScope(); + + return container; +} diff --git a/src/extension.test.ts b/src/extension.test.ts index a27b9fb1..abfe664b 100644 --- a/src/extension.test.ts +++ b/src/extension.test.ts @@ -1,18 +1,38 @@ -import { glob, GlobOptions } from 'glob'; import { spawn } from 'node:child_process'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; +import { type GlobOptions, glob } from 'glob'; import * as semver from 'semver'; +import { afterEach, beforeEach, describe, expect, it, type Mock, vi } from 'vitest'; import { - CancellationTokenSource, commands, debug, TestController, TestItem, TestItemCollection, TestRunProfileKind, tests, - TextDocument, Uri, window, workspace, WorkspaceFolder, + CancellationTokenSource, + commands, + debug, + type TestController, + type TestItem, + type TestItemCollection, + TestRunProfileKind, + type TextDocument, + tests, + Uri, + type WorkspaceFolder, + window, + workspace, } from 'vscode'; import { Configuration } from './Configuration'; import { activate } from './extension'; -import { getPhpUnitVersion, getPhpVersion, normalPath, pestProject, phpUnitProject } from './PHPUnit/__tests__/utils'; - -//updated to match spawn for tests -jest.mock('node:child_process'); +import { + detectParatestStubs, + detectPestStubs, + detectPhpUnitStubs, + pestProject, + phpUnitProject, +} from './PHPUnit/__tests__/utils'; + +vi.mock('child_process', async () => { + const actual = await vi.importActual('child_process'); + return { ...actual, spawn: vi.fn(actual.spawn) }; +}); const setTextDocuments = (textDocuments: TextDocument[]) => { Object.defineProperty(workspace, 'textDocuments', { @@ -43,30 +63,19 @@ const globTextDocuments = (pattern: string, options?: GlobOptions) => { })) as TextDocument[]; }; -// const _setTimeout = global.setTimeout; -// -// const useFakeTimers = (ms: number, fn: Function) => { -// (global as any).setTimeout = (fn: any, _ms?: number) => fn(); -// -// return new Promise((resolve) => { -// fn(); -// _setTimeout(() => resolve(true), ms); -// }); -// }; - const getOutputChannel = () => { - return (window.createOutputChannel as jest.Mock).mock.results[0].value; + return (window.createOutputChannel as Mock).mock.results[0].value; }; const getTestController = () => { - return (tests.createTestController as jest.Mock).mock.results[0].value; + return (tests.createTestController as Mock).mock.results[0].value; }; -const getRunProfile = (ctrl: TestController, kind = TestRunProfileKind.Run) => { - const profile = (ctrl.createRunProfile as jest.Mock).mock.results[0].value; - profile.kind = kind; +const getTestRunProfile = (ctrl: TestController, kind = TestRunProfileKind.Run) => { + const testRunProfile = (ctrl.createRunProfile as Mock).mock.results[0].value; + testRunProfile.kind = kind; - return profile; + return testRunProfile; }; const findTest = (items: TestItemCollection, id: string): TestItem | undefined => { @@ -83,17 +92,11 @@ const findTest = (items: TestItemCollection, id: string): TestItem | undefined = return; }; -// const getTestFile = (ctrl: TestController, pattern: RegExp) => { -// const doc = workspace.textDocuments.find((doc) => doc.uri.fsPath.match(pattern))!; -// -// return findTest(ctrl.items, doc.uri.toString()); -// }; - const getTestRun = (ctrl: TestController) => { - return (ctrl.createTestRun as jest.Mock).mock.results[0].value; + return (ctrl.createTestRun as Mock).mock.results[0].value; }; -const expectTestResultCalled = (ctrl: TestController, expected: any) => { +const expectTestResultCalled = (ctrl: TestController, expected: Record) => { const { enqueued, started, passed, failed, end } = getTestRun(ctrl); expect({ @@ -103,414 +106,467 @@ const expectTestResultCalled = (ctrl: TestController, expected: any) => { failed: failed.mock.calls.length, end: end.mock.calls.length, }).toEqual(expected); - // expect(enqueued).toHaveBeenCalledTimes(expected.enqueued); - // expect(started).toHaveBeenCalledTimes(expected.started); - // expect(passed).toHaveBeenCalledTimes(expected.passed); - // expect(failed).toHaveBeenCalledTimes(expected.failed); - // expect(end).toHaveBeenCalledTimes(expected.end); expect(getOutputChannel().appendLine).toHaveBeenCalled(); }; const countItems = (testItemCollection: TestItemCollection) => { let sum = 0; - testItemCollection.forEach((item) => sum += countItems(item.children)); + testItemCollection.forEach((item) => (sum += countItems(item.children))); sum += testItemCollection.size; return sum; }; +const resolveExpected = (version: string, map: [string, T][], fallback: T): T => { + for (const [minVersion, expected] of map) { + if (semver.gte(version, minVersion)) return expected; + } + return fallback; +}; + describe('Extension Test', () => { - const filterPattern = (method: string) => new RegExp( - `--filter=["']?\\^\\.\\*::\\(${method}\\)\\(\\( with \\(data set \\)\\?\\.\\*\\)\\?\\)\\?\\$["']?`, - ); + const phpBinary = 'php'; - const context: any = { subscriptions: { push: jest.fn() } }; - let cwd: string; + const filterPattern = (method: string) => + new RegExp( + `--filter=["']?\\^\\.\\*::\\(${method}\\)\\(\\( with \\(data set \\)\\?\\.\\*\\)\\?\\)\\?\\$["']?`, + ); - describe('PHPUnit', () => { - const phpBinary = 'php'; - const PHPUNIT_VERSION: string = getPhpUnitVersion(); + const context = { + subscriptions: { push: vi.fn() }, + } as unknown as import('vscode').ExtensionContext; + let cwd: string; - const root = phpUnitProject(''); + const setupEnvironment = async (root: string, phpunitBinary: string, args: string[] = []) => { + setWorkspaceFolders([{ index: 0, name: 'phpunit', uri: Uri.file(root) }]); + setTextDocuments(globTextDocuments('**/*Test.php', { cwd: root })); + (context.subscriptions.push as unknown as Mock).mockReset(); + cwd = root; + const configuration = workspace.getConfiguration('phpunit'); + await configuration.update('php', phpBinary); + await configuration.update('phpunit', phpunitBinary); + await configuration.update('args', args); + }; - beforeEach(() => { - setWorkspaceFolders([{ index: 0, name: 'phpunit', uri: Uri.file(root) }]); - setTextDocuments(globTextDocuments('**/*Test.php', expect.objectContaining({ cwd: root }))); + const setActiveTextEditor = (file: string, selection?: { line: number; character: number }) => { + Object.defineProperty(window, 'activeTextEditor', { + value: { + document: { uri: Uri.file(file) }, + ...(selection && { selection: { active: selection } }), + }, + enumerable: true, + configurable: true, }); + }; - afterEach(() => jest.clearAllMocks()); - - describe('PHPUnit activate()', () => { - beforeEach(async () => { - context.subscriptions.push.mockReset(); - cwd = normalPath(root); - const configuration = workspace.getConfiguration('phpunit'); - await configuration.update('php', phpBinary); - await configuration.update('phpunit', 'vendor/bin/phpunit'); - await configuration.update('args', []); - }); + const activateAndRun = async (opts?: { + include?: string | string[]; + kind?: TestRunProfileKind; + }) => { + await activate(context); + const ctrl = getTestController(); + const testRunProfile = getTestRunProfile(ctrl, opts?.kind); + const ids = opts?.include; + const include = ids ? [ids].flat().map((id) => findTest(ctrl.items, id)) : undefined; + const request = { include, exclude: [], profile: testRunProfile }; + await testRunProfile.runHandler(request, new CancellationTokenSource().token); + return ctrl; + }; - afterEach(() => jest.clearAllMocks()); + const expectSpawnCalled = ( + args: (string | RegExp)[], + envOverrides?: Record, + ) => { + expect(spawn).toHaveBeenCalledWith( + phpBinary, + expect.arrayContaining( + args.map((a) => + a instanceof RegExp + ? expect.stringMatching(a) + : expect.stringMatching(new RegExp(`^${a.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'i')), + ), + ), + expect.objectContaining({ + cwd: expect.stringMatching(new RegExp(`^${cwd.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'i')), + ...(envOverrides && { env: expect.objectContaining(envOverrides) }), + }), + ); + }; - it('should load tests', async () => { - await activate(context); - const ctrl = getTestController(); - const uri = Uri.file(join(root, 'tests/AssertionsTest.php')); - const itemId = `Assertions (Tests\\Assertions)`; + describe.each(detectPhpUnitStubs())('PHPUnit on $name (PHPUnit $phpUnitVersion)', ({ + root, + phpUnitVersion, + binary, + args, + }) => { + beforeEach(() => setupEnvironment(root, binary, args)); + afterEach(() => vi.clearAllMocks()); - const parent = findTest(ctrl.items, itemId)!; - const child = parent.children.get(`${itemId}::Passed`); + it('should load tests', async () => { + await activate(context); + const ctrl = getTestController(); + const uri = Uri.file(join(root, 'tests/AssertionsTest.php')); + const itemId = `Assertions (Tests\\Assertions)`; - expect(parent).toEqual( - expect.objectContaining({ - id: itemId, - uri: expect.objectContaining({ fsPath: uri.fsPath }), - label: '$(symbol-class) AssertionsTest', - }), - ); + const parent = findTest(ctrl.items, itemId)!; + const child = parent.children.get(`${itemId}::Passed`); - expect(child).toEqual( - expect.objectContaining({ - id: `${itemId}::Passed`, - uri: expect.objectContaining({ fsPath: uri.fsPath }), - label: '$(symbol-method) test_passed', - range: { - start: expect.objectContaining({ line: 11, character: 4 }), - end: expect.objectContaining({ line: 14, character: 5 }), - }, - }), - ); + expect(parent).toEqual( + expect.objectContaining({ + id: itemId, + uri: expect.objectContaining({ fsPath: uri.fsPath }), + label: '$(symbol-class) AssertionsTest', + }), + ); - expect(workspace.getConfiguration).toHaveBeenCalledWith('phpunit'); - expect(window.createOutputChannel).toHaveBeenCalledWith('PHPUnit', 'phpunit'); - expect(tests.createTestController).toHaveBeenCalledWith('phpUnitTestController', 'PHPUnit'); - expect(commands.registerCommand).toHaveBeenCalledWith('phpunit.reload', expect.any(Function)); - expect(commands.registerCommand).toHaveBeenCalledWith('phpunit.run-all', expect.any(Function)); - expect(commands.registerCommand).toHaveBeenCalledWith('phpunit.run-file', expect.any(Function)); - expect(commands.registerCommand).toHaveBeenCalledWith('phpunit.run-test-at-cursor', expect.any(Function)); - expect(commands.registerCommand).toHaveBeenCalledWith('phpunit.rerun', expect.any(Function)); - expect(context.subscriptions.push).toHaveBeenCalledTimes(10); - }); + expect(child).toEqual( + expect.objectContaining({ + id: `${itemId}::Passed`, + uri: expect.objectContaining({ fsPath: uri.fsPath }), + label: '$(symbol-method) test_passed', + range: { + start: expect.objectContaining({ line: 15, character: 4 }), + end: expect.objectContaining({ line: 18, character: 5 }), + }, + tags: expect.arrayContaining([ + expect.objectContaining({ id: 'group:integration' }), + ]), + }), + ); + + expect(workspace.getConfiguration).toHaveBeenCalledWith('phpunit'); + expect(window.createOutputChannel).toHaveBeenCalledWith('PHPUnit', 'phpunit'); + expect(tests.createTestController).toHaveBeenCalledWith( + 'phpUnitTestController', + 'PHPUnit', + ); + for (const cmd of [ + 'phpunit.reload', + 'phpunit.run-all', + 'phpunit.run-file', + 'phpunit.run-test-at-cursor', + 'phpunit.rerun', + ]) { + expect(commands.registerCommand).toHaveBeenCalledWith(cmd, expect.any(Function)); + } + expect(context.subscriptions.push).toHaveBeenCalledTimes(7); + }); - it('should run all tests', async () => { - await activate(context); - const ctrl = getTestController(); - const runProfile = getRunProfile(ctrl); - const request = { include: undefined, exclude: [], profile: runProfile }; + it('should only update configuration when phpunit settings change', async () => { + await activate(context); - await runProfile.runHandler(request, new CancellationTokenSource().token); + const onDidChangeConfig = workspace.onDidChangeConfiguration as Mock; + const listenerCall = onDidChangeConfig.mock.calls.find( + (call: unknown[]) => typeof call[0] === 'function', + ); + expect(listenerCall).toBeDefined(); + const listener = listenerCall?.[0]; - expect(spawn).toHaveBeenCalledWith( - phpBinary, - ['vendor/bin/phpunit', '--colors=never', '--teamcity'], - expect.objectContaining({ cwd }), - ); + const spy = vi.spyOn(Configuration.prototype, 'updateWorkspaceConfiguration'); - const expected = semver.gte(PHPUNIT_VERSION, '10.0.0') - ? { enqueued: 28, started: 35, passed: 23, failed: 10, end: 1 } - : { enqueued: 28, started: 29, passed: 16, failed: 11, end: 1 }; + // phpunit config change → should update + listener({ affectsConfiguration: (section: string) => section === 'phpunit' }); + expect(spy).toHaveBeenCalledTimes(1); - expectTestResultCalled(ctrl, expected); - }); + spy.mockClear(); - it('should run test by namespace', async () => { - await activate(context); - const ctrl = getTestController(); - const runProfile = getRunProfile(ctrl); - const id = `namespace:Tests`; - const request = { include: [findTest(ctrl.items, id)], exclude: [], profile: runProfile }; + // non-phpunit config change → should NOT update + listener({ affectsConfiguration: (section: string) => section === 'editor' }); + expect(spy).not.toHaveBeenCalled(); - await runProfile.runHandler(request, new CancellationTokenSource().token); + spy.mockRestore(); + }); - expect(spawn).toHaveBeenCalledWith(phpBinary, [ - 'vendor/bin/phpunit', - `--filter=^(Tests.*)(( with (data set )?.*)?)?$`, - '--colors=never', - '--teamcity', - ], expect.objectContaining({ cwd })); + it('should run all tests', async () => { + const ctrl = await activateAndRun(); - const expected = semver.gte(PHPUNIT_VERSION, '10.0.0') - ? { enqueued: 27, started: 34, passed: 23, failed: 9, end: 1 } - : { enqueued: 27, started: 28, passed: 16, failed: 10, end: 1 }; + const expected = resolveExpected( + phpUnitVersion, + [ + ['12.0.0', { enqueued: 28, started: 26, passed: 15, failed: 9, end: 1 }], + ['10.0.0', { enqueued: 28, started: 34, passed: 22, failed: 10, end: 1 }], + ], + { enqueued: 28, started: 29, passed: 16, failed: 11, end: 1 }, + ); - expectTestResultCalled(ctrl, expected); - }); + expectTestResultCalled(ctrl, expected); + }); - it('should run test suite', async () => { - await activate(context); - const ctrl = getTestController(); - const runProfile = getRunProfile(ctrl); - const id = `Assertions (Tests\\Assertions)`; - const request = { include: [findTest(ctrl.items, id)], exclude: [], profile: runProfile }; + it('should run test by namespace', async () => { + const ctrl = await activateAndRun({ include: 'namespace:Tests' }); - await runProfile.runHandler(request, new CancellationTokenSource().token); + const expected = resolveExpected( + phpUnitVersion, + [ + ['12.0.0', { enqueued: 27, started: 25, passed: 15, failed: 8, end: 1 }], + ['10.0.0', { enqueued: 27, started: 33, passed: 22, failed: 9, end: 1 }], + ], + { enqueued: 27, started: 28, passed: 16, failed: 10, end: 1 }, + ); - expect(spawn).toHaveBeenCalledWith(phpBinary, [ - 'vendor/bin/phpunit', - normalPath(phpUnitProject('tests/AssertionsTest.php')), - '--colors=never', - '--teamcity', - ], expect.objectContaining({ cwd })); + expectTestResultCalled(ctrl, expected); + }); - expectTestResultCalled(ctrl, { enqueued: 9, started: 12, passed: 6, failed: 4, end: 1 }); + it('should run test suite', async () => { + const ctrl = await activateAndRun({ + include: 'Assertions (Tests\\Assertions)', }); - it('should run test case', async () => { - await activate(context); - const ctrl = getTestController(); - const runProfile = getRunProfile(ctrl); - - const method = 'test_throw_exception'; - const id = `Calculator (Tests\\Calculator)::Throw exception`; + const expected = resolveExpected( + phpUnitVersion, + [ + ['12.0.0', { enqueued: 9, started: 6, passed: 1, failed: 3, end: 1 }], + ['10.0.0', { enqueued: 9, started: 11, passed: 5, failed: 4, end: 1 }], + ], + { enqueued: 9, started: 12, passed: 6, failed: 4, end: 1 }, + ); - const request = { include: [findTest(ctrl.items, id)], exclude: [], profile: runProfile }; - - await runProfile.runHandler(request, new CancellationTokenSource().token); + expectTestResultCalled(ctrl, expected); + }); - expect(spawn).toHaveBeenCalledWith(phpBinary, [ - 'vendor/bin/phpunit', - expect.stringMatching(filterPattern(method)), - normalPath(phpUnitProject('tests/CalculatorTest.php')), - '--colors=never', - '--teamcity', - ], expect.objectContaining({ cwd })); + it('should run test case', async () => { + const id = `Calculator (Tests\\Calculator)::Throw exception`; + const ctrl = await activateAndRun({ include: id }); - expectTestResultCalled(ctrl, { enqueued: 1, started: 1, passed: 0, failed: 1, end: 1 }); + expectTestResultCalled(ctrl, { + enqueued: 1, + started: 1, + passed: 0, + failed: 1, + end: 1, + }); - const { failed } = getTestRun(ctrl); - const [, message] = (failed as jest.Mock).mock.calls.find(([test]) => test.id === id); + const { failed } = getTestRun(ctrl); + const [, message] = (failed as Mock).mock.calls.find( + ([test]: { id: string }[]) => test.id === id, + )!; - expect(message.location).toEqual(expect.objectContaining({ + expect(message.location).toEqual( + expect.objectContaining({ range: { start: expect.objectContaining({ line: 53, character: 0 }), end: expect.objectContaining({ line: 53, character: 0 }), }, - })); - }); + }), + ); + }); - it('should refresh tests', async () => { - await activate(context); + it('should run all tests with group arg', async () => { + const configuration = workspace.getConfiguration('phpunit'); + await configuration.update('args', ['--group=integration']); - const ctrl = getTestController(); + await activateAndRun(); - await ctrl.refreshHandler(); - }); + expectSpawnCalled([ + binary, + '--group=integration', + '--colors=never', + '--teamcity', + ]); - it('should resolve tests', async () => { - await activate(context); + await configuration.update('args', []); + }); - const ctrl = getTestController(); + it('should run class with group', async () => { + await activateAndRun({ include: 'Attribute (Tests\\Attribute)' }); - await ctrl.resolveHandler(); + expectSpawnCalled([ + binary, + '--group=integration', + Uri.file(phpUnitProject('tests/AttributeTest.php')).fsPath, + '--colors=never', + '--teamcity', + ]); + }); - expect(countItems(ctrl.items)).toEqual(46); - }); + it('should run method with group', async () => { + await activateAndRun({ include: 'Assertions (Tests\\Assertions)::Passed' }); - it('should resolve tests without phpunit.xml', async () => { - jest.spyOn(Configuration.prototype, 'getConfigurationFile') - .mockReturnValueOnce(undefined as any); + expectSpawnCalled([ + binary, + filterPattern('test_passed'), + Uri.file(phpUnitProject('tests/AssertionsTest.php')).fsPath, + '--colors=never', + '--teamcity', + ]); + }); - await activate(context); + it('should run at cursor with group', async () => { + await activate(context); + setActiveTextEditor(phpUnitProject('tests/AssertionsTest.php'), { + line: 17, + character: 14, + }); - const ctrl = getTestController(); + await commands.executeCommand('phpunit.run-test-at-cursor'); - await ctrl.resolveHandler(); + expectSpawnCalled([ + binary, + filterPattern('test_passed'), + Uri.file(phpUnitProject('tests/AssertionsTest.php')).fsPath, + '--colors=never', + '--teamcity', + ]); + }); - expect(countItems(ctrl.items)).toEqual(46); - }); + it('should refresh tests', async () => { + await activate(context); - it('should resolve tests with phpunit.xml.dist', async () => { - await workspace.getConfiguration('phpunit').update('args', [ - '-c', phpUnitProject('phpunit.xml.dist'), - ]); + const ctrl = getTestController(); - await activate(context); + await ctrl.refreshHandler(); + }); - const ctrl = getTestController(); + it('should resolve tests', async () => { + await activate(context); - await ctrl.resolveHandler(); + const ctrl = getTestController(); - expect(countItems(ctrl.items)).toEqual(13); - }); + await ctrl.resolveHandler(); - it('run phpunit.run-file', async () => { - Object.defineProperty(window, 'activeTextEditor', { - value: { document: { uri: Uri.file(phpUnitProject('tests/AssertionsTest.php')) } }, - enumerable: true, - configurable: true, - }); + expect(countItems(ctrl.items)).toEqual(46); + }); - await activate(context); + it('should resolve tests without phpunit.xml', async () => { + const testsRoot = phpUnitProject('tests'); + setWorkspaceFolders([{ index: 0, name: 'phpunit', uri: Uri.file(testsRoot) }]); + setTextDocuments( + globTextDocuments('**/*Test.php', expect.objectContaining({ cwd: testsRoot })), + ); + await workspace.getConfiguration('phpunit').update('args', []); - await commands.executeCommand('phpunit.run-file'); + await activate(context); - expect(spawn).toHaveBeenCalledWith(phpBinary, [ - 'vendor/bin/phpunit', - // '--filter=^.*::(test_passed)( with data set .*)?$', - normalPath(phpUnitProject('tests/AssertionsTest.php')), - '--colors=never', - '--teamcity', - ], expect.objectContaining({ cwd })); - }); + const ctrl = getTestController(); - it('run phpunit.run-test-at-cursor', async () => { - await activate(context); + await ctrl.resolveHandler(); - Object.defineProperty(window, 'activeTextEditor', { - value: { - document: { uri: Uri.file(phpUnitProject('tests/AssertionsTest.php')) }, - selection: { active: { line: 13, character: 14 } }, - }, - enumerable: true, - configurable: true, - }); + expect(countItems(ctrl.items)).toEqual(144); + }); - await commands.executeCommand('phpunit.run-test-at-cursor'); + it('should resolve tests with phpunit.xml.dist', async () => { + await workspace + .getConfiguration('phpunit') + .update('args', ['-c', phpUnitProject('phpunit.xml.dist')]); - const method = 'test_passed'; + await activate(context); - expect(spawn).toHaveBeenCalledWith(phpBinary, [ - 'vendor/bin/phpunit', - expect.stringMatching(filterPattern(method)), - normalPath(phpUnitProject('tests/AssertionsTest.php')), - '--colors=never', - '--teamcity', - ], expect.objectContaining({ cwd })); - }); + const ctrl = getTestController(); + + await ctrl.resolveHandler(); + expect(countItems(ctrl.items)).toEqual(13); }); - }); - describe('Xdebug', () => { - const phpBinary = 'php'; - // const phpBinary = '/opt/homebrew/Cellar/php@8.1/8.1.32_1/bin/php'; - const root = phpUnitProject(''); + it('run phpunit.run-file', async () => { + setActiveTextEditor(phpUnitProject('tests/AssertionsTest.php')); + await activate(context); - beforeEach(() => { - setWorkspaceFolders([{ index: 0, name: 'phpunit', uri: Uri.file(root) }]); - setTextDocuments(globTextDocuments('**/*Test.php', expect.objectContaining({ cwd: root }))); - }); + await commands.executeCommand('phpunit.run-file'); - beforeEach(async () => { - context.subscriptions.push.mockReset(); - cwd = normalPath(root); - const configuration = workspace.getConfiguration('phpunit'); - await configuration.update('php', phpBinary); - await configuration.update('phpunit', 'vendor/bin/phpunit'); - await configuration.update('args', []); + expectSpawnCalled([ + binary, + Uri.file(phpUnitProject('tests/AssertionsTest.php')).fsPath, + '--colors=never', + '--teamcity', + ]); }); - afterEach(() => jest.clearAllMocks()); - - it('Debug', async () => { + it('run phpunit.run-test-at-cursor', async () => { await activate(context); - const ctrl = getTestController(); - const runProfile = getRunProfile(ctrl, TestRunProfileKind.Debug); - const request = { include: undefined, exclude: [], profile: runProfile }; - - await runProfile.runHandler(request, new CancellationTokenSource().token); - expect(spawn).toHaveBeenCalledWith(phpBinary, expect.arrayContaining([ - '-dxdebug.mode=debug', - '-dxdebug.start_with_request=1', - expect.stringMatching(/-dxdebug\.client_port=\d+/), - 'vendor/bin/phpunit', + setActiveTextEditor(phpUnitProject('tests/AssertionsTest.php'), { + line: 17, + character: 14, + }); + + await commands.executeCommand('phpunit.run-test-at-cursor'); + + expectSpawnCalled([ + binary, + filterPattern('test_passed'), + Uri.file(phpUnitProject('tests/AssertionsTest.php')).fsPath, '--colors=never', '--teamcity', - ]), expect.objectContaining({ - env: expect.objectContaining({ - // eslint-disable-next-line @typescript-eslint/naming-convention - 'XDEBUG_MODE': 'debug', - }), - })); + ]); + }); + + describe('Xdebug', () => { + it('Debug', async () => { + await activateAndRun({ kind: TestRunProfileKind.Debug }); + + expectSpawnCalled( + [ + '-dxdebug.mode=debug', + '-dxdebug.start_with_request=1', + /-dxdebug\.client_port=\d+/, + binary, + '--colors=never', + '--teamcity', + ], + { XDEBUG_MODE: 'debug' }, + ); - expect(debug.startDebugging).toHaveBeenCalledWith(expect.anything(), { - type: 'php', request: 'launch', name: 'PHPUnit', port: expect.any(Number), + expect(debug.startDebugging).toHaveBeenCalledWith(expect.anything(), { + type: 'php', + request: 'launch', + name: 'PHPUnit', + port: expect.any(Number), + }); + expect(debug.stopDebugging).toHaveBeenCalledWith({ type: 'php' }); }); - expect(debug.stopDebugging).toHaveBeenCalledWith({ type: 'php' }); - }); - it('Coverage', async () => { - await activate(context); - const ctrl = getTestController(); - const runProfile = getRunProfile(ctrl, TestRunProfileKind.Coverage); - - const request = { - include: [ - findTest(ctrl.items, 'Assertions (Tests\\Assertions)'), - findTest(ctrl.items, 'Calculator (Tests\\Calculator)'), - ], exclude: [], profile: runProfile, - }; - - await runProfile.runHandler(request, new CancellationTokenSource().token); - ['AssertionsTest.php', 'CalculatorTest.php'].forEach((file, i) => { - expect(spawn).toHaveBeenCalledWith(phpBinary, [ - '-dxdebug.mode=coverage', - 'vendor/bin/phpunit', - expect.stringMatching(file), - '--colors=never', - '--teamcity', - '--coverage-clover', - expect.stringMatching(`phpunit-${i}.xml`), - ], expect.objectContaining({ - env: expect.objectContaining({ - // eslint-disable-next-line @typescript-eslint/naming-convention - 'XDEBUG_MODE': 'coverage', - }), - })); + it('Coverage', async () => { + await activateAndRun({ + include: ['Assertions (Tests\\Assertions)', 'Calculator (Tests\\Calculator)'], + kind: TestRunProfileKind.Coverage, + }); + ['AssertionsTest.php', 'CalculatorTest.php'].forEach((file, i) => { + expectSpawnCalled( + [ + '-dxdebug.mode=coverage', + binary, + new RegExp(file), + '--colors=never', + '--teamcity', + '--coverage-clover', + new RegExp(`phpunit-${i}.xml`), + ], + { XDEBUG_MODE: 'coverage' }, + ); + }); }); }); }); - describe('paratest', () => { - const phpBinary = 'php'; - // const phpBinary = '/opt/homebrew/Cellar/php@8.0/8.0.30_5/bin/php'; - const PHP_VERSION: string = getPhpVersion(phpBinary); - const root = phpUnitProject(''); - let cwd: string; - - if (semver.lt(PHP_VERSION, '7.3.0')) { - return; - } - + describe.each(detectParatestStubs())('paratest on $name', ({ root, binary, args }) => { beforeEach(async () => { - cwd = normalPath(root); - setWorkspaceFolders([{ index: 0, name: 'phpunit', uri: Uri.file(root) }]); - setTextDocuments(globTextDocuments('**/*Test.php', expect.objectContaining({ cwd: root }))); - const configuration = workspace.getConfiguration('phpunit'); - await configuration.update('php', phpBinary); - await configuration.update('phpunit', 'vendor/bin/paratest'); - await configuration.update('args', []); - window.showErrorMessage = jest.fn(); + await setupEnvironment(root, binary, args); + window.showErrorMessage = vi.fn(); }); - afterEach(() => jest.clearAllMocks()); + afterEach(() => vi.clearAllMocks()); it('run phpunit.run-test-at-cursor', async () => { await activate(context); const ctrl = getTestController(); - - Object.defineProperty(window, 'activeTextEditor', { - value: { - document: { uri: Uri.file(phpUnitProject('tests/AssertionsTest.php')) }, - selection: { active: { line: 13, character: 14 } }, - }, - enumerable: true, - configurable: true, + setActiveTextEditor(phpUnitProject('tests/AssertionsTest.php'), { + line: 17, + character: 14, }); await commands.executeCommand('phpunit.run-test-at-cursor'); const method = 'test_passed'; - expect(spawn).toHaveBeenCalledWith(phpBinary, [ - 'vendor/bin/paratest', - expect.stringMatching(filterPattern(method)), - normalPath(phpUnitProject('tests/AssertionsTest.php')), + expectSpawnCalled([ + binary, + filterPattern(method), + Uri.file(phpUnitProject('tests/AssertionsTest.php')).fsPath, '--colors=never', '--teamcity', '--functional', - ], expect.objectContaining({ cwd })); + ]); expect(window.showErrorMessage).not.toHaveBeenCalled(); @@ -518,115 +574,67 @@ describe('Extension Test', () => { }); }); - describe('PEST', () => { - const phpBinary = 'php'; - // const phpBinary = '/opt/homebrew/Cellar/php@8.0/8.0.30_5/bin/php'; - const PHP_VERSION: string = getPhpVersion(phpBinary); - const isPestV1 = semver.gte(PHP_VERSION, '8.0.0') && semver.lt(PHP_VERSION, '8.1.0'); - const isPestV2 = semver.gte(PHP_VERSION, '8.1.0') && semver.lt(PHP_VERSION, '8.2.0'); - const isPestV3 = semver.gte(PHP_VERSION, '8.2.0'); - const isPest = isPestV1 || isPestV2 || isPestV3; - - if (!isPest) { - return; - } - - const root = pestProject(''); - - beforeEach(() => { - setWorkspaceFolders([{ index: 0, name: 'phpunit', uri: Uri.file(root) }]); - setTextDocuments(globTextDocuments('**/*Test.php', expect.objectContaining({ cwd: root }))); + describe.each(detectPestStubs())('PEST on $name (Pest $pestVersion)', ({ + root, + pestVersion, + binary, + args, + }) => { + beforeEach(() => setupEnvironment(root, binary, args)); + afterEach(() => vi.clearAllMocks()); + + it('should run all tests', async () => { + const ctrl = await activateAndRun(); + + const expected = resolveExpected( + pestVersion, + [['3.0.0', { enqueued: 68, started: 70, passed: 13, failed: 55, end: 1 }]], + { enqueued: 68, started: 63, passed: 10, failed: 51, end: 1 }, + ); + + expectTestResultCalled(ctrl, expected); }); - afterEach(() => jest.clearAllMocks()); + it('should run test case', async () => { + const id = `tests/Unit/ExampleTest.php::test_description`; + const ctrl = await activateAndRun({ include: id }); - describe('PEST activate()', () => { - beforeEach(async () => { - context.subscriptions.push.mockReset(); - cwd = normalPath(root); - const configuration = workspace.getConfiguration('phpunit'); - await configuration.update('php', phpBinary); - await configuration.update('phpunit', 'vendor/bin/pest'); - await configuration.update('args', []); - }); - - afterEach(() => jest.clearAllMocks()); - - it('should run all tests', async () => { - await activate(context); - const ctrl = getTestController(); - const runProfile = getRunProfile(ctrl); - const request = { include: undefined, exclude: [], profile: runProfile }; - - await runProfile.runHandler(request, new CancellationTokenSource().token); - - expect(spawn).toHaveBeenCalledWith( - phpBinary, - ['vendor/bin/pest', '--colors=never', '--teamcity'], - expect.objectContaining({ cwd }), - ); - - let expected: any; - if (isPestV1) { - expected = { enqueued: 68, started: 62, passed: 9, failed: 51, end: 1 }; - } else if (isPestV2) { - expected = { enqueued: 68, started: 64, passed: 11, failed: 51, end: 1 }; - } else { - expected = { enqueued: 68, started: 70, passed: 16, failed: 52, end: 1 }; - } - - expectTestResultCalled(ctrl, expected); - }); - - it('should run test case', async () => { - await activate(context); - const ctrl = getTestController(); - const runProfile = getRunProfile(ctrl); - - const method = 'test_description'; - const id = `tests/Unit/ExampleTest.php::test_description`; - - const request = { include: [findTest(ctrl.items, id)], exclude: [], profile: runProfile }; - - await runProfile.runHandler(request, new CancellationTokenSource().token); - - expect(spawn).toHaveBeenCalledWith(phpBinary, [ - 'vendor/bin/pest', - expect.stringMatching(filterPattern(method)), - normalPath(pestProject('tests/Unit/ExampleTest.php')), - '--colors=never', - '--teamcity', - ], expect.objectContaining({ cwd })); - - expectTestResultCalled(ctrl, { enqueued: 1, started: 1, passed: 0, failed: 1, end: 1 }); + expectTestResultCalled(ctrl, { + enqueued: 1, + started: 1, + passed: 0, + failed: 1, + end: 1, }); + }); - it('should run test case with dataset', async () => { - await activate(context); - const ctrl = getTestController(); - const runProfile = getRunProfile(ctrl); + it('should run test case with dataset', async () => { + const id = `tests/Unit/ExampleTest.php::it has user's email`; + const ctrl = await activateAndRun({ include: id }); - const method = `it has user's email`; - const id = `tests/Unit/ExampleTest.php::${method}`; + const expected = resolveExpected( + pestVersion, + [['3.0.0', { enqueued: 1, started: 3, passed: 3, failed: 0, end: 1 }]], + { enqueued: 1, started: 2, passed: 2, failed: 0, end: 1 }, + ); - const request = { include: [findTest(ctrl.items, id)], exclude: [], profile: runProfile }; + expectTestResultCalled(ctrl, expected); + }); - await runProfile.runHandler(request, new CancellationTokenSource().token); + it('should run all tests with group arg', async () => { + const configuration = workspace.getConfiguration('phpunit'); + await configuration.update('args', ['--group=integration']); - expect(spawn).toHaveBeenCalledWith(phpBinary, [ - 'vendor/bin/pest', - expect.stringMatching(filterPattern(method)), - normalPath(pestProject('tests/Unit/ExampleTest.php')), - '--colors=never', - '--teamcity', - ], expect.objectContaining({ cwd })); + await activateAndRun(); - const expected = !isPestV1 - ? { enqueued: 1, started: 3, passed: 3, failed: 0, end: 1 } - : { enqueued: 1, started: 2, passed: 2, failed: 0, end: 1 }; + expectSpawnCalled([ + binary, + '--group=integration', + '--colors=never', + '--teamcity', + ]); - expectTestResultCalled(ctrl, expected); - }); + await configuration.update('args', []); }); }); }); diff --git a/src/extension.ts b/src/extension.ts index 21614c2b..d49aa5d0 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,56 +1,51 @@ +import 'reflect-metadata'; +import type { Container } from 'inversify'; import { - CancellationToken, EventEmitter, ExtensionContext, extensions, GlobPattern, languages, RelativePattern, TestItem, - TestRunProfile, TestRunProfileKind, TestRunRequest, tests, Uri, window, workspace, WorkspaceFolder, + type EventEmitter, + type ExtensionContext, + extensions, + languages, + type OutputChannel, + type TestController, + type TestRunProfile, + TestRunProfileKind, + tests, + type Uri, + window, + workspace, } from 'vscode'; -import { PHPUnitFileCoverage } from './CloverParser'; -import { CommandHandler } from './CommandHandler'; +import { PHPUnitLinkProvider, TestCommandRegistry } from './Commands'; import { Configuration } from './Configuration'; -import { Handler } from './Handler'; -import { CollisionPrinter } from './Observers'; -import { Pattern, PHPUnitXML } from './PHPUnit'; -import { PHPUnitLinkProvider } from './PHPUnitLinkProvider'; +import type { PHPUnitFileCoverage } from './Coverage'; +import { createContainer } from './container'; import { TestCollection } from './TestCollection'; - -const phpUnitXML = new PHPUnitXML(); -const printer = new CollisionPrinter(phpUnitXML); -let testCollection: TestCollection; +import { TestFileDiscovery, TestFileWatcher, TestWatchManager } from './TestDiscovery'; +import { TYPES } from './types'; export async function activate(context: ExtensionContext) { const ctrl = tests.createTestController('phpUnitTestController', 'PHPUnit'); - context.subscriptions.push(ctrl); - testCollection = new TestCollection(ctrl, phpUnitXML); - const outputChannel = window.createOutputChannel('PHPUnit', 'phpunit'); - context.subscriptions.push(outputChannel); - - context.subscriptions.push(languages.registerDocumentLinkProvider({ language: 'phpunit' }, new PHPUnitLinkProvider(phpUnitXML))); + const container = createContainer(ctrl, outputChannel); - const configuration = new Configuration(workspace.getConfiguration('phpunit')); - context.subscriptions.push(workspace.onDidChangeConfiguration(() => configuration.updateWorkspaceConfiguration(workspace.getConfiguration('phpunit')))); - - const configurationFile = await configuration.getConfigurationFile(workspace.workspaceFolders![0].uri.fsPath); - if (configurationFile) { - testCollection.reset(); - await phpUnitXML.loadFile(configurationFile); - } + const testFileDiscovery = container.get(TestFileDiscovery); + const testFileWatcher = container.get(TestFileWatcher); + const testWatchManager = container.get(TestWatchManager); + const testCollection = container.get(TestCollection); + const testCommandRegistry = container.get(TestCommandRegistry); + // Initial load + await testFileDiscovery.loadWorkspaceConfiguration(); await Promise.all(workspace.textDocuments.map((document) => testCollection.add(document.uri))); - const reload = async () => { - await Promise.all( - (await getWorkspaceTestPatterns()).map(({ pattern, exclude }) => findInitialFiles(pattern, exclude)), - ); - }; + // Listeners + testFileWatcher.registerDocumentListeners(context); + testWatchManager.setupFileChangeListener(); - context.subscriptions.push( - workspace.onDidOpenTextDocument((document) => testCollection.add(document.uri)), - workspace.onDidChangeTextDocument((e) => testCollection.change(e.document.uri)), - ); - - ctrl.refreshHandler = reload; + // Test controller + ctrl.refreshHandler = () => testFileDiscovery.reloadAll(); ctrl.resolveHandler = async (item) => { if (!item) { - context.subscriptions.push(...(await startWatchingWorkspace(fileChangedEmitter))); + context.subscriptions.push(...(await testFileWatcher.startWatching())); return; } @@ -59,117 +54,84 @@ export async function activate(context: ExtensionContext) { } }; - const handler = new Handler(ctrl, phpUnitXML, configuration, testCollection, outputChannel, printer); - - const fileChangedEmitter = new EventEmitter(); - const watchingTests = new Map(); - - fileChangedEmitter.event(uri => { - if (watchingTests.has('ALL')) { - handler.startTestRun(new TestRunRequest(undefined, undefined, watchingTests.get('ALL'), true)); - return; - } - - const include: TestItem[] = []; - let profile: TestRunProfile | undefined; - for (const [item, thisProfile] of watchingTests) { - const cast = item as TestItem; - if (cast.uri?.toString() === uri.toString()) { - include.push(...testCollection.findTestsByFile(cast.uri!)); - profile = thisProfile; - } - } + // Run profiles, commands, and disposables + const testRunProfile = createRunProfiles(ctrl, testWatchManager); + registerCommands(context, testCommandRegistry, testRunProfile); + registerDisposables(context, ctrl, outputChannel, container); +} - if (include.length) { - handler.startTestRun(new TestRunRequest(include, undefined, profile, true)); - } - }); +function createRunProfiles(ctrl: TestController, testWatchManager: TestWatchManager) { + const runHandler = testWatchManager.createRunHandler(); - const runHandler = async (request: TestRunRequest, cancellation: CancellationToken) => { - if (!request.continuous) { - return handler.startTestRun(request, cancellation); - } + const testRunProfile = ctrl.createRunProfile( + 'Run Tests', + TestRunProfileKind.Run, + runHandler, + true, + undefined, + true, + ); - if (request.include === undefined) { - watchingTests.set('ALL', request.profile); - cancellation.onCancellationRequested(() => watchingTests.delete('ALL')); - } else { - request.include.forEach(item => watchingTests.set(item, request.profile)); - cancellation.onCancellationRequested(() => request.include!.forEach(item => watchingTests.delete(item))); - } - }; - const testRunProfile = ctrl.createRunProfile('Run Tests', TestRunProfileKind.Run, runHandler, true, undefined, true); if (extensions.getExtension('xdebug.php-debug') !== undefined) { - ctrl.createRunProfile('Debug Tests', TestRunProfileKind.Debug, runHandler, true, undefined, false); + ctrl.createRunProfile( + 'Debug Tests', + TestRunProfileKind.Debug, + runHandler, + true, + undefined, + false, + ); } - const coverageProfile = ctrl.createRunProfile('Run with Coverage', TestRunProfileKind.Coverage, runHandler, true, undefined, false); // TODO Continuous + + const coverageProfile = ctrl.createRunProfile( + 'Run with Coverage', + TestRunProfileKind.Coverage, + runHandler, + true, + undefined, + false, + ); coverageProfile.loadDetailedCoverage = async (_testRun, coverage) => { return (coverage).generateDetailedCoverage(); }; - const commandHandler = new CommandHandler(testCollection, testRunProfile); - context.subscriptions.push(commandHandler.reload(reload)); - context.subscriptions.push(commandHandler.runAll()); - context.subscriptions.push(commandHandler.runFile()); - context.subscriptions.push(commandHandler.runTestAtCursor()); - context.subscriptions.push(commandHandler.rerun(handler)); - context.subscriptions.push(commandHandler.runByGroup(handler)); + return testRunProfile; } -async function getWorkspaceTestPatterns() { - if (!workspace.workspaceFolders) { - return []; - } - - const configuration = new Configuration(workspace.getConfiguration('phpunit')); - - return Promise.all(workspace.workspaceFolders.map(async (workspaceFolder: WorkspaceFolder) => { - const configurationFile = await configuration.getConfigurationFile(workspaceFolder.uri.fsPath); - configurationFile - ? await phpUnitXML.loadFile(Uri.file(configurationFile).fsPath) - : phpUnitXML.setRoot(workspaceFolder.uri.fsPath); - const { includes, excludes } = phpUnitXML.getPatterns(workspaceFolder.uri.fsPath); - - const generateRelativePattern = (includeOrExclude: Pattern) => { - const { uri, pattern } = includeOrExclude.toGlobPattern(); - - return new RelativePattern(uri, pattern); - }; - - return { - workspaceFolder, - pattern: generateRelativePattern(includes), - exclude: generateRelativePattern(excludes), - }; - })); +function registerCommands( + context: ExtensionContext, + testCommandRegistry: TestCommandRegistry, + testRunProfile: TestRunProfile, +) { + testCommandRegistry.setTestRunProfile(testRunProfile); + context.subscriptions.push(testCommandRegistry.reload()); + context.subscriptions.push(testCommandRegistry.runAll()); + context.subscriptions.push(testCommandRegistry.runFile()); + context.subscriptions.push(testCommandRegistry.runTestAtCursor()); + context.subscriptions.push(testCommandRegistry.rerun()); } -async function findInitialFiles(pattern: GlobPattern, exclude: GlobPattern) { - testCollection.reset(); - const files = await workspace.findFiles(pattern, exclude); - await Promise.all(files.map((file) => testCollection.add(file))); -} - -async function startWatchingWorkspace(fileChangedEmitter: EventEmitter) { - return Promise.all((await getWorkspaceTestPatterns()).map(async ({ pattern, exclude }) => { - const watcher = workspace.createFileSystemWatcher(pattern); - - watcher.onDidCreate((uri) => { - testCollection.add(uri); - fileChangedEmitter.fire(uri); - }); - - watcher.onDidChange((uri) => { - testCollection.change(uri); - fileChangedEmitter.fire(uri); - }); - - watcher.onDidDelete((uri) => { - testCollection.delete(uri); - }); +function registerDisposables( + context: ExtensionContext, + ctrl: TestController, + outputChannel: OutputChannel, + container: Container, +) { + const configuration = container.get(Configuration); + const fileChangedEmitter = container.get>(TYPES.FileChangedEmitter); - await findInitialFiles(pattern, exclude); - - return watcher; - })); -} \ No newline at end of file + context.subscriptions.push( + ctrl, + outputChannel, + fileChangedEmitter, + workspace.onDidChangeConfiguration((event) => { + if (event.affectsConfiguration('phpunit')) { + configuration.updateWorkspaceConfiguration(workspace.getConfiguration('phpunit')); + } + }), + languages.registerDocumentLinkProvider( + { language: 'phpunit' }, + container.get(PHPUnitLinkProvider), + ), + ); +} diff --git a/src/test/runTest.ts b/src/test/runTest.ts index 13155465..ad3a8e4c 100644 --- a/src/test/runTest.ts +++ b/src/test/runTest.ts @@ -1,5 +1,5 @@ +import { resolve } from 'node:path'; import { runTests } from '@vscode/test-electron'; -import { resolve } from 'path'; async function main() { try { @@ -13,7 +13,7 @@ async function main() { // Download VS Code, unzip it and run the integration test await runTests({ extensionDevelopmentPath, extensionTestsPath }); - } catch (err) { + } catch (_err) { console.error('Failed to run tests'); process.exit(1); } diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index 258d640b..e7466d3d 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -1,6 +1,6 @@ +import * as path from 'node:path'; import * as glob from 'glob'; -import * as Mocha from 'mocha'; -import * as path from 'path'; +import Mocha from 'mocha'; export function run(): Promise { // Create the mocha test @@ -19,7 +19,7 @@ export function run(): Promise { try { // Run the mocha test - mocha.run((failures) => { + mocha.run((failures: number) => { if (failures > 0) { e(new Error(`${failures} tests failed.`)); } else { diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..9663a08d --- /dev/null +++ b/src/types.ts @@ -0,0 +1,5 @@ +export const TYPES = { + TestController: Symbol.for('TestController'), + OutputChannel: Symbol.for('OutputChannel'), + FileChangedEmitter: Symbol.for('FileChangedEmitter'), +}; diff --git a/src/uri.test.ts b/src/uri.test.ts index 021b485d..9525ee6c 100644 --- a/src/uri.test.ts +++ b/src/uri.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it } from '@jest/globals'; +import { describe, expect, it } from 'vitest'; import { Uri } from 'vscode'; import { URI } from 'vscode-uri'; import { phpUnitProject } from './PHPUnit/__tests__/utils'; diff --git a/tsconfig.json b/tsconfig.json index e6cbbaf7..af15df29 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,14 +17,19 @@ /* Report errors for fallthrough cases in switch statement. */ "noUnusedParameters": true, /* Report errors on unused parameters. */ + "esModuleInterop": true, "skipLibCheck": true, - "isolatedModules": true + "isolatedModules": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true }, "exclude": [ ".vscode-test", "node_modules", "**/__mocks__/*", "**/__tests__/fixtures/**/*", - "**/*.test.[tj]s?(x)" + "**/*.test.[tj]s?(x)", + "vitest.config.ts", + "esbuild.mjs" ] } diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000..285cfdf8 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,22 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + resolve: { + alias: { + vscode: resolve(__dirname, '__mocks__/vscode.ts'), + }, + }, + test: { + globals: false, + environment: 'node', + clearMocks: true, + coverage: { + provider: 'v8', + reportsDirectory: 'coverage', + }, + setupFiles: ['reflect-metadata'], + include: ['**/__tests__/**/*.test.[jt]s?(x)', '**/?(*.)+(spec|test).[tj]s?(x)'], + exclude: ['node_modules', 'out', 'src/test/', 'tests/fixtures', '.vscode-test'], + }, +}); diff --git a/vscode.d.ts b/vscode.d.ts index d858a774..e2e13e4a 100644 --- a/vscode.d.ts +++ b/vscode.d.ts @@ -6477,6 +6477,21 @@ declare module 'vscode' { */ export type CharacterPair = [string, string]; + /** + * Configuration for line comments. + */ + export interface LineCommentRule { + /** + * The line comment token, like `//` + */ + comment: string; + /** + * Whether the comment token should not be indented and placed at the first column. + * Defaults to false. + */ + noIndent?: boolean; + } + /** * Describes how comments for a language work. */ @@ -6485,7 +6500,7 @@ declare module 'vscode' { /** * The line comment token, like `// this is a comment` */ - lineComment?: string; + lineComment?: string | LineCommentRule; /** * The block comment character pair, like `/* block comment */` @@ -10063,7 +10078,7 @@ declare module 'vscode' { } /** - * A panel that contains a webview. + * A panel that contains a {@linkcode Webview}. */ export interface WebviewPanel { /** @@ -10115,7 +10130,7 @@ declare module 'vscode' { /** * Fired when the panel is disposed. * - * This may be because the user closed the panel or because `.dispose()` was + * This may be because the user closed the panel or because {@linkcode WebviewPanel.dispose dispose} was * called on it. * * Trying to use the panel after it has been disposed throws an exception. @@ -10128,7 +10143,7 @@ declare module 'vscode' { * A webview panel may only show in a single column at a time. If it is already showing, this * method moves it to a new column. * - * @param viewColumn View column to show the panel in. Shows in the current `viewColumn` if undefined. + * @param viewColumn View column to show the panel in. Shows in the current {@linkcode WebviewPanel.viewColumn} if undefined. * @param preserveFocus When `true`, the webview will not take focus. */ reveal(viewColumn?: ViewColumn, preserveFocus?: boolean): void; @@ -10138,17 +10153,17 @@ declare module 'vscode' { * * This closes the panel if it showing and disposes of the resources owned by the webview. * Webview panels are also disposed when the user closes the webview panel. Both cases - * fire the `onDispose` event. + * fire the {@linkcode onDidDispose} event. */ dispose(): any; } /** - * Event fired when a webview panel's view state changes. + * Event fired when a {@linkcode WebviewPanel webview panel's} view state changes. */ export interface WebviewPanelOnDidChangeViewStateEvent { /** - * Webview panel whose view state changed. + * {@linkcode WebviewPanel} whose view state changed. */ readonly webviewPanel: WebviewPanel; } @@ -10283,12 +10298,12 @@ declare module 'vscode' { * * To save resources, the editor normally deallocates webview documents (the iframe content) that are not visible. * For example, when the user collapse a view or switches to another top level activity in the sidebar, the - * `WebviewView` itself is kept alive but the webview's underlying document is deallocated. It is recreated when + * {@linkcode WebviewView} itself is kept alive but the webview's underlying document is deallocated. It is recreated when * the view becomes visible again. * - * You can prevent this behavior by setting `retainContextWhenHidden` in the `WebviewOptions`. However this - * increases resource usage and should be avoided wherever possible. Instead, you can use persisted state to - * save off a webview's state so that it can be quickly recreated as needed. + * You can prevent this behavior by setting {@linkcode WebviewOptions.retainContextWhenHidden retainContextWhenHidden} in the {@linkcode WebviewOptions}. + * However this increases resource usage and should be avoided wherever possible. Instead, you can use + * persisted state to save off a webview's state so that it can be quickly recreated as needed. * * To save off a persisted state, inside the webview call `acquireVsCodeApi().setState()` with * any json serializable object. To restore the state again, call `getState()`. For example: @@ -10311,7 +10326,7 @@ declare module 'vscode' { } /** - * Provider for creating `WebviewView` elements. + * Provider for creating {@linkcode WebviewView} elements. */ export interface WebviewViewProvider { /** @@ -10335,7 +10350,7 @@ declare module 'vscode' { * * Text based custom editors use a {@linkcode TextDocument} as their data model. This considerably simplifies * implementing a custom editor as it allows the editor to handle many common operations such as - * undo and backup. The provider is responsible for synchronizing text changes between the webview and the `TextDocument`. + * undo and backup. The provider is responsible for synchronizing text changes between the webview and the {@linkcode TextDocument}. */ export interface CustomTextEditorProvider { @@ -10345,13 +10360,12 @@ declare module 'vscode' { * This is called when a user first opens a resource for a `CustomTextEditorProvider`, or if they reopen an * existing editor using this `CustomTextEditorProvider`. * - * * @param document Document for the resource to resolve. * * @param webviewPanel The webview panel used to display the editor UI for this resource. * * During resolve, the provider must fill in the initial html for the content webview panel and hook up all - * the event listeners on it that it is interested in. The provider can also hold onto the `WebviewPanel` to + * the event listeners on it that it is interested in. The provider can also hold onto the {@linkcode WebviewPanel} to * use later for example in a command. See {@linkcode WebviewPanel} for additional details. * * @param token A cancellation token that indicates the result is no longer needed. @@ -10399,7 +10413,7 @@ declare module 'vscode' { * * This is invoked by the editor when the user undoes this edit. To implement `undo`, your * extension should restore the document and editor to the state they were in just before this - * edit was added to the editor's internal edit stack by `onDidChangeCustomDocument`. + * edit was added to the editor's internal edit stack by {@linkcode CustomEditorProvider.onDidChangeCustomDocument}. */ undo(): Thenable | void; @@ -10408,7 +10422,7 @@ declare module 'vscode' { * * This is invoked by the editor when the user redoes this edit. To implement `redo`, your * extension should restore the document and editor to the state they were in just after this - * edit was added to the editor's internal edit stack by `onDidChangeCustomDocument`. + * edit was added to the editor's internal edit stack by {@linkcode CustomEditorProvider.onDidChangeCustomDocument}. */ redo(): Thenable | void; @@ -10440,7 +10454,7 @@ declare module 'vscode' { /** * Unique identifier for the backup. * - * This id is passed back to your extension in `openCustomDocument` when opening a custom editor from a backup. + * This id is passed back to your extension in {@linkcode CustomReadonlyEditorProvider.openCustomDocument openCustomDocument} when opening a custom editor from a backup. */ readonly id: string; @@ -10505,10 +10519,10 @@ declare module 'vscode' { * Create a new document for a given resource. * * `openCustomDocument` is called when the first time an editor for a given resource is opened. The opened - * document is then passed to `resolveCustomEditor` so that the editor can be shown to the user. + * document is then passed to {@link resolveCustomEditor} so that the editor can be shown to the user. * - * Already opened `CustomDocument` are re-used if the user opened additional editors. When all editors for a - * given resource are closed, the `CustomDocument` is disposed of. Opening an editor at this point will + * Already opened {@linkcode CustomDocument CustomDocuments} are re-used if the user opened additional editors. When all editors for a + * given resource are closed, the {@linkcode CustomDocument CustomDocuments} is disposed of. Opening an editor at this point will * trigger another call to `openCustomDocument`. * * @param uri Uri of the document to open. @@ -10558,18 +10572,18 @@ declare module 'vscode' { * anything from changing some text, to cropping an image, to reordering a list. Your extension is free to * define what an edit is and what data is stored on each edit. * - * Firing `onDidChange` causes the editors to be marked as being dirty. This is cleared when the user either - * saves or reverts the file. + * Firing {@linkcode CustomEditorProvider.onDidChangeCustomDocument onDidChangeCustomDocument} causes the + * editors to be marked as being dirty. This is cleared when the user either saves or reverts the file. * - * Editors that support undo/redo must fire a `CustomDocumentEditEvent` whenever an edit happens. This allows + * Editors that support undo/redo must fire a {@linkcode CustomDocumentEditEvent} whenever an edit happens. This allows * users to undo and redo the edit using the editor's standard keyboard shortcuts. The editor will also mark * the editor as no longer being dirty if the user undoes all edits to the last saved state. * - * Editors that support editing but cannot use the editor's standard undo/redo mechanism must fire a `CustomDocumentContentChangeEvent`. + * Editors that support editing but cannot use the editor's standard undo/redo mechanism must fire a {@linkcode CustomDocumentContentChangeEvent}. * The only way for a user to clear the dirty state of an editor that does not support undo/redo is to either * `save` or `revert` the file. * - * An editor should only ever fire `CustomDocumentEditEvent` events, or only ever fire `CustomDocumentContentChangeEvent` events. + * An editor should only ever fire {@linkcode CustomDocumentEditEvent} events, or only ever fire {@linkcode CustomDocumentContentChangeEvent} events. */ readonly onDidChangeCustomDocument: Event> | Event>; @@ -10579,14 +10593,14 @@ declare module 'vscode' { * This method is invoked by the editor when the user saves a custom editor. This can happen when the user * triggers save while the custom editor is active, by commands such as `save all`, or by auto save if enabled. * - * To implement `save`, the implementer must persist the custom editor. This usually means writing the - * file data for the custom document to disk. After `save` completes, any associated editor instances will - * no longer be marked as dirty. + * The implementer must persist the custom editor. This usually means writing the + * file data for the custom document to disk. After {@linkcode saveCustomDocument} completes, any associated + * editor instances will no longer be marked as dirty. * * @param document Document to save. * @param cancellation Token that signals the save is no longer required (for example, if another save was triggered). * - * @returns Thenable signaling that saving has completed. + * @returns A {@linkcode Thenable} that saving has completed. */ saveCustomDocument(document: T, cancellation: CancellationToken): Thenable; @@ -10594,7 +10608,7 @@ declare module 'vscode' { * Save a custom document to a different location. * * This method is invoked by the editor when the user triggers 'save as' on a custom editor. The implementer must - * persist the custom editor to `destination`. + * persist the custom editor to {@linkcode destination}. * * When the user accepts save as, the current editor is be replaced by an non-dirty editor for the newly saved file. * @@ -10602,7 +10616,7 @@ declare module 'vscode' { * @param destination Location to save to. * @param cancellation Token that signals the save is no longer required. * - * @returns Thenable signaling that saving has completed. + * @returns A {@linkcode Thenable} signaling that saving has completed. */ saveCustomDocumentAs(document: T, destination: Uri, cancellation: CancellationToken): Thenable; @@ -10612,30 +10626,30 @@ declare module 'vscode' { * This method is invoked by the editor when the user triggers `File: Revert File` in a custom editor. (Note that * this is only used using the editor's `File: Revert File` command and not on a `git revert` of the file). * - * To implement `revert`, the implementer must make sure all editor instances (webviews) for `document` + * The implementer must make sure all editor instances (webviews) for {@linkcode document} * are displaying the document in the same state is saved in. This usually means reloading the file from the * workspace. * * @param document Document to revert. * @param cancellation Token that signals the revert is no longer required. * - * @returns Thenable signaling that the change has completed. + * @returns A {@linkcode Thenable} signaling that the revert has completed. */ revertCustomDocument(document: T, cancellation: CancellationToken): Thenable; /** * Back up a dirty custom document. * - * Backups are used for hot exit and to prevent data loss. Your `backup` method should persist the resource in + * Backups are used for hot exit and to prevent data loss. Your {@linkcode backupCustomDocument} method should persist the resource in * its current state, i.e. with the edits applied. Most commonly this means saving the resource to disk in * the `ExtensionContext.storagePath`. When the editor reloads and your custom editor is opened for a resource, * your extension should first check to see if any backups exist for the resource. If there is a backup, your * extension should load the file contents from there instead of from the resource in the workspace. * - * `backup` is triggered approximately one second after the user stops editing the document. If the user - * rapidly edits the document, `backup` will not be invoked until the editing stops. + * {@linkcode backupCustomDocument} is triggered approximately one second after the user stops editing the document. If the user + * rapidly edits the document, {@linkcode backupCustomDocument} will not be invoked until the editing stops. * - * `backup` is not invoked when `auto save` is enabled (since auto save already persists the resource). + * {@linkcode backupCustomDocument} is not invoked when `auto save` is enabled (since auto save already persists the resource). * * @param document Document to backup. * @param context Information that can be used to backup the document. @@ -10643,6 +10657,8 @@ declare module 'vscode' { * extension to decided how to respond to cancellation. If for example your extension is backing up a large file * in an operation that takes time to complete, your extension may decide to finish the ongoing backup rather * than cancelling it to ensure that the editor has some valid backup. + * + * @returns A {@linkcode Thenable} signaling that the backup has completed. */ backupCustomDocument(document: T, context: CustomDocumentBackupContext, cancellation: CancellationToken): Thenable; } diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index 37d7024f..00000000 --- a/webpack.config.js +++ /dev/null @@ -1,48 +0,0 @@ -//@ts-check - -'use strict'; - -const path = require('path'); - -//@ts-check -/** @typedef {import('webpack').Configuration} WebpackConfig **/ - -/** @type WebpackConfig */ -const extensionConfig = { - target: 'node', // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ - mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') - - entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ - output: { - // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ - path: path.resolve(__dirname, 'dist'), - filename: 'extension.js', - libraryTarget: 'commonjs2' - }, - externals: { - vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ - // modules added here also need to be added in the .vscodeignore file - }, - resolve: { - // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader - extensions: ['.ts', '.js'] - }, - module: { - rules: [ - { - test: /\.ts$/, - exclude: /node_modules/, - use: [ - { - loader: 'ts-loader' - } - ] - } - ] - }, - devtool: 'nosources-source-map', - infrastructureLogging: { - level: "log", // enables logging required for problem matchers - }, -}; -module.exports = [ extensionConfig ]; \ No newline at end of file