Improve dataBinding test coverage

This commit is contained in:
Mel O'Hagan
2026-06-10 12:04:06 +01:00
parent 2a54566c75
commit 45f56fb357
5 changed files with 2081 additions and 923 deletions
+1
View File
@@ -12,6 +12,7 @@
"@types/node": "22.18.0",
"@types/proper-lockfile": "^4.1.4",
"@typescript-eslint/parser": "8.41.0",
"@vitest/coverage-v8": "4.1.8",
"@vitest/eslint-plugin": "1.3.5",
"esbuild": "^0.18.17",
"esbuild-node-externals": "^1.14.0",
+1 -1
View File
@@ -101,7 +101,7 @@
"svelte-jester": "^1.3.2",
"vite": "7.3.2",
"vite-plugin-static-copy": "^3.1.2",
"vitest": "^4.1.0"
"vitest": "^4.1.8"
},
"nx": {
"targets": {
-917
View File
@@ -1,917 +0,0 @@
import { expect, describe, it, vi } from "vitest"
import {
runtimeToReadableBinding,
readableToRuntimeBinding,
updateReferencesInObject,
migrateReferencesInObject,
removeBindings,
getSchemaForDatasource,
makeReadableKeyPropSafe,
} from "@/dataBinding"
import { JSONUtils } from "@budibase/frontend-core"
function createMockStore(initialValue) {
let value = initialValue
return {
subscribe: run => {
run(value)
return () => {}
},
set: newValue => {
value = newValue
},
update: updater => {
value = updater(value)
},
_value: () => value,
}
}
function createBuilderStores() {
const workspaceAppStore = {}
const tables = createMockStore({ list: [] })
const queries = createMockStore({ list: [] })
const roles = createMockStore({ list: [] })
const screenStore = createMockStore({ screens: [] })
const appStore = createMockStore({})
const layoutStore = createMockStore({})
const selectedScreen = createMockStore(null)
const componentStore = {
getDefinition: () => null,
getComponentSettings: () => [],
}
return {
module: {
workspaceAppStore,
tables,
queries,
roles,
screenStore,
appStore,
layoutStore,
selectedScreen,
componentStore,
},
tables,
queries,
}
}
vi.mock("@/stores/builder", () => createBuilderStores().module)
import {
tables as tablesStore,
queries as queriesStore,
} from "@/stores/builder"
const getTablesStore = () => tablesStore
const getQueriesStore = () => queriesStore
describe("Builder dataBinding", () => {
beforeEach(() => {
vi.clearAllMocks()
})
describe("makeReadableKeyPropSafe", () => {
it("wraps readable binding segments containing spaces", () => {
expect(makeReadableKeyPropSafe("Query rows")).toBe("[Query rows]")
})
it("preserves readable binding segments without spaces", () => {
expect(makeReadableKeyPropSafe("rows")).toBe("rows")
})
it("preserves already wrapped readable binding segments", () => {
expect(makeReadableKeyPropSafe("[Query rows]")).toBe("[Query rows]")
})
})
describe("runtimeToReadableBinding", () => {
const bindableProperties = [
{
category: "Current User",
icon: "user",
providerId: "user",
readableBinding: "Current User.firstName",
runtimeBinding: "[user].[firstName]",
type: "context",
},
{
category: "Bindings",
icon: "brackets-angle",
readableBinding: "Binding.count",
runtimeBinding: "count",
type: "context",
},
{
category: "Current User",
icon: "user",
providerId: "user",
readableBinding: "Current User.fullName",
runtimeBinding: "[user].[fullName]",
type: "context",
},
]
it("should convert a runtime binding to a readable one", () => {
const textWithBindings = `Hello {{ [user].[firstName] }}! The count is {{ count }}.`
expect(
runtimeToReadableBinding(
bindableProperties,
textWithBindings,
"readableBinding"
)
).toEqual(
`Hello {{ Current User.firstName }}! The count is {{ Binding.count }}.`
)
})
it("should not convert to readable binding if it is already readable", () => {
const textWithBindings = `Hello {{ [user].[firstName] }}! The count is {{ Binding.count }}.`
expect(
runtimeToReadableBinding(
bindableProperties,
textWithBindings,
"readableBinding"
)
).toEqual(
`Hello {{ Current User.firstName }}! The count is {{ Binding.count }}.`
)
})
it("should convert fullName user bindings to readable format", () => {
const textWithBindings = `Hello {{ [user].[fullName] }}`
expect(
runtimeToReadableBinding(
bindableProperties,
textWithBindings,
"readableBinding"
)
).toEqual(`Hello {{ Current User.fullName }}`)
})
})
describe("readableToRuntimeBinding", () => {
const bindableProperties = [
{
category: "Current User",
icon: "user",
providerId: "user",
readableBinding: "Current User.firstName",
runtimeBinding: "[user].[firstName]",
type: "context",
},
{
category: "Bindings",
icon: "brackets-angle",
readableBinding: "Binding.count",
runtimeBinding: "count",
type: "context",
},
{
category: "Bindings",
icon: "brackets-angle",
readableBinding: "location",
runtimeBinding: "[location]",
type: "context",
},
{
category: "Bindings",
icon: "brackets-angle",
readableBinding: "foo.[bar]",
runtimeBinding: "[foo].[qwe]",
type: "context",
},
{
category: "Bindings",
icon: "brackets-angle",
readableBinding: "foo.baz",
runtimeBinding: "[foo].[baz]",
type: "context",
},
{
category: "Current User",
icon: "user",
providerId: "user",
readableBinding: "Current User.fullName",
runtimeBinding: "[user].[fullName]",
type: "context",
},
]
it("should convert a readable binding to a runtime one", () => {
const textWithBindings = `Hello {{ Current User.firstName }}! The count is {{ Binding.count }}.`
expect(
readableToRuntimeBinding(
bindableProperties,
textWithBindings,
"runtimeBinding"
)
).toEqual(`Hello {{ [user].[firstName] }}! The count is {{ count }}.`)
})
it("should not convert a partial match", () => {
const textWithBindings = `location {{ _location Zlocation location locationZ _location_ }}`
expect(
readableToRuntimeBinding(
bindableProperties,
textWithBindings,
"runtimeBinding"
)
).toEqual(
`location {{ _location Zlocation [location] locationZ _location_ }}`
)
})
it("should handle special characters in the readable binding", () => {
const textWithBindings = `{{ foo.baz }}`
expect(
readableToRuntimeBinding(
bindableProperties,
textWithBindings,
"runtimeBinding"
)
).toEqual(`{{ [foo].[baz] }}`)
})
it("should convert fullName user bindings to runtime format", () => {
const textWithBindings = `{{ Current User.fullName }}`
expect(
readableToRuntimeBinding(
bindableProperties,
textWithBindings,
"runtimeBinding"
)
).toEqual(`{{ [user].[fullName] }}`)
})
})
describe("getSchemaForDatasource", () => {
const tableId = "table_1"
const fieldName = "jsonColumn"
beforeEach(() => {
getTablesStore().set({ list: [] })
getQueriesStore().set({ list: [] })
})
it("uses json field schema when it contains a nested schema", () => {
const tablesStore = getTablesStore()
const jsonFieldSchema = {
type: "json",
schema: {
first: { type: "string" },
nested: {
type: "json",
schema: {
deep: { type: "number" },
},
},
},
}
tablesStore.set({
list: [
{
_id: tableId,
schema: {
[fieldName]: jsonFieldSchema,
},
},
],
})
const jsonArraySpy = vi.spyOn(JSONUtils, "getJSONArrayDatasourceSchema")
const datasource = {
type: "jsonarray",
tableId,
fieldName,
label: `${tableId}.${fieldName}`,
}
const { schema } = getSchemaForDatasource(null, datasource)
expect(jsonArraySpy).not.toHaveBeenCalled()
expect(schema.first).toMatchObject({ type: "string", name: "first" })
expect(schema.nested).toMatchObject({ type: "json", name: "nested" })
expect(schema["nested.deep"]).toMatchObject({
type: "number",
name: "nested.deep",
})
schema.first.type = "boolean"
expect(jsonFieldSchema.schema.first.type).toBe("string")
jsonArraySpy.mockRestore()
})
it("falls back to the JSON utility when no nested schema is provided", () => {
const tablesStore = getTablesStore()
const tableSchema = {
[fieldName]: {
type: "json",
},
}
tablesStore.set({
list: [
{
_id: tableId,
schema: tableSchema,
},
],
})
const jsonArraySpy = vi
.spyOn(JSONUtils, "getJSONArrayDatasourceSchema")
.mockReturnValue({
value: { type: "string" },
})
const datasource = {
type: "jsonarray",
tableId,
fieldName,
label: `${tableId}.${fieldName}`,
}
const { schema } = getSchemaForDatasource(null, datasource)
expect(jsonArraySpy).toHaveBeenCalledWith(tableSchema, datasource)
expect(schema.value).toMatchObject({ type: "string", name: "value" })
expect(typeof schema.value.display.type).toBe("string")
jsonArraySpy.mockRestore()
})
})
describe("updateReferencesInObject", () => {
it("should increment steps in sequence on 'add'", () => {
let obj = [
{
id: "a0",
parameters: {
text: "Alpha",
},
},
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.1.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.1.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.3.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.4.row }}",
},
},
]
updateReferencesInObject({
obj,
modifiedIndex: 0,
action: "add",
label: "actions",
})
expect(obj).toEqual([
{
id: "a0",
parameters: {
text: "Alpha",
},
},
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.2.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.2.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.4.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.5.row }}",
},
},
])
})
it("should decrement steps in sequence on 'delete'", () => {
let obj = [
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.1.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.3.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.4.row }}",
},
},
]
updateReferencesInObject({
obj,
modifiedIndex: 2,
action: "delete",
label: "actions",
})
expect(obj).toEqual([
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.1.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.2.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.3.row }}",
},
},
])
})
it("should handle on 'move' to a lower index", () => {
let obj = [
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.0.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.3.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.0.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.2.row }}",
},
},
]
updateReferencesInObject({
obj,
modifiedIndex: 2,
action: "move",
label: "actions",
originalIndex: 4,
})
expect(obj).toEqual([
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "b2",
parameters: {
text: "Banana {{ actions.0.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.4.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.0.row }}",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.3.row }}",
},
},
])
})
it("should not decrement references that sit before the moved action", () => {
let obj = [
{
id: "queryAction",
parameters: {
text: "{{ actions.0.result }}",
},
},
{
id: "notification",
parameters: {
text: "{{ actions.0.result }}",
},
},
{
id: "prompt",
parameters: {
text: "Prompt",
},
},
]
updateReferencesInObject({
obj,
modifiedIndex: 2,
action: "move",
label: "actions",
originalIndex: 1,
})
expect(obj[1].parameters.text).toEqual("{{ actions.0.result }}")
})
it("should skip move updates when the original index is invalid", () => {
let obj = [
{
id: "queryAction",
parameters: {
text: "{{ actions.0.result }}",
},
},
]
updateReferencesInObject({
obj,
modifiedIndex: 0,
action: "move",
label: "actions",
originalIndex: -1,
})
expect(obj[0].parameters.text).toEqual("{{ actions.0.result }}")
})
it("updates references nested inside arrays", () => {
let obj = {
parameters: {
rows: [
{
value: "{{ actions.1.row }}",
},
],
},
}
updateReferencesInObject({
obj,
modifiedIndex: 0,
action: "add",
label: "actions",
})
expect(obj.parameters.rows[0].value).toEqual("{{ actions.2.row }}")
})
it("should handle on 'move' to a higher index", () => {
let obj = [
{
id: "b2",
parameters: {
text: "Banana {{ actions.0.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.0.row }}",
},
},
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.2.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.3.row }}",
},
},
]
updateReferencesInObject({
obj,
modifiedIndex: 2,
action: "move",
label: "actions",
originalIndex: 0,
})
expect(obj).toEqual([
{
id: "b2",
parameters: {
text: "Banana {{ actions.2.row }}",
},
},
{
id: "c3",
parameters: {
text: "Carrot {{ actions.2.row }}",
},
},
{
id: "a1",
parameters: {
text: "Apple",
},
},
{
id: "d4",
parameters: {
text: "Dog {{ actions.1.row }}",
},
},
{
id: "e5",
parameters: {
text: "Eagle {{ actions.3.row }}",
},
},
])
})
it("should handle on 'move' of action being referenced, dragged to a higher index", () => {
let obj = [
{
"##eventHandlerType": "Validate Form",
id: "cCD0Dwcnq",
},
{
"##eventHandlerType": "Close Screen Modal",
id: "3fbbIOfN0H",
},
{
"##eventHandlerType": "Save Row",
parameters: {
tableId: "ta_bb_employee",
},
id: "aehg5cTmhR",
},
{
"##eventHandlerType": "Close Side Panel",
id: "mzkpf86cxo",
},
{
"##eventHandlerType": "Navigate To",
id: "h0uDFeJa8A",
},
{
parameters: {
autoDismiss: true,
type: "success",
message: "{{ actions.1.row }}",
},
"##eventHandlerType": "Show Notification",
id: "JEI5lAyJZ",
},
]
updateReferencesInObject({
obj,
modifiedIndex: 2,
action: "move",
label: "actions",
originalIndex: 1,
})
expect(obj).toEqual([
{
"##eventHandlerType": "Validate Form",
id: "cCD0Dwcnq",
},
{
"##eventHandlerType": "Close Screen Modal",
id: "3fbbIOfN0H",
},
{
"##eventHandlerType": "Save Row",
parameters: {
tableId: "ta_bb_employee",
},
id: "aehg5cTmhR",
},
{
"##eventHandlerType": "Close Side Panel",
id: "mzkpf86cxo",
},
{
"##eventHandlerType": "Navigate To",
id: "h0uDFeJa8A",
},
{
parameters: {
autoDismiss: true,
type: "success",
message: "{{ actions.2.row }}",
},
"##eventHandlerType": "Show Notification",
id: "JEI5lAyJZ",
},
])
})
it("should handle on 'move' of action being referenced, dragged to a lower index", () => {
let obj = [
{
"##eventHandlerType": "Save Row",
parameters: {
tableId: "ta_bb_employee",
},
id: "aehg5cTmhR",
},
{
"##eventHandlerType": "Validate Form",
id: "cCD0Dwcnq",
},
{
"##eventHandlerType": "Close Screen Modal",
id: "3fbbIOfN0H",
},
{
"##eventHandlerType": "Close Side Panel",
id: "mzkpf86cxo",
},
{
"##eventHandlerType": "Navigate To",
id: "h0uDFeJa8A",
},
{
parameters: {
autoDismiss: true,
type: "success",
message: "{{ actions.4.row }}",
},
"##eventHandlerType": "Show Notification",
id: "JEI5lAyJZ",
},
]
updateReferencesInObject({
obj,
modifiedIndex: 0,
action: "move",
label: "actions",
originalIndex: 4,
})
expect(obj).toEqual([
{
"##eventHandlerType": "Save Row",
parameters: {
tableId: "ta_bb_employee",
},
id: "aehg5cTmhR",
},
{
"##eventHandlerType": "Validate Form",
id: "cCD0Dwcnq",
},
{
"##eventHandlerType": "Close Screen Modal",
id: "3fbbIOfN0H",
},
{
"##eventHandlerType": "Close Side Panel",
id: "mzkpf86cxo",
},
{
"##eventHandlerType": "Navigate To",
id: "h0uDFeJa8A",
},
{
parameters: {
autoDismiss: true,
type: "success",
message: "{{ actions.0.row }}",
},
"##eventHandlerType": "Show Notification",
id: "JEI5lAyJZ",
},
])
})
})
describe("migrateReferencesInObject", () => {
it("migrates references nested inside arrays", () => {
let obj = {
parameters: {
rows: [
{
value: "{{ actions.1.row }}",
},
],
},
}
migrateReferencesInObject({
obj,
label: "actions",
steps: [{ id: "first" }, { id: "second" }],
})
expect(obj.parameters.rows[0].value).toEqual("{{ actions.second.row }}")
})
})
describe("removeBindings", () => {
it("removes bindings nested inside arrays", () => {
let obj = {
parameters: {
rows: [
{
value: "Result: {{ actions.1.row }}",
},
],
},
}
removeBindings(obj)
expect(obj.parameters.rows[0].value).toEqual("Result: Invalid binding")
})
})
})
File diff suppressed because it is too large Load Diff
+160 -5
View File
@@ -1313,11 +1313,21 @@
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
"@babel/helper-string-parser@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f"
integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==
"@babel/helper-validator-identifier@^7.28.5":
version "7.28.5"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4"
integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==
"@babel/helper-validator-identifier@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2"
integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==
"@babel/helper-validator-option@^7.16.7", "@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"
@@ -1347,6 +1357,13 @@
dependencies:
"@babel/types" "^7.29.0"
"@babel/parser@^7.29.3":
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==
dependencies:
"@babel/types" "^7.29.7"
"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.28.5":
version "7.28.5"
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz#fbde57974707bbfa0376d34d425ff4fa6c732421"
@@ -2288,6 +2305,14 @@
"@babel/helper-string-parser" "^7.27.1"
"@babel/helper-validator-identifier" "^7.28.5"
"@babel/types@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.7.tgz#8005e31d82712ee7adaef6e23c63b71a62770a92"
integrity sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==
dependencies:
"@babel/helper-string-parser" "^7.29.7"
"@babel/helper-validator-identifier" "^7.29.7"
"@balena/dockerignore@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d"
@@ -2298,6 +2323,11 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@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==
"@budibase/handlebars-helpers@^0.13.2":
version "0.13.2"
resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.13.2.tgz#73ab51c464e91fd955b429017648e0257060db77"
@@ -3866,7 +3896,7 @@
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@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.12", "@jridgewell/trace-mapping@^0.3.18", "@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==
@@ -8071,6 +8101,22 @@
resolved "https://registry.yarnpkg.com/@vercel/oidc/-/oidc-3.1.0.tgz#066caee449b84079f33c7445fc862464fe10ec32"
integrity sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==
"@vitest/coverage-v8@4.1.8":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-4.1.8.tgz#6a5dd34552840a0ace0396d0e94c7459beb80d14"
integrity sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==
dependencies:
"@bcoe/v8-coverage" "^1.0.2"
"@vitest/utils" "4.1.8"
ast-v8-to-istanbul "^1.0.0"
istanbul-lib-coverage "^3.2.2"
istanbul-lib-report "^3.0.1"
istanbul-reports "^3.2.0"
magicast "^0.5.2"
obug "^2.1.1"
std-env "^4.0.0-rc.1"
tinyrainbow "^3.1.0"
"@vitest/eslint-plugin@1.3.5":
version "1.3.5"
resolved "https://registry.yarnpkg.com/@vitest/eslint-plugin/-/eslint-plugin-1.3.5.tgz#51a46d1b9a5654399a7f3e6b0b67713dea6f07f6"
@@ -8091,6 +8137,18 @@
chai "^6.2.2"
tinyrainbow "^3.0.3"
"@vitest/expect@4.1.8":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-4.1.8.tgz#45154f1f8559f55c5281eb0dcb1ac37b581a87d8"
integrity sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==
dependencies:
"@standard-schema/spec" "^1.1.0"
"@types/chai" "^5.2.2"
"@vitest/spy" "4.1.8"
"@vitest/utils" "4.1.8"
chai "^6.2.2"
tinyrainbow "^3.1.0"
"@vitest/mocker@4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-4.1.0.tgz#2aabf6079ad472f89a212d322f7d5da7ad628a0e"
@@ -8100,6 +8158,15 @@
estree-walker "^3.0.3"
magic-string "^0.30.21"
"@vitest/mocker@4.1.8":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-4.1.8.tgz#d006bfc5894a1af51e74deddef2535d6bd436b16"
integrity sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==
dependencies:
"@vitest/spy" "4.1.8"
estree-walker "^3.0.3"
magic-string "^0.30.21"
"@vitest/pretty-format@4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-4.1.0.tgz#b6ccf2868130a647d24af3696d58c09a95eb83c1"
@@ -8107,6 +8174,13 @@
dependencies:
tinyrainbow "^3.0.3"
"@vitest/pretty-format@4.1.8":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-4.1.8.tgz#d9d2e248b900d7ad9556c4374fcdf1871c615193"
integrity sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==
dependencies:
tinyrainbow "^3.1.0"
"@vitest/runner@4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-4.1.0.tgz#4e12c0f086eb3a4ae3fae84d9d68b22d02942cbf"
@@ -8115,6 +8189,14 @@
"@vitest/utils" "4.1.0"
pathe "^2.0.3"
"@vitest/runner@4.1.8":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-4.1.8.tgz#4631808f3996359b74ccc3ca262990e14c295d50"
integrity sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==
dependencies:
"@vitest/utils" "4.1.8"
pathe "^2.0.3"
"@vitest/snapshot@4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-4.1.0.tgz#67372979da692ccf5dfa4a3bb603f683c0640202"
@@ -8125,11 +8207,26 @@
magic-string "^0.30.21"
pathe "^2.0.3"
"@vitest/snapshot@4.1.8":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-4.1.8.tgz#37470135d64ea11bb2a839b1c6b7f5de7018f6ee"
integrity sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==
dependencies:
"@vitest/pretty-format" "4.1.8"
"@vitest/utils" "4.1.8"
magic-string "^0.30.21"
pathe "^2.0.3"
"@vitest/spy@4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-4.1.0.tgz#b9143a63cca83de34ac1777c733f8561b73fa9ba"
integrity sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==
"@vitest/spy@4.1.8":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-4.1.8.tgz#3abfe9301d25c39f808dcaa9f10fec0dd370e564"
integrity sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==
"@vitest/utils@4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-4.1.0.tgz#2baf26a2a28c4aabe336315dc59722df2372c38d"
@@ -8139,6 +8236,15 @@
convert-source-map "^2.0.0"
tinyrainbow "^3.0.3"
"@vitest/utils@4.1.8":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-4.1.8.tgz#099ea5255cec08735410cf707edaba2c158c5ad9"
integrity sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==
dependencies:
"@vitest/pretty-format" "4.1.8"
convert-source-map "^2.0.0"
tinyrainbow "^3.1.0"
"@vladfrangu/async_event_emitter@^2.2.4", "@vladfrangu/async_event_emitter@^2.4.6":
version "2.4.7"
resolved "https://registry.yarnpkg.com/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.7.tgz#5d6db8b20e2a3d729834e7cda429d1b6723ff91b"
@@ -8771,6 +8877,15 @@ ast-module-types@^4.0.0:
resolved "https://registry.yarnpkg.com/ast-module-types/-/ast-module-types-4.0.0.tgz#17e1cadd5b5b108e7295b0cf0cff21ccc226b639"
integrity sha512-Kd0o8r6CDazJGCRzs8Ivpn0xj19oNKrULhoJFzhGjRsLpekF2zyZs9Ukz+JvZhWD6smszfepakTFhAaYpsI12g==
ast-v8-to-istanbul@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.3.tgz#ba858c396a3d45f36a6963594fdfcd4675dfd445"
integrity sha512-jCMQ6ZylLPudp0CDfBmQBZUsrh1/8psbmu9ibeVWKuHWD0YrH9YABwlKu5kVEFoT0GCQQW9Z/SxfuEbbkGQCRg==
dependencies:
"@jridgewell/trace-mapping" "^0.3.31"
estree-walker "^3.0.3"
js-tokens "^10.0.0"
async-function@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b"
@@ -14863,7 +14978,7 @@ istanbul-lib-instrument@^6.0.0, istanbul-lib-instrument@^6.0.2:
istanbul-lib-coverage "^3.2.0"
semver "^7.5.4"
istanbul-lib-report@^3.0.0:
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==
@@ -14881,7 +14996,7 @@ istanbul-lib-source-maps@^5.0.0:
debug "^4.1.1"
istanbul-lib-coverage "^3.0.0"
istanbul-reports@^3.1.3:
istanbul-reports@^3.1.3, istanbul-reports@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93"
integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==
@@ -15453,6 +15568,11 @@ js-md4@^0.3.2:
resolved "https://registry.yarnpkg.com/js-md4/-/js-md4-0.3.2.tgz#cd3b3dc045b0c404556c81ddb5756c23e59d7cf5"
integrity sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==
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"
@@ -16839,6 +16959,15 @@ magic-string@^0.30.11, magic-string@^0.30.21, magic-string@^0.30.3, magic-string
dependencies:
"@jridgewell/sourcemap-codec" "^1.5.5"
magicast@^0.5.2:
version "0.5.3"
resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.5.3.tgz#1800f6e76dd8b0dbe7257438a2c336aefabbd905"
integrity sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==
dependencies:
"@babel/parser" "^7.29.3"
"@babel/types" "^7.29.0"
source-map-js "^1.2.1"
maildev@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/maildev/-/maildev-2.2.1.tgz#0a7ea8188bc6d9fea6bd08dbc63ecf4872acc67c"
@@ -22754,7 +22883,7 @@ tinyglobby@^0.2.12, tinyglobby@^0.2.15, tinyglobby@^0.2.17:
fdir "^6.5.0"
picomatch "^4.0.4"
tinyrainbow@^3.0.3:
tinyrainbow@^3.0.3, tinyrainbow@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-3.1.0.tgz#1d8a623893f95cf0a2ddb9e5d11150e191409421"
integrity sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==
@@ -23636,7 +23765,7 @@ vite@7.3.2:
optionalDependencies:
fsevents "~2.3.3"
"vite@^6.0.0 || ^7.0.0 || ^8.0.0-0":
"vite@^6.0.0 || ^7.0.0 || ^8.0.0", "vite@^6.0.0 || ^7.0.0 || ^8.0.0-0":
version "8.0.16"
resolved "https://registry.yarnpkg.com/vite/-/vite-8.0.16.tgz#ae073866c06563d6634a90169a496e11bd84f1a6"
integrity sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==
@@ -23680,6 +23809,32 @@ vitest@^4.1.0:
vite "^6.0.0 || ^7.0.0 || ^8.0.0-0"
why-is-node-running "^2.3.0"
vitest@^4.1.8:
version "4.1.8"
resolved "https://registry.yarnpkg.com/vitest/-/vitest-4.1.8.tgz#9fed17277bf7350497e54338898a7afd46dfd509"
integrity sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==
dependencies:
"@vitest/expect" "4.1.8"
"@vitest/mocker" "4.1.8"
"@vitest/pretty-format" "4.1.8"
"@vitest/runner" "4.1.8"
"@vitest/snapshot" "4.1.8"
"@vitest/spy" "4.1.8"
"@vitest/utils" "4.1.8"
es-module-lexer "^2.0.0"
expect-type "^1.3.0"
magic-string "^0.30.21"
obug "^2.1.1"
pathe "^2.0.3"
picomatch "^4.0.3"
std-env "^4.0.0-rc.1"
tinybench "^2.9.0"
tinyexec "^1.0.2"
tinyglobby "^0.2.15"
tinyrainbow "^3.1.0"
vite "^6.0.0 || ^7.0.0 || ^8.0.0"
why-is-node-running "^2.3.0"
vuvuzela@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b"