diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d00bd744d..9c301ab07 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -44,6 +44,7 @@ 8000, // used by mkdocs 9000, 9091, // used by docker production + 51204, // used for test coverage report 24678 // used by nuxt when hot-reloading using polling ], // Use 'onCreateCommand' to run commands at the end of container creation. diff --git a/.vscode/test-block.code-snippets b/.vscode/test-block.code-snippets new file mode 100644 index 000000000..ef8503cac --- /dev/null +++ b/.vscode/test-block.code-snippets @@ -0,0 +1,30 @@ +{ + "Test Block": { + "prefix": "mtest", + "body": [ + "import { mount } from \"@vue/test-utils\";", + "import { describe, expect, test, vi } from \"vitest\";", + "import { makeWrapper } from \"~/tests/utils\";", + "", + "const wrapper = () => makeWrapper(() => {", + " return ${1:composable}();", + "});", + "", + "describe(\"${TM_FILENAME_BASE/(.*)\\..+$/$1/}\", () => {", + " describe(\"${2:method}\", () => {", + " test(\"It does the thing\", () => {", + " const { ${2:method} } = wrapper();", + " const result = ${2:method}();", + " expect(result).toBe(EXPECTED);", + " });", + " });", + "});", + "", + ], + "description": "Insert a test block", + "scope": "typescript", + "include": [ + "**/*.test.{ts,tsx,vue}" + ] + } +} diff --git a/frontend/app/composables/shopping-list-page/sub-composables/__tests__/mocks.ts b/frontend/app/composables/shopping-list-page/sub-composables/__tests__/mocks.ts new file mode 100644 index 000000000..3837d5c91 --- /dev/null +++ b/frontend/app/composables/shopping-list-page/sub-composables/__tests__/mocks.ts @@ -0,0 +1,83 @@ +import type { IngredientFood, RecipeSummary, ShoppingListItemOut, ShoppingListMultiPurposeLabelOut, ShoppingListOut } from "~/lib/api/types/household"; + +export const MOCK_ITEM: ShoppingListItemOut = { + shoppingListId: "", + id: "", + groupId: "", + householdId: "", + display: "MOCK_ITEM", + updatedAt: "100", + position: 1, + checked: false, + createdAt: "100", +}; + +export const MOCK_RECIPE: RecipeSummary = { + id: "recipe-id", + name: "Recipe!", +}; + +export const MOCK_RECIPE2: RecipeSummary = { + ...MOCK_RECIPE, + id: undefined, + name: "Recipe 2!", +}; + +export const MOCK_FOOD: IngredientFood = { + id: "1", + name: "food 1", +}; + +export const MOCK_FOOD2: IngredientFood = { + id: "2", + name: "food 2", +}; + +export const MOCK_LABEL: ShoppingListMultiPurposeLabelOut = { + shoppingListId: "", + labelId: "", + id: "", + label: { + name: "MOCK_LABEL", + groupId: "", + id: "", + }, +}; + +export const MOCK_LABEL2: ShoppingListMultiPurposeLabelOut = { + shoppingListId: "", + labelId: "", + id: "", + label: { + name: "MOCK_LABEL2", + groupId: "", + id: "", + }, +}; + +export const MOCK_SHOPPING_LIST: ShoppingListOut = { + groupId: "", + userId: "", + id: "", + householdId: "", + labelSettings: [ + MOCK_LABEL, + MOCK_LABEL2, + ], + listItems: [ + MOCK_ITEM, + ], + recipeReferences: [{ + id: "", + shoppingListId: "", + recipeId: "", + recipeQuantity: 0, + recipe: MOCK_RECIPE, + }, { + id: "", + shoppingListId: "", + recipeId: "", + recipeQuantity: 0, + recipe: MOCK_RECIPE2, + }], +}; diff --git a/frontend/app/composables/shopping-list-page/sub-composables/__tests__/use-shopping-list-copy.test.ts b/frontend/app/composables/shopping-list-page/sub-composables/__tests__/use-shopping-list-copy.test.ts new file mode 100644 index 000000000..a2e4f737c --- /dev/null +++ b/frontend/app/composables/shopping-list-page/sub-composables/__tests__/use-shopping-list-copy.test.ts @@ -0,0 +1,89 @@ +import * as vueusecore from "@vueuse/core"; +import { describe, expect, test, vi } from "vitest"; +import type { ShoppingListItemOut } from "~/lib/api/types/household"; +import { makeWrapper } from "~/tests/utils"; +import { useShoppingListCopy } from "../use-shopping-list-copy"; +import { MOCK_ITEM } from "./mocks"; + +vi.mock("@vueuse/core", { spy: true }); + +const mockCopy = vi.fn().mockImplementation(args => new Promise(resolve => resolve(args))); + +vi.mocked(vueusecore.useClipboard).mockImplementation(() => { + return { + isSupported: computed(() => true), + copied: computed(() => true), + text: computed(() => ""), + copy: mockCopy, + }; +}); +const wrapper = () => makeWrapper(useShoppingListCopy); + +const TEST_HEADER = "SPECIAL HEADER!"; + +const MOCK_LIST: { [key: string]: ShoppingListItemOut[] } = { + [TEST_HEADER]: [MOCK_ITEM], + [TEST_HEADER + "2"]: [MOCK_ITEM], +}; + +describe("Shopping list copy composable", () => { + describe("copyListItems", () => { + test("copies markdown lists correctly", () => { + const { copyListItems } = wrapper(); + copyListItems(MOCK_LIST, "markdown"); + const expected = [ + "# SPECIAL HEADER!", + "- [ ] MOCK_ITEM", + "", + "# SPECIAL HEADER!2", + "- [ ] MOCK_ITEM", + ].join("\n"); + + expect(mockCopy).toBeCalledWith(expected); + }); + test("copies plain text lists correctly", () => { + const { copyListItems } = wrapper(); + copyListItems(MOCK_LIST, "plain"); + const expected = [ + "[SPECIAL HEADER!]", + "MOCK_ITEM", + "", + "[SPECIAL HEADER!2]", + "MOCK_ITEM", + ].join("\n"); + + expect(mockCopy).toBeCalledWith(expected); + }); + }); + + describe("formatCopiedLabelHeading", () => { + test("copies markdown headers correctly", () => { + const { formatCopiedLabelHeading } = wrapper(); + const header = formatCopiedLabelHeading("markdown", TEST_HEADER); + expect(header).toEqual(`# ${TEST_HEADER}`); + }); + test("copies plain text headers correctly", () => { + const { formatCopiedLabelHeading } = wrapper(); + const header = formatCopiedLabelHeading("plain", TEST_HEADER); + expect(header).toEqual(`[${TEST_HEADER}]`); + }); + }); + + describe("formatCopiedListItem", () => { + test("copies markdown items correctly", () => { + const { formatCopiedListItem } = wrapper(); + const header = formatCopiedListItem("markdown", MOCK_ITEM); + expect(header).toEqual(`- [ ] ${MOCK_ITEM.display}`); + }); + test("copies plain text items correctly", () => { + const { formatCopiedListItem } = wrapper(); + const header = formatCopiedListItem("plain", MOCK_ITEM); + expect(header).toEqual(MOCK_ITEM.display); + }); + test("copies items without a display as empty", () => { + const { formatCopiedListItem } = wrapper(); + const header = formatCopiedListItem("plain", { ...MOCK_ITEM, display: undefined }); + expect(header).toEqual(""); + }); + }); +}); diff --git a/frontend/app/composables/shopping-list-page/sub-composables/__tests__/use-shopping-list-sorting.test.ts b/frontend/app/composables/shopping-list-page/sub-composables/__tests__/use-shopping-list-sorting.test.ts new file mode 100644 index 000000000..114a263de --- /dev/null +++ b/frontend/app/composables/shopping-list-page/sub-composables/__tests__/use-shopping-list-sorting.test.ts @@ -0,0 +1,175 @@ +import { describe, expect, test } from "vitest"; +import type { ShoppingListOut } from "~/lib/api/types/household"; +import { makeWrapper } from "~/tests/utils"; +import { useShoppingListSorting } from "../use-shopping-list-sorting"; +import { MOCK_FOOD, MOCK_FOOD2, MOCK_ITEM, MOCK_LABEL, MOCK_LABEL2, MOCK_SHOPPING_LIST } from "./mocks"; + +const wrapper = () => makeWrapper(() => { + const { t } = useI18n(); + return { + t, + ...useShoppingListSorting(), + }; +}); + +describe("use-shopping-list-sorting", () => { + describe("sortItems", () => { + const { sortItems } = wrapper(); + test("sorts by position first", () => { + const result = sortItems(MOCK_ITEM, { ...MOCK_ITEM, position: 0 }); + const result2 = sortItems({ ...MOCK_ITEM, position: 0 }, MOCK_ITEM); + expect(result).toBe(1); + expect(result2).toBe(-1); + }); + test("sorts by createdAt next", () => { + const result = sortItems(MOCK_ITEM, { ...MOCK_ITEM, createdAt: "0" }); + const result2 = sortItems({ ...MOCK_ITEM, createdAt: "0" }, MOCK_ITEM); + expect(result).toBe(1); + expect(result2).toBe(-1); + }); + test("sorts similar items into the same spot", () => { + const result = sortItems(MOCK_ITEM, MOCK_ITEM); + expect(result).toBe(0); + }); + test("handles nulls", () => { + const result = sortItems(MOCK_ITEM, { ...MOCK_ITEM, position: undefined }); + const result2 = sortItems({ ...MOCK_ITEM, position: undefined }, MOCK_ITEM); + expect(result).toBe(1); + expect(result2).toBe(-1); + }); + test("handles nulls", () => { + const result = sortItems(MOCK_ITEM, { ...MOCK_ITEM, createdAt: undefined }); + const result2 = sortItems({ ...MOCK_ITEM, createdAt: undefined }, MOCK_ITEM); + expect(result).toBe(1); + expect(result2).toBe(-1); + }); + }); + describe("sortListItems", () => { + const { sortListItems } = wrapper(); + test("sorts by position first", () => { + const sortedList = { ...MOCK_SHOPPING_LIST, listItems: [MOCK_ITEM, { ...MOCK_ITEM, position: 0 }, { ...MOCK_ITEM, createdAt: "0" }] }; + sortListItems(sortedList); + expect(sortedList.listItems).toEqual([ + { ...MOCK_ITEM, position: 0 }, + { ...MOCK_ITEM, createdAt: "0" }, + MOCK_ITEM, + ]); + }); + test("handles nulls", () => { + const sortedList = { ...MOCK_SHOPPING_LIST, listItems: undefined }; + sortListItems(sortedList); + expect(sortedList.listItems).toEqual(undefined); + }); + }); + describe("updateItemsByLabel", () => { + const { updateItemsByLabel, t } = wrapper(); + test("sorts by group", () => { + const sortedList = { + ...MOCK_SHOPPING_LIST, listItems: [ + MOCK_ITEM, + { ...MOCK_ITEM, label: MOCK_LABEL2.label, labelId: "2" }, + { ...MOCK_ITEM, label: MOCK_LABEL.label, labelId: "1" }, + { ...MOCK_ITEM, label: MOCK_LABEL.label, labelId: "1" }, + ], + }; + const result = updateItemsByLabel(sortedList); + expect(result).toEqual({ + [t("shopping-list.no-label")]: [ + MOCK_ITEM, + ], + [MOCK_LABEL.label.name]: [ + { ...MOCK_ITEM, label: MOCK_LABEL.label, labelId: "1" }, + { ...MOCK_ITEM, label: MOCK_LABEL.label, labelId: "1" }, + ], + [MOCK_LABEL2.label.name]: [ + { ...MOCK_ITEM, label: MOCK_LABEL2.label, labelId: "2" }, + ], + }); + }); + test("ignores checked items", () => { + const sortedList = { + ...MOCK_SHOPPING_LIST, listItems: [ + MOCK_ITEM, + { ...MOCK_ITEM, label: MOCK_LABEL2.label, labelId: "2" }, + { ...MOCK_ITEM, label: MOCK_LABEL.label, labelId: "1" }, + { ...MOCK_ITEM, label: MOCK_LABEL.label, labelId: "1", checked: true }, + ], + }; + const result = updateItemsByLabel(sortedList); + expect(result).toEqual({ + [t("shopping-list.no-label")]: [ + MOCK_ITEM, + ], + [MOCK_LABEL.label.name]: [ + { ...MOCK_ITEM, label: MOCK_LABEL.label, labelId: "1" }, + ], + [MOCK_LABEL2.label.name]: [ + { ...MOCK_ITEM, label: MOCK_LABEL2.label, labelId: "2" }, + ], + }); + }); + test("returns unordered labels if no ordering is specified", () => { + const sortedList = { + ...MOCK_SHOPPING_LIST, + labelSettings: undefined, + listItems: [ + MOCK_ITEM, + { ...MOCK_ITEM, label: MOCK_LABEL2.label, labelId: "2" }, + { ...MOCK_ITEM, label: MOCK_LABEL.label, labelId: "1" }, + { ...MOCK_ITEM, label: MOCK_LABEL.label, labelId: "1", checked: true }, + ], + }; + const result = updateItemsByLabel(sortedList); + expect(result).toEqual({ + [t("shopping-list.no-label")]: [ + MOCK_ITEM, + ], + [MOCK_LABEL2.label.name]: [ + { ...MOCK_ITEM, label: MOCK_LABEL2.label, labelId: "2" }, + ], + [MOCK_LABEL.label.name]: [ + { ...MOCK_ITEM, label: MOCK_LABEL.label, labelId: "1" }, + ], + }); + }); + }); + describe("groupAndSortListItemsByFood", () => { + const { groupAndSortListItemsByFood } = wrapper(); + test("sorts by group", () => { + const sortedList = { ...MOCK_SHOPPING_LIST }; + groupAndSortListItemsByFood(sortedList); + expect(sortedList.listItems).toEqual(MOCK_SHOPPING_LIST.listItems); + }); + test("groups checked items together", () => { + const sortedList: ShoppingListOut = { + ...MOCK_SHOPPING_LIST, listItems: [ + { ...MOCK_ITEM, checked: true, food: MOCK_FOOD }, + { ...MOCK_ITEM, checked: true, food: MOCK_FOOD2 }, + ], + }; + groupAndSortListItemsByFood(sortedList); + expect(sortedList.listItems).toEqual([ + { ...MOCK_ITEM, checked: true, food: MOCK_FOOD }, + { ...MOCK_ITEM, checked: true, food: MOCK_FOOD2, position: 1 }, + ]); + }); + test("populates position and created at if not present", () => { + const sortedList: ShoppingListOut = { + ...MOCK_SHOPPING_LIST, listItems: [ + { ...MOCK_ITEM, food: MOCK_FOOD, position: undefined }, + { ...MOCK_ITEM, food: MOCK_FOOD2, createdAt: undefined }, + ], + }; + groupAndSortListItemsByFood(sortedList); + expect(sortedList.listItems).toEqual([ + { ...MOCK_ITEM, food: MOCK_FOOD2, createdAt: undefined }, + { ...MOCK_ITEM, food: MOCK_FOOD, position: 1 }, + ]); + }); + test("handles nulls", () => { + const sortedList: ShoppingListOut = { ...MOCK_SHOPPING_LIST, listItems: undefined }; + groupAndSortListItemsByFood(sortedList); + expect(sortedList.listItems).toEqual(undefined); + }); + }); +}); diff --git a/frontend/app/composables/shopping-list-page/sub-composables/__tests__/use-shopping-list-state.test.ts b/frontend/app/composables/shopping-list-page/sub-composables/__tests__/use-shopping-list-state.test.ts new file mode 100644 index 000000000..68482a56f --- /dev/null +++ b/frontend/app/composables/shopping-list-page/sub-composables/__tests__/use-shopping-list-state.test.ts @@ -0,0 +1,63 @@ +import { describe, expect, test } from "vitest"; +import type { ShoppingListOut } from "~/lib/api/types/household"; +import { makeWrapper } from "~/tests/utils"; +import { useShoppingListState } from "../use-shopping-list-state"; +import { MOCK_ITEM, MOCK_RECIPE, MOCK_RECIPE2, MOCK_SHOPPING_LIST } from "./mocks"; + +const wrapper = (list: ShoppingListOut = MOCK_SHOPPING_LIST) => makeWrapper(() => { + const { shoppingList, ...state } = useShoppingListState(); + shoppingList.value = list; + return { + shoppingList, + ...state, + }; +}); + +describe("use-shopping-list-state", () => { + describe("checked items are sorted", () => { + const { sortCheckedItems } = wrapper(); + + test("by timestamp", () => { + const sorted = sortCheckedItems(MOCK_ITEM, { ...MOCK_ITEM, updatedAt: "200" }); + const sorted2 = sortCheckedItems(MOCK_ITEM, { ...MOCK_ITEM, updatedAt: "0" }); + expect(sorted).toBe(1); + expect(sorted2).toBe(-1); + }); + test("by position if timestamps match", () => { + const sorted = sortCheckedItems(MOCK_ITEM, { ...MOCK_ITEM, position: 2 }); + const sorted2 = sortCheckedItems(MOCK_ITEM, { ...MOCK_ITEM, position: 0 }); + const sorted3 = sortCheckedItems({ ...MOCK_ITEM, position: undefined }, { ...MOCK_ITEM, position: undefined }); + expect(sorted).toBe(1); + expect(sorted2).toBe(-1); + expect(sorted3).toBe(1); + }); + }); + + describe("recipeMap", () => { + test("Updates to match shopping list recipe references", () => { + const { recipeMap } = wrapper(); + expect(recipeMap).toEqual(new Map([ + [MOCK_RECIPE.id, MOCK_RECIPE], + ["", MOCK_RECIPE2], + ])); + }); + test("handles nulls", () => { + const { recipeMap } = wrapper({ ...MOCK_SHOPPING_LIST, recipeReferences: undefined }); + expect(recipeMap).toEqual(new Map([])); + }); + }); + + describe("checked and unchecked items", () => { + test("update appropriately", () => { + const mockCheckedItem = { ...MOCK_ITEM, checked: true }; + const { listItems: { checked, unchecked } } = wrapper({ + ...MOCK_SHOPPING_LIST, listItems: [ + MOCK_ITEM, + mockCheckedItem, + ], + }); + expect(unchecked[0]).toEqual(MOCK_ITEM); + expect(checked[0]).toEqual(mockCheckedItem); + }); + }); +}); diff --git a/frontend/app/tests/setup.ts b/frontend/app/tests/setup.ts new file mode 100644 index 000000000..11bd133f9 --- /dev/null +++ b/frontend/app/tests/setup.ts @@ -0,0 +1,18 @@ +import { config } from "@vue/test-utils"; +import { createI18n } from "vue-i18n"; + +function loadEnLocales() { + // eslint-disable-next-line @typescript-eslint/no-require-imports + return require("../lang/messages/en-US.json") as Record; +} + +const i18n = createI18n({ + locale: "en-US", + messages: { + "en-US": loadEnLocales(), + }, +}); + +config.global.plugins = [...(config.global.plugins ?? []), i18n]; + +export { i18n }; diff --git a/frontend/app/tests/utils.ts b/frontend/app/tests/utils.ts index 4f1bd5d3f..94657e2d4 100644 --- a/frontend/app/tests/utils.ts +++ b/frontend/app/tests/utils.ts @@ -1,3 +1,4 @@ +import { mount } from "@vue/test-utils"; import { createI18n } from "vue-i18n"; function loadEnLocales() { @@ -14,3 +15,12 @@ export function stubI18n() { }); return i18n.global; } + +export const makeWrapper = (setup: () => T) => { + const Wrapper = { + template: "
", + setup, + }; + const { vm } = mount(Wrapper); + return vm as unknown as ReturnType; +}; diff --git a/frontend/package.json b/frontend/package.json index 88f183131..3bedb2687 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,6 +12,8 @@ "lint:log": "yarn lint:js --debug", "test": "vitest", "test:ci": "vitest --watch=false", + "test:coverage": "vitest run --coverage", + "test:ui": "vitest --ui", "cleanup": "nuxt cleanup" }, "lint-staged": { @@ -48,6 +50,9 @@ "@types/node": "^25.5.2", "@types/sortablejs": "^1.15.8", "@vitejs/plugin-vue": "^6.0.7", + "@vitest/coverage-v8": "3.2.4", + "@vitest/ui": "3.2.4", + "@vue/test-utils": "^2.4.6", "eslint": "^9.22.0", "eslint-config-prettier": "^10.0.2", "eslint-plugin-format": "^1.0.1", @@ -57,6 +62,7 @@ "prettier": "^3.5.2", "sass-embedded": "^1.85.1", "typescript": "^5.3", + "unplugin-auto-import": "^21.0.0", "vite-plugin-commonjs": "^0.10.4", "vitest": "^3.0.7" }, diff --git a/frontend/vitest.config.js b/frontend/vitest.config.js index d5bcb429e..4895435a4 100644 --- a/frontend/vitest.config.js +++ b/frontend/vitest.config.js @@ -1,11 +1,26 @@ import path from "path"; import vue from "@vitejs/plugin-vue"; +import AutoImport from "unplugin-auto-import/vite"; export default { - plugins: [vue()], + plugins: [ + vue(), + AutoImport({ + imports: ["vue", "@vueuse/core", "vue-i18n"], + dts: false, + }), + ], test: { globals: true, environment: "jsdom", + setupFiles: ["./app/tests/setup.ts"], + coverage: { + provider: "v8", + include: ["app/{lib,components,composables,layouts,pages}/**/*.{ts,tsx,vue}"], + exclude: ["**/*.test.*", "node_modules/**", "dist/**", "coverage/**", "**/__tests__/**"], + reporter: ["html", "text-summary"], + all: true, + }, }, resolve: { alias: { diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 54b37804d..2a678aa23 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@ampproject/remapping@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + "@antfu/install-pkg@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@antfu/install-pkg/-/install-pkg-1.1.0.tgz#78fa036be1a6081b5a77a5cf59f50c7752b6ba26" @@ -281,7 +289,7 @@ "@babel/template" "^7.29.7" "@babel/types" "^7.29.7" -"@babel/parser@^7.24.6", "@babel/parser@^7.25.3", "@babel/parser@^7.27.0", "@babel/parser@^7.28.4", "@babel/parser@^7.28.5", "@babel/parser@^7.29.3", "@babel/parser@^7.29.7": +"@babel/parser@^7.24.6", "@babel/parser@^7.25.3", "@babel/parser@^7.25.4", "@babel/parser@^7.27.0", "@babel/parser@^7.28.4", "@babel/parser@^7.28.5", "@babel/parser@^7.29.3", "@babel/parser@^7.29.7": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.7.tgz#837b87387cbf5ec5530cb634b3c622f68edb9334" integrity sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg== @@ -904,7 +912,7 @@ "@babel/types" "^7.29.7" debug "^4.3.1" -"@babel/types@^7.26.8", "@babel/types@^7.28.4", "@babel/types@^7.29.0", "@babel/types@^7.29.7", "@babel/types@^7.4.4": +"@babel/types@^7.25.4", "@babel/types@^7.26.8", "@babel/types@^7.28.4", "@babel/types@^7.29.0", "@babel/types@^7.29.7", "@babel/types@^7.4.4": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.7.tgz#8005e31d82712ee7adaef6e23c63b71a62770a92" integrity sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA== @@ -920,6 +928,11 @@ "@babel/helper-string-parser" "^8.0.0-rc.6" "@babel/helper-validator-identifier" "^8.0.0-rc.6" +"@bcoe/v8-coverage@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz#bbe12dca5b4ef983a0d0af4b07b9bc90ea0ababa" + integrity sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA== + "@bomb.sh/tab@^0.0.15": version "0.0.15" resolved "https://registry.yarnpkg.com/@bomb.sh/tab/-/tab-0.0.15.tgz#678fd24b3b3ab7e9e426cf541b3ee2cf8fb661ec" @@ -1852,6 +1865,11 @@ dependencies: minipass "^7.0.4" +"@istanbuljs/schema@^0.1.2": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.6.tgz#8dc9afa2ac1506cb1a58f89940f1c124446c8df3" + integrity sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw== + "@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" @@ -1886,7 +1904,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.28", "@jridgewell/trace-mapping@^0.3.31": +"@jridgewell/trace-mapping@^0.3.23", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.28", "@jridgewell/trace-mapping@^0.3.31": version "0.3.31" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== @@ -2377,6 +2395,11 @@ vue-i18n "^10.0.7" vue-router "^4.5.1" +"@one-ini/wasm@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@one-ini/wasm/-/wasm-0.1.1.tgz#6013659736c9dbfccc96e8a9c2b3de317df39323" + integrity sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw== + "@oxc-minify/binding-android-arm-eabi@0.131.0": version "0.131.0" resolved "https://registry.yarnpkg.com/@oxc-minify/binding-android-arm-eabi/-/binding-android-arm-eabi-0.131.0.tgz#031cab3588c2b31d124699d9de3a71d4022e9ee1" @@ -3647,6 +3670,25 @@ dependencies: "@rolldown/pluginutils" "^1.0.1" +"@vitest/coverage-v8@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz#a2d8d040288c1956a1c7d0a0e2cdcfc7a3319f13" + integrity sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ== + dependencies: + "@ampproject/remapping" "^2.3.0" + "@bcoe/v8-coverage" "^1.0.2" + ast-v8-to-istanbul "^0.3.3" + debug "^4.4.1" + istanbul-lib-coverage "^3.2.2" + istanbul-lib-report "^3.0.1" + istanbul-lib-source-maps "^5.0.6" + istanbul-reports "^3.1.7" + magic-string "^0.30.17" + magicast "^0.3.5" + std-env "^3.9.0" + test-exclude "^7.0.1" + tinyrainbow "^2.0.0" + "@vitest/expect@3.2.4": version "3.2.4" resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.2.4.tgz#8362124cd811a5ee11c5768207b9df53d34f2433" @@ -3699,6 +3741,19 @@ dependencies: tinyspy "^4.0.3" +"@vitest/ui@3.2.4": + version "3.2.4" + resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-3.2.4.tgz#df8080537c1dcfeae353b2d3cb3301d9acafe04a" + integrity sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA== + dependencies: + "@vitest/utils" "3.2.4" + fflate "^0.8.2" + flatted "^3.3.3" + pathe "^2.0.3" + sirv "^3.0.1" + tinyglobby "^0.2.14" + tinyrainbow "^2.0.0" + "@vitest/utils@3.2.4": version "3.2.4" resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-3.2.4.tgz#c0813bc42d99527fb8c5b138c7a88516bca46fea" @@ -3877,6 +3932,14 @@ resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.35.tgz#192eb3d720c40715db79313454c4937432a4e86d" integrity sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA== +"@vue/test-utils@^2.4.6": + version "2.4.10" + resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-2.4.10.tgz#f3b006e03918e66b5df1f2a6f7f5200663b525d3" + integrity sha512-SmoZ5EA1kYiAFs9NkYdiFFQF+cSnUwnvlYEbY+DogWQZUiqOm/Y29eSbc5T6yi75SgSF9863SBeXniIEoPajCA== + dependencies: + js-beautify "^1.14.9" + vue-component-type-helpers "^3.0.0" + "@vuetify/loader-shared@^2.1.2": version "2.1.2" resolved "https://registry.yarnpkg.com/@vuetify/loader-shared/-/loader-shared-2.1.2.tgz#faf27cb8c40ba5a45b930b9a2785e35525e9c96f" @@ -3911,6 +3974,11 @@ resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-14.3.0.tgz#a3e7e6391f9ed7f363cbb28c32c4a278efaacbd0" integrity sha512-bZpge9eSXwa4ToSiqJ7j6KRwhAsneMFoSz3LMWKQDkqimm3D/tbFlrklrs/IOqC8tEcYmXQZJ6N0UrjhBirVCg== +abbrev@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" + integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== + abbrev@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-3.0.1.tgz#8ac8b3b5024d31464fe2a5feeea9f4536bf44025" @@ -4095,6 +4163,15 @@ ast-kit@^2.1.2, ast-kit@^2.1.3: "@babel/parser" "^7.28.5" pathe "^2.0.3" +ast-v8-to-istanbul@^0.3.3: + version "0.3.12" + resolved "https://registry.yarnpkg.com/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.12.tgz#8eb1b7c86ef8499859be761b17ffd91406c0c36f" + integrity sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g== + dependencies: + "@jridgewell/trace-mapping" "^0.3.31" + estree-walker "^3.0.3" + js-tokens "^10.0.0" + ast-walker-scope@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/ast-walker-scope/-/ast-walker-scope-0.6.2.tgz#b827e8949c129802f76fe0f142e95fd7efda57dc" @@ -4608,6 +4685,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + commander@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" @@ -4674,6 +4756,14 @@ confbox@^0.2.4: resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.4.tgz#592e7be71f882a4a874e3c88f0ac1ef6f7da1ce5" integrity sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ== +config-chain@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + consola@^3.2.3, consola@^3.4.2: version "3.4.2" resolved "https://registry.yarnpkg.com/consola/-/consola-3.4.2.tgz#5af110145397bb67afdab77013fdc34cae590ea7" @@ -5100,6 +5190,16 @@ easy-bem@^1.0.2: resolved "https://registry.yarnpkg.com/easy-bem/-/easy-bem-1.1.1.tgz#1bfcc10425498090bcfddc0f9c000aba91399e03" integrity sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A== +editorconfig@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-1.0.7.tgz#8d6e178aeb507c206d65e1804c1d7510d110d434" + integrity sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw== + dependencies: + "@one-ini/wasm" "0.1.1" + commander "^10.0.0" + minimatch "^9.0.1" + semver "^7.5.3" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -5883,6 +5983,11 @@ fdir@^6.2.0, fdir@^6.5.0: resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== +fflate@^0.8.2: + version "0.8.3" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.3.tgz#bc27d8eb30343d4d512abb03480202ce65d825fc" + integrity sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA== + file-entry-cache@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" @@ -5938,7 +6043,7 @@ flat-cache@^4.0.0: flatted "^3.2.9" keyv "^4.5.4" -flatted@^3.2.9: +flatted@^3.2.9, flatted@^3.3.3: version "3.4.2" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.4.2.tgz#f5c23c107f0f37de8dbdf24f13722b3b98d52726" integrity sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA== @@ -6154,7 +6259,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^10.0.0: +glob@^10.0.0, glob@^10.4.1, glob@^10.4.2: version "10.5.0" resolved "https://registry.yarnpkg.com/glob/-/glob-10.5.0.tgz#8ec0355919cd3338c28428a23d4f24ecc5fe738c" integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg== @@ -6333,6 +6438,11 @@ html-entities@^2.6.0: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.6.0.tgz#7c64f1ea3b36818ccae3d3fb48b6974208e984f8" integrity sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ== +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== + http-errors@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.1.tgz#36d2f65bc909c8790018dd36fb4d93da6caae06b" @@ -6461,6 +6571,11 @@ ini@4.1.1: resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1" integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g== +ini@^1.3.4: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + internal-slot@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" @@ -6804,6 +6919,37 @@ isomorphic-dompurify@^3.4.0: dompurify "^3.4.5" jsdom "^29.1.1" +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.2: + 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-report@^3.0.0, istanbul-lib-report@^3.0.1: + 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.6: + 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.7: + 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" @@ -6839,6 +6985,27 @@ jmespath@^0.16.0: resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076" integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw== +js-beautify@^1.14.9: + version "1.15.4" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.15.4.tgz#f579f977ed4c930cef73af8f98f3f0a608acd51e" + integrity sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA== + dependencies: + config-chain "^1.1.13" + editorconfig "^1.0.4" + glob "^10.4.2" + js-cookie "^3.0.5" + nopt "^7.2.1" + +js-cookie@^3.0.5: + version "3.0.8" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.8.tgz#444e6f4b27a5d844594fef61c9d6bca5f0787688" + integrity sha512-yeJd4aNAdYZQjaon2bpD/Gb0B/omw7HQOsynXXcOiWVCacbBcPlgn8S/d1X6blFSaHao7ozqtW7NZW19xpCtIw== + +js-tokens@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-10.0.0.tgz#dffe7599b4a8bb7fe30aff8d0235234dffb79831" + integrity sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -7234,6 +7401,15 @@ magic-string@^0.30.11, magic-string@^0.30.12, magic-string@^0.30.17, magic-strin dependencies: "@jridgewell/sourcemap-codec" "^1.5.5" +magicast@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.5.tgz#8301c3c7d66704a0771eb1bad74274f0ec036739" + integrity sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ== + dependencies: + "@babel/parser" "^7.25.4" + "@babel/types" "^7.25.4" + source-map-js "^1.2.0" + magicast@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.5.3.tgz#1800f6e76dd8b0dbe7257438a2c336aefabbd905" @@ -7243,6 +7419,13 @@ magicast@^0.5.2: "@babel/types" "^7.29.0" source-map-js "^1.2.1" +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" + marked@^15.0.12: version "15.0.12" resolved "https://registry.yarnpkg.com/marked/-/marked-15.0.12.tgz#30722c7346e12d0a2d0207ab9b0c4f0102d86c4e" @@ -7346,7 +7529,7 @@ minimatch@^5.0.1, minimatch@^5.1.0: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.4: +minimatch@^9.0.1, minimatch@^9.0.4: version "9.0.9" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.9.tgz#9b0cb9fcb78087f6fd7eababe2511c4d3d60574e" integrity sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg== @@ -7538,6 +7721,13 @@ node-releases@^2.0.36: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.46.tgz#d188a129a83f5e03a101aacb58f260f2ee8faaa1" integrity sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ== +nopt@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.1.tgz#1cac0eab9b8e97c9093338446eddd40b2c8ca1e7" + integrity sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w== + dependencies: + abbrev "^2.0.0" + nopt@^8.0.0: version "8.1.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-8.1.0.tgz#b11d38caf0f8643ce885818518064127f602eae3" @@ -8368,6 +8558,11 @@ proper-lockfile@^4.1.2: retry "^0.12.0" signal-exit "^3.0.2" +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== + proxy-from-env@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz#a7487568adad577cfaaa7e88c49cab3ab3081aba" @@ -9086,7 +9281,7 @@ smob@^1.0.0: resolved "https://registry.yarnpkg.com/smob/-/smob-1.6.2.tgz#190b94c25530c631a7ccc63de0d4c0087222d21d" integrity sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw== -"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.1: +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.0, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== @@ -9513,6 +9708,15 @@ terser@^5.17.4: commander "^2.20.0" source-map-support "~0.5.20" +test-exclude@^7.0.1: + version "7.0.2" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-7.0.2.tgz#482392077630bc57d5630c13abe908bb910dfc65" + integrity sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^10.4.1" + minimatch "^10.2.2" + text-decoder@^1.1.0: version "1.2.7" resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.2.7.tgz#5d073a9a74b9c0a9d28dfadcab96b604af57d8ba" @@ -9921,6 +10125,18 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== +unplugin-auto-import@^21.0.0: + version "21.0.0" + resolved "https://registry.yarnpkg.com/unplugin-auto-import/-/unplugin-auto-import-21.0.0.tgz#d1ac3bf95f80fb4182ec8f3d65d3e3aad38a63ac" + integrity sha512-vWuC8SwqJmxZFYwPojhOhOXDb5xFhNNcEVb9K/RFkyk/3VnfaOjzitWN7v+8DEKpMjSsY2AEGXNgt6I0yQrhRQ== + dependencies: + local-pkg "^1.1.2" + magic-string "^0.30.21" + picomatch "^4.0.3" + unimport "^5.6.0" + unplugin "^2.3.11" + unplugin-utils "^0.3.1" + unplugin-utils@^0.2.3: version "0.2.5" resolved "https://registry.yarnpkg.com/unplugin-utils/-/unplugin-utils-0.2.5.tgz#d2fe44566ffffd7f216579bbb01184f6702e379b" @@ -10327,6 +10543,11 @@ vue-bundle-renderer@^2.2.0: dependencies: ufo "^1.6.1" +vue-component-type-helpers@^3.0.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/vue-component-type-helpers/-/vue-component-type-helpers-3.3.3.tgz#9f31a7610348de6fa151c0166600f7ed5808beb3" + integrity sha512-x4nsFpy5Pe8fqPzp/5vkTPeTTDBpAx4WVtV47Ejt0+2FQrq4pRRsJs7JmYRqMFzTu/LW+pCWEjQ3YVCkPV7f9g== + vue-demi@^0.14.10: version "0.14.10" resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"