diff --git a/components/AccountPlaceholder.vue b/components/AccountPlaceholder.vue index 6b61f929ff9729c0150b69d70f3393d79d892071..a155f1427b905fff3437a515ea8c3c08bf53554f 100644 --- a/components/AccountPlaceholder.vue +++ b/components/AccountPlaceholder.vue @@ -1,6 +1,6 @@ <script setup lang="ts"> import userData from '~/data/mock/user.json'; -import {UserMapper} from "~/utils/mapper/UserMapper"; +import {UserMapper} from "~/server/utils/mapper/UserMapper"; const user = ref<User>(UserMapper.from(userData)); diff --git a/components/ExerciceItem.vue b/components/Parcours/ExerciceItem.vue similarity index 100% rename from components/ExerciceItem.vue rename to components/Parcours/ExerciceItem.vue diff --git a/components/Parcours/Exercices.vue b/components/Parcours/Exercices.vue index e53d45d2fe0292f78781b2df6926ac1b201907b8..1734ac10cddc4e8e03ad8872d6764e23f3f9ca25 100644 --- a/components/Parcours/Exercices.vue +++ b/components/Parcours/Exercices.vue @@ -1,15 +1,8 @@ <script setup lang="ts"> -import L, {type LeafletMouseEvent, Marker, type PointTuple} from 'leaflet'; +import L, {type LeafletMouseEvent, Marker, type MarkerOptions, type PointTuple} from 'leaflet'; import 'leaflet.markercluster'; -import myData from '~/data/mock/exercices.json'; import type {Exercise} from "~/types/Exercise"; - -const {$api} = useNuxtApp(); -const map = ref(null) as any; -const inCreation = ref(false); -const exercises = await $api.exercises.getExercises(); -const exerciseSearch = ref(''); -const selectedExercises: Exercise[] = []; +import type {Step} from "~/types/Step"; // TODO : Move to a separate file interface MarkerCluster { @@ -17,48 +10,69 @@ interface MarkerCluster { markers: Marker[]; } +interface MarkerProps { + name?: string, + lat: number, + lng: number, + options: MarkerOptions, + popup?: string +} + +const {$api} = useNuxtApp(); + +// Map utilities +const exerciseSearch = ref(''); +const inCreation = ref(false); +const locations = ref<MarkerProps[]>([]); +const map = ref(null) as any; let markerCluster: MarkerCluster; +let createCluster: MarkerCluster; -// DATA -const zoom = ref(17) -const chantrerie: PointTuple = [47.287, -1.524] +const exercises = ref<Exercise[]>([]); +const selectedExercises: Exercise[] = []; +const steps = ref<Step[]>([]); -const locations: any = myData.map((exo) => { - return { - name: exo.id, - lat: exo.lat, - lng: exo.lng, - options: { - icon: L.icon({ +// TODO : Make it dynamic +const zoom = ref(17) +const center: PointTuple = [47.287, -1.524] + +async function updateLocations() { + locations.value = steps.value.map((step) => { + return { + name: step.id.toString(), + lat: step.latitude, + lng: step.longitude, + options: { + icon: L.icon({ + iconUrl: '/svg/pin.svg', + iconSize: [30, 30], + }) + } + } + }) + markerCluster?.markerCluster?.clearLayers(); + markerCluster = await useLMarkerCluster({ + leafletObject: map?.value?.leafletObject, + markers: locations.value as MarkerProps[] + }) + markerCluster.markers.forEach((marker: Marker) => { + marker.on('click', onMarkerSelect); + marker.on('mouseover', () => { + marker.setIcon(L.icon({ + iconUrl: '/svg/pin.svg', + iconSize: [45, 45], + })); + }); + marker.on('mouseout', () => { + marker.setIcon(L.icon({ iconUrl: '/svg/pin.svg', iconSize: [30, 30], - }) - }, - popup: exo.name - } -}) + })); + }); + }) +} -// TODO & FIXME : menu contextuel à revoir const items = ref([ - [ - { - label: 'Appearance', - children: [ - { - label: 'System', - icon: 'i-lucide-monitor' - }, - { - label: 'Light', - icon: 'i-lucide-sun' - }, - { - label: 'Dark', - icon: 'i-lucide-moon' - } - ] - } - ], [ { label: 'Delete the point', @@ -69,22 +83,23 @@ const items = ref([ ], ]) -// Functions async function onMapReady() { - markerCluster = await useLMarkerCluster({ + createCluster = await useLMarkerCluster({ leafletObject: map?.value?.leafletObject, - markers: locations + markers: [], }); + steps.value = (await $api.step.postArea(map.value.leafletObject.getBounds())).message as Step[]; + await updateLocations(); - map.value.leafletObject.on('moveend', () => { - // ask api for new markers in bounds - // map.value.leafletObject.getBounds() + map.value.leafletObject.on('moveend', async () => { + steps.value = (await $api.step.postArea(map.value.leafletObject.getBounds())).message as Step[]; + await updateLocations(); }); } function deleteMarker(): void { if (!inCreation.value) return; - markerCluster.markerCluster.clearLayers(); + createCluster.markerCluster.clearLayers(); inCreation.value = false; } @@ -99,66 +114,19 @@ function MapEvents(e: LeafletMouseEvent): void { iconUrl: '/svg/pinadd.svg', iconSize: [30, 30], })); - markerCluster.markerCluster.addLayer(newMarker); + createCluster.markerCluster.addLayer(newMarker); } -// TODO : changement d'affichage des clusters -const _cluster_visible = (cluster: any) => L.divIcon({ - html: `<div style="background-color: red;">${cluster.getChildCount()}</div>`, - className: 'marker-cluster', - iconSize: L.point(40, 40) -}); - -// FIXME : still a lot of works around this -function hooverMarker(exo: Exercise): void { - markerCluster.markers.find((marker: Marker) => { - if (marker.getLatLng().lat === exo.lat && marker.getLatLng().lng === exo.lng) { - if (map.value.leafletObject.hasLayer(marker)) { - // Not in a cluster (ie marker is visible on map) - marker.setIcon(L.icon({ - iconUrl: '/svg/pin.svg', - iconSize: [45, 45], - })); - // } else { - // In a cluster (ie marker is not visible on map) - // map.value.leafletObject.eachLayer((layer: any) => { - // if (layer instanceof L.FeatureGroup && layer.hasLayer(marker)) { - // (layer as any).options = { - // iconCreateFunction: (cluster: any) => { - // return L.divIcon({ - // html: `<div style="background-color: red;">${cluster.getChildCount()}</div>`, - // className: 'marker-cluster', - // iconSize: L.point(40, 40) - // }); - // } - // } - // console.log((layer as any)); - // console.log((layer as any)._markerCluster); - // (newMarkerCluster as any).refreshClusters(); - // (layer as any).setIcon(cluster_visible); - // map.value.leafletObject.removeLayer(layer); - // map.value.leafletObject.addLayer(layer); - // (map.value.leafletObject as L.LayerGroup) - // } - // }); - } - } - }); +// TODO : reimplement these ? => see git history +function mouseoverExercise(_: Exercise): void { + return } - -function leaveMarker(exo: Exercise): void { - markerCluster.markers.find((marker: any) => { - if (marker.getLatLng().lat === exo.lat && marker.getLatLng().lng === exo.lng) { - marker.setIcon(L.icon({ - iconUrl: '/svg/pin.svg', - iconSize: [30, 30], - })); - } - }); +function mouseoutExercise(_: Exercise): void { + return } function filterExercise(): Exercise[] { - return exercises.filter((exo: Exercise) => { + return exercises.value.filter((exo: Exercise) => { return exo.name.toLowerCase().includes(exerciseSearch.value.toLowerCase()); }); } @@ -167,7 +135,7 @@ function onExerciceClick(exo: Exercise): void { if (exo.selected) { selectedExercises.splice(selectedExercises.indexOf(exo), 1); document.getElementById(`exercise-item-${exo.id}`)?.classList.remove('exercise-selected'); - exercises.find((exercise: Exercise) => { + exercises.value.find((exercise: Exercise) => { if (exercise.id === exo.id) { exercise.selected = false; } @@ -175,35 +143,49 @@ function onExerciceClick(exo: Exercise): void { } else { selectedExercises.push(exo); document.getElementById(`exercise-item-${exo.id}`)?.classList.add('exercise-selected'); - exercises.find((exercise: Exercise) => { + exercises.value.find((exercise: Exercise) => { if (exercise.id === exo.id) { exercise.selected = true; } }) } } + +function onMarkerSelect(e: PointerEvent): void { + if (e.target instanceof Marker) { + const stepId = (e.target as Marker).options.title; + exercises.value = steps.value + .filter((step: Step) => step.id.toString() === stepId) + .map((step: Step) => { + return step.specificExercises + .concat(step.terrainType.genericExercises); + }).flat(); + } +} </script> <template> <div id="exercices"> <UContextMenu :items="items" :ui="{ content: 'w-48' }"> - <LMap - ref="map" - :zoom="zoom" - :min-zoom="15" - :center="chantrerie" - :use-global-leaflet="true" - :options="{ zoomSnap: 0.75 }" - @ready="onMapReady" - @click="MapEvents" - > - <LTileLayer - url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" - attribution="&copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a>" - layer-type="base" - name="OpenStreetMap" - /> - </LMap> + <div> + <LMap + ref="map" + :zoom="zoom" + :min-zoom="15" + :center="center" + :use-global-leaflet="true" + :options="{ zoomSnap: 0.75 }" + @ready="onMapReady" + @click="MapEvents" + > + <LTileLayer + url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + attribution="&copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a>" + layer-type="base" + name="OpenStreetMap" + /> + </LMap> + </div> </UContextMenu> <div id="side" class="flex flex-col w-full h-full p-2 overflow-hidden"> <UInput @@ -222,13 +204,13 @@ function onExerciceClick(exo: Exercise): void { </UInput> <USeparator class="m-1 w-full"/> <div id="exercices-list" class="flex flex-col w-full h-full overflow-auto gap-1"> - <ExerciceItem + <ParcoursExerciceItem v-for="exercise in filterExercise()" :id="'exercise-item-'+exercise.id" :key="exercise.id" ref="list" :exercise="exercise as Exercise" class="skeletton gap-4" @click="onExerciceClick(exercise)" - @mouseover="hooverMarker(exercise as Exercise)" @mouseleave="leaveMarker(exercise as Exercise)"/> + @mouseover="mouseoverExercise(exercise as Exercise)" @mouseleave="mouseoutExercise(exercise as Exercise)"/> <div class="skeletton gap-4"> <USkeleton class="h-12 w-12 rounded-full"/> <div class="grid gap-2 w-full"> diff --git a/package-lock.json b/package-lock.json index d65a610b6943a840ea2fe5f078c1beb5e5361d3f..8fb3542ba8186ae28566fd332f222108bf0e409d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,7 @@ "name": "nuxt-app", "hasInstallScript": true, "dependencies": { - "@nuxt/eslint": "^1.0.1", + "@nuxt/eslint": "^1.1.0", "@nuxt/ui": "^3.0.0-alpha.13", "@nuxtjs/leaflet": "^1.2.6", "eslint": "^9.20.1", @@ -22,9 +22,9 @@ "@iconify-json/material-symbols": "^1.2.14", "@nuxt/test-utils": "^3.15.4", "@vue/test-utils": "^2.4.6", - "happy-dom": "^17.1.0", + "happy-dom": "^17.1.1", "typescript": "^5.7.3", - "vitest": "^3.0.5" + "vitest": "^3.0.6" } }, "node_modules/@alloc/quick-lru": { @@ -584,9 +584,9 @@ } }, "node_modules/@clack/prompts": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.9.1.tgz", - "integrity": "sha512-JIpyaboYZeWYlyP0H+OoPPxd6nqueG/CmN6ixBiNFsIDHREevjIf0n0Ohh5gr5C8pEDknzgvz+pIJ8dMhzWIeg==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.10.0.tgz", + "integrity": "sha512-H3rCl6CwW1NdQt9rE3n373t7o5cthPv7yUoxF2ytZvyvlJv89C5RYMJu83Hed8ODgys5vpBU0GKxIRG83jd8NQ==", "license": "MIT", "dependencies": { "@clack/core": "0.4.1", @@ -1966,15 +1966,15 @@ } }, "node_modules/@nuxt/eslint": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@nuxt/eslint/-/eslint-1.0.1.tgz", - "integrity": "sha512-Bh6M9Tjf4jyIyfobu/ekW6YHMCsWpvZHuZN/6tRVKwXgAL6fiJG6tHm3uYJ5ILcVTdp6tz/j/sW8dgP+ijHLDQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@nuxt/eslint/-/eslint-1.1.0.tgz", + "integrity": "sha512-T5CmWwMhJIjpPk2yTSj2aOifBug5bRA3sv8ec6FpWZV+cMBV9wnXsAxrIHjX+PZMt691It89ORunPjkoPSCDVQ==", "license": "MIT", "dependencies": { "@eslint/config-inspector": "^1.0.0", - "@nuxt/devtools-kit": "^1.7.0", - "@nuxt/eslint-config": "1.0.1", - "@nuxt/eslint-plugin": "1.0.1", + "@nuxt/devtools-kit": "^2.1.0", + "@nuxt/eslint-config": "1.1.0", + "@nuxt/eslint-plugin": "1.1.0", "@nuxt/kit": "^3.15.4", "chokidar": "^4.0.3", "eslint-flat-config-utils": "^2.0.1", @@ -1982,8 +1982,8 @@ "find-up": "^7.0.0", "get-port-please": "^3.1.2", "mlly": "^1.7.4", - "pathe": "^2.0.2", - "unimport": "^4.1.0" + "pathe": "^2.0.3", + "unimport": "^4.1.2" }, "peerDependencies": { "eslint": "^9.0.0", @@ -2000,30 +2000,30 @@ } }, "node_modules/@nuxt/eslint-config": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@nuxt/eslint-config/-/eslint-config-1.0.1.tgz", - "integrity": "sha512-N1sSvtrCWehBHOhB4VBVDxZyDxkXv5b4QN+NQC0suCGR4VekZj8mciaepWFTb66gNrpA/IHYfBId308Na++FwA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@nuxt/eslint-config/-/eslint-config-1.1.0.tgz", + "integrity": "sha512-xPKoACePUL5ItyLRqsExTnuQOeOr0JiQ7ESY7XKeJZAxAUUiWRuxpxDbPoHX9REKlz2oVBSzFQZFnJzpOPNyrA==", "license": "MIT", "dependencies": { "@antfu/install-pkg": "^1.0.0", - "@clack/prompts": "^0.9.1", - "@eslint/js": "^9.19.0", - "@nuxt/eslint-plugin": "1.0.1", - "@stylistic/eslint-plugin": "^3.0.1", - "@typescript-eslint/eslint-plugin": "^8.23.0", - "@typescript-eslint/parser": "^8.23.0", - "eslint-config-flat-gitignore": "^2.0.0", + "@clack/prompts": "^0.10.0", + "@eslint/js": "^9.20.0", + "@nuxt/eslint-plugin": "1.1.0", + "@stylistic/eslint-plugin": "^4.0.0", + "@typescript-eslint/eslint-plugin": "^8.24.1", + "@typescript-eslint/parser": "^8.24.1", + "eslint-config-flat-gitignore": "^2.1.0", "eslint-flat-config-utils": "^2.0.1", - "eslint-merge-processors": "^1.0.0", + "eslint-merge-processors": "^2.0.0", "eslint-plugin-import-x": "^4.6.1", "eslint-plugin-jsdoc": "^50.6.3", "eslint-plugin-regexp": "^2.7.0", - "eslint-plugin-unicorn": "^56.0.1", + "eslint-plugin-unicorn": "^57.0.0", "eslint-plugin-vue": "^9.32.0", - "eslint-processor-vue-blocks": "^1.0.0", - "globals": "^15.14.0", + "eslint-processor-vue-blocks": "^2.0.0", + "globals": "^15.15.0", "local-pkg": "^1.0.0", - "pathe": "^2.0.2", + "pathe": "^2.0.3", "vue-eslint-parser": "^9.4.3" }, "peerDependencies": { @@ -2036,6 +2036,18 @@ } } }, + "node_modules/@nuxt/eslint-config/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@nuxt/eslint-config/node_modules/local-pkg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.0.0.tgz", @@ -2053,18 +2065,44 @@ } }, "node_modules/@nuxt/eslint-plugin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@nuxt/eslint-plugin/-/eslint-plugin-1.0.1.tgz", - "integrity": "sha512-pqad64otqRmYTnaUSD1Jc57iWHACdWebD6UUb1hLVl/ML1B4yFxn5xq8kXRjzQsSKX3yMs7dFTYS0ygw04n+SA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@nuxt/eslint-plugin/-/eslint-plugin-1.1.0.tgz", + "integrity": "sha512-WRN2xvEdNfqLgjllDG8jtK/31daGitVpr2yb7N9XNNYIh29mWD0GP1lN8znBbJvnG3AXwN9qOb8NAXXvekw/IQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "^8.23.0", - "@typescript-eslint/utils": "^8.23.0" + "@typescript-eslint/types": "^8.24.1", + "@typescript-eslint/utils": "^8.24.1" }, "peerDependencies": { "eslint": "^9.0.0" } }, + "node_modules/@nuxt/eslint/node_modules/@nuxt/devtools-kit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-2.1.0.tgz", + "integrity": "sha512-1fhwU7dDq/vIpjpNRwjEmTllRT1O0nzyBEhY187bQ8xBpoCC93t3zG3iTKcl8XkpT1aK9SqcgmXOnj5fNIAaYA==", + "license": "MIT", + "dependencies": { + "@nuxt/kit": "^3.15.4", + "@nuxt/schema": "^3.15.4", + "execa": "^9.5.2" + }, + "peerDependencies": { + "vite": ">=6.0" + } + }, + "node_modules/@nuxt/eslint/node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@nuxt/eslint/node_modules/escape-string-regexp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", @@ -2077,6 +2115,69 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@nuxt/eslint/node_modules/execa": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", + "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.3", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.0", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@nuxt/eslint/node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@nuxt/eslint/node_modules/human-signals": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz", + "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@nuxt/eslint/node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@nuxt/eslint/node_modules/local-pkg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.0.0.tgz", @@ -2093,29 +2194,122 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/@nuxt/eslint/node_modules/unimport": { + "node_modules/@nuxt/eslint/node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@nuxt/eslint/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@nuxt/eslint/node_modules/signal-exit": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/unimport/-/unimport-4.1.0.tgz", - "integrity": "sha512-y5ZYDG+j7IB45+Y6CIkWIKou4E1JFigCUw6vI+h15HdYAKmT0oQWcawnxXuwJG8srJyXhIZuWz5uXB1MQ/ARZw==", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@nuxt/eslint/node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@nuxt/eslint/node_modules/tinyglobby": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.11.tgz", + "integrity": "sha512-32TmKeeKUahv0Go8WmQgiEp9Y21NuxjwjqiRC1nrUB51YacfSwuB44xgXD+HdIppmMRgjQNPdrHyA6vIybYZ+g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.4.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/@nuxt/eslint/node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@nuxt/eslint/node_modules/unimport": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unimport/-/unimport-4.1.2.tgz", + "integrity": "sha512-oVUL7PSlyVV3QRhsdcyYEMaDX8HJyS/CnUonEJTYA3//bWO+o/4gG8F7auGWWWkrrxBQBYOO8DKe+C53ktpRXw==", "license": "MIT", "dependencies": { "acorn": "^8.14.0", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", - "fast-glob": "^3.3.3", "local-pkg": "^1.0.0", "magic-string": "^0.30.17", "mlly": "^1.7.4", - "pathe": "^2.0.2", + "pathe": "^2.0.3", "picomatch": "^4.0.2", "pkg-types": "^1.3.1", "scule": "^1.3.0", "strip-literal": "^3.0.0", - "unplugin": "^2.1.2", - "unplugin-utils": "^0.2.3" + "tinyglobby": "^0.2.11", + "unplugin": "^2.2.0", + "unplugin-utils": "^0.2.4" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/@nuxt/eslint/node_modules/unplugin": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.2.0.tgz", + "integrity": "sha512-m1ekpSwuOT5hxkJeZGRxO7gXbXT3gF26NjQ7GdVHoLoF8/nopLcd/QfPigpCy7i51oFHiRJg/CyHhj4vs2+KGw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" }, "engines": { - "node": ">=18.20.6" + "node": ">=18.12.0" } }, "node_modules/@nuxt/fonts": { @@ -3578,12 +3772,12 @@ } }, "node_modules/@stylistic/eslint-plugin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-3.0.1.tgz", - "integrity": "sha512-rQ3tcT5N2cynofJfbjUsnL4seoewTaOVBLyUEwtNldo7iNMPo3h/GUQk+Cl3iHEWwRxjq2wuH6q0FufQrbVL1A==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-4.0.1.tgz", + "integrity": "sha512-RwKkRKiDrF4ptiur54ckDhOByQYKYZ1dEmI5K8BJCmuGpauFJXzVL1UQYTA2zq702CqMFdYiJcVFJWfokIgFxw==", "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^8.13.0", + "@typescript-eslint/utils": "^8.23.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "estraverse": "^5.3.0", @@ -3593,7 +3787,7 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "eslint": ">=8.40.0" + "eslint": ">=9.0.0" } }, "node_modules/@swc/helpers": { @@ -3986,16 +4180,16 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.23.0.tgz", - "integrity": "sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz", + "integrity": "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==", "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.23.0", - "@typescript-eslint/type-utils": "8.23.0", - "@typescript-eslint/utils": "8.23.0", - "@typescript-eslint/visitor-keys": "8.23.0", + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/type-utils": "8.24.1", + "@typescript-eslint/utils": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -4024,15 +4218,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.23.0.tgz", - "integrity": "sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.1.tgz", + "integrity": "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.23.0", - "@typescript-eslint/types": "8.23.0", - "@typescript-eslint/typescript-estree": "8.23.0", - "@typescript-eslint/visitor-keys": "8.23.0", + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/typescript-estree": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", "debug": "^4.3.4" }, "engines": { @@ -4048,13 +4242,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.23.0.tgz", - "integrity": "sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.1.tgz", + "integrity": "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.23.0", - "@typescript-eslint/visitor-keys": "8.23.0" + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4065,13 +4259,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.23.0.tgz", - "integrity": "sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz", + "integrity": "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==", "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.23.0", - "@typescript-eslint/utils": "8.23.0", + "@typescript-eslint/typescript-estree": "8.24.1", + "@typescript-eslint/utils": "8.24.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, @@ -4088,9 +4282,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz", - "integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.1.tgz", + "integrity": "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4101,13 +4295,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.23.0.tgz", - "integrity": "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.1.tgz", + "integrity": "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.23.0", - "@typescript-eslint/visitor-keys": "8.23.0", + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -4127,15 +4321,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.23.0.tgz", - "integrity": "sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.1.tgz", + "integrity": "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.23.0", - "@typescript-eslint/types": "8.23.0", - "@typescript-eslint/typescript-estree": "8.23.0" + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/typescript-estree": "8.24.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4150,12 +4344,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz", - "integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==", + "version": "8.24.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.1.tgz", + "integrity": "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.23.0", + "@typescript-eslint/types": "8.24.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -4361,15 +4555,15 @@ } }, "node_modules/@vitest/expect": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.5.tgz", - "integrity": "sha512-nNIOqupgZ4v5jWuQx2DSlHLEs7Q4Oh/7AYwNyE+k0UQzG7tSmjPXShUikn1mpNGzYEN2jJbTvLejwShMitovBA==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.6.tgz", + "integrity": "sha512-zBduHf/ja7/QRX4HdP1DSq5XrPgdN+jzLOwaTq/0qZjYfgETNFCKf9nOAp2j3hmom3oTbczuUzrzg9Hafh7hNg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.5", - "@vitest/utils": "3.0.5", - "chai": "^5.1.2", + "@vitest/spy": "3.0.6", + "@vitest/utils": "3.0.6", + "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, "funding": { @@ -4377,13 +4571,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.5.tgz", - "integrity": "sha512-CLPNBFBIE7x6aEGbIjaQAX03ZZlBMaWwAjBdMkIf/cAn6xzLTiM3zYqO/WAbieEjsAZir6tO71mzeHZoodThvw==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.6.tgz", + "integrity": "sha512-KPztr4/tn7qDGZfqlSPQoF2VgJcKxnDNhmfR3VgZ6Fy1bO8T9Fc1stUiTXtqz0yG24VpD00pZP5f8EOFknjNuQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.5", + "@vitest/spy": "3.0.6", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -4404,9 +4598,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.5.tgz", - "integrity": "sha512-CjUtdmpOcm4RVtB+up8r2vVDLR16Mgm/bYdkGFe3Yj/scRfCpbSi2W/BDSDcFK7ohw8UXvjMbOp9H4fByd/cOA==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.6.tgz", + "integrity": "sha512-Zyctv3dbNL+67qtHfRnUE/k8qxduOamRfAL1BurEIQSyOEFffoMvx2pnDSSbKAAVxY0Ej2J/GH2dQKI0W2JyVg==", "dev": true, "license": "MIT", "dependencies": { @@ -4417,38 +4611,38 @@ } }, "node_modules/@vitest/runner": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.5.tgz", - "integrity": "sha512-BAiZFityFexZQi2yN4OX3OkJC6scwRo8EhRB0Z5HIGGgd2q+Nq29LgHU/+ovCtd0fOfXj5ZI6pwdlUmC5bpi8A==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.6.tgz", + "integrity": "sha512-JopP4m/jGoaG1+CBqubV/5VMbi7L+NQCJTu1J1Pf6YaUbk7bZtaq5CX7p+8sY64Sjn1UQ1XJparHfcvTTdu9cA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.0.5", - "pathe": "^2.0.2" + "@vitest/utils": "3.0.6", + "pathe": "^2.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.5.tgz", - "integrity": "sha512-GJPZYcd7v8QNUJ7vRvLDmRwl+a1fGg4T/54lZXe+UOGy47F9yUfE18hRCtXL5aHN/AONu29NGzIXSVFh9K0feA==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.6.tgz", + "integrity": "sha512-qKSmxNQwT60kNwwJHMVwavvZsMGXWmngD023OHSgn873pV0lylK7dwBTfYP7e4URy5NiBCHHiQGA9DHkYkqRqg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.5", + "@vitest/pretty-format": "3.0.6", "magic-string": "^0.30.17", - "pathe": "^2.0.2" + "pathe": "^2.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/spy": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.5.tgz", - "integrity": "sha512-5fOzHj0WbUNqPK6blI/8VzZdkBlQLnT25knX0r4dbZI9qoZDf3qAdjoMmDcLG5A83W6oUUFJgUd0EYBc2P5xqg==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.6.tgz", + "integrity": "sha512-HfOGx/bXtjy24fDlTOpgiAEJbRfFxoX3zIGagCqACkFKKZ/TTOE6gYMKXlqecvxEndKFuNHcHqP081ggZ2yM0Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4459,14 +4653,14 @@ } }, "node_modules/@vitest/utils": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.5.tgz", - "integrity": "sha512-N9AX0NUoUtVwKwy21JtwzaqR5L5R5A99GAbrHfCCXK1lp593i/3AZAXhSP43wRQuxYsflrdzEfXZFo1reR1Nkg==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.6.tgz", + "integrity": "sha512-18ktZpf4GQFTbf9jK543uspU03Q2qya7ZGya5yiZ0Gx0nnnalBvd5ZBislbl2EhLjM8A8rt4OilqKG7QwcGkvQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.5", - "loupe": "^3.1.2", + "@vitest/pretty-format": "3.0.6", + "loupe": "^3.1.3", "tinyrainbow": "^2.0.0" }, "funding": { @@ -5377,12 +5571,12 @@ "license": "MIT" }, "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-4.0.0.tgz", + "integrity": "sha512-p1n8zyCkt1BVrKNFymOHjcDSAl7oq/gUvfgULv2EblgpPVQlQr9yHnWjg9IJ2MhfwPqiYqMMrr01OY7yQoK2yA==", "license": "MIT", "engines": { - "node": ">=6" + "node": ">=18.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5503,9 +5697,9 @@ "license": "CC-BY-4.0" }, "node_modules/chai": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", - "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", + "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", "dev": true, "license": "MIT", "dependencies": { @@ -6688,21 +6882,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/error-ex/node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "license": "MIT" - }, "node_modules/error-stack-parser-es": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz", @@ -6851,9 +7030,9 @@ } }, "node_modules/eslint-config-flat-gitignore": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.0.0.tgz", - "integrity": "sha512-9iH+DZO94uxsw5iFjzqa9GfahA5oK3nA1GoJK/6u8evAtooYJMwuSWiLcGDfrdLoqdQ5/kqFJKKuMY/+SAasvg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.1.0.tgz", + "integrity": "sha512-cJzNJ7L+psWp5mXM7jBX+fjHtBvvh06RBlcweMhKD8jWqQw0G78hOW5tpVALGHGFPsBV+ot2H+pdDGJy6CV8pA==", "license": "MIT", "dependencies": { "@eslint/compat": "^1.2.5" @@ -6898,9 +7077,9 @@ } }, "node_modules/eslint-merge-processors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-merge-processors/-/eslint-merge-processors-1.0.0.tgz", - "integrity": "sha512-4GybyHmhXtT7/W8RAouQzNM0791sYasJCTYHIAYjuiJvbNFY0jMKkoESREhX+mjX37dxiN6v4EqhZ1nc0tJF7A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-merge-processors/-/eslint-merge-processors-2.0.0.tgz", + "integrity": "sha512-sUuhSf3IrJdGooquEUB5TNpGNpBoQccbnaLHsb1XkBLUPPqCNivCpY05ZcpCOiV9uHwO2yxXEWVczVclzMxYlA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" @@ -6983,27 +7162,27 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "56.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-56.0.1.tgz", - "integrity": "sha512-FwVV0Uwf8XPfVnKSGpMg7NtlZh0G0gBarCaFcMUOoqPxXryxdYxTRRv4kH6B9TFCVIrjRXG+emcxIk2ayZilog==", + "version": "57.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-57.0.0.tgz", + "integrity": "sha512-zUYYa6zfNdTeG9BISWDlcLmz16c+2Ck2o5ZDHh0UzXJz3DEP7xjmlVDTzbyV0W+XksgZ0q37WEWzN2D2Ze+g9Q==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "@eslint-community/eslint-utils": "^4.4.0", - "ci-info": "^4.0.0", + "@babel/helper-validator-identifier": "^7.25.9", + "@eslint-community/eslint-utils": "^4.4.1", + "ci-info": "^4.1.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.38.1", + "core-js-compat": "^3.40.0", "esquery": "^1.6.0", - "globals": "^15.9.0", - "indent-string": "^4.0.0", - "is-builtin-module": "^3.2.1", - "jsesc": "^3.0.2", + "globals": "^15.15.0", + "indent-string": "^5.0.0", + "is-builtin-module": "^4.0.0", + "jsesc": "^3.1.0", "pluralize": "^8.0.0", - "read-pkg-up": "^7.0.1", + "read-package-up": "^11.0.0", "regexp-tree": "^0.1.27", - "regjsparser": "^0.10.0", - "semver": "^7.6.3", - "strip-indent": "^3.0.0" + "regjsparser": "^0.12.0", + "semver": "^7.7.1", + "strip-indent": "^4.0.0" }, "engines": { "node": ">=18.18" @@ -7012,7 +7191,19 @@ "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": ">=8.56.0" + "eslint": ">=9.20.0" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint-plugin-vue": { @@ -7065,16 +7256,16 @@ } }, "node_modules/eslint-processor-vue-blocks": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-processor-vue-blocks/-/eslint-processor-vue-blocks-1.0.0.tgz", - "integrity": "sha512-q+Wn9bCml65NwYtuINVCE5dUqZa/uVoY4jfc8qEDwWbcGqdRyfJJmAONNZsreA4Q9EJqjYGjk8Hk1QuwAktgkw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-processor-vue-blocks/-/eslint-processor-vue-blocks-2.0.0.tgz", + "integrity": "sha512-u4W0CJwGoWY3bjXAuFpc/b6eK3NQEI8MoeW7ritKj3G3z/WtHrKjkqf+wk8mPEy5rlMGS+k6AZYOw2XBoN/02Q==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { "@vue/compiler-sfc": "^3.3.0", - "eslint": "^8.50.0 || ^9.0.0" + "eslint": ">=9.0.0" } }, "node_modules/eslint-scope": { @@ -7626,6 +7817,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-up-simple": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz", + "integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -8078,9 +8281,9 @@ } }, "node_modules/happy-dom": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-17.1.0.tgz", - "integrity": "sha512-9tUhXyePCjzUMycaHS/IzrIpF69xiq/laAT7golk4MtZ6t8ft5+Rv7U3lfrs2b4NMH0JTL3EhZzjfahrPmOnaQ==", + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-17.1.1.tgz", + "integrity": "sha512-OSTkBlmD/6Do7gCd7nZB5iFq1bF9VQg/iFmjHmxvVX2S1UiOpo6sT+aFNnu3XUsB8hCZb9+GZ0G1g1TaMiAggw==", "dev": true, "license": "MIT", "dependencies": { @@ -8119,9 +8322,21 @@ "license": "MIT" }, "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC" }, "node_modules/html-tags": { @@ -8283,12 +8498,15 @@ } }, "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/index-to-position": { @@ -8361,15 +8579,15 @@ } }, "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-4.0.0.tgz", + "integrity": "sha512-rWP3AMAalQSesXO8gleROyL2iKU73SX5Er66losQn9rWOWL4Gef0a/xOEOVqjWGMuR2vHG3FJ8UUmT700O8oFg==", "license": "MIT", "dependencies": { - "builtin-modules": "^3.3.0" + "builtin-modules": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=18.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -8714,12 +8932,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "license": "MIT" }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "license": "MIT" - }, "node_modules/json-schema-to-typescript-lite": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/json-schema-to-typescript-lite/-/json-schema-to-typescript-lite-14.1.0.tgz", @@ -9125,12 +9337,6 @@ "url": "https://github.com/sponsors/antonk52" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" - }, "node_modules/listhen": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/listhen/-/listhen-1.9.0.tgz", @@ -9775,24 +9981,17 @@ } }, "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", "license": "BSD-2-Clause", "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "license": "ISC", - "bin": { - "semver": "bin/semver" + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/normalize-path": { @@ -10145,15 +10344,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -11145,135 +11335,42 @@ "destr": "^2.0.3" } }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "license": "MIT", - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "license": "MIT", - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", "license": "MIT", "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" + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, "node_modules/readable-stream": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", @@ -11380,23 +11477,27 @@ } }, "node_modules/regjsparser": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz", - "integrity": "sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "license": "MIT", "bin": { "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" } }, "node_modules/reka-ui": { @@ -11710,9 +11811,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -12179,15 +12280,18 @@ } }, "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", "license": "MIT", "dependencies": { - "min-indent": "^1.0.0" + "min-indent": "^1.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-json-comments": { @@ -13766,15 +13870,15 @@ } }, "node_modules/vite-node": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.5.tgz", - "integrity": "sha512-02JEJl7SbtwSDJdYS537nU6l+ktdvcREfLksk/NDAqtdKWGqHl+joXzEubHROmS3E6pip+Xgu2tFezMu75jH7A==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.6.tgz", + "integrity": "sha512-s51RzrTkXKJrhNbUzQRsarjmAae7VmMPAsRT7lppVpIg6mK3zGthP9Hgz0YQQKuNcF+Ii7DfYk3Fxz40jRmePw==", "license": "MIT", "dependencies": { "cac": "^6.7.14", "debug": "^4.4.0", "es-module-lexer": "^1.6.0", - "pathe": "^2.0.2", + "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0" }, "bin": { @@ -14050,31 +14154,31 @@ } }, "node_modules/vitest": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.5.tgz", - "integrity": "sha512-4dof+HvqONw9bvsYxtkfUp2uHsTN9bV2CZIi1pWgoFpL1Lld8LA1ka9q/ONSsoScAKG7NVGf2stJTI7XRkXb2Q==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.6.tgz", + "integrity": "sha512-/iL1Sc5VeDZKPDe58oGK4HUFLhw6b5XdY1MYawjuSaDA4sEfYlY9HnS6aCEG26fX+MgUi7MwlduTBHHAI/OvMA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "3.0.5", - "@vitest/mocker": "3.0.5", - "@vitest/pretty-format": "^3.0.5", - "@vitest/runner": "3.0.5", - "@vitest/snapshot": "3.0.5", - "@vitest/spy": "3.0.5", - "@vitest/utils": "3.0.5", - "chai": "^5.1.2", + "@vitest/expect": "3.0.6", + "@vitest/mocker": "3.0.6", + "@vitest/pretty-format": "^3.0.6", + "@vitest/runner": "3.0.6", + "@vitest/snapshot": "3.0.6", + "@vitest/spy": "3.0.6", + "@vitest/utils": "3.0.6", + "chai": "^5.2.0", "debug": "^4.4.0", "expect-type": "^1.1.0", "magic-string": "^0.30.17", - "pathe": "^2.0.2", + "pathe": "^2.0.3", "std-env": "^3.8.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinypool": "^1.0.2", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0", - "vite-node": "3.0.5", + "vite-node": "3.0.6", "why-is-node-running": "^2.3.0" }, "bin": { @@ -14090,8 +14194,8 @@ "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.0.5", - "@vitest/ui": "3.0.5", + "@vitest/browser": "3.0.6", + "@vitest/ui": "3.0.6", "happy-dom": "*", "jsdom": "*" }, diff --git a/package.json b/package.json index 4748729435c5ba2a0c1f65f8d467455f55fac6c6..3ae171200f7888c5b8b75bfde7afedaffa47eb92 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "test": "node_modules/.bin/vitest run --passWithNoTests" }, "dependencies": { - "@nuxt/eslint": "^1.0.1", + "@nuxt/eslint": "^1.1.0", "@nuxt/ui": "^3.0.0-alpha.13", "@nuxtjs/leaflet": "^1.2.6", "eslint": "^9.20.1", @@ -29,13 +29,13 @@ "@iconify-json/material-symbols": "^1.2.14", "@nuxt/test-utils": "^3.15.4", "@vue/test-utils": "^2.4.6", - "happy-dom": "^17.1.0", + "happy-dom": "^17.1.1", "typescript": "^5.7.3", - "vitest": "^3.0.5" + "vitest": "^3.0.6" }, "overrides": { "glob": "^11.0.1", - "happy-dom": "^17.1.0", + "happy-dom": "^17.1.1", "esbuild": "^0.25.0" } } diff --git a/plugins/api.ts b/plugins/api.ts index c24ff4cf2a743ca08c5077be3b9fd7655fbfabc6..774cb8882b795880cb2333aa44f51d3937376c7b 100644 --- a/plugins/api.ts +++ b/plugins/api.ts @@ -1,15 +1,18 @@ import ExerciseModule from "~/repository/module/exercise"; import UserModule from '~/repository/module/user'; +import StepModule from "~/repository/module/step"; interface IApiInstance { - users: UserModule; exercises: ExerciseModule; + step: StepModule; + users: UserModule; } export default defineNuxtPlugin(() => { const modules: IApiInstance = { - users: new UserModule(), - exercises: new ExerciseModule() + exercises: new ExerciseModule(), + step: new StepModule(), + users: new UserModule() }; return { diff --git a/repository/module/exercise.ts b/repository/module/exercise.ts index 79b489ca7f1f1dffedfba26769fba287cb90e949..b7b72962d2a53ced6a0a1e729496e5cf8eabee27 100644 --- a/repository/module/exercise.ts +++ b/repository/module/exercise.ts @@ -1,11 +1,9 @@ -import type {IExercise} from "~/repository/model/IExercise"; import {type Exercise, ExerciseClass} from "~/types/Exercise"; import type {ResponseBody} from "~/types/ResponseBody"; -import {ExerciseMapperFrom} from "~/utils/mapper/ExerciseMapper"; class ExerciseModule { - private readonly RESSOURCE: string = '/api/exercise' - private exercises: IExercise[] = []; + private readonly RESSOURCE: string = '/exercise' + private exercises: Exercise[] = []; /** * Get an exercise by its id @@ -20,7 +18,7 @@ class ExerciseModule { if (!ex) { return new ExerciseClass(this.getNewId()); } - return ExerciseMapperFrom(ex); + return ex; } /** @@ -31,7 +29,7 @@ class ExerciseModule { if (!this.exercises.length) { await this.fetchExercises(); } - return this.exercises.map((e) => ExerciseMapperFrom(e)); + return this.exercises.map((e) => e); } /** @@ -39,18 +37,18 @@ class ExerciseModule { * @param exercise the exercise to save * @return either a response as a string or the saved exercise with their associated status code */ - async saveExercise(exercise: Exercise): Promise<ResponseBody<string | IExercise>> { + async saveExercise(exercise: Exercise): Promise<ResponseBody<string | Exercise>> { const method = this.exercises.find((e) => e.id === exercise.id) ? 'PATCH' : 'POST'; - const data: ResponseBody<string | IExercise> = (await $fetch(this.RESSOURCE, { + const data: ResponseBody<string | Exercise> = (await $fetch(this.RESSOURCE, { method: method, body: JSON.stringify(exercise) })); if (data.statusCode == 200) { - this.exercises = this.exercises.map((e) => e.id === exercise.id ? data.message as IExercise : e); + this.exercises = this.exercises.map((e) => e.id === exercise.id ? data.message as Exercise: e); } else if (data.statusCode == 201) { - this.exercises.push(data.message as IExercise); + this.exercises.push(data.message as Exercise); } return data; } diff --git a/repository/module/step.ts b/repository/module/step.ts new file mode 100644 index 0000000000000000000000000000000000000000..26c9dc52dbfcaeeb9d16ea3d7eb920167dcd084a --- /dev/null +++ b/repository/module/step.ts @@ -0,0 +1,37 @@ +import type {LatLngBounds} from "leaflet"; +import type {ResponseBody} from "~/types/ResponseBody"; +import type {Step} from "~/types/Step"; + +type AreaBody = { + latMin: number; + latMax: number; + longMin: number; + longMax: number; +} + +class StepModule { + private readonly RESOURCE = '/step'; + + /** + * Return the products as array + * @param body + * @returns + */ + async postArea(body: LatLngBounds): Promise<ResponseBody<string | Step[]>> { + return await $fetch(`${this.RESOURCE}/fetch-in-area`, { + method: 'POST', + body: JSON.stringify(boundsToAreaBody(body)) + }) + } +} + +export default StepModule; + +function boundsToAreaBody(bounds: LatLngBounds): AreaBody { + return { + latMin: bounds?.getSouthWest().lat, + latMax: bounds?.getNorthEast().lat, + longMin: bounds?.getSouthWest().lng, + longMax: bounds?.getNorthEast().lng + } +} \ No newline at end of file diff --git a/repository/module/user.ts b/repository/module/user.ts index ae83479158908a0406b366a9886714aaa197bc02..338a8ceb9c9ea95e53388ab617f2aabcc9a34891 100644 --- a/repository/module/user.ts +++ b/repository/module/user.ts @@ -3,7 +3,7 @@ import type {ResponseBody} from "~/types/ResponseBody"; import type {IUser} from "~/repository/model/IUser"; class UserModule { - private readonly RESOURCE = '/api/auth'; + private readonly RESOURCE = '/auth'; /** * Return the products as array diff --git a/repository/model/IExercise.ts b/server/model/IExercise.ts similarity index 100% rename from repository/model/IExercise.ts rename to server/model/IExercise.ts diff --git a/server/model/IStep.ts b/server/model/IStep.ts new file mode 100644 index 0000000000000000000000000000000000000000..98231a69f8c631fb08fcb773f104092a4c24e752 --- /dev/null +++ b/server/model/IStep.ts @@ -0,0 +1,27 @@ +import type {IExercise} from "~/repository/model/IExercise"; + +export type ISpecificExercise = { + id: number; + exercise: IExercise; +} + +export type IGenericExercise = { + id: number; + exercise: IExercise; +} + +export type ITerrainType = { + id: number; + name: string; + description: string; + genericExercises: IGenericExercise[]; +} + +export type IStep = { + id: number; + latitude: number; + longitude: number; + radius: number; + specificExercise: ISpecificExercise[]; + terrainType: ITerrainType; +} diff --git a/repository/model/IUser.ts b/server/model/IUser.ts similarity index 100% rename from repository/model/IUser.ts rename to server/model/IUser.ts diff --git a/repository/model/LoginBody.ts b/server/model/LoginBody.ts similarity index 100% rename from repository/model/LoginBody.ts rename to server/model/LoginBody.ts diff --git a/server/api/auth/login.post.ts b/server/routes/auth/login.post.ts similarity index 82% rename from server/api/auth/login.post.ts rename to server/routes/auth/login.post.ts index 86114ac3434727a37fb6bc5c623c54012e5b4359..3602675b41698be31d64e654412e24a3012a9ac9 100644 --- a/server/api/auth/login.post.ts +++ b/server/routes/auth/login.post.ts @@ -2,14 +2,13 @@ import {appendResponseHeader, defineEventHandler, readBody} from "h3"; import {useRuntimeConfig} from "#imports"; export default defineEventHandler(async (event) => { - const url = event.path.replace('/api/', ''); const config = useRuntimeConfig(event); const headers = new Headers(); headers.set('Content-Type', 'application/json'); headers.set('accept', '*/*'); - const res = await fetch(`${config.public.apiBase}/${url}`, { + const res = await fetch(`${config.public.apiBase}${event.path}`, { method: 'POST', headers: headers, body: JSON.stringify(await readBody(event)) diff --git a/server/api/exercise/.delete.ts b/server/routes/exercise/.delete.ts similarity index 85% rename from server/api/exercise/.delete.ts rename to server/routes/exercise/.delete.ts index aaa9f5ab2ce5dd8ee415a591bc77e23819ab405d..fbcd077c616b984fd34e4fad3f3ac56372c0fcef 100644 --- a/server/api/exercise/.delete.ts +++ b/server/routes/exercise/.delete.ts @@ -4,14 +4,13 @@ import type {ResponseBody} from "~/types/ResponseBody"; // TODO : TU des différents retours de l'api export default defineEventHandler(async (event) => { - const url = event.path.replace('/api/', ''); const config = useRuntimeConfig(event); const headers = new Headers(); headers.set('accept', '*/*'); headers.set('Cookie', event.headers.get('Cookie') as string); - const res = await fetch(`${config.public.apiBase}/${url}`, { + const res = await fetch(`${config.public.apiBase}${event.path}`, { method: 'DELETE', headers: headers }) diff --git a/server/api/exercise/.get.ts b/server/routes/exercise/.get.ts similarity index 61% rename from server/api/exercise/.get.ts rename to server/routes/exercise/.get.ts index e1eda3dba0304f1b14ae993dd8a20748f5d8fd60..90ce48a0c89b4772d39511af32b09756f10f7b1d 100644 --- a/server/api/exercise/.get.ts +++ b/server/routes/exercise/.get.ts @@ -1,24 +1,24 @@ import {defineEventHandler} from "h3"; import {useRuntimeConfig} from "#imports"; +import {ExerciseMapperFrom} from "~/server/utils/mapper/ExerciseMapper"; +import type {IExercise} from "~/server/model/IExercise"; import type {ResponseBody} from "~/types/ResponseBody"; -import type {IExercise} from "~/repository/model/IExercise"; // TODO : TU des différents retours de l'api export default defineEventHandler(async (event) => { - const url = event.path.replace('/api/', ''); const config = useRuntimeConfig(event); const headers = new Headers(); headers.set('Content-Type', 'application/json'); headers.set('accept', '*/*'); - const res = await fetch(`${config.public.apiBase}/${url}`, { + const res = await fetch(`${config.public.apiBase}${event.path}`, { method: 'GET', headers: headers }) return { statusCode: res.status, - message: await res.json() - } as ResponseBody<IExercise[]>; + message: (await res.json() as IExercise[]).map((e) => ExerciseMapperFrom(e)) + } as ResponseBody<Exercise[]>; }) \ No newline at end of file diff --git a/server/api/exercise/.patch.ts b/server/routes/exercise/.patch.ts similarity index 79% rename from server/api/exercise/.patch.ts rename to server/routes/exercise/.patch.ts index 7ae8d21f05b35fad63adb0a3c81142ada4a5e3c7..fbe5b8f7aee5aa0bb1258d414e3c0ef359587e96 100644 --- a/server/api/exercise/.patch.ts +++ b/server/routes/exercise/.patch.ts @@ -1,11 +1,11 @@ import {defineEventHandler, readBody} from "h3"; import {useRuntimeConfig} from "#imports"; +import {ExerciseMapperFrom} from "~/server/utils/mapper/ExerciseMapper"; +import type {IExercise} from "~/server/model/IExercise"; import type {ResponseBody} from "~/types/ResponseBody"; -import type {IExercise} from "~/repository/model/IExercise"; // TODO : TU des différents retours de l'api export default defineEventHandler(async (event) => { - const url = event.path.replace('/api/', ''); const config = useRuntimeConfig(event); const headers = new Headers(); @@ -13,7 +13,7 @@ export default defineEventHandler(async (event) => { headers.set('accept', '*/*'); headers.set('Cookie', event.headers.get('Cookie') as string); - const res = await fetch(`${config.public.apiBase}/${url}`, { + const res = await fetch(`${config.public.apiBase}${event.path}`, { method: 'PATCH', headers: headers, body: ExerciseToPostBody(await readBody(event)) @@ -22,8 +22,8 @@ export default defineEventHandler(async (event) => { if(res.ok) { return { statusCode: res.status, - message: await res.json() as IExercise - } as ResponseBody<IExercise> + message: ExerciseMapperFrom(await res.json() as IExercise) + } as ResponseBody<Exercise> } else { return await res.json() as ResponseBody<string> } diff --git a/server/api/exercise/.post.ts b/server/routes/exercise/.post.ts similarity index 79% rename from server/api/exercise/.post.ts rename to server/routes/exercise/.post.ts index 2dc97621310782244e69e52a93b269b120d07032..8874e8a12bcea3625300f5c204c80b2b91bfc159 100644 --- a/server/api/exercise/.post.ts +++ b/server/routes/exercise/.post.ts @@ -1,12 +1,12 @@ import {defineEventHandler, readBody} from "h3"; import {useRuntimeConfig} from "#imports"; -import type {ResponseBody} from "~/types/ResponseBody"; +import {ExerciseMapperFrom} from "~/server/utils/mapper/ExerciseMapper"; import type {Exercise} from "~/types/Exercise"; -import type {IExercise} from "~/repository/model/IExercise"; +import type {IExercise} from "~/server/model/IExercise"; +import type {ResponseBody} from "~/types/ResponseBody"; // TODO : TU des différents retours de l'api export default defineEventHandler(async (event) => { - const url = event.path.replace('/api/', ''); const config = useRuntimeConfig(event); const headers = new Headers(); @@ -14,7 +14,7 @@ export default defineEventHandler(async (event) => { headers.set('accept', '*/*'); headers.set('Cookie', event.headers.get('Cookie') as string); - const res = await fetch(`${config.public.apiBase}/${url}`, { + const res = await fetch(`${config.public.apiBase}${event.path}`, { method: 'POST', headers: headers, body: ExerciseToPostBody(await readBody(event)) @@ -23,8 +23,8 @@ export default defineEventHandler(async (event) => { if(res.ok) { return { statusCode: res.status, - message: await res.json() as IExercise - } as ResponseBody<IExercise> + message: ExerciseMapperFrom(await res.json() as IExercise) + } as ResponseBody<Exercise> } else { return await res.json() as ResponseBody<string> } diff --git a/server/api/exercise/fetch-sub-categories.get.ts b/server/routes/exercise/fetch-sub-categories.get.ts similarity index 79% rename from server/api/exercise/fetch-sub-categories.get.ts rename to server/routes/exercise/fetch-sub-categories.get.ts index 892e83b3d055f53b6b579133a983d5e343a2133c..725df11a311c83bcc08684473335ea5cbcf37d2e 100644 --- a/server/api/exercise/fetch-sub-categories.get.ts +++ b/server/routes/exercise/fetch-sub-categories.get.ts @@ -1,16 +1,15 @@ import {defineEventHandler} from "h3"; import {useRuntimeConfig} from "#imports"; -import type {ResponseBody} from "~/types/ResponseBody"; +import type {ResponseBody} from "../../../types/ResponseBody"; export default defineEventHandler(async (event) => { - const url = event.path.replace('/api/', ''); const config = useRuntimeConfig(event); const headers = new Headers(); headers.set('Content-Type', 'application/json'); headers.set('accept', '*/*'); - const res = await fetch(`${config.public.apiBase}/${url}`, { + const res = await fetch(`${config.public.apiBase}${event.path}`, { method: 'GET', headers: headers }) diff --git a/server/routes/step/fetch-in-area.post.ts b/server/routes/step/fetch-in-area.post.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad382bd5163c72c4253fecc5811ae98aa927dfdd --- /dev/null +++ b/server/routes/step/fetch-in-area.post.ts @@ -0,0 +1,31 @@ +import {defineEventHandler, readBody} from "h3"; +import {useRuntimeConfig} from "#imports"; +import {StepMapperFrom} from "../../utils/mapper/StepMapper"; +import type {IStep} from "../../model/IStep"; +import type {ResponseBody} from "../../../types/ResponseBody"; +import type {Step} from "../../../types/Step"; + +// TODO : TU des différents retours de l'api +export default defineEventHandler(async (event) => { + const config = useRuntimeConfig(event); + + const headers = new Headers(); + headers.set('Content-Type', 'application/json'); + headers.set('accept', '*/*'); + headers.set('Cookie', event.headers.get('Cookie') as string); + + const res = await fetch(`${config.public.apiBase}${event.path}`, { + method: 'POST', + headers: headers, + body: JSON.stringify(await readBody(event)) + }) + + if(res.ok) { + return { + statusCode: res.status, + message: (await res.json() as IStep[]).map((s) => StepMapperFrom(s)) + } as ResponseBody<Step[]> + } else { + return await res.json() as ResponseBody<string> + } +}) \ No newline at end of file diff --git a/utils/mapper/ExerciseMapper.test.ts b/server/utils/mapper/ExerciseMapper.test.ts similarity index 93% rename from utils/mapper/ExerciseMapper.test.ts rename to server/utils/mapper/ExerciseMapper.test.ts index c6bb06bbc91bcb26974b40b03504acbda59f90fd..60d1e6a58290ae15536fe0bedd118c2675e75a71 100644 --- a/utils/mapper/ExerciseMapper.test.ts +++ b/server/utils/mapper/ExerciseMapper.test.ts @@ -1,6 +1,8 @@ import {expect, test} from 'vitest' import {ExerciseMapperFrom, ExerciseMapperTo} from './ExerciseMapper' -import type {IExercise} from "~/repository/model/IExercise"; +import {ExerciseCategory} from "../../../types/enum/ExerciseCategory"; +import type {Exercise} from "../../../types/Exercise"; +import type {IExercise} from "../../model/IExercise"; const iExercise: IExercise = { id: 1, diff --git a/utils/mapper/ExerciseMapper.ts b/server/utils/mapper/ExerciseMapper.ts similarity index 75% rename from utils/mapper/ExerciseMapper.ts rename to server/utils/mapper/ExerciseMapper.ts index 3da9e52552e5e2cbc56e6b0a7abfdd11003b8c8d..cdf02a5c56c1f8b1a5f5dad50300052fc95d02fb 100644 --- a/utils/mapper/ExerciseMapper.ts +++ b/server/utils/mapper/ExerciseMapper.ts @@ -1,5 +1,7 @@ -import type {Exercise} from "~/types/Exercise"; -import type {IExercise} from "~/repository/model/IExercise"; +import type {Exercise} from "../../../types/Exercise"; +import type {ExerciseCategory} from "../../../types/enum/ExerciseCategory"; +import type {ExerciseSubCategory} from "../../../types/enum/ExerciseSubCategory"; +import type {IExercise} from "../../model/IExercise"; export function ExerciseMapperFrom(iExercise: IExercise): Exercise { return { @@ -10,7 +12,7 @@ export function ExerciseMapperFrom(iExercise: IExercise): Exercise { generalInstructions: iExercise.generalInstructions, diagram: iExercise.diagram, video: iExercise.video, - category: iExercise.category.name as ExerciseCategory, + category: iExercise.category?.name as ExerciseCategory, subCategory: iExercise.subCategory?.name as ExerciseSubCategory, selected: false } diff --git a/server/utils/mapper/StepMapper.test.ts b/server/utils/mapper/StepMapper.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a1036497ecfaa6fc7feb146456e326395e689d8 --- /dev/null +++ b/server/utils/mapper/StepMapper.test.ts @@ -0,0 +1,62 @@ +import {expect, test, describe} from 'vitest' +import {StepMapperFrom, StepMapperTo} from "./StepMapper"; +import type {IStep} from "../../model/IStep"; +import type {Step} from "../../../types/Step"; + +const iStep: IStep = { + id: 0, + latitude: 0, + longitude: 0, + radius: 0, + specificExercise: [], + terrainType: { + id: 0, + name: 'name', + description: 'description', + genericExercises: [] + } +} + +const step: Step = { + id: 0, + latitude: 0, + longitude: 0, + radius: 0, + specificExercises: [], + terrainType: { + id: 0, + name: 'name', + description: 'description', + genericExercises: [] + } +} + +describe.todo('unimplemented suite') +// StepMapperFrom +test('StepMapperFrom', () => { + const mappedStep = StepMapperFrom(iStep) + + expect(mappedStep).toStrictEqual(step) +}) + +// StepMapperTo +test('StepMapperTo', () => { + const mappedIStep = StepMapperTo(step) + + expect(mappedIStep).toStrictEqual(iStep) +}) + +// StepMapperFlipFlop +test('StepMapperFlipFlop', () => { + const mappedIStep = StepMapperTo(StepMapperFrom(iStep)) + const mappedStep = StepMapperFrom(StepMapperTo(step)) + + expect(mappedIStep).toStrictEqual(iStep) + expect(mappedStep).toStrictEqual(step) +}) + +// StepMapperFromNull, should throw an error +test('StepMapperNull', () => { + expect(() => StepMapperFrom(null)).toThrow(TypeError) + expect(() => StepMapperTo(null)).toThrow(TypeError) +}) \ No newline at end of file diff --git a/server/utils/mapper/StepMapper.ts b/server/utils/mapper/StepMapper.ts new file mode 100644 index 0000000000000000000000000000000000000000..0a5c44adf480031e1a1e57a1fa697cdc1bb80265 --- /dev/null +++ b/server/utils/mapper/StepMapper.ts @@ -0,0 +1,55 @@ +import {ExerciseMapperFrom, ExerciseMapperTo} from "./ExerciseMapper"; +import type {IStep} from "../../model/IStep"; +import type {Step} from "../../../types/Step"; + +export function StepMapperFrom(iStep: IStep): Step { + return { + id: iStep.id, + latitude: iStep.latitude, + longitude: iStep.longitude, + radius: iStep.radius, + specificExercises: iStep.specificExercise.map((se) => { + return { + ...ExerciseMapperFrom(se.exercise), + type: 'specific' + } + }), + terrainType: { + id: iStep.terrainType.id, + name: iStep.terrainType.name, + description: iStep.terrainType.description, + genericExercises: iStep.terrainType.genericExercises.map((ge) => { + return { + ...ExerciseMapperFrom(ge.exercise), + type: 'generic ' + iStep.terrainType.name + } + }) + } + } +} + +export function StepMapperTo(step: Step): IStep { + return { + id: step.id, + latitude: step.latitude, + longitude: step.longitude, + radius: step.radius, + specificExercise: step.specificExercises.map((se) => { + return { + id: se.id, + exercise: ExerciseMapperTo(se.exercise) + } + }), + terrainType: { + id: step.terrainType.id, + name: step.terrainType.name, + description: step.terrainType.description, + genericExercises: step.terrainType.genericExercises.map((ge) => { + return { + id: ge.id, + exercise: ExerciseMapperTo(ge.exercise) + } + }) + } + } +} diff --git a/utils/mapper/UserMapper.test.ts b/server/utils/mapper/UserMapper.test.ts similarity index 100% rename from utils/mapper/UserMapper.test.ts rename to server/utils/mapper/UserMapper.test.ts diff --git a/utils/mapper/UserMapper.ts b/server/utils/mapper/UserMapper.ts similarity index 100% rename from utils/mapper/UserMapper.ts rename to server/utils/mapper/UserMapper.ts diff --git a/types/Exercise.ts b/types/Exercise.ts index d6d3be0245543e8da2115b05c9dcad344ffd7817..8cf060dad54f664da5abb478fa1c7a73cf3eda81 100644 --- a/types/Exercise.ts +++ b/types/Exercise.ts @@ -10,9 +10,8 @@ export type Exercise = { generalInstructions?: string; diagram?: string; video?: string; - // FIXME: to remove - lat?: number; - lng?: number; + + type?: string; selected?: boolean; }; diff --git a/types/Step.ts b/types/Step.ts new file mode 100644 index 0000000000000000000000000000000000000000..829ac2e153d10177de4a7fc949f3f857c6956b0a --- /dev/null +++ b/types/Step.ts @@ -0,0 +1,15 @@ +export type TerrainType = { + id: number; + name: string; + description: string; + genericExercises: Exercise[]; +} + +export type Step = { + id: number; + latitude: number; + longitude: number; + radius: number; + specificExercises: Exercise[]; + terrainType: TerrainType; +}