diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..86f9446b --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,45 @@ +name: Test + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [22.x] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: "yarn" + cache-dependency-path: "src/extension/yarn.lock" + + - name: Install just + run: | + wget -qO - 'https://proget.makedeb.org/debian-feeds/prebuilt-mpr.pub' | gpg --dearmor | sudo tee /usr/share/keyrings/prebuilt-mpr-archive-keyring.gpg 1> /dev/null + echo "deb [signed-by=/usr/share/keyrings/prebuilt-mpr-archive-keyring.gpg] https://proget.makedeb.org prebuilt-mpr $(lsb_release -cs)" | sudo tee /etc/apt/sources.list.d/prebuilt-mpr.list + sudo apt update + sudo apt install -y just + + - name: Install dependencies + run: just deps + + - name: Run tests with coverage + run: just test coverage + + - name: Upload coverage reports + uses: codecov/codecov-action@v3 + with: + directory: ./src/coverage/ + fail_ci_if_error: false diff --git a/justfile b/justfile index 79043fe0..f4b4c9a9 100644 --- a/justfile +++ b/justfile @@ -47,3 +47,14 @@ publish target="both": run-view: cd "{{ web_view_dir }}" && yarn dev + +test mode="": + #!/usr/bin/env bash + cd "{{ extension_dir }}" + if [ "{{ mode }}" = "watch" ]; then + yarn test:watch + elif [ "{{ mode }}" = "coverage" ]; then + yarn test --coverage + else + yarn test + fi diff --git a/src/extension/__mocks__/vscode.js b/src/extension/__mocks__/vscode.js new file mode 100644 index 00000000..a96535a5 --- /dev/null +++ b/src/extension/__mocks__/vscode.js @@ -0,0 +1,39 @@ +// Minimal VS Code mock for Jest testing +module.exports = { + TreeItem: class { + constructor(label, collapsibleState) { + this.label = label; + this.collapsibleState = collapsibleState; + } + }, + TreeItemCollapsibleState: { + None: 0, + Collapsed: 1, + Expanded: 2, + }, + ThemeIcon: class { + constructor(id) { + this.id = id; + } + }, + Uri: { + file: jest.fn(), + }, + window: { + showErrorMessage: jest.fn(), + showInformationMessage: jest.fn(), + createTreeView: jest.fn(), + }, + commands: { + registerCommand: jest.fn(), + }, + workspace: { + getConfiguration: jest.fn(), + onDidChangeConfiguration: jest.fn(), + }, + ConfigurationTarget: { + Global: 1, + Workspace: 2, + WorkspaceFolder: 3, + }, +}; diff --git a/src/extension/jest.config.js b/src/extension/jest.config.js new file mode 100644 index 00000000..92378cfc --- /dev/null +++ b/src/extension/jest.config.js @@ -0,0 +1,20 @@ +/** @type {import('jest').Config} */ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + roots: ["/src"], + testMatch: ["**/*.test.ts"], + transform: { + "^.+\\.ts$": "ts-jest", + }, + collectCoverageFrom: ["src/**/*.ts", "!src/**/*.d.ts", "!src/**/*.test.ts"], + coverageDirectory: "coverage", + coverageReporters: ["text", "lcov", "html"], + moduleFileExtensions: ["ts", "js", "json"], + verbose: true, + clearMocks: true, + restoreMocks: true, + moduleNameMapper: { + "^vscode$": "/__mocks__/vscode.js", + }, +}; diff --git a/src/extension/package.json b/src/extension/package.json index 8c3c47ec..632b84f7 100644 --- a/src/extension/package.json +++ b/src/extension/package.json @@ -220,13 +220,21 @@ "package": "vsce package --out versions/", "install-package": "code --install-extension versions/quick-command-buttons-$npm_package_version.vsix", "vsce-publish": "vsce publish", - "ovsx-publish": "ovsx publish" + "ovsx-publish": "ovsx publish", + "test": "jest", + "test:watch": "jest --watch", + "test:coverage": "jest --coverage", + "test:ci": "jest --ci --coverage --watchAll=false" }, "devDependencies": { + "@jest/globals": "^30.1.2", + "@types/jest": "^30.0.0", "@types/node": "24.3.0", "@types/vscode": "^1.90.0", - "typescript": "5.9.2", - "@vscode/vsce": "3.0.0" + "@vscode/vsce": "3.0.0", + "jest": "^30.1.3", + "ts-jest": "^29.4.1", + "typescript": "5.9.2" }, "dependencies": {} } diff --git a/src/extension/src/adapters.test.ts b/src/extension/src/adapters.test.ts new file mode 100644 index 00000000..ef08202d --- /dev/null +++ b/src/extension/src/adapters.test.ts @@ -0,0 +1,52 @@ +import * as vscode from "vscode"; +import { createVSCodeConfigReader } from "./adapters"; + +describe("adapters", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe("getButtonsFromConfig", () => { + it("should return buttons from config", () => { + const mockButtons = [ + { name: "Test Button", command: "test command" }, + { name: "Another Button", command: "another command" }, + ]; + + const mockConfig = { + get: jest.fn((key: string) => + key === "buttons" ? mockButtons : undefined + ), + }; + + (vscode.workspace.getConfiguration as jest.Mock).mockReturnValue( + mockConfig + ); + + const configReader = createVSCodeConfigReader(); + const result = configReader.getButtons(); + + expect(result).toEqual(mockButtons); + expect(vscode.workspace.getConfiguration).toHaveBeenCalledWith( + "quickCommandButtons" + ); + expect(mockConfig.get).toHaveBeenCalledWith("buttons"); + }); + + it("should return empty array when no buttons in config", () => { + const mockConfig = { + get: jest.fn(() => undefined), + }; + + (vscode.workspace.getConfiguration as jest.Mock).mockReturnValue( + mockConfig + ); + + const configReader = createVSCodeConfigReader(); + const result = configReader.getButtons(); + + expect(result).toEqual([]); + expect(mockConfig.get).toHaveBeenCalledWith("buttons"); + }); + }); +}); diff --git a/src/extension/src/adapters.ts b/src/extension/src/adapters.ts index 4798ec88..120d2deb 100644 --- a/src/extension/src/adapters.ts +++ b/src/extension/src/adapters.ts @@ -1,6 +1,13 @@ import * as vscode from "vscode"; import { ButtonConfig, RefreshButtonConfig } from "./types"; +const CONFIG_SECTION = "quickCommandButtons"; +const DEFAULT_REFRESH_CONFIG: RefreshButtonConfig = { + icon: "$(refresh)", + color: "#00BCD4", + enabled: true, +}; + export type TerminalExecutor = ( command: string, useVsCodeApi?: boolean, @@ -22,21 +29,30 @@ export type QuickPickCreator = < T extends vscode.QuickPickItem >() => vscode.QuickPick; +const getButtonsFromConfig = ( + config: vscode.WorkspaceConfiguration +): ButtonConfig[] => config.get("buttons") || []; + +const getRefreshConfigFromConfig = ( + config: vscode.WorkspaceConfiguration +): RefreshButtonConfig => config.get("refreshButton") || DEFAULT_REFRESH_CONFIG; + +const isQuickCommandButtonsConfigChange = ( + event: vscode.ConfigurationChangeEvent +): boolean => event.affectsConfiguration(CONFIG_SECTION); + export const createVSCodeConfigReader = (): ConfigReader => ({ - getButtons: () => - vscode.workspace.getConfiguration("quickCommandButtons").get("buttons") || - [], - getRefreshConfig: () => - vscode.workspace - .getConfiguration("quickCommandButtons") - .get("refreshButton") || { - icon: "$(refresh)", - color: "#00BCD4", - enabled: true, - }, + getButtons: () => { + const config = vscode.workspace.getConfiguration(CONFIG_SECTION); + return getButtonsFromConfig(config); + }, + getRefreshConfig: () => { + const config = vscode.workspace.getConfiguration(CONFIG_SECTION); + return getRefreshConfigFromConfig(config); + }, onConfigChange: (listener: () => void) => vscode.workspace.onDidChangeConfiguration((event) => { - if (!event.affectsConfiguration("quickCommandButtons")) return; + if (!isQuickCommandButtonsConfigChange(event)) return; listener(); }), }); diff --git a/src/extension/src/command-executor.test.ts b/src/extension/src/command-executor.test.ts new file mode 100644 index 00000000..39ae3bb7 --- /dev/null +++ b/src/extension/src/command-executor.test.ts @@ -0,0 +1,847 @@ +import { + validateShortcuts, + findShortcutItem, + determineButtonExecutionType, + createQuickPickItems, + executeTerminalCommand, + executeCommandsRecursively, +} from "./command-executor"; +import { ButtonConfig } from "./types"; + +describe("command-executor", () => { + describe("validateShortcuts", () => { + it("should return empty array for unique shortcuts", () => { + const items = [ + { + command: { name: "test1", shortcut: "a" } as ButtonConfig, + description: "", + label: "Test 1", + }, + { + command: { name: "test2", shortcut: "b" } as ButtonConfig, + description: "", + label: "Test 2", + }, + ]; + + const result = validateShortcuts(items); + + expect(result).toEqual([]); + }); + + it("should return duplicated shortcuts (case insensitive)", () => { + const items = [ + { + command: { name: "test1", shortcut: "a" } as ButtonConfig, + description: "", + label: "Test 1", + }, + { + command: { name: "test2", shortcut: "A" } as ButtonConfig, + description: "", + label: "Test 2", + }, + { + command: { name: "test3", shortcut: "b" } as ButtonConfig, + description: "", + label: "Test 3", + }, + ]; + + const result = validateShortcuts(items); + + expect(result).toEqual(["a"]); + }); + + it("should return multiple duplicated shortcuts", () => { + const items = [ + { + command: { name: "test1", shortcut: "a" } as ButtonConfig, + description: "", + label: "Test 1", + }, + { + command: { name: "test2", shortcut: "A" } as ButtonConfig, + description: "", + label: "Test 2", + }, + { + command: { name: "test3", shortcut: "b" } as ButtonConfig, + description: "", + label: "Test 3", + }, + { + command: { name: "test4", shortcut: "B" } as ButtonConfig, + description: "", + label: "Test 4", + }, + ]; + + const result = validateShortcuts(items); + + expect(result).toEqual(["a", "b"]); + }); + + it("should handle items without shortcuts", () => { + const items = [ + { + command: { name: "test1" } as ButtonConfig, + description: "", + label: "Test 1", + }, + { + command: { name: "test2", shortcut: "a" } as ButtonConfig, + description: "", + label: "Test 2", + }, + ]; + + const result = validateShortcuts(items); + + expect(result).toEqual([]); + }); + + it("should handle empty array", () => { + const items: Array<{ + command: ButtonConfig; + description: string; + label: string; + }> = []; + + const result = validateShortcuts(items); + + expect(result).toEqual([]); + }); + + it("should handle all items without shortcuts", () => { + const items = [ + { + command: { name: "test1" } as ButtonConfig, + description: "", + label: "Test 1", + }, + { + command: { name: "test2" } as ButtonConfig, + description: "", + label: "Test 2", + }, + ]; + + const result = validateShortcuts(items); + + expect(result).toEqual([]); + }); + }); + + describe("findShortcutItem", () => { + const items = [ + { + command: { name: "test1", shortcut: "a" } as ButtonConfig, + description: "", + label: "Test 1", + }, + { + command: { name: "test2", shortcut: "B" } as ButtonConfig, + description: "", + label: "Test 2", + }, + { + command: { name: "test3" } as ButtonConfig, + description: "", + label: "Test 3", + }, + ]; + + it("should find item with matching shortcut (case insensitive)", () => { + const result = findShortcutItem(items, "a"); + + expect(result).toEqual(items[0]); + }); + + it("should find item with uppercase shortcut using lowercase input", () => { + const result = findShortcutItem(items, "b"); + + expect(result).toEqual(items[1]); + }); + + it("should find item with lowercase shortcut using uppercase input", () => { + const result = findShortcutItem(items, "A"); + + expect(result).toEqual(items[0]); + }); + + it("should return undefined for non-existent shortcut", () => { + const result = findShortcutItem(items, "z"); + + expect(result).toBeUndefined(); + }); + + it("should return undefined for multi-character input", () => { + const result = findShortcutItem(items, "ab"); + + expect(result).toBeUndefined(); + }); + + it("should return undefined for empty input", () => { + const result = findShortcutItem(items, ""); + + expect(result).toBeUndefined(); + }); + + it("should return undefined when no items have shortcuts", () => { + const itemsWithoutShortcuts = [ + { + command: { name: "test1" } as ButtonConfig, + description: "", + label: "Test 1", + }, + ]; + + const result = findShortcutItem(itemsWithoutShortcuts, "a"); + + expect(result).toBeUndefined(); + }); + + it("should return undefined for empty items array", () => { + const result = findShortcutItem([], "a"); + + expect(result).toBeUndefined(); + }); + }); + + describe("determineButtonExecutionType", () => { + it("should return 'executeAll' for button with group and executeAll flag", () => { + const button: ButtonConfig = { + name: "test", + group: [{ name: "child", command: "echo test" }], + executeAll: true, + }; + + const result = determineButtonExecutionType(button); + + expect(result).toBe("executeAll"); + }); + + it("should return 'showQuickPick' for button with group but no executeAll flag", () => { + const button: ButtonConfig = { + name: "test", + group: [{ name: "child", command: "echo test" }], + }; + + const result = determineButtonExecutionType(button); + + expect(result).toBe("showQuickPick"); + }); + + it("should return 'showQuickPick' for button with group and executeAll set to false", () => { + const button: ButtonConfig = { + name: "test", + group: [{ name: "child", command: "echo test" }], + executeAll: false, + }; + + const result = determineButtonExecutionType(button); + + expect(result).toBe("showQuickPick"); + }); + + it("should return 'executeCommand' for button with command but no group", () => { + const button: ButtonConfig = { + name: "test", + command: "echo test", + }; + + const result = determineButtonExecutionType(button); + + expect(result).toBe("executeCommand"); + }); + + it("should return 'invalid' for button without command and without group", () => { + const button: ButtonConfig = { + name: "test", + }; + + const result = determineButtonExecutionType(button); + + expect(result).toBe("invalid"); + }); + + it("should return 'invalid' for button with empty command string", () => { + const button: ButtonConfig = { + name: "test", + command: "", + }; + + const result = determineButtonExecutionType(button); + + expect(result).toBe("invalid"); + }); + + it("should return 'executeCommand' for button with both command and group (group takes precedence when executeAll is false)", () => { + const button: ButtonConfig = { + name: "test", + command: "echo test", + group: [{ name: "child", command: "echo child" }], + executeAll: false, + }; + + const result = determineButtonExecutionType(button); + + expect(result).toBe("showQuickPick"); + }); + + it("should return 'executeAll' for button with both command and group when executeAll is true", () => { + const button: ButtonConfig = { + name: "test", + command: "echo test", + group: [{ name: "child", command: "echo child" }], + executeAll: true, + }; + + const result = determineButtonExecutionType(button); + + expect(result).toBe("executeAll"); + }); + }); + + describe("createQuickPickItems", () => { + it("should create QuickPickItem with shortcut in label", () => { + const commands: ButtonConfig[] = [ + { + name: "Test Command", + command: "echo test", + shortcut: "t", + }, + ]; + + const result = createQuickPickItems(commands); + + expect(result).toEqual([ + { + label: "Test Command (t)", + description: "echo test", + command: commands[0], + }, + ]); + }); + + it("should create QuickPickItem without shortcut in label", () => { + const commands: ButtonConfig[] = [ + { + name: "Test Command", + command: "echo test", + }, + ]; + + const result = createQuickPickItems(commands); + + expect(result).toEqual([ + { + label: "Test Command", + description: "echo test", + command: commands[0], + }, + ]); + }); + + it("should handle empty command string", () => { + const commands: ButtonConfig[] = [ + { + name: "Test Command", + command: "", + shortcut: "t", + }, + ]; + + const result = createQuickPickItems(commands); + + expect(result).toEqual([ + { + label: "Test Command (t)", + description: "", + command: commands[0], + }, + ]); + }); + + it("should handle command without command property", () => { + const commands: ButtonConfig[] = [ + { + name: "Test Command", + shortcut: "t", + }, + ]; + + const result = createQuickPickItems(commands); + + expect(result).toEqual([ + { + label: "Test Command (t)", + description: "", + command: commands[0], + }, + ]); + }); + + it("should handle multiple commands with mixed configurations", () => { + const commands: ButtonConfig[] = [ + { + name: "Command 1", + command: "echo 1", + shortcut: "1", + }, + { + name: "Command 2", + command: "echo 2", + }, + { + name: "Command 3", + shortcut: "3", + }, + ]; + + const result = createQuickPickItems(commands); + + expect(result).toEqual([ + { + label: "Command 1 (1)", + description: "echo 1", + command: commands[0], + }, + { + label: "Command 2", + description: "echo 2", + command: commands[1], + }, + { + label: "Command 3 (3)", + description: "", + command: commands[2], + }, + ]); + }); + + it("should handle empty commands array", () => { + const commands: ButtonConfig[] = []; + + const result = createQuickPickItems(commands); + + expect(result).toEqual([]); + }); + + it("should preserve original command object reference", () => { + const commands: ButtonConfig[] = [ + { + name: "Test Command", + command: "echo test", + additionalProperty: "custom", + } as ButtonConfig & { additionalProperty: string }, + ]; + + const result = createQuickPickItems(commands); + + expect(result[0].command).toBe(commands[0]); + }); + }); + + describe("executeTerminalCommand", () => { + it("should call terminalExecutor with command and default parameters", () => { + const mockTerminalExecutor = jest.fn(); + const button: ButtonConfig = { + name: "Test Button", + command: "echo test", + }; + + executeTerminalCommand(button, mockTerminalExecutor); + + expect(mockTerminalExecutor).toHaveBeenCalledWith( + "echo test", + false, + undefined + ); + }); + + it("should call terminalExecutor with useVsCodeApi true", () => { + const mockTerminalExecutor = jest.fn(); + const button: ButtonConfig = { + name: "Test Button", + command: "echo test", + useVsCodeApi: true, + }; + + executeTerminalCommand(button, mockTerminalExecutor); + + expect(mockTerminalExecutor).toHaveBeenCalledWith( + "echo test", + true, + undefined + ); + }); + + it("should call terminalExecutor with custom terminal name", () => { + const mockTerminalExecutor = jest.fn(); + const button: ButtonConfig = { + name: "Test Button", + command: "echo test", + terminalName: "Custom Terminal", + }; + + executeTerminalCommand(button, mockTerminalExecutor); + + expect(mockTerminalExecutor).toHaveBeenCalledWith( + "echo test", + false, + "Custom Terminal" + ); + }); + + it("should call terminalExecutor with all parameters", () => { + const mockTerminalExecutor = jest.fn(); + const button: ButtonConfig = { + name: "Test Button", + command: "echo test", + useVsCodeApi: true, + terminalName: "Custom Terminal", + }; + + executeTerminalCommand(button, mockTerminalExecutor); + + expect(mockTerminalExecutor).toHaveBeenCalledWith( + "echo test", + true, + "Custom Terminal" + ); + }); + + it("should not call terminalExecutor when command is undefined", () => { + const mockTerminalExecutor = jest.fn(); + const button: ButtonConfig = { + name: "Test Button", + }; + + executeTerminalCommand(button, mockTerminalExecutor); + + expect(mockTerminalExecutor).not.toHaveBeenCalled(); + }); + + it("should not call terminalExecutor when command is empty string", () => { + const mockTerminalExecutor = jest.fn(); + const button: ButtonConfig = { + name: "Test Button", + command: "", + }; + + executeTerminalCommand(button, mockTerminalExecutor); + + expect(mockTerminalExecutor).not.toHaveBeenCalled(); + }); + }); + + describe("executeCommandsRecursively", () => { + it("should execute terminal commands for buttons without groups", () => { + const mockTerminalExecutor = jest.fn(); + const commands: ButtonConfig[] = [ + { + name: "Command 1", + command: "echo test1", + }, + { + name: "Command 2", + command: "echo test2", + useVsCodeApi: true, + }, + { + name: "Command 3", + command: "echo test3", + terminalName: "Custom Terminal", + }, + ]; + + executeCommandsRecursively(commands, mockTerminalExecutor); + + expect(mockTerminalExecutor).toHaveBeenCalledTimes(3); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 1, + "echo test1", + false, + undefined + ); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 2, + "echo test2", + true, + undefined + ); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 3, + "echo test3", + false, + "Custom Terminal" + ); + }); + + it("should recursively execute commands for buttons with groups and executeAll flag", () => { + const mockTerminalExecutor = jest.fn(); + const commands: ButtonConfig[] = [ + { + name: "Group Command", + group: [ + { + name: "Child 1", + command: "echo child1", + }, + { + name: "Child 2", + command: "echo child2", + useVsCodeApi: true, + }, + ], + executeAll: true, + }, + ]; + + executeCommandsRecursively(commands, mockTerminalExecutor); + + expect(mockTerminalExecutor).toHaveBeenCalledTimes(2); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 1, + "echo child1", + false, + undefined + ); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 2, + "echo child2", + true, + undefined + ); + }); + + it("should not execute commands for buttons with groups but no executeAll flag", () => { + const mockTerminalExecutor = jest.fn(); + const commands: ButtonConfig[] = [ + { + name: "Group Command", + group: [ + { + name: "Child 1", + command: "echo child1", + }, + ], + executeAll: false, + }, + ]; + + executeCommandsRecursively(commands, mockTerminalExecutor); + + expect(mockTerminalExecutor).not.toHaveBeenCalled(); + }); + + it("should handle nested groups with executeAll flags", () => { + const mockTerminalExecutor = jest.fn(); + const commands: ButtonConfig[] = [ + { + name: "Level 1 Group", + group: [ + { + name: "Level 2 Group", + group: [ + { + name: "Level 3 Command", + command: "echo level3", + }, + ], + executeAll: true, + }, + { + name: "Level 2 Command", + command: "echo level2", + }, + ], + executeAll: true, + }, + ]; + + executeCommandsRecursively(commands, mockTerminalExecutor); + + expect(mockTerminalExecutor).toHaveBeenCalledTimes(2); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 1, + "echo level3", + false, + undefined + ); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 2, + "echo level2", + false, + undefined + ); + }); + + it("should skip buttons without commands and without groups", () => { + const mockTerminalExecutor = jest.fn(); + const commands: ButtonConfig[] = [ + { + name: "Valid Command", + command: "echo valid", + }, + { + name: "Invalid Command", + }, + ]; + + executeCommandsRecursively(commands, mockTerminalExecutor); + + expect(mockTerminalExecutor).toHaveBeenCalledTimes(1); + expect(mockTerminalExecutor).toHaveBeenCalledWith( + "echo valid", + false, + undefined + ); + }); + + it("should skip buttons with empty command strings", () => { + const mockTerminalExecutor = jest.fn(); + const commands: ButtonConfig[] = [ + { + name: "Valid Command", + command: "echo valid", + }, + { + name: "Empty Command", + command: "", + }, + ]; + + executeCommandsRecursively(commands, mockTerminalExecutor); + + expect(mockTerminalExecutor).toHaveBeenCalledTimes(1); + expect(mockTerminalExecutor).toHaveBeenCalledWith( + "echo valid", + false, + undefined + ); + }); + + it("should handle empty commands array", () => { + const mockTerminalExecutor = jest.fn(); + const commands: ButtonConfig[] = []; + + executeCommandsRecursively(commands, mockTerminalExecutor); + + expect(mockTerminalExecutor).not.toHaveBeenCalled(); + }); + + it("should handle mixed command types in single array", () => { + const mockTerminalExecutor = jest.fn(); + const commands: ButtonConfig[] = [ + { + name: "Regular Command", + command: "echo regular", + }, + { + name: "Group with executeAll", + group: [ + { + name: "Child Command", + command: "echo child", + }, + ], + executeAll: true, + }, + { + name: "Group without executeAll", + group: [ + { + name: "Ignored Child", + command: "echo ignored", + }, + ], + executeAll: false, + }, + { + name: "Invalid Command", + }, + ]; + + executeCommandsRecursively(commands, mockTerminalExecutor); + + expect(mockTerminalExecutor).toHaveBeenCalledTimes(2); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 1, + "echo regular", + false, + undefined + ); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 2, + "echo child", + false, + undefined + ); + }); + + it("should handle complex nested structure with mixed executeAll flags", () => { + const mockTerminalExecutor = jest.fn(); + const commands: ButtonConfig[] = [ + { + name: "Root Group", + group: [ + { + name: "Branch 1", + group: [ + { + name: "Leaf 1", + command: "echo leaf1", + }, + { + name: "Leaf 2", + command: "echo leaf2", + }, + ], + executeAll: true, + }, + { + name: "Branch 2", + group: [ + { + name: "Ignored Leaf", + command: "echo ignored", + }, + ], + executeAll: false, + }, + { + name: "Direct Command", + command: "echo direct", + }, + ], + executeAll: true, + }, + ]; + + executeCommandsRecursively(commands, mockTerminalExecutor); + + expect(mockTerminalExecutor).toHaveBeenCalledTimes(3); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 1, + "echo leaf1", + false, + undefined + ); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 2, + "echo leaf2", + false, + undefined + ); + expect(mockTerminalExecutor).toHaveBeenNthCalledWith( + 3, + "echo direct", + false, + undefined + ); + }); + }); +}); diff --git a/src/extension/src/command-executor.ts b/src/extension/src/command-executor.ts index 156772e0..f3b4814a 100644 --- a/src/extension/src/command-executor.ts +++ b/src/extension/src/command-executor.ts @@ -14,12 +14,8 @@ export type QuickPickConfig = { items: QuickPickItem[]; }; -export const createQuickPickWithShortcuts = ( - config: QuickPickConfig, - terminalExecutor: TerminalExecutor, - quickPickCreator: QuickPickCreator -) => { - const shortcuts = config.items +export const validateShortcuts = (items: QuickPickItem[]): string[] => { + const shortcuts = items .filter((item) => item.command.shortcut) .map((item) => item.command.shortcut!.toLowerCase()); @@ -27,10 +23,63 @@ export const createQuickPickWithShortcuts = ( (shortcut, index) => shortcuts.indexOf(shortcut) !== index ); + return [...new Set(duplicates)]; +}; + +export const findShortcutItem = ( + items: QuickPickItem[], + inputValue: string +): QuickPickItem | undefined => { + if (inputValue.length !== 1) return undefined; + + return items.find( + (item) => item.command.shortcut?.toLowerCase() === inputValue.toLowerCase() + ); +}; + +export const createQuickPickCommandExecutor = ( + terminalExecutor: TerminalExecutor, + quickPickCreator: QuickPickCreator, + quickPick: vscode.QuickPick +) => { + let commandExecuted = false; + + return (item: QuickPickItem) => { + if (commandExecuted) return; + commandExecuted = true; + + quickPick.dispose(); + executeButtonCommand(item.command, terminalExecutor, quickPickCreator); + }; +}; + +export const determineButtonExecutionType = ( + button: ButtonConfig +): "executeAll" | "showQuickPick" | "executeCommand" | "invalid" => { + if (button.group) { + if (button.executeAll) { + return "executeAll"; + } + return "showQuickPick"; + } + + if (!button.command || button.command.trim() === "") { + return "invalid"; + } + + return "executeCommand"; +}; + +export const createQuickPickWithShortcuts = ( + config: QuickPickConfig, + terminalExecutor: TerminalExecutor, + quickPickCreator: QuickPickCreator +) => { + const duplicates = validateShortcuts(config.items); + if (duplicates.length > 0) { - const uniqueDuplicates = [...new Set(duplicates)]; vscode.window.showErrorMessage( - `Duplicate shortcuts detected: ${uniqueDuplicates.join( + `Duplicate shortcuts detected: ${duplicates.join( ", " )}. Please ensure each shortcut is unique.` ); @@ -42,15 +91,11 @@ export const createQuickPickWithShortcuts = ( quickPick.title = config.title; quickPick.placeholder = config.placeholder; - let commandExecuted = false; - - const executeCommand = (item: QuickPickItem) => { - if (commandExecuted) return; - commandExecuted = true; - - quickPick.dispose(); - executeButtonCommand(item.command, terminalExecutor, quickPickCreator); - }; + const executeCommand = createQuickPickCommandExecutor( + terminalExecutor, + quickPickCreator, + quickPick + ); quickPick.onDidAccept(() => { const selected = quickPick.selectedItems[0]; @@ -59,11 +104,7 @@ export const createQuickPickWithShortcuts = ( }); quickPick.onDidChangeValue((value) => { - if (value.length !== 1) return; - - const shortcutItem = config.items.find( - (item) => item.command.shortcut?.toLowerCase() === value.toLowerCase() - ); + const shortcutItem = findShortcutItem(config.items, value); if (!shortcutItem) return; executeCommand(shortcutItem); @@ -72,23 +113,20 @@ export const createQuickPickWithShortcuts = ( quickPick.show(); }; -export const executeButtonCommand = ( +export const createQuickPickItems = ( + commands: ButtonConfig[] +): QuickPickItem[] => { + return commands.map((cmd) => ({ + label: cmd.shortcut ? `${cmd.name} (${cmd.shortcut})` : cmd.name, + description: cmd.command || "", + command: cmd, + })); +}; + +export const executeTerminalCommand = ( button: ButtonConfig, - terminalExecutor: TerminalExecutor, - quickPickCreator?: QuickPickCreator + terminalExecutor: TerminalExecutor ) => { - if (button.group) { - if (button.executeAll) { - executeAllCommands(button, terminalExecutor); - return; - } - - if (quickPickCreator) { - showGroupQuickPick(button, terminalExecutor, quickPickCreator); - return; - } - } - if (!button.command) return; terminalExecutor( @@ -98,6 +136,33 @@ export const executeButtonCommand = ( ); }; +export const executeButtonCommand = ( + button: ButtonConfig, + terminalExecutor: TerminalExecutor, + quickPickCreator?: QuickPickCreator +) => { + const executionType = determineButtonExecutionType(button); + + switch (executionType) { + case "executeAll": + executeAllCommands(button, terminalExecutor); + break; + + case "showQuickPick": + if (quickPickCreator) { + showGroupQuickPick(button, terminalExecutor, quickPickCreator); + } + break; + + case "executeCommand": + executeTerminalCommand(button, terminalExecutor); + break; + + case "invalid": + return; + } +}; + const showGroupQuickPick = ( button: ButtonConfig, terminalExecutor: TerminalExecutor, @@ -105,11 +170,7 @@ const showGroupQuickPick = ( ) => { if (!button.group) return; - const items: QuickPickItem[] = button.group.map((cmd) => ({ - label: cmd.shortcut ? `${cmd.name} (${cmd.shortcut})` : cmd.name, - description: cmd.command || "", - command: cmd, - })); + const items = createQuickPickItems(button.group); createQuickPickWithShortcuts( { @@ -122,15 +183,13 @@ const showGroupQuickPick = ( ); }; -const executeAllCommands = ( - button: ButtonConfig, +export const executeCommandsRecursively = ( + commands: ButtonConfig[], terminalExecutor: TerminalExecutor -) => { - if (!button.group) return; - - button.group.forEach((cmd) => { +): void => { + commands.forEach((cmd) => { if (cmd.group && cmd.executeAll) { - executeAllCommands(cmd, terminalExecutor); + executeCommandsRecursively(cmd.group, terminalExecutor); } else if (cmd.command) { terminalExecutor( cmd.command, @@ -140,3 +199,12 @@ const executeAllCommands = ( } }); }; + +const executeAllCommands = ( + button: ButtonConfig, + terminalExecutor: TerminalExecutor +) => { + if (!button.group) return; + + executeCommandsRecursively(button.group, terminalExecutor); +}; diff --git a/src/extension/src/command-tree-provider.test.ts b/src/extension/src/command-tree-provider.test.ts new file mode 100644 index 00000000..332f26fa --- /dev/null +++ b/src/extension/src/command-tree-provider.test.ts @@ -0,0 +1,232 @@ +import { ButtonConfig } from "./types"; +import { + createTreeItemsFromGroup, + createRootTreeItems, + CommandTreeItem, + GroupTreeItem, +} from "./command-tree-provider"; + +describe("command-tree-provider", () => { + describe("createTreeItemsFromGroup", () => { + it("should create command tree items from simple commands", () => { + const commands: ButtonConfig[] = [ + { name: "Test Command 1", command: "echo hello" }, + { name: "Test Command 2", command: "ls -la" }, + ]; + + const result = createTreeItemsFromGroup(commands); + + expect(result).toHaveLength(2); + expect(result[0]).toBeInstanceOf(CommandTreeItem); + expect(result[0].label).toBe("Test Command 1"); + expect(result[0].commandString).toBe("echo hello"); + expect(result[0].useVsCodeApi).toBe(false); + expect(result[0].terminalName).toBeUndefined(); + + expect(result[1]).toBeInstanceOf(CommandTreeItem); + expect(result[1].label).toBe("Test Command 2"); + expect(result[1].commandString).toBe("ls -la"); + expect(result[1].useVsCodeApi).toBe(false); + expect(result[1].terminalName).toBeUndefined(); + }); + + it("should create command tree items with VS Code API and terminal name", () => { + const commands: ButtonConfig[] = [ + { + name: "VS Code Command", + command: "workbench.action.openSettings", + useVsCodeApi: true, + terminalName: "settings-terminal", + }, + ]; + + const result = createTreeItemsFromGroup(commands); + + expect(result).toHaveLength(1); + expect(result[0].label).toBe("VS Code Command"); + expect(result[0].commandString).toBe("workbench.action.openSettings"); + expect(result[0].useVsCodeApi).toBe(true); + expect(result[0].terminalName).toBe("settings-terminal"); + }); + + it("should handle commands with empty command string", () => { + const commands: ButtonConfig[] = [ + { name: "Empty Command", command: "" }, + { name: "No Command Property" } as ButtonConfig, + ]; + + const result = createTreeItemsFromGroup(commands); + + expect(result).toHaveLength(2); + expect(result[0].commandString).toBe(""); + expect(result[1].commandString).toBe(""); + }); + + it("should handle empty commands array", () => { + const commands: ButtonConfig[] = []; + + const result = createTreeItemsFromGroup(commands); + + expect(result).toHaveLength(0); + expect(result).toEqual([]); + }); + + it("should preserve original command objects without modification", () => { + const commands: ButtonConfig[] = [ + { + name: "Original Command", + command: "test command", + useVsCodeApi: true, + terminalName: "test-terminal", + color: "red", + }, + ]; + const originalCommands = JSON.parse(JSON.stringify(commands)); + + createTreeItemsFromGroup(commands); + + expect(commands).toEqual(originalCommands); + }); + + it("should handle mixed command configurations", () => { + const commands: ButtonConfig[] = [ + { name: "Simple", command: "echo simple" }, + { + name: "Complex", + command: "npm test", + useVsCodeApi: false, + terminalName: "test-terminal", + }, + { + name: "VS Code", + command: "workbench.action.reload", + useVsCodeApi: true, + }, + ]; + + const result = createTreeItemsFromGroup(commands); + + expect(result).toHaveLength(3); + expect(result[0].useVsCodeApi).toBe(false); + expect(result[0].terminalName).toBeUndefined(); + expect(result[1].useVsCodeApi).toBe(false); + expect(result[1].terminalName).toBe("test-terminal"); + expect(result[2].useVsCodeApi).toBe(true); + expect(result[2].terminalName).toBeUndefined(); + }); + }); + + describe("createRootTreeItems", () => { + it("should create mixed command and group tree items", () => { + const buttons: ButtonConfig[] = [ + { name: "Simple Command", command: "echo hello" }, + { + name: "Command Group", + group: [ + { name: "Group Command 1", command: "ls" }, + { name: "Group Command 2", command: "pwd" }, + ], + }, + { + name: "VS Code Command", + command: "workbench.action.reload", + useVsCodeApi: true, + }, + ]; + + const result = createRootTreeItems(buttons); + + expect(result).toHaveLength(3); + expect(result[0]).toBeInstanceOf(CommandTreeItem); + expect(result[0].label).toBe("Simple Command"); + expect((result[0] as CommandTreeItem).commandString).toBe("echo hello"); + + expect(result[1]).toBeInstanceOf(GroupTreeItem); + expect(result[1].label).toBe("Command Group"); + expect((result[1] as GroupTreeItem).commands).toHaveLength(2); + + expect(result[2]).toBeInstanceOf(CommandTreeItem); + expect(result[2].label).toBe("VS Code Command"); + expect((result[2] as CommandTreeItem).useVsCodeApi).toBe(true); + }); + + it("should verify correct item types and labels", () => { + const buttons: ButtonConfig[] = [ + { + name: "Terminal Command", + command: "npm run build", + terminalName: "build-terminal", + }, + { + name: "Development Tools", + group: [{ name: "Start Server", command: "npm start" }], + }, + ]; + + const result = createRootTreeItems(buttons); + + expect(result).toHaveLength(2); + + const commandItem = result[0] as CommandTreeItem; + expect(commandItem).toBeInstanceOf(CommandTreeItem); + expect(commandItem.label).toBe("Terminal Command"); + expect(commandItem.commandString).toBe("npm run build"); + expect(commandItem.terminalName).toBe("build-terminal"); + expect(commandItem.useVsCodeApi).toBe(false); + + const groupItem = result[1] as GroupTreeItem; + expect(groupItem).toBeInstanceOf(GroupTreeItem); + expect(groupItem.label).toBe("Development Tools"); + expect(groupItem.commands).toHaveLength(1); + expect(groupItem.commands[0].name).toBe("Start Server"); + }); + + it("should handle empty button array scenario", () => { + const buttons: ButtonConfig[] = []; + + const result = createRootTreeItems(buttons); + + expect(result).toHaveLength(0); + expect(result).toEqual([]); + }); + + it("should handle buttons with no command property", () => { + const buttons: ButtonConfig[] = [ + { name: "Invalid Button" } as ButtonConfig, + { name: "Empty Command", command: "" }, + ]; + + const result = createRootTreeItems(buttons); + + expect(result).toHaveLength(2); + expect(result[0]).toBeInstanceOf(CommandTreeItem); + expect((result[0] as CommandTreeItem).commandString).toBe(""); + expect(result[1]).toBeInstanceOf(CommandTreeItem); + expect((result[1] as CommandTreeItem).commandString).toBe(""); + }); + + it("should handle nested group structures", () => { + const buttons: ButtonConfig[] = [ + { + name: "Main Group", + group: [ + { name: "Sub Command 1", command: "echo test1" }, + { name: "Sub Command 2", command: "echo test2" }, + { name: "Sub Command 3", command: "echo test3" }, + ], + }, + ]; + + const result = createRootTreeItems(buttons); + + expect(result).toHaveLength(1); + expect(result[0]).toBeInstanceOf(GroupTreeItem); + const groupItem = result[0] as GroupTreeItem; + expect(groupItem.label).toBe("Main Group"); + expect(groupItem.commands).toHaveLength(3); + expect(groupItem.commands[0].name).toBe("Sub Command 1"); + expect(groupItem.commands[1].name).toBe("Sub Command 2"); + expect(groupItem.commands[2].name).toBe("Sub Command 3"); + }); + }); +}); diff --git a/src/extension/src/command-tree-provider.ts b/src/extension/src/command-tree-provider.ts index cd8fc651..03be5e7f 100644 --- a/src/extension/src/command-tree-provider.ts +++ b/src/extension/src/command-tree-provider.ts @@ -41,6 +41,39 @@ export class GroupTreeItem extends vscode.TreeItem { type TreeItem = CommandTreeItem | GroupTreeItem; +export const createTreeItemsFromGroup = ( + commands: ButtonConfig[] +): CommandTreeItem[] => { + return commands.map( + (cmd) => + new CommandTreeItem( + cmd.name, + cmd.command || "", + cmd.useVsCodeApi || false, + cmd.terminalName + ) + ); +}; + +export const createRootTreeItems = (buttons: ButtonConfig[]): TreeItem[] => { + return buttons.map((button) => { + if (button.group) { + return new GroupTreeItem(button.name, button.group); + } + + if (button.command) { + return new CommandTreeItem( + button.name, + button.command, + button.useVsCodeApi || false, + button.terminalName + ); + } + + return new CommandTreeItem(button.name, "", false); + }); +}; + export class CommandTreeProvider implements vscode.TreeDataProvider { private _onDidChangeTreeData = new vscode.EventEmitter< TreeItem | undefined | null | void @@ -61,17 +94,7 @@ export class CommandTreeProvider implements vscode.TreeDataProvider { } if (element instanceof GroupTreeItem) { - return Promise.resolve( - element.commands.map( - (cmd) => - new CommandTreeItem( - cmd.name, - cmd.command || "", - cmd.useVsCodeApi || false, - cmd.terminalName - ) - ) - ); + return Promise.resolve(createTreeItemsFromGroup(element.commands)); } return Promise.resolve([]); @@ -79,23 +102,7 @@ export class CommandTreeProvider implements vscode.TreeDataProvider { private getRootItems = (): TreeItem[] => { const buttons = this.configReader.getButtons(); - - return buttons.map((button) => { - if (button.group) { - return new GroupTreeItem(button.name, button.group); - } - - if (button.command) { - return new CommandTreeItem( - button.name, - button.command, - button.useVsCodeApi || false, - button.terminalName - ); - } - - return new CommandTreeItem(button.name, "", false); - }); + return createRootTreeItems(buttons); }; static create = (configReader: ConfigReader): CommandTreeProvider => diff --git a/src/extension/src/main.test.ts b/src/extension/src/main.test.ts new file mode 100644 index 00000000..01e2f80e --- /dev/null +++ b/src/extension/src/main.test.ts @@ -0,0 +1,211 @@ +import * as vscode from "vscode"; +import { registerCommands } from "./main"; +import { StatusBarManager } from "./status-bar-manager"; +import { CommandTreeProvider } from "./command-tree-provider"; +import { TerminalManager } from "./terminal-manager"; +import { createShowAllCommandsCommand } from "./show-all-commands"; +import { ConfigWebviewProvider } from "./webview-provider"; + +// Mock other modules +jest.mock("./command-executor", () => ({ + executeButtonCommand: jest.fn(), +})); + +jest.mock("./show-all-commands", () => ({ + createShowAllCommandsCommand: jest.fn(), +})); + +jest.mock("./webview-provider", () => ({ + ConfigWebviewProvider: { + createWebviewCommand: jest.fn(), + }, +})); + +jest.mock("./command-tree-provider", () => ({ + CommandTreeProvider: { + executeFromTree: jest.fn(), + }, +})); + +describe("main", () => { + let mockContext: vscode.ExtensionContext; + let mockConfigReader: any; + let mockQuickPickCreator: any; + let mockTerminalManager: TerminalManager; + let mockStatusBarManager: StatusBarManager; + let mockTreeProvider: CommandTreeProvider; + + beforeEach(() => { + jest.clearAllMocks(); + + mockContext = { + extensionUri: "mockUri" as any, + } as vscode.ExtensionContext; + + mockConfigReader = { + getButtons: jest.fn(), + onConfigChange: jest.fn(), + }; + + mockQuickPickCreator = jest.fn(); + + mockTerminalManager = { + executeCommand: jest.fn(), + } as any; + + mockStatusBarManager = { + refreshButtons: jest.fn(), + } as any; + + mockTreeProvider = { + refresh: jest.fn(), + } as any; + + (vscode.commands.registerCommand as jest.Mock).mockReturnValue( + "mockDisposable" + ); + }); + + describe("registerCommands", () => { + it("should register quickCommandButtons.execute command", () => { + const commands = registerCommands( + mockContext, + mockConfigReader, + mockQuickPickCreator, + mockTerminalManager, + mockStatusBarManager, + mockTreeProvider + ); + + expect(vscode.commands.registerCommand).toHaveBeenCalledWith( + "quickCommandButtons.execute", + expect.any(Function) + ); + expect(commands.executeCommand).toBe("mockDisposable"); + }); + + it("should register quickCommandButtons.executeFromTree command", () => { + const commands = registerCommands( + mockContext, + mockConfigReader, + mockQuickPickCreator, + mockTerminalManager, + mockStatusBarManager, + mockTreeProvider + ); + + expect(vscode.commands.registerCommand).toHaveBeenCalledWith( + "quickCommandButtons.executeFromTree", + expect.any(Function) + ); + expect(commands.executeFromTreeCommand).toBe("mockDisposable"); + }); + + it("should register quickCommandButtons.refreshTree command", () => { + const commands = registerCommands( + mockContext, + mockConfigReader, + mockQuickPickCreator, + mockTerminalManager, + mockStatusBarManager, + mockTreeProvider + ); + + expect(vscode.commands.registerCommand).toHaveBeenCalledWith( + "quickCommandButtons.refreshTree", + expect.any(Function) + ); + expect(commands.refreshTreeCommand).toBe("mockDisposable"); + }); + + it("should register quickCommandButtons.refresh command", () => { + const commands = registerCommands( + mockContext, + mockConfigReader, + mockQuickPickCreator, + mockTerminalManager, + mockStatusBarManager, + mockTreeProvider + ); + + expect(vscode.commands.registerCommand).toHaveBeenCalledWith( + "quickCommandButtons.refresh", + expect.any(Function) + ); + expect(commands.refreshCommand).toBe("mockDisposable"); + }); + + it("should register quickCommandButtons.showAllCommands command", () => { + const mockShowAllCommand = jest.fn(); + (createShowAllCommandsCommand as jest.Mock).mockReturnValue( + mockShowAllCommand + ); + + const commands = registerCommands( + mockContext, + mockConfigReader, + mockQuickPickCreator, + mockTerminalManager, + mockStatusBarManager, + mockTreeProvider + ); + + expect(vscode.commands.registerCommand).toHaveBeenCalledWith( + "quickCommandButtons.showAllCommands", + mockShowAllCommand + ); + expect(createShowAllCommandsCommand).toHaveBeenCalledWith( + mockConfigReader, + mockTerminalManager.executeCommand, + mockQuickPickCreator + ); + expect(commands.showAllCommandsCommand).toBe("mockDisposable"); + }); + + it("should register quickCommandButtons.openConfig command", () => { + const mockWebviewCommand = jest.fn(); + (ConfigWebviewProvider.createWebviewCommand as jest.Mock).mockReturnValue( + mockWebviewCommand + ); + + const commands = registerCommands( + mockContext, + mockConfigReader, + mockQuickPickCreator, + mockTerminalManager, + mockStatusBarManager, + mockTreeProvider + ); + + expect(vscode.commands.registerCommand).toHaveBeenCalledWith( + "quickCommandButtons.openConfig", + mockWebviewCommand + ); + expect(ConfigWebviewProvider.createWebviewCommand).toHaveBeenCalledWith( + mockContext.extensionUri, + mockConfigReader + ); + expect(commands.openConfigCommand).toBe("mockDisposable"); + }); + + it("should return all registered command disposables", () => { + const commands = registerCommands( + mockContext, + mockConfigReader, + mockQuickPickCreator, + mockTerminalManager, + mockStatusBarManager, + mockTreeProvider + ); + + expect(commands).toEqual({ + executeCommand: "mockDisposable", + executeFromTreeCommand: "mockDisposable", + refreshCommand: "mockDisposable", + refreshTreeCommand: "mockDisposable", + showAllCommandsCommand: "mockDisposable", + openConfigCommand: "mockDisposable", + }); + }); + }); +}); diff --git a/src/extension/src/main.ts b/src/extension/src/main.ts index 7b6ac911..02665e4c 100644 --- a/src/extension/src/main.ts +++ b/src/extension/src/main.ts @@ -12,25 +12,14 @@ import { createVSCodeQuickPickCreator, } from "./adapters"; -export const activate = (context: vscode.ExtensionContext) => { - const configReader = createVSCodeConfigReader(); - const statusBarCreator = createVSCodeStatusBarCreator(); - const quickPickCreator = createVSCodeQuickPickCreator(); - - const terminalManager = TerminalManager.create(); - const statusBarManager = StatusBarManager.create( - configReader, - statusBarCreator - ); - const treeProvider = CommandTreeProvider.create(configReader); - - statusBarManager.refreshButtons(); - - const configChangeListener = configReader.onConfigChange(() => { - statusBarManager.refreshButtons(); - treeProvider.refresh(); - }); - +export const registerCommands = ( + context: vscode.ExtensionContext, + configReader: ReturnType, + quickPickCreator: ReturnType, + terminalManager: TerminalManager, + statusBarManager: StatusBarManager, + treeProvider: CommandTreeProvider +) => { const executeCommand = vscode.commands.registerCommand( "quickCommandButtons.execute", (button: ButtonConfig) => @@ -78,17 +67,50 @@ export const activate = (context: vscode.ExtensionContext) => { ) ); - const treeView = vscode.window.createTreeView("quickCommandsTree", { - treeDataProvider: treeProvider, - }); - - context.subscriptions.push( + return { executeCommand, executeFromTreeCommand, - refreshTreeCommand, refreshCommand, + refreshTreeCommand, showAllCommandsCommand, openConfigCommand, + }; +}; + +export const activate = (context: vscode.ExtensionContext) => { + const configReader = createVSCodeConfigReader(); + const statusBarCreator = createVSCodeStatusBarCreator(); + const quickPickCreator = createVSCodeQuickPickCreator(); + + const terminalManager = TerminalManager.create(); + const statusBarManager = StatusBarManager.create( + configReader, + statusBarCreator + ); + const treeProvider = CommandTreeProvider.create(configReader); + + statusBarManager.refreshButtons(); + + const configChangeListener = configReader.onConfigChange(() => { + statusBarManager.refreshButtons(); + treeProvider.refresh(); + }); + + const commands = registerCommands( + context, + configReader, + quickPickCreator, + terminalManager, + statusBarManager, + treeProvider + ); + + const treeView = vscode.window.createTreeView("quickCommandsTree", { + treeDataProvider: treeProvider, + }); + + context.subscriptions.push( + ...Object.values(commands), treeView, statusBarManager, configChangeListener diff --git a/src/extension/src/show-all-commands.test.ts b/src/extension/src/show-all-commands.test.ts new file mode 100644 index 00000000..823846d6 --- /dev/null +++ b/src/extension/src/show-all-commands.test.ts @@ -0,0 +1,193 @@ +import { createQuickPickItemsFromButtons } from "./show-all-commands"; +import { ButtonConfig } from "./types"; + +describe("show-all-commands", () => { + describe("createQuickPickItemsFromButtons", () => { + it("should create QuickPickItems with shortcuts", () => { + const buttons: ButtonConfig[] = [ + { + name: "Test Command 1", + command: "echo test1", + shortcut: "1", + }, + { + name: "Test Command 2", + command: "echo test2", + shortcut: "2", + }, + ]; + + const result = createQuickPickItemsFromButtons(buttons); + + expect(result).toHaveLength(2); + expect(result[0]).toEqual({ + label: "Test Command 1 (1)", + description: "echo test1", + command: buttons[0], + }); + expect(result[1]).toEqual({ + label: "Test Command 2 (2)", + description: "echo test2", + command: buttons[1], + }); + }); + + it("should create QuickPickItems without shortcuts", () => { + const buttons: ButtonConfig[] = [ + { + name: "Test Command 1", + command: "echo test1", + }, + { + name: "Test Command 2", + command: "echo test2", + }, + ]; + + const result = createQuickPickItemsFromButtons(buttons); + + expect(result).toHaveLength(2); + expect(result[0]).toEqual({ + label: "Test Command 1", + description: "echo test1", + command: buttons[0], + }); + expect(result[1]).toEqual({ + label: "Test Command 2", + description: "echo test2", + command: buttons[1], + }); + }); + + it("should handle group buttons", () => { + const buttons: ButtonConfig[] = [ + { + name: "Test Group", + group: [ + { + name: "Nested Command 1", + command: "echo nested1", + }, + { + name: "Nested Command 2", + command: "echo nested2", + }, + ], + }, + ]; + + const result = createQuickPickItemsFromButtons(buttons); + + expect(result).toHaveLength(1); + expect(result[0]).toEqual({ + label: "Test Group", + description: "2 commands", + command: buttons[0], + }); + }); + + it("should handle group buttons with shortcuts", () => { + const buttons: ButtonConfig[] = [ + { + name: "Test Group", + shortcut: "g", + group: [ + { + name: "Nested Command", + command: "echo nested", + }, + ], + }, + ]; + + const result = createQuickPickItemsFromButtons(buttons); + + expect(result).toHaveLength(1); + expect(result[0]).toEqual({ + label: "Test Group (g)", + description: "1 commands", + command: buttons[0], + }); + }); + + it("should handle buttons with no command", () => { + const buttons: ButtonConfig[] = [ + { + name: "Test Button", + }, + ]; + + const result = createQuickPickItemsFromButtons(buttons); + + expect(result).toHaveLength(1); + expect(result[0]).toEqual({ + label: "Test Button", + description: "", + command: buttons[0], + }); + }); + + it("should handle empty array", () => { + const buttons: ButtonConfig[] = []; + + const result = createQuickPickItemsFromButtons(buttons); + + expect(result).toHaveLength(0); + expect(result).toEqual([]); + }); + + it("should preserve object references", () => { + const buttons: ButtonConfig[] = [ + { + name: "Test Command", + command: "echo test", + }, + ]; + + const result = createQuickPickItemsFromButtons(buttons); + + expect(result[0].command).toBe(buttons[0]); + }); + + it("should handle mixed configurations", () => { + const buttons: ButtonConfig[] = [ + { + name: "Command Button", + command: "echo command", + shortcut: "c", + }, + { + name: "Group Button", + group: [ + { + name: "Nested", + command: "echo nested", + }, + ], + }, + { + name: "Empty Button", + }, + ]; + + const result = createQuickPickItemsFromButtons(buttons); + + expect(result).toHaveLength(3); + expect(result[0]).toEqual({ + label: "Command Button (c)", + description: "echo command", + command: buttons[0], + }); + expect(result[1]).toEqual({ + label: "Group Button", + description: "1 commands", + command: buttons[1], + }); + expect(result[2]).toEqual({ + label: "Empty Button", + description: "", + command: buttons[2], + }); + }); + }); +}); diff --git a/src/extension/src/show-all-commands.ts b/src/extension/src/show-all-commands.ts index b08fc900..3fa0bd8c 100644 --- a/src/extension/src/show-all-commands.ts +++ b/src/extension/src/show-all-commands.ts @@ -4,6 +4,21 @@ import { QuickPickItem, } from "./command-executor"; import { ConfigReader, QuickPickCreator, TerminalExecutor } from "./adapters"; +import { ButtonConfig } from "./types"; + +export const createQuickPickItemsFromButtons = ( + buttons: ButtonConfig[] +): QuickPickItem[] => { + return buttons.map((button) => ({ + label: button.shortcut + ? `${button.name} (${button.shortcut})` + : button.name, + description: button.group + ? `${button.group.length} commands` + : button.command || "", + command: button, + })); +}; export const createShowAllCommandsCommand = ( configReader: ConfigReader, @@ -18,15 +33,7 @@ export const createShowAllCommandsCommand = ( return; } - const items: QuickPickItem[] = buttons.map((button) => ({ - label: button.shortcut - ? `${button.name} (${button.shortcut})` - : button.name, - description: button.group - ? `${button.group.length} commands` - : button.command || "", - command: button, - })); + const items = createQuickPickItemsFromButtons(buttons); createQuickPickWithShortcuts( { diff --git a/src/extension/src/status-bar-manager.test.ts b/src/extension/src/status-bar-manager.test.ts new file mode 100644 index 00000000..38879b70 --- /dev/null +++ b/src/extension/src/status-bar-manager.test.ts @@ -0,0 +1,267 @@ +import { calculateButtonPriority, createTooltipText, createButtonCommand, configureRefreshButton } from "./status-bar-manager"; +import { ButtonConfig } from "./types"; + +describe("status-bar-manager", () => { + describe("calculateButtonPriority", () => { + it("should calculate priority for index 0", () => { + const result = calculateButtonPriority(0); + expect(result).toBe(1000); + }); + + it("should calculate priority for positive index", () => { + const result = calculateButtonPriority(5); + expect(result).toBe(995); + }); + + it("should calculate priority for large index", () => { + const result = calculateButtonPriority(500); + expect(result).toBe(500); + }); + + it("should handle negative index", () => { + const result = calculateButtonPriority(-1); + expect(result).toBe(1001); + }); + + it("should maintain descending order for sequential indices", () => { + const priority0 = calculateButtonPriority(0); + const priority1 = calculateButtonPriority(1); + const priority2 = calculateButtonPriority(2); + + expect(priority0).toBeGreaterThan(priority1); + expect(priority1).toBeGreaterThan(priority2); + }); + }); + + describe("createTooltipText", () => { + it("should return button name with options text for group buttons", () => { + const button: ButtonConfig = { + name: "Test Group", + group: [ + { name: "Child 1", command: "echo test1" }, + { name: "Child 2", command: "echo test2" } + ] + }; + + const result = createTooltipText(button); + expect(result).toBe("Test Group (Click to see options)"); + }); + + it("should return command when button has command and no group", () => { + const button: ButtonConfig = { + name: "Test Button", + command: "echo hello" + }; + + const result = createTooltipText(button); + expect(result).toBe("echo hello"); + }); + + it("should return button name when button has no command and no group", () => { + const button: ButtonConfig = { + name: "Test Button" + }; + + const result = createTooltipText(button); + expect(result).toBe("Test Button"); + }); + + it("should return button name with options text for empty group", () => { + const button: ButtonConfig = { + name: "Empty Group", + group: [] + }; + + const result = createTooltipText(button); + expect(result).toBe("Empty Group (Click to see options)"); + }); + + it("should prioritize group over command when both exist", () => { + const button: ButtonConfig = { + name: "Mixed Button", + command: "echo test", + group: [{ name: "Child", command: "echo child" }] + }; + + const result = createTooltipText(button); + expect(result).toBe("Mixed Button (Click to see options)"); + }); + }); + + describe("createButtonCommand", () => { + it("should create command object with correct structure for command button", () => { + const button: ButtonConfig = { + name: "Test Button", + command: "echo hello" + }; + + const result = createButtonCommand(button); + + expect(result).toEqual({ + command: "quickCommandButtons.execute", + title: "Execute Command", + arguments: [button] + }); + }); + + it("should create command object with correct structure for group button", () => { + const button: ButtonConfig = { + name: "Test Group", + group: [ + { name: "Child 1", command: "echo test1" }, + { name: "Child 2", command: "echo test2" } + ] + }; + + const result = createButtonCommand(button); + + expect(result).toEqual({ + command: "quickCommandButtons.execute", + title: "Execute Command", + arguments: [button] + }); + }); + + it("should preserve button object reference in arguments", () => { + const button: ButtonConfig = { + name: "Reference Test", + command: "echo reference" + }; + + const result = createButtonCommand(button); + + expect(result.arguments[0]).toBe(button); + }); + + it("should handle button with no command or group", () => { + const button: ButtonConfig = { + name: "Minimal Button" + }; + + const result = createButtonCommand(button); + + expect(result).toEqual({ + command: "quickCommandButtons.execute", + title: "Execute Command", + arguments: [button] + }); + }); + + it("should handle button with additional properties", () => { + const button: ButtonConfig = { + name: "Complex Button", + command: "echo test", + color: "#FF0000", + shortcut: "t" + }; + + const result = createButtonCommand(button); + + expect(result).toEqual({ + command: "quickCommandButtons.execute", + title: "Execute Command", + arguments: [button] + }); + expect(result.arguments[0]).toEqual(button); + }); + }); + + describe("configureRefreshButton", () => { + let mockStatusBarItem: any; + + beforeEach(() => { + mockStatusBarItem = { + text: "", + tooltip: "", + command: "", + color: "" + }; + }); + + it("should configure refresh button with all properties", () => { + const refreshConfig = { + icon: "🔄", + color: "#00FF00" + }; + + configureRefreshButton(mockStatusBarItem, refreshConfig); + + expect(mockStatusBarItem.text).toBe("🔄"); + expect(mockStatusBarItem.tooltip).toBe("Refresh Quick Command Buttons"); + expect(mockStatusBarItem.command).toBe("quickCommandButtons.refresh"); + expect(mockStatusBarItem.color).toBe("#00FF00"); + }); + + it("should configure refresh button with minimal properties", () => { + const refreshConfig = { + icon: "⟳" + }; + + configureRefreshButton(mockStatusBarItem, refreshConfig); + + expect(mockStatusBarItem.text).toBe("⟳"); + expect(mockStatusBarItem.tooltip).toBe("Refresh Quick Command Buttons"); + expect(mockStatusBarItem.command).toBe("quickCommandButtons.refresh"); + expect(mockStatusBarItem.color).toBeUndefined(); + }); + + it("should handle refresh config with color set to undefined", () => { + const refreshConfig = { + icon: "↻", + color: undefined + }; + + configureRefreshButton(mockStatusBarItem, refreshConfig); + + expect(mockStatusBarItem.text).toBe("↻"); + expect(mockStatusBarItem.tooltip).toBe("Refresh Quick Command Buttons"); + expect(mockStatusBarItem.command).toBe("quickCommandButtons.refresh"); + expect(mockStatusBarItem.color).toBeUndefined(); + }); + + it("should handle refresh config with empty icon", () => { + const refreshConfig = { + icon: "", + color: "#FF0000" + }; + + configureRefreshButton(mockStatusBarItem, refreshConfig); + + expect(mockStatusBarItem.text).toBe(""); + expect(mockStatusBarItem.tooltip).toBe("Refresh Quick Command Buttons"); + expect(mockStatusBarItem.command).toBe("quickCommandButtons.refresh"); + expect(mockStatusBarItem.color).toBe("#FF0000"); + }); + + it("should handle refresh config with null color", () => { + const refreshConfig = { + icon: "↺", + color: null + }; + + configureRefreshButton(mockStatusBarItem, refreshConfig); + + expect(mockStatusBarItem.text).toBe("↺"); + expect(mockStatusBarItem.tooltip).toBe("Refresh Quick Command Buttons"); + expect(mockStatusBarItem.command).toBe("quickCommandButtons.refresh"); + expect(mockStatusBarItem.color).toBeNull(); + }); + + it("should preserve existing statusBarItem properties not being configured", () => { + mockStatusBarItem.alignment = "left"; + mockStatusBarItem.priority = 1001; + + const refreshConfig = { + icon: "🔃", + color: "#0000FF" + }; + + configureRefreshButton(mockStatusBarItem, refreshConfig); + + expect(mockStatusBarItem.alignment).toBe("left"); + expect(mockStatusBarItem.priority).toBe(1001); + expect(mockStatusBarItem.text).toBe("🔃"); + expect(mockStatusBarItem.color).toBe("#0000FF"); + }); + }); +}); diff --git a/src/extension/src/status-bar-manager.ts b/src/extension/src/status-bar-manager.ts index d9725fcb..fd50df3e 100644 --- a/src/extension/src/status-bar-manager.ts +++ b/src/extension/src/status-bar-manager.ts @@ -2,6 +2,32 @@ import * as vscode from "vscode"; import { ButtonConfig } from "./types"; import { ConfigReader, StatusBarCreator } from "./adapters"; +export const calculateButtonPriority = (index: number): number => { + return 1000 - index; +}; + +export const createTooltipText = (button: ButtonConfig): string => { + return button.group + ? `${button.name} (Click to see options)` + : button.command || button.name; +}; + +export const createButtonCommand = (button: ButtonConfig) => ({ + command: "quickCommandButtons.execute", + title: "Execute Command", + arguments: [button], +}); + +export const configureRefreshButton = ( + button: vscode.StatusBarItem, + refreshConfig: any +) => { + button.text = refreshConfig.icon; + button.tooltip = "Refresh Quick Command Buttons"; + button.command = "quickCommandButtons.refresh"; + button.color = refreshConfig.color; +}; + export class StatusBarManager { private statusBarItems: vscode.StatusBarItem[] = []; @@ -22,23 +48,17 @@ export class StatusBarManager { buttons.forEach((button, index) => { const statusBarItem = this.statusBarCreator( vscode.StatusBarAlignment.Left, - 1000 - index + calculateButtonPriority(index) ); statusBarItem.text = button.name; - statusBarItem.tooltip = button.group - ? `${button.name} (Click to see options)` - : button.command || button.name; + statusBarItem.tooltip = createTooltipText(button); if (button.color) { statusBarItem.color = button.color; } - statusBarItem.command = { - command: "quickCommandButtons.execute", - title: "Execute Command", - arguments: [button], - }; + statusBarItem.command = createButtonCommand(button); statusBarItem.show(); this.statusBarItems.push(statusBarItem); @@ -55,10 +75,7 @@ export class StatusBarManager { 1001 ); - refreshButton.text = refreshConfig.icon; - refreshButton.tooltip = "Refresh Quick Command Buttons"; - refreshButton.command = "quickCommandButtons.refresh"; - refreshButton.color = refreshConfig.color; + configureRefreshButton(refreshButton, refreshConfig); refreshButton.show(); this.statusBarItems.push(refreshButton); diff --git a/src/extension/src/terminal-manager.test.ts b/src/extension/src/terminal-manager.test.ts new file mode 100644 index 00000000..8468e376 --- /dev/null +++ b/src/extension/src/terminal-manager.test.ts @@ -0,0 +1,58 @@ +import { + shouldCreateNewTerminal, + determineTerminalName, +} from "./terminal-manager"; + +describe("terminal-manager", () => { + describe("shouldCreateNewTerminal", () => { + it("should return true when terminal is undefined", () => { + const result = shouldCreateNewTerminal(undefined); + expect(result).toBe(true); + }); + + it("should return true when terminal has exit status", () => { + const mockTerminal = { + exitStatus: { code: 0 }, + } as any; + + const result = shouldCreateNewTerminal(mockTerminal); + expect(result).toBe(true); + }); + + it("should return false when terminal exists and has no exit status", () => { + const mockTerminal = { + exitStatus: undefined, + } as any; + + const result = shouldCreateNewTerminal(mockTerminal); + expect(result).toBe(false); + }); + }); + + describe("determineTerminalName", () => { + it("should return custom terminal name when provided", () => { + const result = determineTerminalName("CustomTerminal", "npm test"); + expect(result).toBe("CustomTerminal"); + }); + + it("should return first word of command when no custom name", () => { + const result = determineTerminalName(undefined, "npm test --verbose"); + expect(result).toBe("npm"); + }); + + it("should return 'Terminal' when command is empty", () => { + const result = determineTerminalName(undefined, ""); + expect(result).toBe("Terminal"); + }); + + it("should return 'Terminal' when command contains only spaces", () => { + const result = determineTerminalName(undefined, " "); + expect(result).toBe("Terminal"); + }); + + it("should handle single word commands", () => { + const result = determineTerminalName(undefined, "ls"); + expect(result).toBe("ls"); + }); + }); +}); diff --git a/src/extension/src/terminal-manager.ts b/src/extension/src/terminal-manager.ts index 53206a5e..0c3ee254 100644 --- a/src/extension/src/terminal-manager.ts +++ b/src/extension/src/terminal-manager.ts @@ -1,6 +1,19 @@ import * as vscode from "vscode"; import { TerminalExecutor } from "./adapters"; +export const shouldCreateNewTerminal = ( + terminal: vscode.Terminal | undefined +): boolean => { + return !terminal || !!terminal.exitStatus; +}; + +export const determineTerminalName = ( + customTerminalName: string | undefined, + command: string +): string => { + return customTerminalName || command.split(" ")[0] || "Terminal"; +}; + export class TerminalManager { private terminals = new Map(); @@ -14,21 +27,16 @@ export class TerminalManager { return; } - const terminalName = - customTerminalName || this.generateTerminalName(command); + const terminalName = determineTerminalName(customTerminalName, command); let terminal = this.terminals.get(terminalName); - if (!terminal || terminal.exitStatus) { + if (shouldCreateNewTerminal(terminal)) { terminal = vscode.window.createTerminal(terminalName); this.terminals.set(terminalName, terminal); } - terminal.show(); - terminal.sendText(command); - }; - - private generateTerminalName = (command: string): string => { - return command.split(" ")[0] || "Terminal"; + terminal!.show(); + terminal!.sendText(command); }; dispose = () => { diff --git a/src/extension/src/webview-provider.test.ts b/src/extension/src/webview-provider.test.ts new file mode 100644 index 00000000..35dd84e0 --- /dev/null +++ b/src/extension/src/webview-provider.test.ts @@ -0,0 +1,547 @@ +import { generateFallbackHtml, replaceAssetPaths, injectSecurityAndVSCodeApi, checkWebviewFilesExist, buildWebviewHtml, updateButtonConfiguration } from "./webview-provider"; +import * as vscode from "vscode"; +import * as fs from "fs"; +import * as path from "path"; + +// Mock fs module +jest.mock("fs"); + +describe("webview-provider", () => { + describe("generateFallbackHtml", () => { + it("should return HTML with configuration UI not available message", () => { + const result = generateFallbackHtml(); + + expect(result).toContain(""); + expect(result).toContain("Configuration UI"); + expect(result).toContain("Configuration UI Not Available"); + expect(result).toContain("cd src/web-view && npm run build"); + }); + + it("should return valid HTML structure", () => { + const result = generateFallbackHtml(); + + expect(result).toContain(""); + expect(result).toContain(""); + expect(result).toContain(""); + expect(result).toContain(""); + expect(result).toContain(""); + expect(result).toContain(""); + }); + + it("should include viewport meta tag", () => { + const result = generateFallbackHtml(); + + expect(result).toContain(''); + }); + }); + + describe("replaceAssetPaths", () => { + it("should replace /assets/ with provided assetsUri", () => { + const html = ' '; + const mockUri = { toString: () => "vscode-webview://assets-uri" } as vscode.Uri; + + const result = replaceAssetPaths(html, mockUri); + + expect(result).toBe(' '); + }); + + it("should replace multiple occurrences of /assets/", () => { + const html = ''; + const mockUri = { toString: () => "vscode-webview://test-uri" } as vscode.Uri; + + const result = replaceAssetPaths(html, mockUri); + + expect(result).toBe(''); + }); + + it("should handle HTML without /assets/ paths", () => { + const html = '
No assets here

Just regular content

'; + const mockUri = { toString: () => "vscode-webview://unused-uri" } as vscode.Uri; + + const result = replaceAssetPaths(html, mockUri); + + expect(result).toBe('
No assets here

Just regular content

'); + }); + + it("should handle empty HTML string", () => { + const html = ""; + const mockUri = { toString: () => "vscode-webview://empty-uri" } as vscode.Uri; + + const result = replaceAssetPaths(html, mockUri); + + expect(result).toBe(""); + }); + + it("should handle HTML with only /assets/ without following path", () => { + const html = '
/assets/
text /assets/ more text'; + const mockUri = { toString: () => "vscode-webview://edge-case-uri" } as vscode.Uri; + + const result = replaceAssetPaths(html, mockUri); + + expect(result).toBe('
vscode-webview://edge-case-uri/
text vscode-webview://edge-case-uri/ more text'); + }); + + it("should handle complex HTML structure with nested assets", () => { + const html = ` + + + + + + + logo + + + + `; + const mockUri = { toString: () => "vscode-webview://complex-uri" } as vscode.Uri; + + const result = replaceAssetPaths(html, mockUri); + + expect(result).toContain('href="vscode-webview://complex-uri/styles/main.css"'); + expect(result).toContain('href="vscode-webview://complex-uri/favicon.ico"'); + expect(result).toContain('src="vscode-webview://complex-uri/images/logo.png"'); + expect(result).toContain('src="vscode-webview://complex-uri/js/main.js"'); + }); + }); + + describe("injectSecurityAndVSCodeApi", () => { + const mockWebview = { + cspSource: "vscode-webview://test-source" + } as vscode.Webview; + + it("should inject CSP meta tag and vscode API script into head section", () => { + const html = 'Test'; + + const result = injectSecurityAndVSCodeApi(html, mockWebview); + + expect(result).toContain(' { + const html = 'Test Title'; + + const result = injectSecurityAndVSCodeApi(html, mockWebview); + + const headIndex = result.indexOf(''); + const metaIndex = result.indexOf(''); + const titleIndex = result.indexOf('Test Title'); + + expect(metaIndex).toBeGreaterThan(headIndex); + expect(scriptIndex).toBeGreaterThan(metaIndex); + expect(titleIndex).toBeGreaterThan(scriptIndex); + }); + + it("should handle HTML without head tag", () => { + const html = '
No head tag
'; + + const result = injectSecurityAndVSCodeApi(html, mockWebview); + + expect(result).toBe('
No head tag
'); + }); + + it("should handle empty HTML string", () => { + const html = ''; + + const result = injectSecurityAndVSCodeApi(html, mockWebview); + + expect(result).toBe(''); + }); + + it("should handle HTML with multiple head tags", () => { + const html = 'FirstSecond head'; + + const result = injectSecurityAndVSCodeApi(html, mockWebview); + + const firstHeadIndex = result.indexOf(''); + const metaIndex = result.indexOf('', firstHeadIndex + 1); + + expect(metaIndex).toBeGreaterThan(firstHeadIndex); + expect(metaIndex).toBeLessThan(secondHeadIndex); + expect(result.indexOf(' { + const html = 'Test'; + + const result = injectSecurityAndVSCodeApi(html, mockWebview); + + expect(result).toContain(''); + expect(result).toContain('Test'); + expect(result).toContain(''); + expect(result).toContain(' { + const customWebview = { + cspSource: "vscode-webview://custom-source-123" + } as vscode.Webview; + const html = ''; + + const result = injectSecurityAndVSCodeApi(html, customWebview); + + expect(result).toContain('style-src vscode-webview://custom-source-123 \'unsafe-inline\''); + expect(result).toContain('script-src vscode-webview://custom-source-123 \'unsafe-inline\''); + expect(result).toContain('img-src vscode-webview://custom-source-123 https: data:'); + }); + }); + + describe("checkWebviewFilesExist", () => { + const mockedFs = fs as jest.Mocked; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("should return true when index.html exists in webview path", () => { + const webviewPath = "/test/webview/path"; + const expectedIndexPath = path.join(webviewPath, "index.html"); + + mockedFs.existsSync.mockImplementation((filePath) => { + return filePath === expectedIndexPath; + }); + + const result = checkWebviewFilesExist(webviewPath); + + expect(result).toBe(true); + expect(mockedFs.existsSync).toHaveBeenCalledWith(expectedIndexPath); + }); + + it("should return false when index.html does not exist in webview path", () => { + const webviewPath = "/test/missing/path"; + const expectedIndexPath = path.join(webviewPath, "index.html"); + + mockedFs.existsSync.mockReturnValue(false); + + const result = checkWebviewFilesExist(webviewPath); + + expect(result).toBe(false); + expect(mockedFs.existsSync).toHaveBeenCalledWith(expectedIndexPath); + }); + + it("should handle empty webview path", () => { + const webviewPath = ""; + const expectedIndexPath = path.join(webviewPath, "index.html"); + + mockedFs.existsSync.mockReturnValue(false); + + const result = checkWebviewFilesExist(webviewPath); + + expect(result).toBe(false); + expect(mockedFs.existsSync).toHaveBeenCalledWith(expectedIndexPath); + }); + + it("should handle relative webview path", () => { + const webviewPath = "./relative/path"; + const expectedIndexPath = path.join(webviewPath, "index.html"); + + mockedFs.existsSync.mockImplementation((filePath) => { + return filePath === expectedIndexPath; + }); + + const result = checkWebviewFilesExist(webviewPath); + + expect(result).toBe(true); + expect(mockedFs.existsSync).toHaveBeenCalledWith(expectedIndexPath); + }); + + it("should handle path with special characters", () => { + const webviewPath = "/test/path with spaces/and-special_chars"; + const expectedIndexPath = path.join(webviewPath, "index.html"); + + mockedFs.existsSync.mockImplementation((filePath) => { + return filePath === expectedIndexPath; + }); + + const result = checkWebviewFilesExist(webviewPath); + + expect(result).toBe(true); + expect(mockedFs.existsSync).toHaveBeenCalledWith(expectedIndexPath); + }); + }); + + describe("buildWebviewHtml", () => { + const mockedFs = fs as jest.Mocked; + + let mockExtensionUri: vscode.Uri; + let mockWebview: vscode.Webview; + let mockAssetsUri: vscode.Uri; + + beforeEach(() => { + jest.clearAllMocks(); + + mockExtensionUri = { + fsPath: "/test/extension/path" + } as vscode.Uri; + + mockWebview = { + cspSource: "vscode-webview://test-source", + asWebviewUri: jest.fn() + } as unknown as vscode.Webview; + + mockAssetsUri = { + toString: () => "vscode-webview://assets-uri" + } as vscode.Uri; + + (mockWebview.asWebviewUri as jest.Mock).mockReturnValue(mockAssetsUri); + (vscode.Uri.file as jest.Mock).mockReturnValue(mockAssetsUri); + }); + + it("should return fallback HTML when webview files do not exist", () => { + const webviewPath = path.join(mockExtensionUri.fsPath, "web-view-dist"); + const indexPath = path.join(webviewPath, "index.html"); + + mockedFs.existsSync.mockImplementation((filePath) => filePath !== indexPath); + + const result = buildWebviewHtml(mockExtensionUri, mockWebview); + + expect(result).toContain("Configuration UI Not Available"); + expect(result).toContain("cd src/web-view && npm run build"); + expect(mockedFs.existsSync).toHaveBeenCalledWith(indexPath); + }); + + it("should process HTML file when webview files exist", () => { + const webviewPath = path.join(mockExtensionUri.fsPath, "web-view-dist"); + const indexPath = path.join(webviewPath, "index.html"); + const mockHtml = 'Test'; + + mockedFs.existsSync.mockImplementation((filePath) => filePath === indexPath); + mockedFs.readFileSync.mockReturnValue(mockHtml); + + const result = buildWebviewHtml(mockExtensionUri, mockWebview); + + expect(result).toBeDefined(); + expect(mockedFs.existsSync).toHaveBeenCalledWith(indexPath); + expect(mockedFs.readFileSync).toHaveBeenCalledWith(indexPath, "utf8"); + expect(vscode.Uri.file).toHaveBeenCalledWith(path.join(webviewPath, "assets")); + expect(mockWebview.asWebviewUri).toHaveBeenCalledWith(mockAssetsUri); + }); + + it("should replace asset paths and inject security content", () => { + const webviewPath = path.join(mockExtensionUri.fsPath, "web-view-dist"); + const indexPath = path.join(webviewPath, "index.html"); + const mockHtml = 'Test'; + + mockedFs.existsSync.mockImplementation((filePath) => filePath === indexPath); + mockedFs.readFileSync.mockReturnValue(mockHtml); + + const result = buildWebviewHtml(mockExtensionUri, mockWebview); + + // Check asset path replacement + expect(result).toContain('src="vscode-webview://assets-uri/icon.png"'); + expect(result).toContain('src="vscode-webview://assets-uri/script.js"'); + + // Check security injection + expect(result).toContain(' { + const webviewPath = path.join(mockExtensionUri.fsPath, "web-view-dist"); + const indexPath = path.join(webviewPath, "index.html"); + const mockHtml = ` + + + Complex Test + + + + + logo + + + + + `; + + mockedFs.existsSync.mockImplementation((filePath) => filePath === indexPath); + mockedFs.readFileSync.mockReturnValue(mockHtml); + + const result = buildWebviewHtml(mockExtensionUri, mockWebview); + + expect(result).toContain('href="vscode-webview://assets-uri/styles/main.css"'); + expect(result).toContain('href="vscode-webview://assets-uri/favicon.ico"'); + expect(result).toContain('src="vscode-webview://assets-uri/images/logo.png"'); + expect(result).toContain('src="vscode-webview://assets-uri/js/main.js"'); + expect(result).toContain('src="vscode-webview://assets-uri/js/utils.js"'); + }); + + it("should handle empty HTML file", () => { + const webviewPath = path.join(mockExtensionUri.fsPath, "web-view-dist"); + const indexPath = path.join(webviewPath, "index.html"); + const mockHtml = ""; + + mockedFs.existsSync.mockImplementation((filePath) => filePath === indexPath); + mockedFs.readFileSync.mockReturnValue(mockHtml); + + const result = buildWebviewHtml(mockExtensionUri, mockWebview); + + expect(result).toBe(""); + expect(mockedFs.readFileSync).toHaveBeenCalledWith(indexPath, "utf8"); + }); + + it("should handle HTML without assets paths", () => { + const webviewPath = path.join(mockExtensionUri.fsPath, "web-view-dist"); + const indexPath = path.join(webviewPath, "index.html"); + const mockHtml = 'No Assets
Simple content
'; + + mockedFs.existsSync.mockImplementation((filePath) => filePath === indexPath); + mockedFs.readFileSync.mockReturnValue(mockHtml); + + const result = buildWebviewHtml(mockExtensionUri, mockWebview); + + expect(result).toContain('
Simple content
'); + expect(result).toContain(' { + const mockConfig = { + update: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + (vscode.workspace.getConfiguration as jest.Mock).mockReturnValue(mockConfig); + mockConfig.update.mockResolvedValue(undefined); + }); + + it("should successfully update button configuration and show success message", async () => { + const buttons = [ + { name: "Test Button", command: "echo test" }, + { name: "Group Button", group: [{ name: "Sub Button", command: "echo sub" }] } + ]; + + await updateButtonConfiguration(buttons); + + expect(vscode.workspace.getConfiguration).toHaveBeenCalledWith("quickCommandButtons"); + expect(mockConfig.update).toHaveBeenCalledWith( + "buttons", + buttons, + vscode.ConfigurationTarget.Workspace + ); + expect(vscode.window.showInformationMessage).toHaveBeenCalledWith("Configuration updated successfully!"); + expect(vscode.window.showErrorMessage).not.toHaveBeenCalled(); + }); + + it("should handle empty button array", async () => { + const buttons: any[] = []; + + await updateButtonConfiguration(buttons); + + expect(vscode.workspace.getConfiguration).toHaveBeenCalledWith("quickCommandButtons"); + expect(mockConfig.update).toHaveBeenCalledWith( + "buttons", + buttons, + vscode.ConfigurationTarget.Workspace + ); + expect(vscode.window.showInformationMessage).toHaveBeenCalledWith("Configuration updated successfully!"); + }); + + it("should handle button configuration with all properties", async () => { + const buttons = [ + { + name: "Complex Button", + command: "echo complex", + useVsCodeApi: true, + color: "#FF0000", + terminalName: "custom-terminal", + shortcut: "c", + executeAll: false + } + ]; + + await updateButtonConfiguration(buttons); + + expect(mockConfig.update).toHaveBeenCalledWith( + "buttons", + buttons, + vscode.ConfigurationTarget.Workspace + ); + expect(vscode.window.showInformationMessage).toHaveBeenCalledWith("Configuration updated successfully!"); + }); + + it("should handle nested group configurations", async () => { + const buttons = [ + { + name: "Parent Group", + group: [ + { name: "Child 1", command: "echo child1" }, + { + name: "Nested Group", + group: [ + { name: "Deep Child", command: "echo deep" } + ] + } + ] + } + ]; + + await updateButtonConfiguration(buttons); + + expect(mockConfig.update).toHaveBeenCalledWith( + "buttons", + buttons, + vscode.ConfigurationTarget.Workspace + ); + expect(vscode.window.showInformationMessage).toHaveBeenCalledWith("Configuration updated successfully!"); + }); + + it("should show error message when configuration update fails", async () => { + const buttons = [{ name: "Test Button", command: "echo test" }]; + const error = new Error("Configuration update failed"); + mockConfig.update.mockRejectedValue(error); + + // Mock console.error to avoid noise in test output + const consoleSpy = jest.spyOn(console, 'error').mockImplementation(); + + await updateButtonConfiguration(buttons); + + expect(vscode.workspace.getConfiguration).toHaveBeenCalledWith("quickCommandButtons"); + expect(mockConfig.update).toHaveBeenCalledWith( + "buttons", + buttons, + vscode.ConfigurationTarget.Workspace + ); + expect(vscode.window.showErrorMessage).toHaveBeenCalledWith( + "Failed to update configuration. Please try again." + ); + expect(vscode.window.showInformationMessage).not.toHaveBeenCalled(); + expect(consoleSpy).toHaveBeenCalledWith("Failed to update configuration:", error); + + consoleSpy.mockRestore(); + }); + + it("should handle workspace configuration service error", async () => { + const buttons = [{ name: "Test Button", command: "echo test" }]; + const error = new Error("Workspace service unavailable"); + (vscode.workspace.getConfiguration as jest.Mock).mockImplementation(() => { + throw error; + }); + + // Mock console.error to avoid noise in test output + const consoleSpy = jest.spyOn(console, 'error').mockImplementation(); + + await updateButtonConfiguration(buttons); + + expect(vscode.window.showErrorMessage).toHaveBeenCalledWith( + "Failed to update configuration. Please try again." + ); + expect(vscode.window.showInformationMessage).not.toHaveBeenCalled(); + expect(consoleSpy).toHaveBeenCalledWith("Failed to update configuration:", error); + + consoleSpy.mockRestore(); + }); + }); +}); diff --git a/src/extension/src/webview-provider.ts b/src/extension/src/webview-provider.ts index 1cb09119..0231956d 100644 --- a/src/extension/src/webview-provider.ts +++ b/src/extension/src/webview-provider.ts @@ -4,6 +4,93 @@ import * as fs from "fs"; import { ButtonConfig } from "./types"; import { ConfigReader } from "./adapters"; +export const generateFallbackHtml = (): string => { + return ` + + + + + + Configuration UI + + +
+

Configuration UI Not Available

+

Please build the web-view first:

+
cd src/web-view && npm run build
+
+ + + `; +}; + +export const replaceAssetPaths = ( + html: string, + assetsUri: vscode.Uri +): string => { + return html.replace(/\/assets\//g, `${assetsUri}/`); +}; + +export const injectSecurityAndVSCodeApi = ( + html: string, + webview: vscode.Webview +): string => { + return html.replace( + "", + ` + + ` + ); +}; + +export const checkWebviewFilesExist = (webviewPath: string): boolean => { + const indexPath = path.join(webviewPath, "index.html"); + return fs.existsSync(indexPath); +}; + +export const buildWebviewHtml = ( + extensionUri: vscode.Uri, + webview: vscode.Webview +): string => { + const webviewPath = path.join(extensionUri.fsPath, "web-view-dist"); + + if (!checkWebviewFilesExist(webviewPath)) { + return generateFallbackHtml(); + } + + const indexPath = path.join(webviewPath, "index.html"); + let html = fs.readFileSync(indexPath, "utf8"); + + const assetsPath = vscode.Uri.file(path.join(webviewPath, "assets")); + const assetsUri = webview.asWebviewUri(assetsPath); + + html = replaceAssetPaths(html, assetsUri); + html = injectSecurityAndVSCodeApi(html, webview); + + return html; +}; + +export const updateButtonConfiguration = async ( + buttons: ButtonConfig[] +): Promise => { + try { + const config = vscode.workspace.getConfiguration("quickCommandButtons"); + await config.update( + "buttons", + buttons, + vscode.ConfigurationTarget.Workspace + ); + vscode.window.showInformationMessage("Configuration updated successfully!"); + } catch (error) { + console.error("Failed to update configuration:", error); + vscode.window.showErrorMessage( + "Failed to update configuration. Please try again." + ); + } +}; + export class ConfigWebviewProvider implements vscode.WebviewViewProvider { public static readonly viewType = "quickCommandsConfig"; private _view?: vscode.WebviewView; @@ -43,71 +130,11 @@ export class ConfigWebviewProvider implements vscode.WebviewViewProvider { } private async _updateConfiguration(buttons: ButtonConfig[]) { - try { - const config = vscode.workspace.getConfiguration("quickCommandButtons"); - await config.update( - "buttons", - buttons, - vscode.ConfigurationTarget.Workspace - ); - vscode.window.showInformationMessage( - "Configuration updated successfully!" - ); - } catch (error) { - console.error("Failed to update configuration:", error); - vscode.window.showErrorMessage( - "Failed to update configuration. Please try again." - ); - } + await updateButtonConfiguration(buttons); } private _getHtmlForWebview(webview: vscode.Webview): string { - // Path to the built web-view files - const webviewPath = path.join(this._extensionUri.fsPath, "web-view-dist"); - - // Check if built files exist - const indexPath = path.join(webviewPath, "index.html"); - if (!fs.existsSync(indexPath)) { - return ` - - - - - - Configuration UI - - -
-

Configuration UI Not Available

-

Please build the web-view first:

-
cd src/web-view && npm run build
-
- - - `; - } - - // Read the built HTML file - let html = fs.readFileSync(indexPath, "utf8"); - - // Convert relative paths to webview URIs - const assetsPath = vscode.Uri.file(path.join(webviewPath, "assets")); - const assetsUri = webview.asWebviewUri(assetsPath); - - // Replace asset paths - html = html.replace(/\/assets\//g, `${assetsUri}/`); - - // Inject CSP and other necessary modifications - html = html.replace( - "", - ` - - ` - ); - - return html; + return buildWebviewHtml(this._extensionUri, webview); } public static createWebviewCommand( @@ -125,8 +152,7 @@ export class ConfigWebviewProvider implements vscode.WebviewViewProvider { } ); - const provider = new ConfigWebviewProvider(extensionUri, configReader); - panel.webview.html = provider._getHtmlForWebview(panel.webview); + panel.webview.html = buildWebviewHtml(extensionUri, panel.webview); panel.webview.onDidReceiveMessage(async (data) => { switch (data.type) { @@ -137,7 +163,7 @@ export class ConfigWebviewProvider implements vscode.WebviewViewProvider { }); break; case "setConfig": - await provider._updateConfiguration(data.data); + await updateButtonConfiguration(data.data); break; } }, undefined); diff --git a/src/extension/tsconfig.json b/src/extension/tsconfig.json index a720e18e..1f064c3a 100644 --- a/src/extension/tsconfig.json +++ b/src/extension/tsconfig.json @@ -9,7 +9,9 @@ "strict": true, "esModuleInterop": true, "skipLibCheck": true, - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "types": ["node", "jest", "vscode"] }, - "exclude": ["node_modules", ".vscode-test"] -} \ No newline at end of file + "exclude": ["node_modules", ".vscode-test", "coverage", "**/*.test.ts"] +} diff --git a/src/extension/yarn.lock b/src/extension/yarn.lock index 7dfb6b4b..827272a8 100644 --- a/src/extension/yarn.lock +++ b/src/extension/yarn.lock @@ -106,6 +106,296 @@ jsonwebtoken "^9.0.0" uuid "^8.3.0" +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.27.2": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.4.tgz#96fdf1af1b8859c8474ab39c295312bfb7c24b04" + integrity sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw== + +"@babel/core@^7.23.9", "@babel/core@^7.27.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.4.tgz#12a550b8794452df4c8b084f95003bce1742d496" + integrity sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.3" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.28.3" + "@babel/helpers" "^7.28.4" + "@babel/parser" "^7.28.4" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.4" + "@babel/types" "^7.28.4" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.27.5", "@babel/generator@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.3.tgz#9626c1741c650cbac39121694a0f2d7451b8ef3e" + integrity sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw== + dependencies: + "@babel/parser" "^7.28.3" + "@babel/types" "^7.28.2" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" + integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== + dependencies: + "@babel/compat-data" "^7.27.2" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-transforms@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz#a2b37d3da3b2344fe085dab234426f2b9a2fa5f6" + integrity sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.28.3" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.8.0": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" + integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.28.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.4.tgz#fe07274742e95bdf7cf1443593eeb8926ab63827" + integrity sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.4" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.27.2", "@babel/parser@^7.28.3", "@babel/parser@^7.28.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.4.tgz#da25d4643532890932cc03f7705fe19637e03fa8" + integrity sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg== + dependencies: + "@babel/types" "^7.28.4" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz#34c017d54496f9b11b61474e7ea3dfd5563ffe07" + integrity sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c" + integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18" + integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/template@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + +"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.3", "@babel/traverse@^7.28.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.4.tgz#8d456101b96ab175d487249f60680221692b958b" + integrity sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.3" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.4" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.4" + debug "^4.3.1" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.2", "@babel/types@^7.28.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.4.tgz#0a4e618f4c60a7cd6c11cb2d48060e4dbe38ac3a" + integrity sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@emnapi/core@^1.4.3": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.5.0.tgz#85cd84537ec989cebb2343606a1ee663ce4edaf0" + integrity sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg== + dependencies: + "@emnapi/wasi-threads" "1.1.0" + tslib "^2.4.0" + +"@emnapi/runtime@^1.4.3": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.5.0.tgz#9aebfcb9b17195dce3ab53c86787a6b7d058db73" + integrity sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf" + integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== + dependencies: + tslib "^2.4.0" + "@isaacs/balanced-match@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz#3081dadbc3460661b751e7591d7faea5df39dd29" @@ -130,6 +420,388 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + 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" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@30.1.2": + version "30.1.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-30.1.2.tgz#3d32b966454d57874520b27647129228a654c995" + integrity sha512-BGMAxj8VRmoD0MoA/jo9alMXSRoqW8KPeqOfEo1ncxnRLatTBCpRoOwlwlEMdudp68Q6WSGwYrrLtTGOh8fLzw== + dependencies: + "@jest/types" "30.0.5" + "@types/node" "*" + chalk "^4.1.2" + jest-message-util "30.1.0" + jest-util "30.0.5" + slash "^3.0.0" + +"@jest/core@30.1.3": + version "30.1.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-30.1.3.tgz#c097dcead36ac6ccee2825a35078163465f8b79d" + integrity sha512-LIQz7NEDDO1+eyOA2ZmkiAyYvZuo6s1UxD/e2IHldR6D7UYogVq3arTmli07MkENLq6/3JEQjp0mA8rrHHJ8KQ== + dependencies: + "@jest/console" "30.1.2" + "@jest/pattern" "30.0.1" + "@jest/reporters" "30.1.3" + "@jest/test-result" "30.1.3" + "@jest/transform" "30.1.2" + "@jest/types" "30.0.5" + "@types/node" "*" + ansi-escapes "^4.3.2" + chalk "^4.1.2" + ci-info "^4.2.0" + exit-x "^0.2.2" + graceful-fs "^4.2.11" + jest-changed-files "30.0.5" + jest-config "30.1.3" + jest-haste-map "30.1.0" + jest-message-util "30.1.0" + jest-regex-util "30.0.1" + jest-resolve "30.1.3" + jest-resolve-dependencies "30.1.3" + jest-runner "30.1.3" + jest-runtime "30.1.3" + jest-snapshot "30.1.2" + jest-util "30.0.5" + jest-validate "30.1.0" + jest-watcher "30.1.3" + micromatch "^4.0.8" + pretty-format "30.0.5" + slash "^3.0.0" + +"@jest/diff-sequences@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz#0ededeae4d071f5c8ffe3678d15f3a1be09156be" + integrity sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw== + +"@jest/environment@30.1.2": + version "30.1.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-30.1.2.tgz#f1bd73a7571f96104a3ff2007747c2ce12b5c038" + integrity sha512-N8t1Ytw4/mr9uN28OnVf0SYE2dGhaIxOVYcwsf9IInBKjvofAjbFRvedvBBlyTYk2knbJTiEjEJ2PyyDIBnd9w== + dependencies: + "@jest/fake-timers" "30.1.2" + "@jest/types" "30.0.5" + "@types/node" "*" + jest-mock "30.0.5" + +"@jest/expect-utils@30.1.2": + version "30.1.2" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-30.1.2.tgz#88ea18040f707c9fadb6fd9e77568cae5266cee8" + integrity sha512-HXy1qT/bfdjCv7iC336ExbqqYtZvljrV8odNdso7dWK9bSeHtLlvwWWC3YSybSPL03Gg5rug6WLCZAZFH72m0A== + dependencies: + "@jest/get-type" "30.1.0" + +"@jest/expect@30.1.2": + version "30.1.2" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-30.1.2.tgz#35283e8bd083aab6cc26d4d30aeeacb5e7190a0f" + integrity sha512-tyaIExOwQRCxPCGNC05lIjWJztDwk2gPDNSDGg1zitXJJ8dC3++G/CRjE5mb2wQsf89+lsgAgqxxNpDLiCViTA== + dependencies: + expect "30.1.2" + jest-snapshot "30.1.2" + +"@jest/fake-timers@30.1.2": + version "30.1.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-30.1.2.tgz#cb0df6995034d50c6973ffd3ffdaa1353a816c41" + integrity sha512-Beljfv9AYkr9K+ETX9tvV61rJTY706BhBUtiaepQHeEGfe0DbpvUA5Z3fomwc5Xkhns6NWrcFDZn+72fLieUnA== + dependencies: + "@jest/types" "30.0.5" + "@sinonjs/fake-timers" "^13.0.0" + "@types/node" "*" + jest-message-util "30.1.0" + jest-mock "30.0.5" + jest-util "30.0.5" + +"@jest/get-type@30.1.0": + version "30.1.0" + resolved "https://registry.yarnpkg.com/@jest/get-type/-/get-type-30.1.0.tgz#4fcb4dc2ebcf0811be1c04fd1cb79c2dba431cbc" + integrity sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA== + +"@jest/globals@30.1.2", "@jest/globals@^30.1.2": + version "30.1.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-30.1.2.tgz#821cad7d8ef3dc145979088bb0bfbc1f81a5d8ce" + integrity sha512-teNTPZ8yZe3ahbYnvnVRDeOjr+3pu2uiAtNtrEsiMjVPPj+cXd5E/fr8BL7v/T7F31vYdEHrI5cC/2OoO/vM9A== + dependencies: + "@jest/environment" "30.1.2" + "@jest/expect" "30.1.2" + "@jest/types" "30.0.5" + jest-mock "30.0.5" + +"@jest/pattern@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/pattern/-/pattern-30.0.1.tgz#d5304147f49a052900b4b853dedb111d080e199f" + integrity sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA== + dependencies: + "@types/node" "*" + jest-regex-util "30.0.1" + +"@jest/reporters@30.1.3": + version "30.1.3" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-30.1.3.tgz#015b5838b3edf60f6e995186cd805b7fcbac86b3" + integrity sha512-VWEQmJWfXMOrzdFEOyGjUEOuVXllgZsoPtEHZzfdNz18RmzJ5nlR6kp8hDdY8dDS1yGOXAY7DHT+AOHIPSBV0w== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "30.1.2" + "@jest/test-result" "30.1.3" + "@jest/transform" "30.1.2" + "@jest/types" "30.0.5" + "@jridgewell/trace-mapping" "^0.3.25" + "@types/node" "*" + chalk "^4.1.2" + collect-v8-coverage "^1.0.2" + exit-x "^0.2.2" + glob "^10.3.10" + graceful-fs "^4.2.11" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^5.0.0" + istanbul-reports "^3.1.3" + jest-message-util "30.1.0" + jest-util "30.0.5" + jest-worker "30.1.0" + slash "^3.0.0" + string-length "^4.0.2" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-30.0.5.tgz#7bdf69fc5a368a5abdb49fd91036c55225846473" + integrity sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA== + dependencies: + "@sinclair/typebox" "^0.34.0" + +"@jest/snapshot-utils@30.1.2": + version "30.1.2" + resolved "https://registry.yarnpkg.com/@jest/snapshot-utils/-/snapshot-utils-30.1.2.tgz#320500eba29a25c33e9ec968154e521873624309" + integrity sha512-vHoMTpimcPSR7OxS2S0V1Cpg8eKDRxucHjoWl5u4RQcnxqQrV3avETiFpl8etn4dqxEGarBeHbIBety/f8mLXw== + dependencies: + "@jest/types" "30.0.5" + chalk "^4.1.2" + graceful-fs "^4.2.11" + natural-compare "^1.4.0" + +"@jest/source-map@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-30.0.1.tgz#305ebec50468f13e658b3d5c26f85107a5620aaa" + integrity sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.25" + callsites "^3.1.0" + graceful-fs "^4.2.11" + +"@jest/test-result@30.1.3": + version "30.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-30.1.3.tgz#69fe7ff93da8c0c47bae245727e0ce23571d058e" + integrity sha512-P9IV8T24D43cNRANPPokn7tZh0FAFnYS2HIfi5vK18CjRkTDR9Y3e1BoEcAJnl4ghZZF4Ecda4M/k41QkvurEQ== + dependencies: + "@jest/console" "30.1.2" + "@jest/types" "30.0.5" + "@types/istanbul-lib-coverage" "^2.0.6" + collect-v8-coverage "^1.0.2" + +"@jest/test-sequencer@30.1.3": + version "30.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-30.1.3.tgz#df64038d46150e704ed07c5fee4626609f518089" + integrity sha512-82J+hzC0qeQIiiZDThh+YUadvshdBswi5nuyXlEmXzrhw5ZQSRHeQ5LpVMD/xc8B3wPePvs6VMzHnntxL+4E3w== + dependencies: + "@jest/test-result" "30.1.3" + graceful-fs "^4.2.11" + jest-haste-map "30.1.0" + slash "^3.0.0" + +"@jest/transform@30.1.2": + version "30.1.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-30.1.2.tgz#42624a9c89f2427cd413b989aaf9f6aeb58cae56" + integrity sha512-UYYFGifSgfjujf1Cbd3iU/IQoSd6uwsj8XHj5DSDf5ERDcWMdJOPTkHWXj4U+Z/uMagyOQZ6Vne8C4nRIrCxqA== + dependencies: + "@babel/core" "^7.27.4" + "@jest/types" "30.0.5" + "@jridgewell/trace-mapping" "^0.3.25" + babel-plugin-istanbul "^7.0.0" + chalk "^4.1.2" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.11" + jest-haste-map "30.1.0" + jest-regex-util "30.0.1" + jest-util "30.0.5" + micromatch "^4.0.8" + pirates "^4.0.7" + slash "^3.0.0" + write-file-atomic "^5.0.1" + +"@jest/types@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-30.0.5.tgz#29a33a4c036e3904f1cfd94f6fe77f89d2e1cc05" + integrity sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ== + dependencies: + "@jest/pattern" "30.0.1" + "@jest/schemas" "30.0.5" + "@types/istanbul-lib-coverage" "^2.0.6" + "@types/istanbul-reports" "^3.0.4" + "@types/node" "*" + "@types/yargs" "^17.0.33" + chalk "^4.1.2" + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.23", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@napi-rs/wasm-runtime@^0.2.11": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.10.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@pkgr/core@^0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.9.tgz#d229a7b7f9dac167a156992ef23c7f023653f53b" + integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA== + +"@sinclair/typebox@^0.34.0": + version "0.34.41" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.34.41.tgz#aa51a6c1946df2c5a11494a2cdb9318e026db16c" + integrity sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g== + +"@sinonjs/commons@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^13.0.0": + version "13.0.5" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz#36b9dbc21ad5546486ea9173d6bea063eb1717d5" + integrity sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw== + dependencies: + "@sinonjs/commons" "^3.0.1" + +"@tybys/wasm-util@^0.10.0": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414" + integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== + dependencies: + tslib "^2.4.0" + +"@types/babel__core@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== + dependencies: + "@babel/types" "^7.28.2" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.1", "@types/istanbul-lib-coverage@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^30.0.0": + version "30.0.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-30.0.0.tgz#5e85ae568006712e4ad66f25433e9bdac8801f1d" + integrity sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA== + dependencies: + expect "^30.0.0" + pretty-format "^30.0.0" + +"@types/node@*": + version "24.4.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.4.0.tgz#4ca9168c016a55ab15b7765ad1674ab807489600" + integrity sha512-gUuVEAK4/u6F9wRLznPUU4WGUacSEBDPoC2TrBkw3GAnOLHBL45QdfHOXp1kJ4ypBGLxTOB+t7NJLpKoC3gznQ== + dependencies: + undici-types "~7.11.0" + "@types/node@24.3.0": version "24.3.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-24.3.0.tgz#89b09f45cb9a8ee69466f18ee5864e4c3eb84dec" @@ -137,11 +809,28 @@ dependencies: undici-types "~7.10.0" +"@types/stack-utils@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + "@types/vscode@^1.90.0": version "1.103.0" resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.103.0.tgz#4a0d9777d952992c9ebdbe8dad067032d2fbc1fb" integrity sha512-o4hanZAQdNfsKecexq9L3eHICd0AAvdbLk6hA60UzGXbGH/q8b/9xv2RgR7vV3ZcHuyKVq7b37IGd/+gM4Tu+Q== +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.33": + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== + dependencies: + "@types/yargs-parser" "*" + "@typespec/ts-http-runtime@^0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.0.tgz#f506ff2170e594a257f8e78aa196088f3a46a22d" @@ -151,6 +840,108 @@ https-proxy-agent "^7.0.0" tslib "^2.6.2" +"@ungap/structured-clone@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== + +"@unrs/resolver-binding-android-arm-eabi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz#9f5b04503088e6a354295e8ea8fe3cb99e43af81" + integrity sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw== + +"@unrs/resolver-binding-android-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz#7414885431bd7178b989aedc4d25cccb3865bc9f" + integrity sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g== + +"@unrs/resolver-binding-darwin-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz#b4a8556f42171fb9c9f7bac8235045e82aa0cbdf" + integrity sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g== + +"@unrs/resolver-binding-darwin-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz#fd4d81257b13f4d1a083890a6a17c00de571f0dc" + integrity sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ== + +"@unrs/resolver-binding-freebsd-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz#d2513084d0f37c407757e22f32bd924a78cfd99b" + integrity sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw== + +"@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz#844d2605d057488d77fab09705f2866b86164e0a" + integrity sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw== + +"@unrs/resolver-binding-linux-arm-musleabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz#204892995cefb6bd1d017d52d097193bc61ddad3" + integrity sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw== + +"@unrs/resolver-binding-linux-arm64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz#023eb0c3aac46066a10be7a3f362e7b34f3bdf9d" + integrity sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ== + +"@unrs/resolver-binding-linux-arm64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz#9e6f9abb06424e3140a60ac996139786f5d99be0" + integrity sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w== + +"@unrs/resolver-binding-linux-ppc64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz#b111417f17c9d1b02efbec8e08398f0c5527bb44" + integrity sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA== + +"@unrs/resolver-binding-linux-riscv64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz#92ffbf02748af3e99873945c9a8a5ead01d508a9" + integrity sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ== + +"@unrs/resolver-binding-linux-riscv64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz#0bec6f1258fc390e6b305e9ff44256cb207de165" + integrity sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew== + +"@unrs/resolver-binding-linux-s390x-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz#577843a084c5952f5906770633ccfb89dac9bc94" + integrity sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg== + +"@unrs/resolver-binding-linux-x64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz#36fb318eebdd690f6da32ac5e0499a76fa881935" + integrity sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w== + +"@unrs/resolver-binding-linux-x64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz#bfb9af75f783f98f6a22c4244214efe4df1853d6" + integrity sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA== + +"@unrs/resolver-binding-wasm32-wasi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz#752c359dd875684b27429500d88226d7cc72f71d" + integrity sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ== + dependencies: + "@napi-rs/wasm-runtime" "^0.2.11" + +"@unrs/resolver-binding-win32-arm64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz#ce5735e600e4c2fbb409cd051b3b7da4a399af35" + integrity sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw== + +"@unrs/resolver-binding-win32-ia32-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz#72fc57bc7c64ec5c3de0d64ee0d1810317bc60a6" + integrity sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ== + +"@unrs/resolver-binding-win32-x64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz#538b1e103bf8d9864e7b85cc96fa8d6fb6c40777" + integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g== + "@vscode/vsce-sign-alpine-arm64@2.0.5": version "2.0.5" resolved "https://registry.yarnpkg.com/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.5.tgz#e34cbf91f4e86a6cf52abc2e6e75084ae18f6c4a" @@ -248,6 +1039,13 @@ agent-base@^7.1.0, agent-base@^7.1.2: resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.4.tgz#e3cd76d4c548ee895d3c3fd8dc1f6c5b9032e7a8" integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ== +ansi-escapes@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -265,18 +1063,38 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" +ansi-styles@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + ansi-styles@^6.1.0: version "6.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== +anymatch@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -295,6 +1113,68 @@ azure-devops-node-api@^12.5.0: tunnel "0.0.6" typed-rest-client "^1.8.4" +babel-jest@30.1.2: + version "30.1.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-30.1.2.tgz#decd53b3a0cafca49443f93fb7a2c0fba55510da" + integrity sha512-IQCus1rt9kaSh7PQxLYRY5NmkNrNlU2TpabzwV7T2jljnpdHOcmnYYv8QmE04Li4S3a2Lj8/yXyET5pBarPr6g== + dependencies: + "@jest/transform" "30.1.2" + "@types/babel__core" "^7.20.5" + babel-plugin-istanbul "^7.0.0" + babel-preset-jest "30.0.1" + chalk "^4.1.2" + graceful-fs "^4.2.11" + slash "^3.0.0" + +babel-plugin-istanbul@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz#d8b518c8ea199364cf84ccc82de89740236daf92" + integrity sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-instrument "^6.0.2" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@30.0.1: + version "30.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.0.1.tgz#f271b2066d2c1fb26a863adb8e13f85b06247125" + integrity sha512-zTPME3pI50NsFW8ZBaVIOeAxzEY7XHlmWeXXu9srI+9kNfzCUTy8MFan46xOGZY8NZThMqq+e3qZUKsvXbasnQ== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.27.3" + "@types/babel__core" "^7.20.5" + +babel-preset-current-node-syntax@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz#20730d6cdc7dda5d89401cab10ac6a32067acde6" + integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg== + 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" + +babel-preset-jest@30.0.1: + version "30.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-30.0.1.tgz#7d28db9531bce264e846c8483d54236244b8ae88" + integrity sha512-+YHejD5iTWI46cZmcc/YtX4gaKBtdqCHCVfuVinizVpbmyjO3zYmeuyFdfA8duRqQZfgCAMlsfmkVbJ+e2MAJw== + dependencies: + babel-plugin-jest-hoist "30.0.1" + babel-preset-current-node-syntax "^1.1.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -305,6 +1185,11 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +baseline-browser-mapping@^2.8.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.8.3.tgz#e52e1d836fd242384ee152dce7b62952e4442619" + integrity sha512-mcE+Wr2CAhHNWxXN/DdTI+n4gsPc5QpXpWnyCQWiQYIYZX+ZMJ8juXZgjRa/0/YPJo/NSsgW15/YgmI4nbysYw== + bl@^4.0.3: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -327,6 +1212,45 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.24.0: + version "4.26.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.26.0.tgz#035ca84b4ff312a3c6a7014a77beb83456a882dd" + integrity sha512-P9go2WrP9FiPwLv3zqRD/Uoxo0RSHjzFCiQz7d4vbmwNqQFo9T9WCeP/Qn5EbcKQY6DBbkxEXNcpJOmncNrb7A== + dependencies: + baseline-browser-mapping "^2.8.2" + caniuse-lite "^1.0.30001741" + electron-to-chromium "^1.5.218" + node-releases "^2.0.21" + update-browserslist-db "^1.1.3" + +bs-logger@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -337,6 +1261,11 @@ buffer-equal-constant-time@^1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" @@ -368,6 +1297,26 @@ call-bound@^1.0.2: call-bind-apply-helpers "^1.0.2" get-intrinsic "^1.3.0" +callsites@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001741: + version "1.0.30001741" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz#67fb92953edc536442f3c9da74320774aa523143" + integrity sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw== + chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -377,6 +1326,19 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + cheerio-select@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4" @@ -411,11 +1373,40 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +ci-info@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.3.0.tgz#c39b1013f8fdbd28cd78e62318357d02da160cd7" + integrity sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ== + +cjs-module-lexer@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz#586e87d4341cb2661850ece5190232ccdebcff8b" + integrity sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + cockatiel@^3.1.2: version "3.2.1" resolved "https://registry.yarnpkg.com/cockatiel/-/cockatiel-3.2.1.tgz#575f937bc4040a20ae27352a6d07c9c5a741981f" integrity sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q== +collect-v8-coverage@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -457,7 +1448,12 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -cross-spawn@^7.0.6: +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cross-spawn@^7.0.3, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -489,6 +1485,13 @@ debug@4, debug@^4.3.4: dependencies: ms "^2.1.3" +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + decompress-response@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" @@ -496,11 +1499,21 @@ decompress-response@^6.0.0: dependencies: mimic-response "^3.1.0" +dedent@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.7.0.tgz#c1f9445335f0175a96587be245a282ff451446ca" + integrity sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ== + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +deepmerge@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + default-browser-id@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-5.0.0.tgz#a1d98bf960c15082d8a3fa69e83150ccccc3af26" @@ -529,6 +1542,11 @@ detect-libc@^2.0.0: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== +detect-newline@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + dom-serializer@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" @@ -580,6 +1598,16 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" +electron-to-chromium@^1.5.218: + version "1.5.218" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.218.tgz#921042a011a98a4620853c9d391ab62bcc124400" + integrity sha512-uwwdN0TUHs8u6iRgN8vKeWZMRll4gBkz+QMqdS7DDe49uiK68/UX92lFb61oiFPrpYZNeZIqa4bA7O6Aiasnzg== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -620,6 +1648,13 @@ entities@~2.1.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + es-define-property@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" @@ -647,16 +1682,75 @@ es-set-tostringtag@^2.1.0: has-tostringtag "^1.0.2" hasown "^2.0.2" +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +execa@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + 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" + +exit-x@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/exit-x/-/exit-x-0.2.2.tgz#1f9052de3b8d99a696b10dad5bced9bdd5c3aa64" + integrity sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ== + expand-template@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== +expect@30.1.2, expect@^30.0.0: + version "30.1.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-30.1.2.tgz#094909c2443f76b9e208fafac4a315aaaf924580" + integrity sha512-xvHszRavo28ejws8FpemjhwswGj4w/BetHIL8cU49u4sGyXDw2+p3YbeDbj6xzlxi6kWTjIRSTJ+9sNXPnF0Zg== + dependencies: + "@jest/expect-utils" "30.1.2" + "@jest/get-type" "30.1.0" + jest-matcher-utils "30.1.2" + jest-message-util "30.1.0" + jest-mock "30.0.5" + jest-util "30.0.5" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fb-watchman@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -664,7 +1758,22 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -foreground-child@^3.3.1: +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +foreground-child@^3.1.0, foreground-child@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== @@ -688,11 +1797,31 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" @@ -709,6 +1838,11 @@ get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: hasown "^2.0.2" math-intrinsics "^1.1.0" +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + get-proto@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" @@ -717,11 +1851,28 @@ get-proto@^1.0.1: dunder-proto "^1.0.1" es-object-atoms "^1.0.0" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + github-from-package@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== +glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^11.0.0: version "11.0.3" resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.3.tgz#9d8087e6d72ddb3c4707b1d2778f80ea3eaefcd6" @@ -734,16 +1885,50 @@ glob@^11.0.0: package-json-from-dist "^1.0.0" path-scurry "^2.0.0" +glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + 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" + gopd@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== +graceful-fs@^4.2.11: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +handlebars@^4.7.8: + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.2" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + has-symbols@^1.0.3, has-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" @@ -770,6 +1955,11 @@ hosted-git-info@^4.0.2: dependencies: lru-cache "^6.0.0" +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + htmlparser2@^10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-10.0.0.tgz#77ad249037b66bf8cc99c6e286ef73b83aeb621d" @@ -796,6 +1986,11 @@ https-proxy-agent@^7.0.0: agent-base "^7.1.2" debug "4" +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + iconv-lite@0.6.3, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -808,7 +2003,28 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -inherits@^2.0.3, inherits@^2.0.4: +import-local@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -818,6 +2034,11 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + is-docker@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" @@ -828,6 +2049,11 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-generator-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + is-inside-container@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" @@ -835,6 +2061,16 @@ is-inside-container@^1.0.0: dependencies: is-docker "^3.0.0" +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-wsl@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-3.1.0.tgz#e1c657e39c10090afcbedec61720f6b924c3cbd2" @@ -847,6 +2083,57 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^6.0.0, istanbul-lib-instrument@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + 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" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^5.0.0: + version "5.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz#acaef948df7747c8eb5fbf1265cb980f6353a441" + integrity sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A== + dependencies: + "@jridgewell/trace-mapping" "^0.3.23" + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + +istanbul-reports@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93" + integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jackspeak@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.1.1.tgz#96876030f450502047fc7e8c7fcf8ce8124e43ae" @@ -854,6 +2141,390 @@ jackspeak@^4.1.1: dependencies: "@isaacs/cliui" "^8.0.2" +jest-changed-files@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-30.0.5.tgz#ec448f83bd9caa894dd7da8707f207c356a19924" + integrity sha512-bGl2Ntdx0eAwXuGpdLdVYVr5YQHnSZlQ0y9HVDu565lCUAe9sj6JOtBbMmBBikGIegne9piDDIOeiLVoqTkz4A== + dependencies: + execa "^5.1.1" + jest-util "30.0.5" + p-limit "^3.1.0" + +jest-circus@30.1.3: + version "30.1.3" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-30.1.3.tgz#7ee0089f22b2b3e72ab04aee8e037c364a6d73d1" + integrity sha512-Yf3dnhRON2GJT4RYzM89t/EXIWNxKTpWTL9BfF3+geFetWP4XSvJjiU1vrWplOiUkmq8cHLiwuhz+XuUp9DscA== + dependencies: + "@jest/environment" "30.1.2" + "@jest/expect" "30.1.2" + "@jest/test-result" "30.1.3" + "@jest/types" "30.0.5" + "@types/node" "*" + chalk "^4.1.2" + co "^4.6.0" + dedent "^1.6.0" + is-generator-fn "^2.1.0" + jest-each "30.1.0" + jest-matcher-utils "30.1.2" + jest-message-util "30.1.0" + jest-runtime "30.1.3" + jest-snapshot "30.1.2" + jest-util "30.0.5" + p-limit "^3.1.0" + pretty-format "30.0.5" + pure-rand "^7.0.0" + slash "^3.0.0" + stack-utils "^2.0.6" + +jest-cli@30.1.3: + version "30.1.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-30.1.3.tgz#3fb8dea88886379eb95a08f954bfc2ed17a9be4f" + integrity sha512-G8E2Ol3OKch1DEeIBl41NP7OiC6LBhfg25Btv+idcusmoUSpqUkbrneMqbW9lVpI/rCKb/uETidb7DNteheuAQ== + dependencies: + "@jest/core" "30.1.3" + "@jest/test-result" "30.1.3" + "@jest/types" "30.0.5" + chalk "^4.1.2" + exit-x "^0.2.2" + import-local "^3.2.0" + jest-config "30.1.3" + jest-util "30.0.5" + jest-validate "30.1.0" + yargs "^17.7.2" + +jest-config@30.1.3: + version "30.1.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-30.1.3.tgz#10bcf4cd979119bfac6a130fb79d837057ce33d4" + integrity sha512-M/f7gqdQEPgZNA181Myz+GXCe8jXcJsGjCMXUzRj22FIXsZOyHNte84e0exntOvdPaeh9tA0w+B8qlP2fAezfw== + dependencies: + "@babel/core" "^7.27.4" + "@jest/get-type" "30.1.0" + "@jest/pattern" "30.0.1" + "@jest/test-sequencer" "30.1.3" + "@jest/types" "30.0.5" + babel-jest "30.1.2" + chalk "^4.1.2" + ci-info "^4.2.0" + deepmerge "^4.3.1" + glob "^10.3.10" + graceful-fs "^4.2.11" + jest-circus "30.1.3" + jest-docblock "30.0.1" + jest-environment-node "30.1.2" + jest-regex-util "30.0.1" + jest-resolve "30.1.3" + jest-runner "30.1.3" + jest-util "30.0.5" + jest-validate "30.1.0" + micromatch "^4.0.8" + parse-json "^5.2.0" + pretty-format "30.0.5" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@30.1.2: + version "30.1.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-30.1.2.tgz#8ff4217e5b63fef49a5b37462999d8f5299a4eb4" + integrity sha512-4+prq+9J61mOVXCa4Qp8ZjavdxzrWQXrI80GNxP8f4tkI2syPuPrJgdRPZRrfUTRvIoUwcmNLbqEJy9W800+NQ== + dependencies: + "@jest/diff-sequences" "30.0.1" + "@jest/get-type" "30.1.0" + chalk "^4.1.2" + pretty-format "30.0.5" + +jest-docblock@30.0.1: + version "30.0.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-30.0.1.tgz#545ff59f2fa88996bd470dba7d3798a8421180b1" + integrity sha512-/vF78qn3DYphAaIc3jy4gA7XSAz167n9Bm/wn/1XhTLW7tTBIzXtCJpb/vcmc73NIIeeohCbdL94JasyXUZsGA== + dependencies: + detect-newline "^3.1.0" + +jest-each@30.1.0: + version "30.1.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-30.1.0.tgz#228756d5ea9e4dcb462fc2e90a44ec27dd482d23" + integrity sha512-A+9FKzxPluqogNahpCv04UJvcZ9B3HamqpDNWNKDjtxVRYB8xbZLFuCr8JAJFpNp83CA0anGQFlpQna9Me+/tQ== + dependencies: + "@jest/get-type" "30.1.0" + "@jest/types" "30.0.5" + chalk "^4.1.2" + jest-util "30.0.5" + pretty-format "30.0.5" + +jest-environment-node@30.1.2: + version "30.1.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-30.1.2.tgz#ae2f20442f8abc3c6b20120dc789fa38faff568f" + integrity sha512-w8qBiXtqGWJ9xpJIA98M0EIoq079GOQRQUyse5qg1plShUCQ0Ek1VTTcczqKrn3f24TFAgFtT+4q3aOXvjbsuA== + dependencies: + "@jest/environment" "30.1.2" + "@jest/fake-timers" "30.1.2" + "@jest/types" "30.0.5" + "@types/node" "*" + jest-mock "30.0.5" + jest-util "30.0.5" + jest-validate "30.1.0" + +jest-haste-map@30.1.0: + version "30.1.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-30.1.0.tgz#e54d84e07fac15ea3a98903b735048e36d7d2ed3" + integrity sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg== + dependencies: + "@jest/types" "30.0.5" + "@types/node" "*" + anymatch "^3.1.3" + fb-watchman "^2.0.2" + graceful-fs "^4.2.11" + jest-regex-util "30.0.1" + jest-util "30.0.5" + jest-worker "30.1.0" + micromatch "^4.0.8" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.3" + +jest-leak-detector@30.1.0: + version "30.1.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-30.1.0.tgz#8b86e7c5f1e3e4f2a32d930ec769103ad0985874" + integrity sha512-AoFvJzwxK+4KohH60vRuHaqXfWmeBATFZpzpmzNmYTtmRMiyGPVhkXpBqxUQunw+dQB48bDf4NpUs6ivVbRv1g== + dependencies: + "@jest/get-type" "30.1.0" + pretty-format "30.0.5" + +jest-matcher-utils@30.1.2: + version "30.1.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-30.1.2.tgz#3f1b63949f740025aff740c6c6a1b653ae370fbb" + integrity sha512-7ai16hy4rSbDjvPTuUhuV8nyPBd6EX34HkBsBcBX2lENCuAQ0qKCPb/+lt8OSWUa9WWmGYLy41PrEzkwRwoGZQ== + dependencies: + "@jest/get-type" "30.1.0" + chalk "^4.1.2" + jest-diff "30.1.2" + pretty-format "30.0.5" + +jest-message-util@30.1.0: + version "30.1.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-30.1.0.tgz#653a9bb1a33306eddf13455ce0666ba621b767c4" + integrity sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg== + dependencies: + "@babel/code-frame" "^7.27.1" + "@jest/types" "30.0.5" + "@types/stack-utils" "^2.0.3" + chalk "^4.1.2" + graceful-fs "^4.2.11" + micromatch "^4.0.8" + pretty-format "30.0.5" + slash "^3.0.0" + stack-utils "^2.0.6" + +jest-mock@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-30.0.5.tgz#ef437e89212560dd395198115550085038570bdd" + integrity sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ== + dependencies: + "@jest/types" "30.0.5" + "@types/node" "*" + jest-util "30.0.5" + +jest-pnp-resolver@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@30.0.1: + version "30.0.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-30.0.1.tgz#f17c1de3958b67dfe485354f5a10093298f2a49b" + integrity sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA== + +jest-resolve-dependencies@30.1.3: + version "30.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-30.1.3.tgz#04bbe95c9f4af51046dde940698d7121b49d0167" + integrity sha512-DNfq3WGmuRyHRHfEet+Zm3QOmVFtIarUOQHHryKPc0YL9ROfgWZxl4+aZq/VAzok2SS3gZdniP+dO4zgo59hBg== + dependencies: + jest-regex-util "30.0.1" + jest-snapshot "30.1.2" + +jest-resolve@30.1.3: + version "30.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-30.1.3.tgz#cc1019b28374ca7bcf7e58d57a4300449f390ec5" + integrity sha512-DI4PtTqzw9GwELFS41sdMK32Ajp3XZQ8iygeDMWkxlRhm7uUTOFSZFVZABFuxr0jvspn8MAYy54NxZCsuCTSOw== + dependencies: + chalk "^4.1.2" + graceful-fs "^4.2.11" + jest-haste-map "30.1.0" + jest-pnp-resolver "^1.2.3" + jest-util "30.0.5" + jest-validate "30.1.0" + slash "^3.0.0" + unrs-resolver "^1.7.11" + +jest-runner@30.1.3: + version "30.1.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-30.1.3.tgz#3253a0faab8f404aa9e0010911e8acbaf220865b" + integrity sha512-dd1ORcxQraW44Uz029TtXj85W11yvLpDuIzNOlofrC8GN+SgDlgY4BvyxJiVeuabA1t6idjNbX59jLd2oplOGQ== + dependencies: + "@jest/console" "30.1.2" + "@jest/environment" "30.1.2" + "@jest/test-result" "30.1.3" + "@jest/transform" "30.1.2" + "@jest/types" "30.0.5" + "@types/node" "*" + chalk "^4.1.2" + emittery "^0.13.1" + exit-x "^0.2.2" + graceful-fs "^4.2.11" + jest-docblock "30.0.1" + jest-environment-node "30.1.2" + jest-haste-map "30.1.0" + jest-leak-detector "30.1.0" + jest-message-util "30.1.0" + jest-resolve "30.1.3" + jest-runtime "30.1.3" + jest-util "30.0.5" + jest-watcher "30.1.3" + jest-worker "30.1.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@30.1.3: + version "30.1.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-30.1.3.tgz#bca7cb48d53c5b5ae21399e7a65e21271f500004" + integrity sha512-WS8xgjuNSphdIGnleQcJ3AKE4tBKOVP+tKhCD0u+Tb2sBmsU8DxfbBpZX7//+XOz81zVs4eFpJQwBNji2Y07DA== + dependencies: + "@jest/environment" "30.1.2" + "@jest/fake-timers" "30.1.2" + "@jest/globals" "30.1.2" + "@jest/source-map" "30.0.1" + "@jest/test-result" "30.1.3" + "@jest/transform" "30.1.2" + "@jest/types" "30.0.5" + "@types/node" "*" + chalk "^4.1.2" + cjs-module-lexer "^2.1.0" + collect-v8-coverage "^1.0.2" + glob "^10.3.10" + graceful-fs "^4.2.11" + jest-haste-map "30.1.0" + jest-message-util "30.1.0" + jest-mock "30.0.5" + jest-regex-util "30.0.1" + jest-resolve "30.1.3" + jest-snapshot "30.1.2" + jest-util "30.0.5" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@30.1.2: + version "30.1.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-30.1.2.tgz#4001a94d8394bb077a1c96246f0107c81aba4f12" + integrity sha512-4q4+6+1c8B6Cy5pGgFvjDy/Pa6VYRiGu0yQafKkJ9u6wQx4G5PqI2QR6nxTl43yy7IWsINwz6oT4o6tD12a8Dg== + dependencies: + "@babel/core" "^7.27.4" + "@babel/generator" "^7.27.5" + "@babel/plugin-syntax-jsx" "^7.27.1" + "@babel/plugin-syntax-typescript" "^7.27.1" + "@babel/types" "^7.27.3" + "@jest/expect-utils" "30.1.2" + "@jest/get-type" "30.1.0" + "@jest/snapshot-utils" "30.1.2" + "@jest/transform" "30.1.2" + "@jest/types" "30.0.5" + babel-preset-current-node-syntax "^1.1.0" + chalk "^4.1.2" + expect "30.1.2" + graceful-fs "^4.2.11" + jest-diff "30.1.2" + jest-matcher-utils "30.1.2" + jest-message-util "30.1.0" + jest-util "30.0.5" + pretty-format "30.0.5" + semver "^7.7.2" + synckit "^0.11.8" + +jest-util@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-30.0.5.tgz#035d380c660ad5f1748dff71c4105338e05f8669" + integrity sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g== + dependencies: + "@jest/types" "30.0.5" + "@types/node" "*" + chalk "^4.1.2" + ci-info "^4.2.0" + graceful-fs "^4.2.11" + picomatch "^4.0.2" + +jest-validate@30.1.0: + version "30.1.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-30.1.0.tgz#585aae6c9ee1ac138dbacbece8a7838ca7773e60" + integrity sha512-7P3ZlCFW/vhfQ8pE7zW6Oi4EzvuB4sgR72Q1INfW9m0FGo0GADYlPwIkf4CyPq7wq85g+kPMtPOHNAdWHeBOaA== + dependencies: + "@jest/get-type" "30.1.0" + "@jest/types" "30.0.5" + camelcase "^6.3.0" + chalk "^4.1.2" + leven "^3.1.0" + pretty-format "30.0.5" + +jest-watcher@30.1.3: + version "30.1.3" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-30.1.3.tgz#2f381da5c2c76a46c46ba2108e6607c585421dc0" + integrity sha512-6jQUZCP1BTL2gvG9E4YF06Ytq4yMb4If6YoQGRR6PpjtqOXSP3sKe2kqwB6SQ+H9DezOfZaSLnmka1NtGm3fCQ== + dependencies: + "@jest/test-result" "30.1.3" + "@jest/types" "30.0.5" + "@types/node" "*" + ansi-escapes "^4.3.2" + chalk "^4.1.2" + emittery "^0.13.1" + jest-util "30.0.5" + string-length "^4.0.2" + +jest-worker@30.1.0: + version "30.1.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-30.1.0.tgz#a89c36772be449d4bdb60697fb695a1673b12ac2" + integrity sha512-uvWcSjlwAAgIu133Tt77A05H7RIk3Ho8tZL50bQM2AkvLdluw9NG48lRCl3Dt+MOH719n/0nnb5YxUwcuJiKRA== + dependencies: + "@types/node" "*" + "@ungap/structured-clone" "^1.3.0" + jest-util "30.0.5" + merge-stream "^2.0.0" + supports-color "^8.1.1" + +jest@^30.1.3: + version "30.1.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-30.1.3.tgz#c962290f65c32d44a0624f785b2d780835525a23" + integrity sha512-Ry+p2+NLk6u8Agh5yVqELfUJvRfV51hhVBRIB5yZPY7mU0DGBmOuFG5GebZbMbm86cdQNK0fhJuDX8/1YorISQ== + dependencies: + "@jest/core" "30.1.3" + "@jest/types" "30.0.5" + import-local "^3.2.0" + jest-cli "30.1.3" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + jsonc-parser@^3.2.0: version "3.3.1" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.3.1.tgz#f2a524b4f7fd11e3d791e559977ad60b98b798b4" @@ -905,6 +2576,11 @@ leven@^3.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + linkify-it@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e" @@ -912,6 +2588,13 @@ linkify-it@^3.0.1: dependencies: uc.micro "^1.0.1" +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" @@ -942,16 +2625,33 @@ lodash.isstring@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^11.0.0: version "11.1.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.1.0.tgz#afafb060607108132dbc1cf8ae661afb69486117" integrity sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A== +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -959,6 +2659,25 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + markdown-it@^12.3.2: version "12.3.2" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.3.2.tgz#bf92ac92283fe983fe4de8ff8abfb5ad72cd0c90" @@ -980,6 +2699,19 @@ mdurl@^1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -997,6 +2729,11 @@ mime@^1.3.4: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + mimic-response@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" @@ -1009,19 +2746,26 @@ minimatch@^10.0.3: dependencies: "@isaacs/brace-expansion" "^5.0.0" -minimatch@^3.0.3: +minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0, minimist@^1.2.3: +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -minipass@^7.1.2: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== @@ -1046,6 +2790,21 @@ napi-build-utils@^2.0.0: resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-2.0.0.tgz#13c22c0187fcfccce1461844136372a47ddc027e" integrity sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA== +napi-postinstall@^0.3.0: + version "0.3.3" + resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.3.3.tgz#93d045c6b576803ead126711d3093995198c6eb9" + integrity sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + node-abi@^3.3.0: version "3.75.0" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.75.0.tgz#2f929a91a90a0d02b325c43731314802357ed764" @@ -1058,6 +2817,28 @@ node-addon-api@^4.3.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f" integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ== +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.21: + version "2.0.21" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.21.tgz#f59b018bc0048044be2d4c4c04e4c8b18160894c" + integrity sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + nth-check@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" @@ -1070,13 +2851,20 @@ object-inspect@^1.13.3: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== -once@^1.3.1, once@^1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + open@^10.1.0: version "10.2.0" resolved "https://registry.yarnpkg.com/open/-/open-10.2.0.tgz#b9d855be007620e80b6fb05fac98141fe62db73c" @@ -1087,11 +2875,47 @@ open@^10.1.0: is-inside-container "^1.0.0" wsl-utils "^0.1.0" +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + package-json-from-dist@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + 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" + parse-semver@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/parse-semver/-/parse-semver-1.1.1.tgz#9a4afd6df063dc4826f93fba4a99cf223f666cb8" @@ -1121,11 +2945,29 @@ parse5@^7.0.0, parse5@^7.3.0: dependencies: entities "^6.0.0" -path-key@^3.1.0: +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.0.tgz#9f052289f23ad8bf9397a2a0425e7b8615c58580" @@ -1139,6 +2981,33 @@ pend@~1.2.0: resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + +pirates@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" + integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + prebuild-install@^7.0.1: version "7.1.3" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.3.tgz#d630abad2b147443f20a212917beae68b8092eec" @@ -1157,6 +3026,15 @@ prebuild-install@^7.0.1: tar-fs "^2.0.0" tunnel-agent "^0.6.0" +pretty-format@30.0.5, pretty-format@^30.0.0: + version "30.0.5" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-30.0.5.tgz#e001649d472800396c1209684483e18a4d250360" + integrity sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw== + dependencies: + "@jest/schemas" "30.0.5" + ansi-styles "^5.2.0" + react-is "^18.3.1" + pump@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d" @@ -1165,6 +3043,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +pure-rand@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-7.0.1.tgz#6f53a5a9e3e4a47445822af96821ca509ed37566" + integrity sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ== + qs@^6.9.1: version "6.14.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" @@ -1182,6 +3065,11 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-is@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + read@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" @@ -1198,6 +3086,23 @@ readable-stream@^3.1.1, readable-stream@^3.4.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + run-applescript@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-7.0.0.tgz#e5a553c2bffd620e169d276c1cd8f1b64778fbeb" @@ -1223,7 +3128,12 @@ semver@^5.1.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^7.3.5, semver@^7.5.2, semver@^7.5.4: +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.3.5, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.7.2: version "7.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== @@ -1280,6 +3190,11 @@ side-channel@^1.1.0: side-channel-map "^1.0.1" side-channel-weakmap "^1.0.2" +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" @@ -1299,6 +3214,44 @@ simple-get@^4.0.0: once "^1.3.1" simple-concat "^1.0.0" +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +string-length@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -1308,7 +3261,7 @@ simple-get@^4.0.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^4.1.0: +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -1354,6 +3307,21 @@ strip-ansi@^7.0.1: dependencies: ansi-regex "^6.0.1" +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -1366,6 +3334,27 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +synckit@^0.11.8: + version "0.11.11" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.11.tgz#c0b619cf258a97faa209155d9cd1699b5c998cb0" + integrity sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw== + dependencies: + "@pkgr/core" "^0.2.9" + tar-fs@^2.0.0: version "2.1.3" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.3.tgz#fb3b8843a26b6f13a08e606f7922875eb1fbbf92" @@ -1387,12 +3376,48 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + tmp@^0.2.3: version "0.2.5" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.5.tgz#b06bcd23f0f3c8357b426891726d16015abfd8f8" integrity sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow== -tslib@^2.2.0, tslib@^2.6.2: +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-jest@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.4.1.tgz#42d33beb74657751d315efb9a871fe99e3b9b519" + integrity sha512-SaeUtjfpg9Uqu8IbeDKtdaS0g8lS6FT6OzM3ezrDfErPJPHNDo/Ey+VFGP1bQIDfagYDLyRpd7O15XpG1Es2Uw== + dependencies: + bs-logger "^0.2.6" + fast-json-stable-stringify "^2.1.0" + handlebars "^4.7.8" + json5 "^2.2.3" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.7.2" + type-fest "^4.41.0" + yargs-parser "^21.1.1" + +tslib@^2.2.0, tslib@^2.4.0, tslib@^2.6.2: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -1409,6 +3434,21 @@ tunnel@0.0.6: resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^4.41.0: + version "4.41.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" + integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== + typed-rest-client@^1.8.4: version "1.8.11" resolved "https://registry.yarnpkg.com/typed-rest-client/-/typed-rest-client-1.8.11.tgz#6906f02e3c91e8d851579f255abf0fd60800a04d" @@ -1428,6 +3468,11 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== +uglify-js@^3.1.4: + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== + underscore@^1.12.1: version "1.13.7" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.7.tgz#970e33963af9a7dda228f17ebe8399e5fbe63a10" @@ -1438,11 +3483,51 @@ undici-types@~7.10.0: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.10.0.tgz#4ac2e058ce56b462b056e629cc6a02393d3ff350" integrity sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag== +undici-types@~7.11.0: + version "7.11.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.11.0.tgz#075798115d0bbc4e4fc7c173f38727ca66bfb592" + integrity sha512-kt1ZriHTi7MU+Z/r9DOdAI3ONdaR3M3csEaRc6ewa4f4dTvX4cQCbJ4NkEn0ohE4hHtq85+PhPSTY+pO/1PwgA== + undici@^7.12.0: version "7.15.0" resolved "https://registry.yarnpkg.com/undici/-/undici-7.15.0.tgz#7485007549ad1782b7cab2abfaa1c1aa7b75e106" integrity sha512-7oZJCPvvMvTd0OlqWsIxTuItTpJBpU1tcbVl24FMn3xt3+VSunwUasmfPJRE57oNO1KsZ4PgA1xTdAX4hq8NyQ== +unrs-resolver@^1.7.11: + version "1.11.1" + resolved "https://registry.yarnpkg.com/unrs-resolver/-/unrs-resolver-1.11.1.tgz#be9cd8686c99ef53ecb96df2a473c64d304048a9" + integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg== + dependencies: + napi-postinstall "^0.3.0" + optionalDependencies: + "@unrs/resolver-binding-android-arm-eabi" "1.11.1" + "@unrs/resolver-binding-android-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-x64" "1.11.1" + "@unrs/resolver-binding-freebsd-x64" "1.11.1" + "@unrs/resolver-binding-linux-arm-gnueabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm-musleabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-arm64-musl" "1.11.1" + "@unrs/resolver-binding-linux-ppc64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-musl" "1.11.1" + "@unrs/resolver-binding-linux-s390x-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-musl" "1.11.1" + "@unrs/resolver-binding-wasm32-wasi" "1.11.1" + "@unrs/resolver-binding-win32-arm64-msvc" "1.11.1" + "@unrs/resolver-binding-win32-ia32-msvc" "1.11.1" + "@unrs/resolver-binding-win32-x64-msvc" "1.11.1" + +update-browserslist-db@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + url-join@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" @@ -1458,6 +3543,22 @@ uuid@^8.3.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +v8-to-istanbul@^9.0.1: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + whatwg-encoding@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" @@ -1477,6 +3578,11 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -1486,6 +3592,15 @@ which@^2.0.1: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" @@ -1500,6 +3615,14 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +write-file-atomic@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" + integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^4.0.1" + wsl-utils@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/wsl-utils/-/wsl-utils-0.1.0.tgz#8783d4df671d4d50365be2ee4c71917a0557baab" @@ -1520,11 +3643,39 @@ xmlbuilder@~11.0.0: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yauzl@^2.3.1: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" @@ -1539,3 +3690,8 @@ yazl@^2.2.2: integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== dependencies: buffer-crc32 "~0.2.3" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==